예제 #1
0
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
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
파일: elf.py 프로젝트: tly000/miasm
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
예제 #6
0
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
예제 #7
0
파일: parse_asm.py 프로젝트: tly000/miasm
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
예제 #8
0
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
예제 #9
0
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
예제 #10
0
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
예제 #11
0
파일: elf.py 프로젝트: tly000/miasm
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)