Skip to content

Commit 5736062

Browse files
committed
Python: LLILFunction.prepare_to_copy_function and copy_to
1 parent 6530578 commit 5736062

File tree

1 file changed

+294
-8
lines changed

1 file changed

+294
-8
lines changed

python/lowlevelil.py

Lines changed: 294 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
import ctypes
2222
import struct
23-
from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar, Set, Callable, Any, Iterator, overload
23+
from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar, Set, \
24+
Callable, Any, Iterator, overload, Mapping
2425
from dataclasses import dataclass
2526

2627
# Binary Ninja components
@@ -511,6 +512,22 @@ def create(
511512
core_inst = CoreLowLevelILInstruction.from_BNLowLevelILInstruction(inst)
512513
return ILInstruction[core_inst.operation](func, expr_index, core_inst, instr_index) # type: ignore
513514

515+
def copy_to(
516+
self, dest: 'LowLevelILFunction',
517+
sub_expr_handler: Optional[Callable[['LowLevelILInstruction'], ExpressionIndex]] = None
518+
) -> ExpressionIndex:
519+
"""
520+
``copy_to`` deep copies an expression into a new IL function.
521+
If provided, the function ``sub_expr_handler`` will be called on every copied sub-expression
522+
523+
.. 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.
524+
525+
:param LowLevelILFunction dest: Function to copy the expression to
526+
:param sub_expr_handler: Optional function to call on every copied sub-expression
527+
:return: Index of the copied expression in the target function
528+
"""
529+
return self.function.copy_expr_to(self, dest, sub_expr_handler)
530+
514531
def __str__(self):
515532
tokens = self.tokens
516533
if tokens is None:
@@ -3853,6 +3870,8 @@ def copy_expr(self, original: LowLevelILInstruction) -> ExpressionIndex:
38533870
"""
38543871
``copy_expr`` adds an expression to the function which is equivalent to the given expression
38553872
3873+
.. 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.
3874+
38563875
:param LowLevelILInstruction original: the original IL Instruction you want to copy
38573876
:return: The index of the newly copied expression
38583877
"""
@@ -3871,7 +3890,7 @@ def replace_expr(self, original: InstructionOrExpression, new: InstructionOrExpr
38713890
"""
38723891
``replace_expr`` allows modification of expressions but ONLY during lifting.
38733892
3874-
.. 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.
3893+
.. 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.
38753894
38763895
:param ExpressionIndex original: the ExpressionIndex to replace (may also be an expression index)
38773896
:param ExpressionIndex new: the ExpressionIndex to add to the current LowLevelILFunction (may also be an expression index)
@@ -3889,11 +3908,229 @@ def replace_expr(self, original: InstructionOrExpression, new: InstructionOrExpr
38893908

38903909
core.BNReplaceLowLevelILExpr(self.handle, original, new)
38913910

3911+
def copy_expr_to(
3912+
self, expr: LowLevelILInstruction, dest: 'LowLevelILFunction',
3913+
sub_expr_handler: Optional[Callable[[LowLevelILInstruction], ExpressionIndex]] = None
3914+
) -> ExpressionIndex:
3915+
"""
3916+
``copy_expr_to`` deep copies an expression from this function into a target function
3917+
If provided, the function ``sub_expr_handler`` will be called on every copied sub-expression
3918+
3919+
.. 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.
3920+
3921+
:param LowLevelILInstruction expr: Expression in this function to copy
3922+
:param LowLevelILFunction dest: Function to copy the expression to
3923+
:param sub_expr_handler: Optional function to call on every copied sub-expression
3924+
:return: Index of the copied expression in the target function
3925+
"""
3926+
3927+
if sub_expr_handler is None:
3928+
sub_expr_handler = lambda sub_expr: self.copy_expr_to(sub_expr, dest)
3929+
loc = ILSourceLocation.from_instruction(expr)
3930+
3931+
if expr.operation == LowLevelILOperation.LLIL_NOP:
3932+
expr: LowLevelILNop
3933+
return dest.nop(loc)
3934+
if expr.operation == LowLevelILOperation.LLIL_SET_REG:
3935+
expr: LowLevelILSetReg
3936+
return dest.set_reg(expr.size, expr.dest, sub_expr_handler(expr.src), expr.flags, loc)
3937+
if expr.operation == LowLevelILOperation.LLIL_SET_REG_SPLIT:
3938+
expr: LowLevelILSetRegSplit
3939+
return dest.set_reg_split(expr.size, expr.hi, expr.lo, sub_expr_handler(expr.src), expr.flags, loc)
3940+
if expr.operation == LowLevelILOperation.LLIL_SET_REG_STACK_REL:
3941+
expr: LowLevelILSetRegStackRel
3942+
return dest.set_reg_stack_top_relative(expr.size, expr.stack, sub_expr_handler(expr.dest), sub_expr_handler(expr.src), expr.flags, loc)
3943+
if expr.operation == LowLevelILOperation.LLIL_REG_STACK_PUSH:
3944+
expr: LowLevelILRegStackPush
3945+
return dest.reg_stack_push(expr.size, expr.stack, sub_expr_handler(expr.src), expr.flags, loc)
3946+
if expr.operation == LowLevelILOperation.LLIL_SET_FLAG:
3947+
expr: LowLevelILSetFlag
3948+
return dest.set_flag(expr.dest.name, sub_expr_handler(expr.src), loc)
3949+
if expr.operation == LowLevelILOperation.LLIL_LOAD:
3950+
expr: LowLevelILLoad
3951+
return dest.load(expr.size, sub_expr_handler(expr.src), expr.flags, loc)
3952+
if expr.operation == LowLevelILOperation.LLIL_STORE:
3953+
expr: LowLevelILStore
3954+
return dest.store(expr.size, sub_expr_handler(expr.dest), sub_expr_handler(expr.src), expr.flags, loc)
3955+
if expr.operation == LowLevelILOperation.LLIL_REG:
3956+
expr: LowLevelILReg
3957+
return dest.reg(expr.size, expr.src, loc)
3958+
if expr.operation == LowLevelILOperation.LLIL_REG_SPLIT:
3959+
expr: LowLevelILRegSplit
3960+
return dest.reg_split(expr.size, expr.hi, expr.lo, loc)
3961+
if expr.operation == LowLevelILOperation.LLIL_REG_STACK_REL:
3962+
expr: LowLevelILRegStackRel
3963+
return dest.reg_stack_top_relative(expr.size, expr.stack, sub_expr_handler(expr.src), loc)
3964+
if expr.operation == LowLevelILOperation.LLIL_REG_STACK_POP:
3965+
expr: LowLevelILRegStackPop
3966+
return dest.reg_stack_pop(expr.size, expr.stack, loc)
3967+
if expr.operation == LowLevelILOperation.LLIL_FLAG:
3968+
expr: LowLevelILFlag
3969+
return dest.flag(expr.src.name, loc)
3970+
if expr.operation == LowLevelILOperation.LLIL_FLAG_BIT:
3971+
expr: LowLevelILFlagBit
3972+
return dest.flag_bit(expr.size, expr.src.name, expr.bit, loc)
3973+
if expr.operation == LowLevelILOperation.LLIL_JUMP:
3974+
expr: LowLevelILJump
3975+
return dest.jump(sub_expr_handler(expr.dest), loc)
3976+
if expr.operation == LowLevelILOperation.LLIL_CALL:
3977+
expr: LowLevelILCall
3978+
return dest.call(sub_expr_handler(expr.dest), loc)
3979+
if expr.operation == LowLevelILOperation.LLIL_CALL_STACK_ADJUST:
3980+
expr: LowLevelILCallStackAdjust
3981+
return dest.call_stack_adjust(sub_expr_handler(expr.dest), expr.stack_adjustment, loc)
3982+
if expr.operation == LowLevelILOperation.LLIL_TAILCALL:
3983+
expr: LowLevelILTailcall
3984+
return dest.tailcall(sub_expr_handler(expr.dest), loc)
3985+
if expr.operation == LowLevelILOperation.LLIL_RET:
3986+
expr: LowLevelILRet
3987+
return dest.ret(sub_expr_handler(expr.dest), loc)
3988+
if expr.operation == LowLevelILOperation.LLIL_JUMP_TO:
3989+
expr: LowLevelILJumpTo
3990+
label_list = {}
3991+
for a, b in expr.targets.items():
3992+
label_a = dest.get_label_for_source_instruction(b)
3993+
if label_a is None:
3994+
return dest.jump(sub_expr_handler(expr.dest), loc)
3995+
label_list[a] = label_a
3996+
return dest.jump_to(sub_expr_handler(expr.dest), label_list, loc)
3997+
if expr.operation == LowLevelILOperation.LLIL_GOTO:
3998+
expr: LowLevelILGoto
3999+
label_a = dest.get_label_for_source_instruction(expr.dest)
4000+
if label_a is None:
4001+
return dest.jump(dest.const_pointer(expr.function.arch.address_size, expr.function[expr.dest].address))
4002+
return dest.goto(label_a, loc)
4003+
if expr.operation == LowLevelILOperation.LLIL_IF:
4004+
expr: LowLevelILIf
4005+
label_a = dest.get_label_for_source_instruction(expr.true)
4006+
label_b = dest.get_label_for_source_instruction(expr.false)
4007+
if label_a is None or label_b is None:
4008+
return dest.undefined(loc)
4009+
return dest.if_expr(sub_expr_handler(expr.condition), label_a, label_b, loc)
4010+
if expr.operation == LowLevelILOperation.LLIL_FLAG_COND:
4011+
expr: LowLevelILFlagCond
4012+
return dest.flag_condition(expr.condition, expr.semantic_class, loc)
4013+
if expr.operation == LowLevelILOperation.LLIL_FLAG_GROUP:
4014+
expr: LowLevelILFlagGroup
4015+
return dest.flag_group(expr.semantic_group.name, loc)
4016+
if expr.operation == LowLevelILOperation.LLIL_TRAP:
4017+
expr: LowLevelILTrap
4018+
return dest.trap(expr.vector, loc)
4019+
if expr.operation == LowLevelILOperation.LLIL_CONST:
4020+
expr: LowLevelILConst
4021+
return dest.const(expr.size, expr.constant, loc)
4022+
if expr.operation == LowLevelILOperation.LLIL_CONST_PTR:
4023+
expr: LowLevelILConstPtr
4024+
return dest.const_pointer(expr.size, expr.constant, loc)
4025+
if expr.operation == LowLevelILOperation.LLIL_EXTERN_PTR:
4026+
expr: LowLevelILExternPtr
4027+
return dest.extern_pointer(expr.size, expr.constant, expr.offset, loc)
4028+
if expr.operation == LowLevelILOperation.LLIL_FLOAT_CONST:
4029+
expr: LowLevelILFloatConst
4030+
return dest.float_const_raw(expr.size, expr.constant, loc)
4031+
if expr.operation in [
4032+
LowLevelILOperation.LLIL_POP,
4033+
LowLevelILOperation.LLIL_NORET,
4034+
LowLevelILOperation.LLIL_SYSCALL,
4035+
LowLevelILOperation.LLIL_BP,
4036+
LowLevelILOperation.LLIL_UNDEF,
4037+
LowLevelILOperation.LLIL_UNIMPL
4038+
]:
4039+
expr:Y
4040+
return dest.expr(expr.operation, size=expr.size, flags=expr.flags, source_location=loc)
4041+
if expr.operation in [
4042+
LowLevelILOperation.LLIL_PUSH,
4043+
LowLevelILOperation.LLIL_NEG,
4044+
LowLevelILOperation.LLIL_NOT,
4045+
LowLevelILOperation.LLIL_SX,
4046+
LowLevelILOperation.LLIL_ZX,
4047+
LowLevelILOperation.LLIL_LOW_PART,
4048+
LowLevelILOperation.LLIL_BOOL_TO_INT,
4049+
LowLevelILOperation.LLIL_UNIMPL_MEM,
4050+
LowLevelILOperation.LLIL_FSQRT,
4051+
LowLevelILOperation.LLIL_FNEG,
4052+
LowLevelILOperation.LLIL_FABS,
4053+
LowLevelILOperation.LLIL_FLOAT_TO_INT,
4054+
LowLevelILOperation.LLIL_INT_TO_FLOAT,
4055+
LowLevelILOperation.LLIL_FLOAT_CONV,
4056+
LowLevelILOperation.LLIL_ROUND_TO_INT,
4057+
LowLevelILOperation.LLIL_FLOOR,
4058+
LowLevelILOperation.LLIL_CEIL,
4059+
LowLevelILOperation.LLIL_FTRUNC,
4060+
]:
4061+
expr: LowLevelILUnaryBase
4062+
return dest.expr(expr.operation, sub_expr_handler(expr.src), size=expr.size, flags=expr.flags, source_location=loc)
4063+
if expr.operation in [
4064+
LowLevelILOperation.LLIL_ADD,
4065+
LowLevelILOperation.LLIL_SUB,
4066+
LowLevelILOperation.LLIL_AND,
4067+
LowLevelILOperation.LLIL_OR,
4068+
LowLevelILOperation.LLIL_XOR,
4069+
LowLevelILOperation.LLIL_LSL,
4070+
LowLevelILOperation.LLIL_LSR,
4071+
LowLevelILOperation.LLIL_ASR,
4072+
LowLevelILOperation.LLIL_ROL,
4073+
LowLevelILOperation.LLIL_ROR,
4074+
LowLevelILOperation.LLIL_MUL,
4075+
LowLevelILOperation.LLIL_MULU_DP,
4076+
LowLevelILOperation.LLIL_MULS_DP,
4077+
LowLevelILOperation.LLIL_DIVU,
4078+
LowLevelILOperation.LLIL_DIVS,
4079+
LowLevelILOperation.LLIL_MODU,
4080+
LowLevelILOperation.LLIL_MODS,
4081+
LowLevelILOperation.LLIL_DIVU_DP,
4082+
LowLevelILOperation.LLIL_DIVS_DP,
4083+
LowLevelILOperation.LLIL_MODU_DP,
4084+
LowLevelILOperation.LLIL_MODS_DP,
4085+
LowLevelILOperation.LLIL_CMP_E,
4086+
LowLevelILOperation.LLIL_CMP_NE,
4087+
LowLevelILOperation.LLIL_CMP_SLT,
4088+
LowLevelILOperation.LLIL_CMP_ULT,
4089+
LowLevelILOperation.LLIL_CMP_SLE,
4090+
LowLevelILOperation.LLIL_CMP_ULE,
4091+
LowLevelILOperation.LLIL_CMP_SGE,
4092+
LowLevelILOperation.LLIL_CMP_UGE,
4093+
LowLevelILOperation.LLIL_CMP_SGT,
4094+
LowLevelILOperation.LLIL_CMP_UGT,
4095+
LowLevelILOperation.LLIL_TEST_BIT,
4096+
LowLevelILOperation.LLIL_ADD_OVERFLOW,
4097+
LowLevelILOperation.LLIL_FADD,
4098+
LowLevelILOperation.LLIL_FSUB,
4099+
LowLevelILOperation.LLIL_FMUL,
4100+
LowLevelILOperation.LLIL_FDIV,
4101+
LowLevelILOperation.LLIL_FCMP_E,
4102+
LowLevelILOperation.LLIL_FCMP_NE,
4103+
LowLevelILOperation.LLIL_FCMP_LT,
4104+
LowLevelILOperation.LLIL_FCMP_LE,
4105+
LowLevelILOperation.LLIL_FCMP_GE,
4106+
LowLevelILOperation.LLIL_FCMP_GT,
4107+
LowLevelILOperation.LLIL_FCMP_O,
4108+
LowLevelILOperation.LLIL_FCMP_UO,
4109+
]:
4110+
expr: LowLevelILBinaryBase
4111+
return dest.expr(expr.operation, sub_expr_handler(expr.left), sub_expr_handler(expr.right), size=expr.size, flags=expr.flags, source_location=loc)
4112+
if expr.operation in [
4113+
LowLevelILOperation.LLIL_ADC,
4114+
LowLevelILOperation.LLIL_SBB,
4115+
LowLevelILOperation.LLIL_RLC,
4116+
LowLevelILOperation.LLIL_RRC,
4117+
]:
4118+
expr: LowLevelILCarryBase
4119+
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)
4120+
if expr.operation == LowLevelILOperation.LLIL_INTRINSIC:
4121+
expr: LowLevelILIntrinsic
4122+
params = []
4123+
for param in expr.params:
4124+
params.append(sub_expr_handler(param))
4125+
return dest.intrinsic(expr.output, expr.intrinsic, params, expr.flags, loc)
4126+
4127+
raise NotImplementedError(f"unknown expr operation {expr.operation} in copy_expr_to")
4128+
38924129
def set_expr_attributes(self, expr: InstructionOrExpression, value: ILInstructionAttributeSet):
38934130
"""
38944131
``set_expr_attributes`` allows modification of instruction attributes but ONLY during lifting.
38954132
3896-
.. 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.
4133+
.. 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.
38974134
38984135
:param ExpressionIndex expr: the ExpressionIndex to replace (may also be an expression index)
38994136
:param set(ILInstructionAttribute) value: the set of attributes to place on the instruction
@@ -4030,17 +4267,21 @@ def set_flag(
40304267
"""
40314268
return self.expr(LowLevelILOperation.LLIL_SET_FLAG, ExpressionIndex(self.arch.get_flag_by_name(flag)), value, source_location=loc)
40324269

4033-
def load(self, size: int, addr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
4270+
def load(
4271+
self, size: int, addr: ExpressionIndex, flags: Optional['architecture.FlagName'] = None,
4272+
loc: Optional['ILSourceLocation'] = None
4273+
) -> ExpressionIndex:
40344274
"""
40354275
``load`` Reads ``size`` bytes from the expression ``addr``
40364276
40374277
:param int size: number of bytes to read
40384278
:param ExpressionIndex addr: the expression to read memory from
4279+
:param FlagName flags: which flags are set by this operation
40394280
:param ILSourceLocation loc: location of returned expression
40404281
:return: The expression ``[addr].size``
40414282
:rtype: ExpressionIndex
40424283
"""
4043-
return self.expr(LowLevelILOperation.LLIL_LOAD, addr, size=size, source_location=loc)
4284+
return self.expr(LowLevelILOperation.LLIL_LOAD, addr, size=size, flags=flags, source_location=loc)
40444285

40454286
def store(
40464287
self, size: int, addr: ExpressionIndex, value: ExpressionIndex, flags: Optional['architecture.FlagName'] = None,
@@ -4172,17 +4413,18 @@ def const_pointer(self, size: int, value: int, loc: Optional['ILSourceLocation']
41724413
"""
41734414
return self.expr(LowLevelILOperation.LLIL_CONST_PTR, value, size=size, source_location=loc)
41744415

4175-
def reloc_pointer(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
4416+
def extern_pointer(self, size: int, value: int, offset: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
41764417
"""
4177-
``reloc_pointer`` returns an expression for the constant relocated pointer ``value`` with size ``size``
4418+
``extern_pointer`` returns an expression for the constant external pointer ``value`` with size ``size`` at offset ``offset``
41784419
41794420
:param int size: the size of the pointer in bytes
41804421
:param int value: address referenced by pointer
4422+
:param int offset: offset into external pointer
41814423
:param ILSourceLocation loc: location of returned expression
41824424
:return: A constant expression of given value and size
41834425
:rtype: ExpressionIndex
41844426
"""
4185-
return self.expr(LowLevelILOperation.LLIL_EXTERN_PTR, value, size=size, source_location=loc)
4427+
return self.expr(LowLevelILOperation.LLIL_EXTERN_PTR, value, offset, size=size, source_location=loc)
41864428

41874429
def float_const_raw(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
41884430
"""
@@ -4792,6 +5034,19 @@ def jump(self, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None)
47925034
"""
47935035
return self.expr(LowLevelILOperation.LLIL_JUMP, dest, source_location=loc)
47945036

5037+
def jump_to(self, dest: ExpressionIndex, targets: Dict[int, 'LowLevelILLabel'], loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
5038+
"""
5039+
``jump_to`` returns an expression which jumps (branches) various targets in ``targets``
5040+
choosing the target in ``targets`` based on the value calculated by ``dest``
5041+
5042+
:param ExpressionIndex dest: the expression choosing which jump target to use
5043+
:param Mapping[int, MediumLevelILLabel] targets: the list of targets for jump locations
5044+
:param ILSourceLocation loc: location of returned expression
5045+
:return: The expression ``jump(dest)``
5046+
:rtype: ExpressionIndex
5047+
"""
5048+
return self.expr(LowLevelILOperation.LLIL_JUMP_TO, dest, len(targets) * 2, self.add_label_map(targets), size=0, source_location=loc)
5049+
47955050
def call(self, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
47965051
"""
47975052
``call`` returns an expression which first pushes the address of the next instruction onto the stack then jumps
@@ -5637,6 +5892,37 @@ def generate_ssa_form(self) -> None:
56375892
"""
56385893
core.BNGenerateLowLevelILSSAForm(self.handle)
56395894

5895+
def prepare_to_copy_function(self, src: 'LowLevelILFunction'):
5896+
"""
5897+
``prepare_to_copy_function`` sets up state in this LLIL function in preparation
5898+
of copying instructions from ``src``
5899+
5900+
:param LowLevelILFunction src: function about to be copied from
5901+
"""
5902+
core.BNPrepareToCopyLowLevelILFunction(self.handle, src.handle)
5903+
5904+
def prepare_to_copy_block(self, src: 'LowLevelILBasicBlock'):
5905+
"""
5906+
``prepare_to_copy_block`` sets up state when copying a function in preparation
5907+
of copying the instructions from the block ``src``
5908+
5909+
:param LowLevelILBasicBlock src: block about to be copied from
5910+
"""
5911+
core.BNPrepareToCopyLowLevelILBasicBlock(self.handle, src.handle)
5912+
5913+
def get_label_for_source_instruction(self, i: InstructionIndex) -> Optional['LowLevelILLabel']:
5914+
"""
5915+
Get the LowLevelILLabel for a given source instruction. The returned label is to an internal object with
5916+
the same lifetime as the containing LowLevelILFunction.
5917+
5918+
:param i: The source instruction index
5919+
:return: The LowLevelILLabel for the source instruction
5920+
"""
5921+
label = core.BNGetLabelForLowLevelILSourceInstruction(self.handle, i)
5922+
if not label:
5923+
return None
5924+
return LowLevelILLabel(handle=label)
5925+
56405926
def add_label_for_address(self, arch: 'architecture.Architecture', addr: int) -> None:
56415927
"""
56425928
``add_label_for_address`` adds a low-level IL label for the given architecture ``arch`` at the given virtual

0 commit comments

Comments
 (0)