C:\Documents and Settings\Administrator\Desktop\x>ex_pe_xor.py bad.bin * Encoded PE Found, Key 0x21, Offset 0x0 * exe found at offset 0x0 C:\Documents and Settings\Administrator\Desktop\x>dir 04/30/2014 08:36 PM <DIR> . 04/30/2014 08:36 PM <DIR> .. 04/30/2014 08:36 PM 24,576 1.exe <- carved 04/30/2014 05:44 PM 24,576 bad.bin 04/30/2014 08:06 PM 3,526 ex_pe_xor.py
Pefile must be installed.
## detects single byte xor encoding by searching for the ## encoded MZ, lfanew and PE, then XORs the data and ## uses pefile to extract the decoded executable. ## written quickly/poorly by alexander hanel import sys import struct import pefile import re from StringIO import StringIO def get_xor(): # read file into a bytearray byte = bytearray(open(sys.argv[1], 'rb').read()) # for each byte in the file stream, excluding the last 256 bytes for i in range(0, len(byte) - 256): # KEY ^ VALUE ^ KEY = VALUE; Simple way to get the key key = byte[i] ^ ord('M') # verify the two bytes contain 'M' & 'Z' if chr(byte[i] ^ key) == 'M' and chr(byte[i+1] ^ key) == 'Z': # skip non-XOR encoded MZ if key == 0: continue # read four bytes into temp, offset to PE aka lfanew temp = byte[(i + 0x3c) : (i + 0x3c + 4)] # decode values with key lfanew = [] for x in temp: lfanew.append( x ^ key) # convert from bytearray to int value, probably a better way to do this pe_offset = struct.unpack( '<i', str(bytearray(lfanew)))[0] # verify results are not negative or read is bigger than file if pe_offset < 0 or pe_offset > len(byte): continue # verify the two decoded bytes are 'P' & 'E' if byte[pe_offset + i ] ^ key == ord('P') and byte[pe_offset + 1 + i] ^ key == ord('E'): print " * Encoded PE Found, Key 0x%x, Offset 0x%x" % (key, i) return (key, i) return (None, None) def getExt(pe): if pe.is_dll() == True: return 'dll' if pe.is_driver() == True: return 'sys' if pe.is_exe() == True: return 'exe' else: return 'bin' def writeFile(count, ext, pe): try: out = open(str(count)+ '.' + ext, 'wb') except: print '\t[FILE ERROR] could not write file' sys.exit() # remove overlay or junk in the trunk out.write(pe.trim()) out.close() def xor_data(key, offset): byte = bytearray(open(sys.argv[1], 'rb').read()) temp = '' for x in byte: temp += chr(x ^ key) return temp def carve(fileH): if type(fileH) is str: fileH = StringIO(fileH) c = 1 # For each address that contains MZ for y in [tmp.start() for tmp in re.finditer('\x4d\x5a', fileH.read())]: fileH.seek(y) try: pe = pefile.PE(data=fileH.read()) except: continue # determine file ext ext = getExt(pe) print ' *', ext , 'found at offset', hex(y) writeFile(c,ext,pe) c += 1 ext = '' fileH.seek(0) pe.close def run(): if len(sys.argv) < 2: print "Usage: ex_pe_xor.py <xored_data>" return key, offset = get_xor() if key == None: return data = xor_data(key, offset) carve(data) run()
No comments:
Post a Comment