def test_rebuild(e): bin = str(e) if bin != raw: print("ERROR: PE file is not reconstructed identical") f = pe_init.PE(bin) bin2 = str(f) if bin != bin2: print("ERROR: PE does not even have a fixpoint")
def parse(self, data, vm=None): # Parse signature if not data.startswith('MZ'): raise ContainerSignatureException() # Build executable instance try: if vm is not None: self._executable = vm_load_pe(vm, filename) else: self._executable = pe_init.PE(data) except Exception, error: raise ContainerParsingException('Cannot read PE: %s' % error)
def parse(self, data, vm=None): from miasm2.jitter.loader.pe import vm_load_pe, guess_arch from elfesteem import pe_init # Parse signature if not data.startswith('MZ'): raise ContainerSignatureException() # Build executable instance try: if vm is not None: self._executable = vm_load_pe(vm, data) else: self._executable = pe_init.PE(data) except Exception, error: raise ContainerParsingException('Cannot read PE: %s' % error)
def extract_section(data, section=False): # Extract text sections from know containers # elfesteem has to be installed try: import elfesteem except ImportError: return data magic = (0x7f, 0x45, 0x4c, 0x46) if data.startswith(struct.pack("%dB" % len(magic), *magic)): from elfesteem import elf_init e = elf_init.ELF(data) res = struct.pack("") for sh in e.sh: if (section == 'text' and sh.sh.name.startswith('.text') ) or sh.sh.name == section: res += data[sh.sh.offset:sh.sh.offset + sh.sh.size] if len(res): return res magic = (0x4d, 0x5a) if data.startswith(struct.pack("%dB" % len(magic), *magic)): if section == 'text': section = '.text' from elfesteem import pe_init e = pe_init.PE(data) for sh in e.SHList: if sh.name.strip('\0') == section: return data[sh.offset:sh.offset + sh.rawsize] magic = ((0xce, 0xfa, 0xed, 0xfe), (0xcf, 0xfa, 0xed, 0xfe)) if data.startswith(tuple([struct.pack("4B", *_) for _ in magic])): if section == 'text': section = '__TEXT' from elfesteem import macho_init e = macho_init.MACHO(data, parseSymbols=False) for s in e.sect.sect: if s.sh.segname == section: return data[s.sh.offset:s.sh.offset + s.sh.size] try: from elfesteem import pe_init, pe e = pe_init.Coff(data) if section == 'text': section = '.text' for sh in e.SHList: if sh.name.strip('\0') == section: return data[sh.offset:sh.offset + sh.rawsize] except ValueError: pass return data
parser.add_argument('file', nargs='+', help='ELF file(s)') args = parser.parse_args() if args.options == None: args.options = [] for file in args.file: if len(args.file) > 1: print("\nFile: %s" % file) raw = open(file, 'rb').read() if raw[:2] in ( # MZ magic for DOS executable, normally for all PE/COFF files struct.pack("2B", 0x4d, 0x5a), # HR magic found in bochsys.dll from IDA struct.pack("2B", 0x48, 0x52), ): e = pe_init.PE(raw) if e.NTsig.signature != 0x4550: print('Not a valid PE') continue else: try: e = pe_init.Coff(raw) except ValueError: print('Not a valid COFF') continue #test_rebuild(e) if 'headers' in args.options: print_petype(e) if 'sections' in args.options: print_sections(e) if 'symtab' in args.options:
machine = Machine(args.architecture) try: attrib = machine.dis_engine.attrib size = int(attrib) except AttributeError: attrib = None size = 32 except ValueError: size = 32 reg_and_id = dict(machine.mn.regs.all_regs_ids_byname) base_expr = machine.base_expr dst_interval = None # Output format if args.PE: pe = pe_init.PE(wsize=size) s_text = pe.SHList.add_section(name="text", addr=0x1000, rawsize=0x1000) s_iat = pe.SHList.add_section(name="iat", rawsize=0x100) new_dll = [({ "name": "USER32.dll", "firstthunk": s_iat.addr }, ["MessageBoxA"])] pe.DirImport.add_dlldesc(new_dll) s_myimp = pe.SHList.add_section(name="myimp", rawsize=len(pe.DirImport)) pe.DirImport.set_rva(s_myimp.addr) pe.Opthdr.AddressOfEntryPoint = s_text.addr addr_main = pe.rva2virt(s_text.addr) virt = pe.virt output = pe dst_interval = interval([(pe.rva2virt(s_text.addr),
def dump_and_rebuild(pid, oep, newimpdir="newimpdir", newiat="newiat"): '''Dump process and rebuild with new original entry point. @param pid: process ID @param oep: original entry point @param newimpdir: name for new section that will contain imports @param newiat: name for new section that will contain new IAT ''' System.request_debug_privileges() process = Process( pid ) try: process.suspend() except WindowsError as e: pass file_path = process.get_filename() file_name = p_os.path.basename(file_path) ####################################################################### # # REBUILD THE DUMPED PE # # I'm sure there is a better way to do this because all we are really # doing is dumping the PE mapped sections. Suggestions welcome! # # The crazy way we do this is to get a memory map of the whole process # then find the pages that are owned by the file that spawned the process. # ####################################################################### mem_map = get_mem_map(process) temp_data_arr = {} for page in mem_map: if file_name.upper() in page["Owner"].upper(): dump_data = process.peek(page["BaseAddress"],page["RegionSize"]) temp_data_arr[page["BaseAddress"]] = dump_data # we need to work with the dump as one contiguous data block in "mapped" format. ordered_mem = temp_data_arr.keys() ordered_mem.sort() block_data = temp_data_arr[ordered_mem[0]] for addr_ptr in range(1,len(ordered_mem)): padding_len = ordered_mem[addr_ptr] - (ordered_mem[0] + len(block_data)) #print "Padding: %d" % padding_len # These should be contiguous pages so there should be no need for padding! block_data += temp_data_arr[ordered_mem[addr_ptr]] + '\x00'*padding_len # The lowest mapped section is the base address base_address = ordered_mem[0] # Elfesteem has a small issue with the way it loads mapped PE files # instead of using the virtual size for segments it uses the raw size # this messes up unpacker dumps so we will fix it manually. pf = pe_init.PE(loadfrommem=True, pestr=block_data) new_sections = [] for tmp_section in pf.SHList: new_sections.append({"name": tmp_section.name ,"offset": tmp_section.addr ,"size": tmp_section.size ,"addr": tmp_section.addr ,"flags": tmp_section.flags ,"rawsize": tmp_section.size}) # Remove existing sections pf.SHList.shlist=[] for tmp_section in new_sections: pf.SHList.add_section(name=tmp_section["name"], data=block_data[tmp_section["offset"]:tmp_section["offset"] + tmp_section["rawsize"]], size=tmp_section["size"], addr=tmp_section["addr"], offset=tmp_section["offset"], rawsize=tmp_section["rawsize"]) pf.NThdr.ImageBase = base_address pf.Opthdr.AddressOfEntryPoint = oep # Disable rebase, since addresses are absolute any rebase will make this explode pf.NThdr.dllcharacteristics = 0x0 ####################################################################### # # At this point pf contains a fully reconstructed PE but with a # broken IAT. Fix the IAT! # ####################################################################### return rebuild_iat(pid, str(pf), base_address, oep, newimpdir=newimpdir, newiat=newiat, loadfrommem=False)
def rebuild_iat(pid, pe_data, base_address, oep, newimpdir="newimpdir", newiat="newiat", loadfrommem=True): """Rebuild the import address table for the pe_data that was passed. @param pid: process ID for winappdbg to attach to and dump IAT offsets @param pe_data: full PE file read in as a binary string @param base_address: base address of PE (this override the base addres set in the pe_data) @param oep: original entry point of the PE (this override the base addres set in the pe_data) @param newimpdir: name for new section that will contain imports @param newiat: name for new section that will contain new IAT @param loadfrommem: pe data is mapped or unmapped (default mapped) """ pf = pe_init.PE(loadfrommem=loadfrommem, pestr=pe_data) pf.NThdr.ImageBase = base_address # get offset to oep rva_oep = oep - base_address pf.Opthdr.AddressOfEntryPoint = rva_oep # clear the existing import table # there are two different versions of elfesteem one that uses an extra .l[] object # and one that does not. If we get the wrong one, just catch the error and continue. try: pf.DirImport.impdesc.l=[] except: pf.DirImport.impdesc =[] ###################################################################### pdata = None data_vr_addr = None data_rva = None # locate section that contains OEP for tmp_sec in pf.SHList: tmp_start = tmp_sec.addr tmp_end = tmp_start + tmp_sec.size if (rva_oep >= tmp_start) and (rva_oep <= tmp_end): try: pdata = pf._rva.get(tmp_start,tmp_end) except AttributeError as e: raise AttributeError("You are using the wrong version of elfesteem, don't use pip instead install from https://github.com/serpilliere/elfesteem") data_vr_addr = base_address + tmp_start data_rva = tmp_start break # make sure we have found the correct section # WARNING! if the pdata section is not the same as the one loaded in memory the IAT extraction will # fail because the addresses and offsets will be wrong. assert pdata != None, "Unable to locate rva_oep: 0x%x in sections: %s" % (rva_oep, pf.SHList) # find all call/jmp to possible IAT function pointers # iat_ptrs is a list of all the addresses that are potential IAT pointers iat_ptrs = call_scan(data_vr_addr, pdata, start_limit=base_address, end_limit=base_address+len(pe_data)) assert len(iat_ptrs) != 0, "Unable to find IAT pointer candidates in code!" imp_table = reslove_iat_pointers(pid, iat_ptrs) # Create a table with module names as the keys and all the functions assigned accordingly #[module]:[func1, func2, ...] mod_table = {} for iat_ptr in imp_table.keys(): # TODO: it is possbile some module names may end with somethin other than .dll tmp_mod = imp_table[iat_ptr][0]+".dll" tmp_fn = imp_table[iat_ptr][1] if tmp_mod in mod_table.keys(): f_arr = mod_table[tmp_mod] # Only add function name if it isn't already assigned if tmp_fn not in f_arr: f_arr.append(tmp_fn) mod_table[tmp_mod] = f_arr else: mod_table[tmp_mod] = [tmp_fn] newiat_rawsize = (( (len(imp_table.keys()) * 4 ) / 0x1000) + 1) * 0x1000 # Create new section to hold new IAT s_newiat = pf.SHList.add_section(name=newiat, rawsize=newiat_rawsize) ###################################################################### # # elfesteem.PE has a special format for describing the IAT directory # We are converting the mod_table into that format... # ###################################################################### new_dll=[({"name": mod_table.keys()[0],"firstthunk": s_newiat.addr}, mod_table[mod_table.keys()[0]])] for mod in mod_table.keys()[1:]: tmp_entry = ({"name": mod,"firstthunk": None}, mod_table[mod]) new_dll.append(tmp_entry) ###################################################################### # # Add the new imports table directory to PE file # ###################################################################### pf.DirImport.add_dlldesc(new_dll) newimpdir_rawsize = ((len(pf.DirImport) / 0x1000) + 1) * 0x1000 s_newimpdir = pf.SHList.add_section(name=newimpdir, rawsize=newimpdir_rawsize) pf.SHList.align_sections(0x1000, 0x1000) pf.DirImport.set_rva(s_newimpdir.addr) ###################################################################### # # Create a mapping from the old IAT pointers to the new ones # iat_map[ <old_pointer> ] = <new_pointer> # # TODO: handle import by ordinal # ###################################################################### iat_map ={} for iat_ptr in imp_table.keys(): if imp_table[iat_ptr][1] == None: continue tmp_mod = imp_table[iat_ptr][0]+".dll" tmp_fn = imp_table[iat_ptr][1] try: iat_map[iat_ptr] = pf.DirImport.get_funcvirt(tmp_mod, tmp_fn) except: continue # If there is some error building the module map stop! assert iat_map != {}, "The iat_map is empty, we are unable to find the new IAT pointers for the old pointers in imp_table." ###################################################################### # # Patch the code section in the PE and replace all references to the # old IAT pointers with references to the new pointers. # ###################################################################### # Make a copy of the code data to work on odata = pdata mode = distorm3.Decode32Bits for op in distorm3.DecomposeGenerator(data_vr_addr, pdata, mode): if not op.valid: continue iat_loc = None if _iat_candidate(op): for operand in op.operands: test_operand = operand.disp & 0xffffffff if test_operand in iat_map.keys(): #print "Fixing IAT pointer for: %s" % op #op_ptr = op.address - base_address #TODO: is this right?? op_ptr = op.address - data_vr_addr op_size = op.size orig_op = odata[op_ptr:op_ptr+op_size] orig_operand = struct.pack('<I',test_operand) new_operand = struct.pack('<I',iat_map[test_operand]) new_op = orig_op.replace(orig_operand, new_operand) odata = odata[:op_ptr] + new_op + odata[op_ptr+op_size:] #stop testing operands break # Copy the patched section back to the PE pf._rva.set(data_rva,odata) # Disable rebase, since addresses are absolute any rebase will make this explode pf.NThdr.dllcharacteristics = 0x0 return str(pf)
def create_modules_chain(jitter, name2module): """ Create the modules entries. Those modules are not linked in this function. kd> dt nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY +0x008 InMemoryOrderLinks : _LIST_ENTRY +0x010 InInitializationOrderLinks : _LIST_ENTRY +0x018 DllBase : Ptr32 Void +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void @jitter: jitter instance @name2module: dict containing association between name and its pe instance """ modules_info = LoadedModules() base_addr = LDR_AD + modules_list_offset # XXXX offset_name = 0x500 offset_path = 0x600 dummy_e = pe_init.PE() dummy_e.NThdr.ImageBase = 0 dummy_e.Opthdr.AddressOfEntryPoint = 0 dummy_e.NThdr.sizeofimage = 0 out = "" for i, (fname, pe_obj) in enumerate([("", dummy_e)] + name2module.items()): if pe_obj is None: log.warning("Unknown module: ommited from link list (%r)", fname) continue addr = base_addr + i * 0x1000 bpath = fname.replace('/', '\\') bname_str = os.path.split(fname)[1].lower() bname = "\x00".join(bname_str) + "\x00" log.info("Add module %x %r", pe_obj.NThdr.ImageBase, bname_str) modules_info.add(bname_str, pe_obj, addr) m_o = "" m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(pe_obj.NThdr.ImageBase) m_o += pck32(pe_obj.rva2virt(pe_obj.Opthdr.AddressOfEntryPoint)) m_o += pck32(pe_obj.NThdr.sizeofimage) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_path) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_name) jitter.vm.add_memory_page(addr, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += bname m_o += "\x00" * 3 jitter.vm.add_memory_page(addr + offset_name, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += "\x00".join(bpath) + "\x00" m_o += "\x00" * 3 jitter.vm.add_memory_page(addr + offset_path, PAGE_READ | PAGE_WRITE, m_o) return modules_info
def build_fake_InLoadOrderModuleList(modules_name): """ +0x000 Flink : Ptr32 -+ This distance +0x004 Blink : Ptr32 | is eight bytes +0x018 DllBase : Ptr32 Void -+ DllBase -> _IMAGE_DOS_HEADER +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void """ o = "" offset_name = 0x700 first_name = "\x00".join(main_pe_name + "\x00\x00") o = "" o += pck32(InLoadOrderModuleList_address) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000) o += pck32(InLoadOrderModuleList_address + 8) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000 + 8) o += pck32(InLoadOrderModuleList_address + 0x10) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000 + 0x10) if main_pe: o += pck32(main_pe.NThdr.ImageBase) o += pck32(main_pe.rva2virt(main_pe.Opthdr.AddressOfEntryPoint)) else: # no fixed values pass o += (0x24 - len(o)) * "A" o += struct.pack('HH', len(first_name), len(first_name)) o += pck32(InLoadOrderModuleList_address + offset_name) o += (0x2C - len(o)) * "A" o += struct.pack('HH', len(first_name), len(first_name)) o += pck32(InLoadOrderModuleList_address + offset_name) o += (offset_name - len(o)) * "B" o += first_name o += (0x1000 - len(o)) * "C" for i, m in enumerate(modules_name): # fname = os.path.join('win_dll', m) if isinstance(m, tuple): fname, e = m else: fname, e = m, None bname = os.path.split(fname)[1].lower() bname = "\x00".join(bname) + "\x00" print hex(InLoadOrderModuleList_address + i * 0x1000) if e is None: e = pe_init.PE(open(fname, 'rb').read()) print "add module", hex(e.NThdr.ImageBase), repr(bname) next_ad = InLoadOrderModuleList_address + (i + 1) * 0x1000 if i == len(modules_name) - 1: next_ad = InLoadOrderModuleList_address m_o = "" m_o += pck32(next_ad) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000) m_o += pck32(next_ad + 8) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000 + 8) m_o += pck32(next_ad + 0x10) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000 + 0x10) m_o += pck32(e.NThdr.ImageBase) m_o += pck32(e.rva2virt(e.Opthdr.AddressOfEntryPoint)) m_o += pck32(e.NThdr.sizeofimage) m_o += (0x24 - len(m_o)) * "A" print hex(len(bname)), repr(bname) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(InLoadOrderModuleList_address + i * 0x1000 + offset_name) m_o += (0x2C - len(m_o)) * "A" m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(InLoadOrderModuleList_address + i * 0x1000 + offset_name) m_o += (offset_name - len(m_o)) * "B" m_o += bname m_o += "\x00" * 3 m_o += (0x1000 - len(m_o)) * "J" print "module", "%.8X" % e.NThdr.ImageBase, fname o += m_o return o
def create_modules_chain(myjit, modules_name): modules_info = {} base_addr = LDR_AD + modules_list_offset # XXXX offset_name = 0x500 offset_path = 0x600 out = "" for i, m in enumerate([(main_pe_name, main_pe), ("", dummy_e)] + modules_name): addr = base_addr + i * 0x1000 # fname = os.path.join('win_dll', m) if isinstance(m, tuple): fname, e = m else: fname, e = m, None bpath = fname.replace('/', '\\') bname = os.path.split(fname)[1].lower() bname = "\x00".join(bname) + "\x00" # print "add module", repr(bname), repr(bpath) # print hex(InInitializationOrderModuleList_address+i*0x1000) if e is None: if i == 0: full_name = fname else: full_name = os.path.join("win_dll", fname) try: e = pe_init.PE(open(full_name, 'rb').read()) except IOError: log.error('no main pe, ldr data will be unconsistant!!') e = None if e is None: continue print "add module", hex(e.NThdr.ImageBase), repr(bname) modules_info[bname] = addr, e m_o = "" m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(e.NThdr.ImageBase) m_o += pck32(e.rva2virt(e.Opthdr.AddressOfEntryPoint)) m_o += pck32(e.NThdr.sizeofimage) m_o += (0x24 - len(m_o)) * "A" print hex(len(bname)), repr(bname) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_path) m_o += (0x2C - len(m_o)) * "A" m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_name) m_o += (offset_name - len(m_o)) * "B" m_o += bname m_o += "\x00" * 3 m_o += (offset_path - len(m_o)) * "B" m_o += "\x00".join(bpath) + "\x00" m_o += "\x00" * 3 # out += m_o myjit.vm.set_mem(addr, m_o) return modules_info
# m_o += pck32(InInitializationOrderModuleList_address # + i*0x1000+offset_name) # # m_o += (offset_name - len(m_o))*"B" # m_o += bname # m_o += "\x00"*3 # # # m_o += (0x1000 - len(m_o))*"J" # # print "module", "%.8X"%e.NThdr.ImageBase, fname # # o += m_o # return o # dummy_e = pe_init.PE() dummy_e.NThdr.ImageBase = 0 dummy_e.Opthdr.AddressOfEntryPoint = 0 dummy_e.NThdr.sizeofimage = 0 def create_modules_chain(myjit, modules_name): modules_info = {} base_addr = LDR_AD + modules_list_offset # XXXX offset_name = 0x500 offset_path = 0x600 out = "" for i, m in enumerate([(main_pe_name, main_pe), ("", dummy_e)] + modules_name): addr = base_addr + i * 0x1000
import sys from elfesteem import pe_init from miasm2.arch.x86.disasm import dis_x86_32 from miasm2.core.asmbloc import bloc2graph from miasm2.core.bin_stream import bin_stream_pe if len(sys.argv) != 3: print 'Example:' print "%s box_upx.exe 0x410f90" % sys.argv[0] sys.exit(0) fname = sys.argv[1] ad = int(sys.argv[2], 16) e = pe_init.PE(open(fname).read()) bs = bin_stream_pe(e.virt) mdis = dis_x86_32(bs) # inform the engine not to disasm nul instructions mdis.dont_dis_nulstart_bloc = True blocs = mdis.dis_multibloc(ad) g = bloc2graph(blocs) open('graph.txt', 'w').write(g)
import sys import argparse from elfesteem import pe_init if __name__ == '__main__': parser = argparse.ArgumentParser(description='Build a PE from a shellcode') parser.add_argument('SHELLCODE',help='Shellcode') args = parser.parse_args() # Get the shellcode with open(args.SHELLCODE, "rb") as f: data = f.read() # Generate a PE pe = pe_init.PE(wsize=32) # Add a ".text" section containing the shellcode to the PE s_text = pe.SHList.add_section(name=".text", addr=0x1000, data=data) # Set the entrypoint to the shellcode's address pe.Opthdr.AddressOfEntryPoint = s_text.addr # Write the PE to "sc_pe.py" open('sc_pe.exe', 'w').write(str(pe))