diff options
| author | Brian Potchik <brian@vector35.com> | 2024-03-02 14:38:47 -0500 |
|---|---|---|
| committer | Brian Potchik <brian@vector35.com> | 2024-03-02 14:38:47 -0500 |
| commit | 2e3b9c925390cc8b1d72a41d0564bb2862d3dba2 (patch) | |
| tree | f40495cd494b8c157a0298259019873a624dc7e2 /python | |
| parent | ff2aa7435c3847f6969364f5d04d0943918429be (diff) | |
Add support for memory intrinsics.
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 24 | ||||
| -rw-r--r-- | python/lowlevelil.py | 75 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 67 |
3 files changed, 161 insertions, 5 deletions
diff --git a/python/architecture.py b/python/architecture.py index 677192e4..c979eacb 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -28,7 +28,7 @@ import binaryninja from . import _binaryninjacore as core from .enums import ( Endianness, ImplicitRegisterExtend, BranchType, LowLevelILFlagCondition, FlagRole, LowLevelILOperation, - InstructionTextTokenType, InstructionTextTokenContext + InstructionTextTokenType, InstructionTextTokenContext, IntrinsicClass ) from .log import log_error from . import lowlevelil @@ -300,6 +300,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__(self._get_register_stack_name) self._cb.getAllRegisterStacks = self._cb.getAllRegisterStacks.__class__(self._get_all_register_stacks) self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__(self._get_register_stack_info) + self._cb.getIntrinsicClass = self._cb.getIntrinsicClass.__class__(self._get_intrinsic_class) self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__(self._get_intrinsic_name) self._cb.getAllIntrinsics = self._cb.getAllIntrinsics.__class__(self._get_all_intrinsics) self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__(self._get_intrinsic_inputs) @@ -481,6 +482,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): self.system_regs = self.__class__.system_regs self._intrinsics: Dict[IntrinsicName, IntrinsicIndex] = {} + self._intrinsic_class_by_index: Dict[IntrinsicIndex, IntrinsicClass] = {} self._intrinsics_by_index: Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} intrinsic_index = IntrinsicIndex(0) for intrinsic in self.__class__.intrinsics.keys(): @@ -1125,6 +1127,11 @@ class Architecture(metaclass=_ArchitectureMetaClass): result[0].topRelativeCount = 0 result[0].stackTopReg = 0 + def _get_intrinsic_class(self, ctxt, intrinsic): + if intrinsic in self._intrinsic_class_by_index: + return self._intrinsic_class_by_index[intrinsic] + return IntrinsicClass.GeneralIntrinsicClass + def _get_intrinsic_name(self, ctxt, intrinsic): try: if intrinsic in self._intrinsics_by_index: @@ -1549,6 +1556,16 @@ class Architecture(metaclass=_ArchitectureMetaClass): raise ValueError("argument 'group_index' must be an integer") return self._semantic_flag_groups_by_index[group_index] + def get_intrinsic_class(self, intrinsic: IntrinsicIndex) -> IntrinsicClass: + """ + ``get_intrinsic_class`` gets the intrinsic class from an intrinsic number. + + :param int intrinsic: intrinsic number + :return: intrinsic class + :rtype: IntrinsicClass + """ + return IntrinsicClass(core.BNGetArchitectureIntrinsicClass(self.handle, intrinsic)) + def get_intrinsic_name(self, intrinsic: IntrinsicIndex) -> IntrinsicName: """ ``get_intrinsic_name`` gets an intrinsic name from an intrinsic number. @@ -2261,9 +2278,11 @@ class CoreArchitecture(Architecture): intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) assert intrinsics is not None, "core.BNGetAllArchitectureIntrinsics returned None" self._intrinsics: Dict[IntrinsicName, IntrinsicIndex] = {} + self._intrinsic_class_by_index: Dict[IntrinsicIndex, IntrinsicClass] = {} self._intrinsics_by_index: Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} self._intrinsics_info: Dict[IntrinsicName, IntrinsicInfo] = {} for i in range(count.value): + intrinsic_class = IntrinsicClass(core.BNGetArchitectureIntrinsicClass(self.handle, intrinsics[i])) name = IntrinsicName(core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i])) input_count = ctypes.c_ulonglong() inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) @@ -2285,6 +2304,8 @@ class CoreArchitecture(Architecture): types.Type.create(core.BNNewTypeReference(outputs[j].type), confidence=outputs[j].confidence) ) core.BNFreeOutputTypeList(outputs, output_count.value) + if intrinsic_class is not IntrinsicClass.GeneralIntrinsicClass: + self._intrinsic_class_by_index[intrinsics[i]] = intrinsic_class self._intrinsics_info[name] = IntrinsicInfo(input_list, output_list) self._intrinsics[name] = intrinsics[i] self._intrinsics_by_index[intrinsics[i]] = (name, self._intrinsics_info[name]) @@ -2719,6 +2740,7 @@ class ArchitectureHook(CoreArchitecture): self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__() self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__() if len(self.__class__.intrinsics) == 0: + self._cb.getIntrinsicClass = self._cb.getIntrinsicClass.__class__() self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__() self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__() self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__() diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 9b2bd4ae..590cae83 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -385,6 +385,10 @@ class LowLevelILInstruction(BaseILInstruction): ("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr") ], LowLevelILOperation.LLIL_INTRINSIC_SSA: [ ("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr") + ], LowLevelILOperation.LLIL_MEMORY_INTRINSIC_OUTPUT_SSA: [ + ("dest_memory", "int"), ("output", "reg_ssa_list") + ], LowLevelILOperation.LLIL_MEMORY_INTRINSIC_SSA: [ + ("output", "expr"), ("intrinsic", "intrinsic"), ("params", "expr_list"), ("src_memory", "int") ], LowLevelILOperation.LLIL_BP: [], LowLevelILOperation.LLIL_TRAP: [("vector", "int")], LowLevelILOperation.LLIL_UNDEF: [], LowLevelILOperation.LLIL_UNIMPL: [], LowLevelILOperation.LLIL_UNIMPL_MEM: [ ("src", "expr") @@ -550,7 +554,7 @@ class LowLevelILInstruction(BaseILInstruction): def tokens(self) -> TokenList: """LLIL tokens (read-only)""" # special case for those instructions that don't have tokens - if isinstance(self, (LowLevelILCallOutputSsa, LowLevelILCallParam, LowLevelILCallStackSsa)): + if isinstance(self, (LowLevelILCallOutputSsa, LowLevelILCallParam, LowLevelILCallStackSsa, LowLevelILMemoryIntrinsicOutputSsa)): return [] count = ctypes.c_ulonglong() @@ -2625,6 +2629,71 @@ class LowLevelILIntrinsicSsa(LowLevelILInstruction, SSA): @dataclass(frozen=True, repr=False, eq=False) +class LowLevelILMemoryIntrinsicOutputSsa(LowLevelILInstruction, SSA): + def __repr__(self): + return f"<LowLevelILMemoryIntrinsicOutputSsa: {self.dest_memory} {self.output}>" + + @property + def dest_memory(self) -> int: + return self._get_int(0) + + @property + def output(self) -> List[SSARegisterOrFlag]: + return self._get_reg_or_flag_ssa_list(1) + + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("dest_memory", self.dest_memory, "int"), + ("output", self.output, "List[SSARegisterOrFlag]"), + ] + + +@dataclass(frozen=True, repr=False, eq=False) +class LowLevelILMemoryIntrinsicSsa(LowLevelILInstruction, SSA): + @property + def output(self) -> List[SSARegisterOrFlag]: + inst = self._get_expr(0) + assert isinstance(inst, LowLevelILMemoryIntrinsicOutputSsa), "LowLevelILMemoryIntrinsicSsa expected LowLevelILMemoryIntrinsicOutputSsa as first operand" + return inst.output + + @property + def dest_memory(self) -> int: + inst = self._get_expr(0) + assert isinstance(inst, LowLevelILMemoryIntrinsicOutputSsa), "LowLevelILMemoryIntrinsicSsa expected LowLevelILMemoryIntrinsicOutputSsa as first operand" + return inst.dest_memory + + @property + def intrinsic(self) -> ILIntrinsic: + return self._get_intrinsic(1) + + @property + def param(self) -> LowLevelILCallParam: + # kept for backwards compatibility use 'params' instead + result = self._get_expr(2) + assert isinstance(result, LowLevelILCallParam) + return result + + @property + def params(self) -> List[LowLevelILInstruction]: + return self.param.src + + @property + def src_memory(self) -> int: + return self._get_int(3) + + @property + def detailed_operands(self) -> List[Tuple[str, LowLevelILOperandType, str]]: + return [ + ("output", self.output, "List[SSARegisterOrFlag]"), + ("intrinsic", self.intrinsic, "ILIntrinsic"), + ("params", self.params, "List[LowLevelILInstruction]"), + ("dest_memory", self.dest_memory, "int"), + ("src_memory", self.src_memory, "int"), + ] + + +@dataclass(frozen=True, repr=False, eq=False) class LowLevelILSetRegSsaPartial(LowLevelILInstruction, SetReg, SSA): @property def full_reg(self) -> SSARegister: @@ -2991,7 +3060,9 @@ ILInstruction:Dict[LowLevelILOperation, LowLevelILInstruction] = { # type: igno LowLevelILOperation.LLIL_ADD_OVERFLOW: LowLevelILAddOverflow, # [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_SYSCALL: LowLevelILSyscall, # [], LowLevelILOperation.LLIL_INTRINSIC: LowLevelILIntrinsic, # [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")], - LowLevelILOperation.LLIL_INTRINSIC_SSA: LowLevelILIntrinsicSsa, # [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")], + LowLevelILOperation.LLIL_INTRINSIC_SSA: LowLevelILIntrinsicSsa, # [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + LowLevelILOperation.LLIL_MEMORY_INTRINSIC_OUTPUT_SSA: LowLevelILMemoryIntrinsicOutputSsa, # [("dest_memory", "int"), ("output", "reg_or_flag_ssa_list")], + LowLevelILOperation.LLIL_MEMORY_INTRINSIC_SSA: LowLevelILMemoryIntrinsicSsa, # [("output", "expr"), ("intrinsic", "intrinsic"), ("params", "expr_list"), ("src_memory", "int")], LowLevelILOperation.LLIL_BP: LowLevelILBp, # [], LowLevelILOperation.LLIL_TRAP: LowLevelILTrap, # [("vector", "int")], LowLevelILOperation.LLIL_UNDEF: LowLevelILUndef, # [], diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 05eeb449..53f87cdc 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -263,6 +263,10 @@ class MediumLevelILInstruction(BaseILInstruction): ("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list") ], MediumLevelILOperation.MLIL_INTRINSIC_SSA: [ ("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list") + ], MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_OUTPUT_SSA: [ + ("dest_memory", "int"), ("output", "var_ssa_list") + ], MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_SSA: [ + ("output", "expr"), ("intrinsic", "intrinsic"), ("params", "expr_list"), ("src_memory", "int") ], MediumLevelILOperation.MLIL_FREE_VAR_SLOT: [ ("dest", "var") ], MediumLevelILOperation.MLIL_FREE_VAR_SLOT_SSA: [ @@ -2222,6 +2226,64 @@ class MediumLevelILIntrinsicSsa(MediumLevelILInstruction, SSA): @dataclass(frozen=True, repr=False, eq=False) +class MediumLevelILMemoryIntrinsicOutputSsa(MediumLevelILInstruction, SSA): + def __repr__(self): + return f"<MediumLevelILMemoryIntrinsicOutputSsa: {self.dest_memory} {self.output}>" + + @property + def dest_memory(self) -> int: + return self._get_int(0) + + @property + def output(self) -> List[SSAVariable]: + return self._get_var_ssa_list(1, 2) + + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("dest_memory", self.dest_memory, "int"), + ("output", self.output, "List[SSAVariable]"), + ] + + +@dataclass(frozen=True, repr=False, eq=False) +class MediumLevelILMemoryIntrinsicSsa(MediumLevelILInstruction, SSA): + @property + def output(self) -> List[SSAVariable]: + inst = self._get_expr(0) + assert isinstance(inst, MediumLevelILMemoryIntrinsicOutputSsa), "MediumLevelILMemoryIntrinsicSsa expected MediumLevelILMemoryIntrinsicOutputSsa as first operand" + return inst.output + + @property + def dest_memory(self) -> int: + inst = self._get_expr(0) + assert isinstance(inst, MediumLevelILMemoryIntrinsicOutputSsa), "MediumLevelILMemoryIntrinsicSsa expected MediumLevelILMemoryIntrinsicOutputSsa as first operand" + return inst.dest_memory + + @property + def intrinsic(self) -> 'lowlevelil.ILIntrinsic': + return self._get_intrinsic(1) + + @property + def params(self) -> List[MediumLevelILInstruction]: + return self._get_expr_list(2, 3) + + @property + def src_memory(self) -> int: + return self._get_int(4) + + @property + def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]: + return [ + ("output", self.output, "List[SSAVariable]"), + ("dest_memory", self.dest_memory, "int"), + ("intrinsic", self.intrinsic, "ILIntrinsic"), + ("params", self.params, "List[MediumLevelILInstruction]"), + ("src_memory", self.src_memory, "int"), + ] + + +@dataclass(frozen=True, repr=False, eq=False) class MediumLevelILSetVarSsaField(MediumLevelILInstruction, SetVar, SSA): @property def dest(self) -> SSAVariable: @@ -2996,8 +3058,9 @@ ILInstruction = { MediumLevelILTailcall, # [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")], MediumLevelILOperation.MLIL_INTRINSIC: MediumLevelILIntrinsic, # [("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], - MediumLevelILOperation.MLIL_INTRINSIC_SSA: - MediumLevelILIntrinsicSsa, # [("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + MediumLevelILOperation.MLIL_INTRINSIC_SSA: MediumLevelILIntrinsicSsa, # [("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_OUTPUT_SSA: MediumLevelILMemoryIntrinsicOutputSsa, # [("dest_memory", "int"), ("output", "var_ssa_list")], + MediumLevelILOperation.MLIL_MEMORY_INTRINSIC_SSA: MediumLevelILMemoryIntrinsicSsa, # [("output", "expr"), ("intrinsic", "intrinsic"), ("params", "expr_list"), ("src_memory", "int")], MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD: MediumLevelILSetVarSsaField, # [("prev", "var_ssa_dest_and_src"), ("offset", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA: |
