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

Code before:
                #
                #     add eax, 0x10
                #
                # assume 0x10 is also an offset (imagine eax is a pointer).
                yield Offset(const), addr
                yield OperandOffset(i, const), addr


def extract_insn_offset_features(fh: FunctionHandle, bb: BBHandle, ih: InsnHandle) -> Iterator[Tuple[Feature, Address]]:
    """
    parse instruction structure offset features

    example:
        .text:0040112F cmp [esi+4], ebx
    """
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if insn.getMnemonicString().startswith("LEA"):
        return

    if capa.features.extractors.ghidra.helpers.is_stack_referenced(insn):
        # ignore stack references
        return

    for i in range(insn.getNumOperands()):
        if insn.getOperandType(i) == OperandType.DYNAMIC:  # e.g. [esi + 4]
            # manual extraction, since the default api calls only work on the 1st dimension of the array
            op_objs = insn.getOpObjects(i)
            if not op_objs:
                continue

            if isinstance(op_objs[-1], ghidra.program.model.scalar.Scalar):
                op_off = op_objs[-1].getValue()
            else:
                op_off = 0

            yield Offset(op_off), ih.address
            yield OperandOffset(i, op_off), ih.address


def extract_insn_bytes_features(fh: FunctionHandle, bb: BBHandle, ih: InsnHandle) -> Iterator[Tuple[Feature, Address]]:
    """
    parse referenced byte sequences
    example:
        push    offset iid_004118d4_IShellLinkA ; riid
    """
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if capa.features.extractors.ghidra.helpers.is_call_or_jmp(insn):
        return


Review comment (suggestion):
```suggestion
    # Ghidra stores operands in 2D arrays if they contain offsets
    for i in range(insn.getNumOperands()):
```

Code after:
                #
                #     add eax, 0x10
                #
                # assume 0x10 is also an offset (imagine eax is a pointer).
                yield Offset(const), addr
                yield OperandOffset(i, const), addr


def extract_insn_offset_features(fh: FunctionHandle, bb: BBHandle, ih: InsnHandle) -> Iterator[Tuple[Feature, Address]]:
    """
    parse instruction structure offset features

    example:
        .text:0040112F cmp [esi+4], ebx
    """
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if insn.getMnemonicString().startswith("LEA"):
        return

    if capa.features.extractors.ghidra.helpers.is_stack_referenced(insn):
        # ignore stack references
        return

    # Ghidra stores operands in 2D arrays if they contain offsets
    for i in range(insn.getNumOperands()):
        if insn.getOperandType(i) == OperandType.DYNAMIC:  # e.g. [esi + 4]
            # manual extraction, since the default api calls only work on the 1st dimension of the array
            op_objs = insn.getOpObjects(i)
            if not op_objs:
                continue

            if isinstance(op_objs[-1], ghidra.program.model.scalar.Scalar):
                op_off = op_objs[-1].getValue()
            else:
                op_off = 0

            yield Offset(op_off), ih.address
            yield OperandOffset(i, op_off), ih.address


def extract_insn_bytes_features(fh: FunctionHandle, bb: BBHandle, ih: InsnHandle) -> Iterator[Tuple[Feature, Address]]:
    """
    parse referenced byte sequences
    example:
        push    offset iid_004118d4_IShellLinkA ; riid
    """
    insn: ghidra.program.database.code.InstructionDB = ih.inner

    if capa.features.extractors.ghidra.helpers.is_call_or_jmp(insn):
        return