def get_import_address_pe(e): """Compute the addresses of imported symbols. @e: pe object Returns a dict mapping from tuple (dll name string, symbol name string) to set of virtual addresses. Example: pe = miasm.analysis.binary.Container.from_string(buf) imports = miasm.jitter.loader.pe.get_import_address_pe(pe.executable) assert imports[('api-ms-win-core-rtlsupport-l1-1-0.dll', 'RtlCaptureStackBackTrace')] == {0x6b88a6d0} """ import2addr = defaultdict(set) if e.DirImport.impdesc is None: return import2addr for s in e.DirImport.impdesc: # fthunk = e.rva2virt(s.firstthunk) # l = "%2d %-25s %s" % (i, repr(s.dlldescname), repr(s)) libname = force_str(s.dlldescname.name.lower()) for ii, imp in enumerate(s.impbynames): if isinstance(imp, pe.ImportByName): funcname = force_str(imp.name) else: funcname = imp # l = " %2d %-16s" % (ii, repr(funcname)) import2addr[(libname, funcname)].add( e.rva2virt(s.firstthunk + (e._wsize * ii) // 8)) return import2addr
def get_export_name_addr_list(e): """Collect names and addresses of symbols exported by the given PE. @e: PE instance Returns a list of tuples (symbol name string, virtual address). Example: pe = miasm.analysis.binary.Container.from_string(buf) exports = miasm.jitter.loader.pe.get_export_name_addr_list(pe.executable) assert exports[0] == ('AcquireSRWLockExclusive', 0x6b89b22a) """ out = [] # add func name for i, n in enumerate(e.DirExport.f_names): addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] f_name = force_str(n.name.name) # log.debug('%s %s' % (f_name, hex(e.rva2virt(addr.rva)))) out.append((f_name, e.rva2virt(addr.rva))) # add func ordinal for i, o in enumerate(e.DirExport.f_nameordinals): addr = e.DirExport.f_address[o.ordinal] # log.debug('%s %s %s' % (o.ordinal, e.DirExport.expdesc.base, # hex(e.rva2virt(addr.rva)))) out.append( (o.ordinal + e.DirExport.expdesc.base, e.rva2virt(addr.rva))) for i, s in enumerate(e.DirExport.f_address): if not s.rva: continue out.append((i + e.DirExport.expdesc.base, e.rva2virt(s.rva))) return out
def is_redirected_export(pe_obj, addr): """Test if the @addr is a forwarded export address. If so, return dllname/function name couple. If not, return False. An export address is a forwarded export if the rva is in the export directory of the pe. @pe_obj: PE instance @addr: virtual address of the function to test """ export_dir = pe_obj.NThdr.optentries[pe.DIRECTORY_ENTRY_EXPORT] addr_rva = pe_obj.virt2rva(addr) if not (export_dir.rva <= addr_rva < export_dir.rva + export_dir.size): return False addr_end = pe_obj.virt.find(b'\x00', addr) data = pe_obj.virt.get(addr, addr_end) data = force_str(data) dllname, func_info = data.split('.', 1) dllname = dllname.lower() # Test if function is forwarded using ordinal if func_info.startswith('#'): func_info = int(func_info[1:]) return dllname, func_info
def get_pe_dependencies(pe_obj): """Return dependency set @pe_obj: pe object""" if pe_obj.DirImport.impdesc is None: return set() out = set() for dependency in pe_obj.DirImport.impdesc: libname = dependency.dlldescname.name.lower() # transform bytes to str libname = force_str(libname) out.add(libname) # If binary has redirected export, add dependencies if pe_obj.DirExport.expdesc != None: addrs = get_export_name_addr_list(pe_obj) for imp_ord_or_name, ad in addrs: # if export is a redirection, search redirected dll # and get function real addr ret = is_redirected_export(pe_obj, ad) if ret is False: continue dllname, func_info = ret dllname = dllname + '.dll' out.add(dllname) return out
def get_import_address_elf(e): import2addr = defaultdict(set) for sh in e.sh: if not hasattr(sh, 'rel'): continue for k, v in viewitems(sh.rel): k = force_str(k) import2addr[('xxx', k)].add(v.offset) return import2addr
def get_import_address_pe(e): import2addr = defaultdict(set) if e.DirImport.impdesc is None: return import2addr for s in e.DirImport.impdesc: # fthunk = e.rva2virt(s.firstthunk) # l = "%2d %-25s %s" % (i, repr(s.dlldescname), repr(s)) libname = force_str(s.dlldescname.name.lower()) for ii, imp in enumerate(s.impbynames): if isinstance(imp, pe.ImportByName): funcname = force_str(imp.name) else: funcname = imp # l = " %2d %-16s" % (ii, repr(funcname)) import2addr[(libname, funcname)].add( e.rva2virt(s.firstthunk + (e._wsize * ii) // 8)) return import2addr
def asm_ast_to_expr_with_size(arg, loc_db, size): if isinstance(arg, AstId): return ExprId(force_str(arg.name), size) if isinstance(arg, AstOp): args = [ asm_ast_to_expr_with_size(tmp, loc_db, size) for tmp in arg.args ] return ExprOp(arg.op, *args) if isinstance(arg, AstInt): return ExprInt(arg.value, size) return None
def preload_pe(vm, e, runtime_lib, patch_vm_imp=True): fa = get_import_address_pe(e) dyn_funcs = {} # log.debug('imported funcs: %s' % fa) for (libname, libfunc), ads in viewitems(fa): for ad in ads: libname = force_str(libname) ad_base_lib = runtime_lib.lib_get_add_base(libname) ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad) libname_s = canon_libname_libfunc(libname, libfunc) dyn_funcs[libname_s] = ad_libfunc if patch_vm_imp: vm.set_mem( ad, struct.pack(cstruct.size2type[e._wsize], ad_libfunc)) return dyn_funcs
def get_export_name_addr_list(e): out = [] # add func name for i, n in enumerate(e.DirExport.f_names): addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] f_name = force_str(n.name.name) # log.debug('%s %s' % (f_name, hex(e.rva2virt(addr.rva)))) out.append((f_name, e.rva2virt(addr.rva))) # add func ordinal for i, o in enumerate(e.DirExport.f_nameordinals): addr = e.DirExport.f_address[o.ordinal] # log.debug('%s %s %s' % (o.ordinal, e.DirExport.expdesc.base, # hex(e.rva2virt(addr.rva)))) out.append( (o.ordinal + e.DirExport.expdesc.base, e.rva2virt(addr.rva))) for i, s in enumerate(e.DirExport.f_address): if not s.rva: continue out.append((i + e.DirExport.expdesc.base, e.rva2virt(s.rva))) return out
def get_pe_dependencies(pe_obj): """Collect the shared libraries upon which this PE depends. @pe_obj: pe object Returns a set of strings of DLL names. Example: pe = miasm.analysis.binary.Container.from_string(buf) deps = miasm.jitter.loader.pe.get_pe_dependencies(pe.executable) assert sorted(deps)[0] == 'api-ms-win-core-appcompat-l1-1-0.dll' """ if pe_obj.DirImport.impdesc is None: return set() out = set() for dependency in pe_obj.DirImport.impdesc: libname = dependency.dlldescname.name.lower() # transform bytes to str libname = force_str(libname) out.add(libname) # If binary has redirected export, add dependencies if pe_obj.DirExport.expdesc != None: addrs = get_export_name_addr_list(pe_obj) for imp_ord_or_name, ad in addrs: # if export is a redirection, search redirected dll # and get function real addr ret = is_redirected_export(pe_obj, ad) if ret is False: continue dllname, func_info = ret dllname = dllname + '.dll' out.add(dllname) return out
def fill_loc_db_with_symbols(elf, loc_db, base_addr=0): """Parse the miasm.loader's ELF @elf to extract symbols, and fill the LocationDB instance @loc_db with parsed symbols. The ELF is considered mapped at @base_addr @elf: miasm.loader's ELF instance @loc_db: LocationDB used to retrieve symbols'offset @base_addr: addr to reloc to (if any) """ # Get symbol sections symbol_sections = [] for section_header in elf.sh: if hasattr(section_header, 'symbols'): for name, sym in viewitems(section_header.symbols): if not name or sym.value == 0: continue name = loc_db.find_free_name(force_str(name)) loc_db.add_location(name, sym.value, strict=False) if hasattr(section_header, 'reltab'): for rel in section_header.reltab: if not rel.sym or rel.offset == 0: continue name = loc_db.find_free_name(force_str(rel.sym)) loc_db.add_location(name, rel.offset, strict=False) if hasattr(section_header, 'symtab'): log.debug("Find %d symbols in %r", len(section_header.symtab), section_header) symbol_sections.append(section_header) elif isinstance( section_header, (elf_init.GNUVerDef, elf_init.GNUVerSym, elf_init.GNUVerNeed)): log.debug("Find GNU version related section, unsupported for now") for section in symbol_sections: for symbol_entry in section.symtab: # Here, the computation of vaddr assumes 'elf' is an executable or a # shared object file # For relocatable file, symbol_entry.value is an offset from the section # base -> not handled here st_bind = symbol_entry.info >> 4 st_type = symbol_entry.info & 0xF if st_type not in [ elf_csts.STT_NOTYPE, elf_csts.STT_OBJECT, elf_csts.STT_FUNC, elf_csts.STT_COMMON, elf_csts.STT_GNU_IFUNC, ]: # Ignore symbols useless in linking continue if st_bind == elf_csts.STB_GLOBAL: # Global symbol weak = False elif st_bind == elf_csts.STB_WEAK: # Weak symbol weak = True else: # Ignore local & others symbols continue absolute = False if symbol_entry.shndx == 0: # SHN_UNDEF continue elif symbol_entry.shndx == 0xfff1: # SHN_ABS absolute = True log.debug("Absolute symbol %r - %x", symbol_entry.name, symbol_entry.value) elif 0xff00 <= symbol_entry.shndx <= 0xffff: # Reserved index (between SHN_LORESERV and SHN_HIRESERVE) raise RuntimeError("Unsupported reserved index: %r" % symbol_entry) name = force_str(symbol_entry.name) if name == "": # Ignore empty symbol log.debug("Empty symbol %r", symbol_entry) continue if absolute: vaddr = symbol_entry.value else: vaddr = symbol_entry.value + base_addr # 'weak' information is only used to force global symbols for now already_existing_loc = loc_db.get_name_location(name) if already_existing_loc is not None: if weak: # Weak symbol, this is ok to already exists, skip it continue else: # Global symbol, force it loc_db.remove_location_name(already_existing_loc, name) already_existing_off = loc_db.get_offset_location(vaddr) if already_existing_off is not None: loc_db.add_location_name(already_existing_off, name) else: loc_db.add_location(name=name, offset=vaddr)