Repository: mandiant/capa
File: capa/features/extractors/ghidra/file.py (Python)

Code before:
        if seg_max.getOffset() < (peoff.getOffset() + 2):
            continue

        if getBytes(peoff, 2) == pex:
            yield off, i


def extract_file_embedded_pe() -> Iterator[Tuple[Feature, Address]]:
    """extract embedded PE features
    """
    for seg in currentProgram.getMemory().getBlocks():
        for ea, _ in check_segment_for_pe(seg):
            yield Characteristic("embedded pe"), FileOffsetAddress(ea)


def extract_file_export_names() -> Iterator[Tuple[Feature, Address]]:
    """extract function exports

    Exports in Ghidra:
        - namespace = Global
        - SourceType = IMPORTED
    """

    fm = currentProgram.getFunctionManager().getFunctions(True) # Only Global functions
    while fm.hasNext():
        f = fm.next().getSymbol()
        if (f.getSource() == SourceType.IMPORTED):
            yield Export(f.toString()), AbsoluteVirtualAddress(f.getAddress().getOffset())


def extract_file_import_names() -> Iterator[Tuple[Feature, Address]]:
    """extract function imports

    1. imports by ordinal:
     - modulename.#ordinal

    2. imports by name, results in two features to support importname-only
       matching:
     - modulename.importname
     - importname
    """

    fm = currentProgram.getFunctionManager().getExternalFunctions()
    while fm.hasNext():
        f = fm.next()
        addr = int(f.getEntryPoint().toString().split(':')[1], 16)  # format: EXTERNAL:<hex_addr>
        fstr = f.getName()  # format: 'importname' / 'Ordinal_*'
        if 'Ordinal_' in fstr:
            fstr = f"#{fstr.split('_')[1]}"
        yield Import(fstr), AbsoluteVirtualAddress(addr)


Review comment (suggestion):
We could possibly skip some indirection here by using `currentProgram.getSymbolTable().getExternalEntryPointIterator()` and `currentProgram.getSymbolTable().getPrimarySymbol(_addr_)`

https://ghidra.re/ghidra_docs/api/ghidra/program/model/symbol/SymbolTable.html#getExternalEntryPointIterator()
https://ghidra.re/ghidra_docs/api/ghidra/program/model/symbol/SymbolTable.html#getPrimarySymbol(ghidra.program.model.address.Address)

Code after:
        if seg_max.getOffset() < (peoff.getOffset() + 2):
            continue

        pe_bytes = capa.features.extractors.ghidra.helpers.get_bytes(peoff, 2)
        if pe_bytes == pex:
            yield off.getOffset(), i


def extract_file_embedded_pe() -> Iterator[Tuple[Feature, Address]]:
    """extract embedded PE features"""

    for ea, _ in check_segment_for_pe():
        yield Characteristic("embedded pe"), FileOffsetAddress(ea)


def extract_file_export_names() -> Iterator[Tuple[Feature, Address]]:
    """extract function exports"""
    st = currentProgram.getSymbolTable()
    for addr in st.getExternalEntryPointIterator():
        yield Export(st.getPrimarySymbol(addr).getName()), AbsoluteVirtualAddress(addr.getOffset())


def extract_file_import_names() -> Iterator[Tuple[Feature, Address]]:
    """extract function imports

    1. imports by ordinal:
     - modulename.#ordinal

    2. imports by name, results in two features to support importname-only
       matching:
     - modulename.importname
     - importname
    """

    for f in currentProgram.getFunctionManager().getExternalFunctions():
        for r in f.getSymbol().getReferences():
            if r.getReferenceType().isData():
                addr = r.getFromAddress().getOffset()  # gets pointer to fake external addr

        fstr = f.toString().split("::")  # format: MODULE.dll::import / MODULE::Ordinal_*
        if "Ordinal_" in fstr[1]:
            fstr[1] = f"#{fstr[1].split('_')[1]}"

        for name in capa.features.extractors.helpers.generate_symbols(fstr[0][:-4], fstr[1]):
            yield Import(name), AbsoluteVirtualAddress(addr)


def extract_file_section_names() -> Iterator[Tuple[Feature, Address]]:
    """extract section names"""

    for block in currentProgram.getMemory().getBlocks():