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

Code before:
            yield Characteristic("indirect call"), ih.address
        if OperandType.isIndirect(insn.getOperandType(0)):
            yield Characteristic("indirect call"), ih.address


def check_nzxor_security_cookie_delta(
    fh: ghidra.program.database.function.FunctionDB, insn: ghidra.program.database.code.InstructionDB
):
    """
    Get the first and last blocks of the function
    Check if insn within first addr of first bb + delta
    Check if insn within last addr of last bb - delta
    """

    model = SimpleBlockModel(currentProgram())  # type: ignore [name-defined] # noqa: F821
    insn_addr = insn.getAddress()
    func_asv = fh.getBody()
    first_addr = func_asv.getMinAddress()
    last_addr = func_asv.getMaxAddress()
    first_bb = model.getFirstCodeBlockContaining(first_addr, monitor())  # type: ignore [name-defined] # noqa: F821
    last_bb = model.getFirstCodeBlockContaining(last_addr, monitor())  # type: ignore [name-defined] # noqa: F821

    if insn_addr < first_addr.add(SECURITY_COOKIE_BYTES_DELTA) and first_bb.contains(insn_addr):
        return True
    if insn_addr > last_addr.add(SECURITY_COOKIE_BYTES_DELTA * -1) and last_bb.contains(insn_addr):
        return True

    return False


def extract_insn_nzxor_characteristic_features(
    fh: FunctionHandle,
    bb: BBHandle,
    ih: InsnHandle,
) -> Iterator[tuple[Feature, Address]]:
    f: ghidra.program.database.function.FunctionDB = fh.inner
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if "XOR" not in insn.getMnemonicString():
        return
    if capa.features.extractors.ghidra.helpers.is_stack_referenced(insn):
        return
    if capa.features.extractors.ghidra.helpers.is_zxor(insn):
        return
    if check_nzxor_security_cookie_delta(f, insn):
        return
    yield Characteristic("nzxor"), ih.address


def extract_features(
    fh: FunctionHandle,

Review comment (security):
We can save a few cycles here by moving the two _model.getFirstCodeBlockContaining_ calls to their respective conditionals, e.g.
```python
    if insn_addr < first_addr.add(SECURITY_COOKIE_BYTES_DELTA):
        first_bb = model.getFirstCodeBlockContaining(first_addr, monitor()) # type: ignore [name-defined] # noqa: F821
        if first_bb.contains(insn_addr):
            return True
```

With this change, we save on the expensive operation of calling _model.getFirstCodeBlockContaining_ by short-circuiting the logic using an arguably less expensive conditional.

Code after:
            yield Characteristic("indirect call"), ih.address
        if OperandType.isIndirect(insn.getOperandType(0)):
            yield Characteristic("indirect call"), ih.address


def check_nzxor_security_cookie_delta(
    fh: ghidra.program.database.function.FunctionDB, insn: ghidra.program.database.code.InstructionDB
):
    """
    Get the first and last blocks of the function
    Check if insn within first addr of first bb + delta
    Check if insn within last addr of last bb - delta
    """

    model = SimpleBlockModel(currentProgram())  # type: ignore [name-defined] # noqa: F821
    insn_addr = insn.getAddress()
    func_asv = fh.getBody()

    first_addr = func_asv.getMinAddress()
    if insn_addr < first_addr.add(SECURITY_COOKIE_BYTES_DELTA):
        first_bb = model.getFirstCodeBlockContaining(first_addr, monitor())  # type: ignore [name-defined] # noqa: F821
        if first_bb.contains(insn_addr):
            return True

    last_addr = func_asv.getMaxAddress()
    if insn_addr > last_addr.add(SECURITY_COOKIE_BYTES_DELTA * -1):
        last_bb = model.getFirstCodeBlockContaining(last_addr, monitor())  # type: ignore [name-defined] # noqa: F821
        if last_bb.contains(insn_addr):
            return True

    return False


def extract_insn_nzxor_characteristic_features(
    fh: FunctionHandle,
    bb: BBHandle,
    ih: InsnHandle,
) -> Iterator[tuple[Feature, Address]]:
    f: ghidra.program.database.function.FunctionDB = fh.inner
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if "XOR" not in insn.getMnemonicString():
        return
    if capa.features.extractors.ghidra.helpers.is_stack_referenced(insn):
        return
    if capa.features.extractors.ghidra.helpers.is_zxor(insn):
        return
    if check_nzxor_security_cookie_delta(f, insn):
        return
    yield Characteristic("nzxor"), ih.address