Repository: mandiant/capa
File: capa/features/extractors/viv/insn.py (Python)

Code before:
                # the symbol table gets stored as a function's attribute in order to avoid running
                # this code everytime the call is made, thus preventing the computational overhead.
                elf = f.vw.parsedbin
                endian = "<" if elf.getEndian() == 0 else ">"
                bitness = elf.bits

                SHT_SYMTAB = 0x2
                for section in elf.sections:
                    if section.vsGetField("sh_info") & SHT_SYMTAB != 0:
                        strtab = elf.sections[section.vsGetField("sh_link")]
                        sh_symtab = Shdr.from_viv(section, elf.getSectionBytes(section.name))
                        sh_strtab = Shdr.from_viv(strtab, elf.getSectionBytes(strtab.name))

                symtab = SymTab(endian, bitness, sh_symtab, sh_strtab)
                f.vw.metadata["SymbolTable"] = symtab

            symtab = f.vw.metadata["SymbolTable"]
            for symbol in symtab.get_symbols():
                sym_name = symtab.get_name(symbol)
                sym_value = symbol.value
                sym_info = symbol.info

                STT_FUNC = 0x2
                if sym_value == target and sym_info & STT_FUNC != 0:
                    yield API(sym_name), ih.address
                    yield FunctionName(sym_name), ih.address

        for _ in range(THUNK_CHAIN_DEPTH_DELTA):
            if target in imports:
                dll, symbol = imports[target]
                for name in capa.features.extractors.helpers.generate_symbols(dll, symbol):
                    yield API(name), ih.address

            # if jump leads to an ENDBRANCH instruction, skip it
            if f.vw.getByteDef(target)[1].startswith(b"\xf3\x0f\x1e"):
                target += 4

            target = capa.features.extractors.viv.helpers.get_coderef_from(f.vw, target)
            if not target:
                return

    # call via import on x64
    # see Lab21-01.exe_:0x14000118C
    elif isinstance(insn.opers[0], envi.archs.amd64.disasm.Amd64RipRelOper):
        op = insn.opers[0]
        target = op.getOperAddr(insn)

        imports = get_imports(f.vw)
        if target in imports:
            dll, symbol = imports[target]
            for name in capa.features.extractors.helpers.generate_symbols(dll, symbol):

Review comment (refactor):
the `FunctionName` feature should be extracted for the target address, not the caller address. `FunctionName` is used to describe a known name for a function, so that we can reference it in rules, like "look for this thing, as long as its not found in a memcpy implementation". 

probably this should be extracted in another function-scoped analysis pass in this file: https://github.com/mandiant/capa/blob/master/capa/features/extractors/viv/function.py

Code after:
                    sym_value = symbol.value
                    sym_info = symbol.info

                    STT_FUNC = 0x2
                    if sym_value == target and sym_info & STT_FUNC != 0:
                        yield API(sym_name), ih.address

        if viv_utils.flirt.is_library_function(f.vw, target):
            name = viv_utils.get_function_name(f.vw, target)
            yield API(name), ih.address
            if name.startswith("_"):
                # some linkers may prefix linked routines with a `_` to avoid name collisions.
                # extract features for both the mangled and un-mangled representations.
                # e.g. `_fwrite` -> `fwrite`
                # see: https://stackoverflow.com/a/2628384/87207
                yield API(name[1:]), ih.address
            return

        for _ in range(THUNK_CHAIN_DEPTH_DELTA):
            if target in imports:
                dll, symbol = imports[target]
                for name in capa.features.extractors.helpers.generate_symbols(dll, symbol):
                    yield API(name), ih.address

            # if jump leads to an ENDBRANCH instruction, skip it
            if f.vw.getByteDef(target)[1].startswith(b"\xf3\x0f\x1e"):
                target += 4

            target = capa.features.extractors.viv.helpers.get_coderef_from(f.vw, target)
            if not target:
                return

    # call via import on x64
    # see Lab21-01.exe_:0x14000118C
    elif isinstance(insn.opers[0], envi.archs.amd64.disasm.Amd64RipRelOper):
        op = insn.opers[0]
        target = op.getOperAddr(insn)

        imports = get_imports(f.vw)
        if target in imports:
            dll, symbol = imports[target]
            for name in capa.features.extractors.helpers.generate_symbols(dll, symbol):
                yield API(name), ih.address

    elif isinstance(insn.opers[0], envi.archs.i386.disasm.i386RegOper):
        try:
            (_, target) = resolve_indirect_call(f.vw, insn.va, insn=insn)
        except NotFoundError:
            # not able to resolve the indirect call, sorry
            return