diff options
| author | Glenn Smith <glenn@vector35.com> | 2025-03-06 15:44:18 -0500 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2025-03-06 17:16:15 -0500 |
| commit | 5736062338006550996756091378670665643994 (patch) | |
| tree | 63604265b7946955765d98ea61661a642f91b813 /python | |
| parent | 6530578682121347405273817588480175565073 (diff) | |
Python: LLILFunction.prepare_to_copy_function and copy_to
Diffstat (limited to 'python')
| -rw-r--r-- | python/lowlevelil.py | 302 |
1 files changed, 294 insertions, 8 deletions
diff --git a/python/lowlevelil.py b/python/lowlevelil.py index b82b75a2..b8fe0b94 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -20,7 +20,8 @@ import ctypes import struct -from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar, Set, Callable, Any, Iterator, overload +from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar, Set, \ + Callable, Any, Iterator, overload, Mapping from dataclasses import dataclass # Binary Ninja components @@ -511,6 +512,22 @@ class LowLevelILInstruction(BaseILInstruction): core_inst = CoreLowLevelILInstruction.from_BNLowLevelILInstruction(inst) return ILInstruction[core_inst.operation](func, expr_index, core_inst, instr_index) # type: ignore + def copy_to( + self, dest: 'LowLevelILFunction', + sub_expr_handler: Optional[Callable[['LowLevelILInstruction'], ExpressionIndex]] = None + ) -> ExpressionIndex: + """ + ``copy_to`` deep copies an expression into a new IL function. + If provided, the function ``sub_expr_handler`` will be called on every copied sub-expression + + .. warning:: This function should ONLY be called as a part of a lifter or workflow. It will otherwise not do anything useful as analysis will not be running. + + :param LowLevelILFunction dest: Function to copy the expression to + :param sub_expr_handler: Optional function to call on every copied sub-expression + :return: Index of the copied expression in the target function + """ + return self.function.copy_expr_to(self, dest, sub_expr_handler) + def __str__(self): tokens = self.tokens if tokens is None: @@ -3853,6 +3870,8 @@ class LowLevelILFunction: """ ``copy_expr`` adds an expression to the function which is equivalent to the given expression + .. warning:: This function should ONLY be called as a part of a lifter or workflow. It will otherwise not do anything useful as analysis will not be running. + :param LowLevelILInstruction original: the original IL Instruction you want to copy :return: The index of the newly copied expression """ @@ -3871,7 +3890,7 @@ class LowLevelILFunction: """ ``replace_expr`` allows modification of expressions but ONLY during lifting. - .. warning:: This function should ONLY be called as a part of a lifter. It will otherwise not do anything useful as there's no way to trigger re-analysis of IL levels at this time. + .. warning:: This function should ONLY be called as a part of a lifter or workflow. It will otherwise not do anything useful as analysis will not be running. :param ExpressionIndex original: the ExpressionIndex to replace (may also be an expression index) :param ExpressionIndex new: the ExpressionIndex to add to the current LowLevelILFunction (may also be an expression index) @@ -3889,11 +3908,229 @@ class LowLevelILFunction: core.BNReplaceLowLevelILExpr(self.handle, original, new) + def copy_expr_to( + self, expr: LowLevelILInstruction, dest: 'LowLevelILFunction', + sub_expr_handler: Optional[Callable[[LowLevelILInstruction], ExpressionIndex]] = None + ) -> ExpressionIndex: + """ + ``copy_expr_to`` deep copies an expression from this function into a target function + If provided, the function ``sub_expr_handler`` will be called on every copied sub-expression + + .. warning:: This function should ONLY be called as a part of a lifter or workflow. It will otherwise not do anything useful as analysis will not be running. + + :param LowLevelILInstruction expr: Expression in this function to copy + :param LowLevelILFunction dest: Function to copy the expression to + :param sub_expr_handler: Optional function to call on every copied sub-expression + :return: Index of the copied expression in the target function + """ + + if sub_expr_handler is None: + sub_expr_handler = lambda sub_expr: self.copy_expr_to(sub_expr, dest) + loc = ILSourceLocation.from_instruction(expr) + + if expr.operation == LowLevelILOperation.LLIL_NOP: + expr: LowLevelILNop + return dest.nop(loc) + if expr.operation == LowLevelILOperation.LLIL_SET_REG: + expr: LowLevelILSetReg + return dest.set_reg(expr.size, expr.dest, sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_SET_REG_SPLIT: + expr: LowLevelILSetRegSplit + return dest.set_reg_split(expr.size, expr.hi, expr.lo, sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_SET_REG_STACK_REL: + expr: LowLevelILSetRegStackRel + return dest.set_reg_stack_top_relative(expr.size, expr.stack, sub_expr_handler(expr.dest), sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_REG_STACK_PUSH: + expr: LowLevelILRegStackPush + return dest.reg_stack_push(expr.size, expr.stack, sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_SET_FLAG: + expr: LowLevelILSetFlag + return dest.set_flag(expr.dest.name, sub_expr_handler(expr.src), loc) + if expr.operation == LowLevelILOperation.LLIL_LOAD: + expr: LowLevelILLoad + return dest.load(expr.size, sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_STORE: + expr: LowLevelILStore + return dest.store(expr.size, sub_expr_handler(expr.dest), sub_expr_handler(expr.src), expr.flags, loc) + if expr.operation == LowLevelILOperation.LLIL_REG: + expr: LowLevelILReg + return dest.reg(expr.size, expr.src, loc) + if expr.operation == LowLevelILOperation.LLIL_REG_SPLIT: + expr: LowLevelILRegSplit + return dest.reg_split(expr.size, expr.hi, expr.lo, loc) + if expr.operation == LowLevelILOperation.LLIL_REG_STACK_REL: + expr: LowLevelILRegStackRel + return dest.reg_stack_top_relative(expr.size, expr.stack, sub_expr_handler(expr.src), loc) + if expr.operation == LowLevelILOperation.LLIL_REG_STACK_POP: + expr: LowLevelILRegStackPop + return dest.reg_stack_pop(expr.size, expr.stack, loc) + if expr.operation == LowLevelILOperation.LLIL_FLAG: + expr: LowLevelILFlag + return dest.flag(expr.src.name, loc) + if expr.operation == LowLevelILOperation.LLIL_FLAG_BIT: + expr: LowLevelILFlagBit + return dest.flag_bit(expr.size, expr.src.name, expr.bit, loc) + if expr.operation == LowLevelILOperation.LLIL_JUMP: + expr: LowLevelILJump + return dest.jump(sub_expr_handler(expr.dest), loc) + if expr.operation == LowLevelILOperation.LLIL_CALL: + expr: LowLevelILCall + return dest.call(sub_expr_handler(expr.dest), loc) + if expr.operation == LowLevelILOperation.LLIL_CALL_STACK_ADJUST: + expr: LowLevelILCallStackAdjust + return dest.call_stack_adjust(sub_expr_handler(expr.dest), expr.stack_adjustment, loc) + if expr.operation == LowLevelILOperation.LLIL_TAILCALL: + expr: LowLevelILTailcall + return dest.tailcall(sub_expr_handler(expr.dest), loc) + if expr.operation == LowLevelILOperation.LLIL_RET: + expr: LowLevelILRet + return dest.ret(sub_expr_handler(expr.dest), loc) + if expr.operation == LowLevelILOperation.LLIL_JUMP_TO: + expr: LowLevelILJumpTo + label_list = {} + for a, b in expr.targets.items(): + label_a = dest.get_label_for_source_instruction(b) + if label_a is None: + return dest.jump(sub_expr_handler(expr.dest), loc) + label_list[a] = label_a + return dest.jump_to(sub_expr_handler(expr.dest), label_list, loc) + if expr.operation == LowLevelILOperation.LLIL_GOTO: + expr: LowLevelILGoto + label_a = dest.get_label_for_source_instruction(expr.dest) + if label_a is None: + return dest.jump(dest.const_pointer(expr.function.arch.address_size, expr.function[expr.dest].address)) + return dest.goto(label_a, loc) + if expr.operation == LowLevelILOperation.LLIL_IF: + expr: LowLevelILIf + label_a = dest.get_label_for_source_instruction(expr.true) + label_b = dest.get_label_for_source_instruction(expr.false) + if label_a is None or label_b is None: + return dest.undefined(loc) + return dest.if_expr(sub_expr_handler(expr.condition), label_a, label_b, loc) + if expr.operation == LowLevelILOperation.LLIL_FLAG_COND: + expr: LowLevelILFlagCond + return dest.flag_condition(expr.condition, expr.semantic_class, loc) + if expr.operation == LowLevelILOperation.LLIL_FLAG_GROUP: + expr: LowLevelILFlagGroup + return dest.flag_group(expr.semantic_group.name, loc) + if expr.operation == LowLevelILOperation.LLIL_TRAP: + expr: LowLevelILTrap + return dest.trap(expr.vector, loc) + if expr.operation == LowLevelILOperation.LLIL_CONST: + expr: LowLevelILConst + return dest.const(expr.size, expr.constant, loc) + if expr.operation == LowLevelILOperation.LLIL_CONST_PTR: + expr: LowLevelILConstPtr + return dest.const_pointer(expr.size, expr.constant, loc) + if expr.operation == LowLevelILOperation.LLIL_EXTERN_PTR: + expr: LowLevelILExternPtr + return dest.extern_pointer(expr.size, expr.constant, expr.offset, loc) + if expr.operation == LowLevelILOperation.LLIL_FLOAT_CONST: + expr: LowLevelILFloatConst + return dest.float_const_raw(expr.size, expr.constant, loc) + if expr.operation in [ + LowLevelILOperation.LLIL_POP, + LowLevelILOperation.LLIL_NORET, + LowLevelILOperation.LLIL_SYSCALL, + LowLevelILOperation.LLIL_BP, + LowLevelILOperation.LLIL_UNDEF, + LowLevelILOperation.LLIL_UNIMPL + ]: + expr:Y + return dest.expr(expr.operation, size=expr.size, flags=expr.flags, source_location=loc) + if expr.operation in [ + LowLevelILOperation.LLIL_PUSH, + LowLevelILOperation.LLIL_NEG, + LowLevelILOperation.LLIL_NOT, + LowLevelILOperation.LLIL_SX, + LowLevelILOperation.LLIL_ZX, + LowLevelILOperation.LLIL_LOW_PART, + LowLevelILOperation.LLIL_BOOL_TO_INT, + LowLevelILOperation.LLIL_UNIMPL_MEM, + LowLevelILOperation.LLIL_FSQRT, + LowLevelILOperation.LLIL_FNEG, + LowLevelILOperation.LLIL_FABS, + LowLevelILOperation.LLIL_FLOAT_TO_INT, + LowLevelILOperation.LLIL_INT_TO_FLOAT, + LowLevelILOperation.LLIL_FLOAT_CONV, + LowLevelILOperation.LLIL_ROUND_TO_INT, + LowLevelILOperation.LLIL_FLOOR, + LowLevelILOperation.LLIL_CEIL, + LowLevelILOperation.LLIL_FTRUNC, + ]: + expr: LowLevelILUnaryBase + return dest.expr(expr.operation, sub_expr_handler(expr.src), size=expr.size, flags=expr.flags, source_location=loc) + if expr.operation in [ + LowLevelILOperation.LLIL_ADD, + LowLevelILOperation.LLIL_SUB, + LowLevelILOperation.LLIL_AND, + LowLevelILOperation.LLIL_OR, + LowLevelILOperation.LLIL_XOR, + LowLevelILOperation.LLIL_LSL, + LowLevelILOperation.LLIL_LSR, + LowLevelILOperation.LLIL_ASR, + LowLevelILOperation.LLIL_ROL, + LowLevelILOperation.LLIL_ROR, + LowLevelILOperation.LLIL_MUL, + LowLevelILOperation.LLIL_MULU_DP, + LowLevelILOperation.LLIL_MULS_DP, + LowLevelILOperation.LLIL_DIVU, + LowLevelILOperation.LLIL_DIVS, + LowLevelILOperation.LLIL_MODU, + LowLevelILOperation.LLIL_MODS, + LowLevelILOperation.LLIL_DIVU_DP, + LowLevelILOperation.LLIL_DIVS_DP, + LowLevelILOperation.LLIL_MODU_DP, + LowLevelILOperation.LLIL_MODS_DP, + LowLevelILOperation.LLIL_CMP_E, + LowLevelILOperation.LLIL_CMP_NE, + LowLevelILOperation.LLIL_CMP_SLT, + LowLevelILOperation.LLIL_CMP_ULT, + LowLevelILOperation.LLIL_CMP_SLE, + LowLevelILOperation.LLIL_CMP_ULE, + LowLevelILOperation.LLIL_CMP_SGE, + LowLevelILOperation.LLIL_CMP_UGE, + LowLevelILOperation.LLIL_CMP_SGT, + LowLevelILOperation.LLIL_CMP_UGT, + LowLevelILOperation.LLIL_TEST_BIT, + LowLevelILOperation.LLIL_ADD_OVERFLOW, + LowLevelILOperation.LLIL_FADD, + LowLevelILOperation.LLIL_FSUB, + LowLevelILOperation.LLIL_FMUL, + LowLevelILOperation.LLIL_FDIV, + LowLevelILOperation.LLIL_FCMP_E, + LowLevelILOperation.LLIL_FCMP_NE, + LowLevelILOperation.LLIL_FCMP_LT, + LowLevelILOperation.LLIL_FCMP_LE, + LowLevelILOperation.LLIL_FCMP_GE, + LowLevelILOperation.LLIL_FCMP_GT, + LowLevelILOperation.LLIL_FCMP_O, + LowLevelILOperation.LLIL_FCMP_UO, + ]: + expr: LowLevelILBinaryBase + return dest.expr(expr.operation, sub_expr_handler(expr.left), sub_expr_handler(expr.right), size=expr.size, flags=expr.flags, source_location=loc) + if expr.operation in [ + LowLevelILOperation.LLIL_ADC, + LowLevelILOperation.LLIL_SBB, + LowLevelILOperation.LLIL_RLC, + LowLevelILOperation.LLIL_RRC, + ]: + expr: LowLevelILCarryBase + return dest.expr(expr.operation, sub_expr_handler(expr.left), sub_expr_handler(expr.right), sub_expr_handler(expr.carry), size=expr.size, flags=expr.flags, source_location=loc) + if expr.operation == LowLevelILOperation.LLIL_INTRINSIC: + expr: LowLevelILIntrinsic + params = [] + for param in expr.params: + params.append(sub_expr_handler(param)) + return dest.intrinsic(expr.output, expr.intrinsic, params, expr.flags, loc) + + raise NotImplementedError(f"unknown expr operation {expr.operation} in copy_expr_to") + def set_expr_attributes(self, expr: InstructionOrExpression, value: ILInstructionAttributeSet): """ ``set_expr_attributes`` allows modification of instruction attributes but ONLY during lifting. - .. warning:: This function should ONLY be called as a part of a lifter. It will otherwise not do anything useful as there's no way to trigger re-analysis of IL levels at this time. + .. warning:: This function should ONLY be called as a part of a lifter or workflow. It will otherwise not do anything useful as analysis will not be running. :param ExpressionIndex expr: the ExpressionIndex to replace (may also be an expression index) :param set(ILInstructionAttribute) value: the set of attributes to place on the instruction @@ -4030,17 +4267,21 @@ class LowLevelILFunction: """ return self.expr(LowLevelILOperation.LLIL_SET_FLAG, ExpressionIndex(self.arch.get_flag_by_name(flag)), value, source_location=loc) - def load(self, size: int, addr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: + def load( + self, size: int, addr: ExpressionIndex, flags: Optional['architecture.FlagName'] = None, + loc: Optional['ILSourceLocation'] = None + ) -> ExpressionIndex: """ ``load`` Reads ``size`` bytes from the expression ``addr`` :param int size: number of bytes to read :param ExpressionIndex addr: the expression to read memory from + :param FlagName flags: which flags are set by this operation :param ILSourceLocation loc: location of returned expression :return: The expression ``[addr].size`` :rtype: ExpressionIndex """ - return self.expr(LowLevelILOperation.LLIL_LOAD, addr, size=size, source_location=loc) + return self.expr(LowLevelILOperation.LLIL_LOAD, addr, size=size, flags=flags, source_location=loc) def store( self, size: int, addr: ExpressionIndex, value: ExpressionIndex, flags: Optional['architecture.FlagName'] = None, @@ -4172,17 +4413,18 @@ class LowLevelILFunction: """ return self.expr(LowLevelILOperation.LLIL_CONST_PTR, value, size=size, source_location=loc) - def reloc_pointer(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: + def extern_pointer(self, size: int, value: int, offset: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ - ``reloc_pointer`` returns an expression for the constant relocated pointer ``value`` with size ``size`` + ``extern_pointer`` returns an expression for the constant external pointer ``value`` with size ``size`` at offset ``offset`` :param int size: the size of the pointer in bytes :param int value: address referenced by pointer + :param int offset: offset into external pointer :param ILSourceLocation loc: location of returned expression :return: A constant expression of given value and size :rtype: ExpressionIndex """ - return self.expr(LowLevelILOperation.LLIL_EXTERN_PTR, value, size=size, source_location=loc) + return self.expr(LowLevelILOperation.LLIL_EXTERN_PTR, value, offset, size=size, source_location=loc) def float_const_raw(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ @@ -4792,6 +5034,19 @@ class LowLevelILFunction: """ return self.expr(LowLevelILOperation.LLIL_JUMP, dest, source_location=loc) + def jump_to(self, dest: ExpressionIndex, targets: Dict[int, 'LowLevelILLabel'], loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: + """ + ``jump_to`` returns an expression which jumps (branches) various targets in ``targets`` + choosing the target in ``targets`` based on the value calculated by ``dest`` + + :param ExpressionIndex dest: the expression choosing which jump target to use + :param Mapping[int, MediumLevelILLabel] targets: the list of targets for jump locations + :param ILSourceLocation loc: location of returned expression + :return: The expression ``jump(dest)`` + :rtype: ExpressionIndex + """ + return self.expr(LowLevelILOperation.LLIL_JUMP_TO, dest, len(targets) * 2, self.add_label_map(targets), size=0, source_location=loc) + def call(self, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex: """ ``call`` returns an expression which first pushes the address of the next instruction onto the stack then jumps @@ -5637,6 +5892,37 @@ class LowLevelILFunction: """ core.BNGenerateLowLevelILSSAForm(self.handle) + def prepare_to_copy_function(self, src: 'LowLevelILFunction'): + """ + ``prepare_to_copy_function`` sets up state in this LLIL function in preparation + of copying instructions from ``src`` + + :param LowLevelILFunction src: function about to be copied from + """ + core.BNPrepareToCopyLowLevelILFunction(self.handle, src.handle) + + def prepare_to_copy_block(self, src: 'LowLevelILBasicBlock'): + """ + ``prepare_to_copy_block`` sets up state when copying a function in preparation + of copying the instructions from the block ``src`` + + :param LowLevelILBasicBlock src: block about to be copied from + """ + core.BNPrepareToCopyLowLevelILBasicBlock(self.handle, src.handle) + + def get_label_for_source_instruction(self, i: InstructionIndex) -> Optional['LowLevelILLabel']: + """ + Get the LowLevelILLabel for a given source instruction. The returned label is to an internal object with + the same lifetime as the containing LowLevelILFunction. + + :param i: The source instruction index + :return: The LowLevelILLabel for the source instruction + """ + label = core.BNGetLabelForLowLevelILSourceInstruction(self.handle, i) + if not label: + return None + return LowLevelILLabel(handle=label) + def add_label_for_address(self, arch: 'architecture.Architecture', addr: int) -> None: """ ``add_label_for_address`` adds a low-level IL label for the given architecture ``arch`` at the given virtual |
