Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| # Copyright (c) 2017 Vector 35 LLC | |
| # | |
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |
| # of this software and associated documentation files (the "Software"), to | |
| # deal in the Software without restriction, including without limitation the | |
| # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
| # sell copies of the Software, and to permit persons to whom the Software is | |
| # furnished to do so, subject to the following conditions: | |
| # | |
| # The above copyright notice and this permission notice shall be included in | |
| # all copies or substantial portions of the Software. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
| # IN THE SOFTWARE. | |
| import ctypes | |
| # Binary Ninja components | |
| import _binaryninjacore as core | |
| from .enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence | |
| import function | |
| import basicblock | |
| import lowlevelil | |
| import types | |
| class SSAVariable(object): | |
| def __init__(self, var, version): | |
| self.var = var | |
| self.version = version | |
| def __repr__(self): | |
| return "<ssa %s version %d>" % (repr(self.var), self.version) | |
| def __eq__(self, other): | |
| return ( | |
| (self.var.identifier, self.version) == | |
| (other.var.identifier, other.version) | |
| ) | |
| def __hash__(self): | |
| return hash((self.var.identifier, self.version)) | |
| class MediumLevelILLabel(object): | |
| def __init__(self, handle = None): | |
| if handle is None: | |
| self.handle = (core.BNMediumLevelILLabel * 1)() | |
| core.BNMediumLevelILInitLabel(self.handle) | |
| else: | |
| self.handle = handle | |
| class MediumLevelILOperationAndSize(object): | |
| def __init__(self, operation, size): | |
| self.operation = operation | |
| self.size = size | |
| def __repr__(self): | |
| if self.size == 0: | |
| return "<%s>" % self.operation.name | |
| return "<%s %d>" % (self.operation.name, self.size) | |
| class MediumLevelILInstruction(object): | |
| """ | |
| ``class MediumLevelILInstruction`` Medium Level Intermediate Language Instructions are infinite length tree-based | |
| instructions. Tree-based instructions use infix notation with the left hand operand being the destination operand. | |
| Infix notation is thus more natural to read than other notations (e.g. x86 ``mov eax, 0`` vs. MLIL ``eax = 0``). | |
| """ | |
| ILOperations = { | |
| MediumLevelILOperation.MLIL_NOP: [], | |
| MediumLevelILOperation.MLIL_SET_VAR: [("dest", "var"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_FIELD: [("dest", "var"), ("offset", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_SPLIT: [("high", "var"), ("low", "var"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_LOAD: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_LOAD_STRUCT: [("src", "expr"), ("offset", "int")], | |
| MediumLevelILOperation.MLIL_STORE: [("dest", "expr"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_STORE_STRUCT: [("dest", "expr"), ("offset", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_VAR: [("src", "var")], | |
| MediumLevelILOperation.MLIL_VAR_FIELD: [("src", "var"), ("offset", "int")], | |
| MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], | |
| MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [("src", "var"), ("offset", "int")], | |
| MediumLevelILOperation.MLIL_CONST: [("constant", "int")], | |
| MediumLevelILOperation.MLIL_CONST_PTR: [("constant", "int")], | |
| MediumLevelILOperation.MLIL_IMPORT: [("constant", "int")], | |
| MediumLevelILOperation.MLIL_ADD: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_ADC: [("left", "expr"), ("right", "expr"), ("carry", "expr")], | |
| MediumLevelILOperation.MLIL_SUB: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_SBB: [("left", "expr"), ("right", "expr"), ("carry", "expr")], | |
| MediumLevelILOperation.MLIL_AND: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_OR: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_XOR: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_LSL: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_LSR: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_ASR: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_ROL: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_RLC: [("left", "expr"), ("right", "expr"), ("carry", "expr")], | |
| MediumLevelILOperation.MLIL_ROR: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_RRC: [("left", "expr"), ("right", "expr"), ("carry", "expr")], | |
| MediumLevelILOperation.MLIL_MUL: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MULU_DP: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MULS_DP: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_DIVU: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_DIVS: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MODU: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MODS: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_NEG: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_NOT: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_SX: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_ZX: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_LOW_PART: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_JUMP: [("dest", "expr")], | |
| MediumLevelILOperation.MLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], | |
| MediumLevelILOperation.MLIL_CALL: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")], | |
| MediumLevelILOperation.MLIL_CALL_UNTYPED: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")], | |
| MediumLevelILOperation.MLIL_CALL_OUTPUT: [("dest", "var_list")], | |
| MediumLevelILOperation.MLIL_CALL_PARAM: [("src", "var_list")], | |
| MediumLevelILOperation.MLIL_RET: [("src", "expr_list")], | |
| MediumLevelILOperation.MLIL_NORET: [], | |
| MediumLevelILOperation.MLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], | |
| MediumLevelILOperation.MLIL_GOTO: [("dest", "int")], | |
| MediumLevelILOperation.MLIL_CMP_E: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_NE: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_ULT: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_SLE: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_ULE: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_SGE: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_UGE: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_SGT: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_CMP_UGT: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_TEST_BIT: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_BOOL_TO_INT: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")], | |
| MediumLevelILOperation.MLIL_SYSCALL: [("output", "var_list"), ("params", "expr_list")], | |
| MediumLevelILOperation.MLIL_SYSCALL_UNTYPED: [("output", "expr"), ("params", "expr"), ("stack", "expr")], | |
| MediumLevelILOperation.MLIL_BP: [], | |
| MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], | |
| MediumLevelILOperation.MLIL_UNDEF: [], | |
| MediumLevelILOperation.MLIL_UNIMPL: [], | |
| MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_SSA: [("dest", "var_ssa"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD: [("prev", "var_ssa_dest_and_src"), ("offset", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA: [("high", "var_ssa"), ("low", "var_ssa"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_ALIASED: [("prev", "var_ssa_dest_and_src"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_SET_VAR_ALIASED_FIELD: [("prev", "var_ssa_dest_and_src"), ("offset", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_VAR_SSA: [("src", "var_ssa")], | |
| MediumLevelILOperation.MLIL_VAR_SSA_FIELD: [("src", "var_ssa"), ("offset", "int")], | |
| MediumLevelILOperation.MLIL_VAR_ALIASED: [("src", "var_ssa")], | |
| MediumLevelILOperation.MLIL_VAR_ALIASED_FIELD: [("src", "var_ssa"), ("offset", "int")], | |
| MediumLevelILOperation.MLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int")], | |
| MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")], | |
| MediumLevelILOperation.MLIL_SYSCALL_SSA: [("output", "expr"), ("params", "expr_list"), ("src_memory", "int")], | |
| MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA: [("output", "expr"), ("params", "expr"), ("stack", "expr")], | |
| MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "var_ssa_list")], | |
| MediumLevelILOperation.MLIL_CALL_PARAM_SSA: [("src_memory", "int"), ("src", "var_ssa_list")], | |
| MediumLevelILOperation.MLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")], | |
| MediumLevelILOperation.MLIL_LOAD_STRUCT_SSA: [("src", "expr"), ("offset", "int"), ("src_memory", "int")], | |
| MediumLevelILOperation.MLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_STORE_STRUCT_SSA: [("dest", "expr"), ("offset", "int"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], | |
| MediumLevelILOperation.MLIL_VAR_PHI: [("dest", "var_ssa"), ("src", "var_ssa_list")], | |
| MediumLevelILOperation.MLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] | |
| } | |
| def __init__(self, func, expr_index, instr_index=None): | |
| instr = core.BNGetMediumLevelILByIndex(func.handle, expr_index) | |
| self.function = func | |
| self.expr_index = expr_index | |
| if instr_index is None: | |
| self.instr_index = core.BNGetMediumLevelILInstructionForExpr(func.handle, expr_index) | |
| else: | |
| self.instr_index = instr_index | |
| self.operation = MediumLevelILOperation(instr.operation) | |
| self.size = instr.size | |
| self.address = instr.address | |
| self.source_operand = instr.sourceOperand | |
| operands = MediumLevelILInstruction.ILOperations[instr.operation] | |
| self.operands = [] | |
| i = 0 | |
| for operand in operands: | |
| name, operand_type = operand | |
| if operand_type == "int": | |
| value = instr.operands[i] | |
| elif operand_type == "expr": | |
| value = MediumLevelILInstruction(func, instr.operands[i]) | |
| elif operand_type == "var": | |
| value = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) | |
| elif operand_type == "var_ssa": | |
| var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) | |
| version = instr.operands[i + 1] | |
| i += 1 | |
| value = SSAVariable(var, version) | |
| elif operand_type == "var_ssa_dest_and_src": | |
| var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) | |
| dest_version = instr.operands[i + 1] | |
| src_version = instr.operands[i + 2] | |
| i += 2 | |
| self.operands.append(SSAVariable(var, dest_version)) | |
| self.dest = SSAVariable(var, dest_version) | |
| value = SSAVariable(var, src_version) | |
| elif operand_type == "int_list": | |
| count = ctypes.c_ulonglong() | |
| operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) | |
| value = [] | |
| for j in xrange(count.value): | |
| value.append(operand_list[j]) | |
| core.BNMediumLevelILFreeOperandList(operand_list) | |
| elif operand_type == "var_list": | |
| count = ctypes.c_ulonglong() | |
| operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) | |
| i += 1 | |
| value = [] | |
| for j in xrange(count.value): | |
| value.append(function.Variable.from_identifier(self.function.source_function, operand_list[j])) | |
| core.BNMediumLevelILFreeOperandList(operand_list) | |
| elif operand_type == "var_ssa_list": | |
| count = ctypes.c_ulonglong() | |
| operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) | |
| i += 1 | |
| value = [] | |
| for j in xrange(count.value / 2): | |
| var_id = operand_list[j * 2] | |
| var_version = operand_list[(j * 2) + 1] | |
| value.append(SSAVariable(function.Variable.from_identifier(self.function.source_function, | |
| var_id), var_version)) | |
| core.BNMediumLevelILFreeOperandList(operand_list) | |
| elif operand_type == "expr_list": | |
| count = ctypes.c_ulonglong() | |
| operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) | |
| i += 1 | |
| value = [] | |
| for j in xrange(count.value): | |
| value.append(MediumLevelILInstruction(func, operand_list[j])) | |
| core.BNMediumLevelILFreeOperandList(operand_list) | |
| self.operands.append(value) | |
| self.__dict__[name] = value | |
| i += 1 | |
| def __str__(self): | |
| tokens = self.tokens | |
| if tokens is None: | |
| return "invalid" | |
| result = "" | |
| for token in tokens: | |
| result += token.text | |
| return result | |
| def __repr__(self): | |
| return "<il: %s>" % str(self) | |
| @property | |
| def tokens(self): | |
| """MLIL tokens (read-only)""" | |
| count = ctypes.c_ulonglong() | |
| tokens = ctypes.POINTER(core.BNInstructionTextToken)() | |
| if ((self.instr_index is not None) and (self.function.source_function is not None) and | |
| (self.expr_index == core.BNGetMediumLevelILIndexForInstruction(self.function.handle, self.instr_index))): | |
| if not core.BNGetMediumLevelILInstructionText(self.function.handle, self.function.source_function.handle, | |
| self.function.arch.handle, self.instr_index, tokens, count): | |
| return None | |
| else: | |
| if not core.BNGetMediumLevelILExprText(self.function.handle, self.function.arch.handle, | |
| self.expr_index, tokens, count): | |
| return None | |
| result = [] | |
| for i in xrange(0, count.value): | |
| token_type = InstructionTextTokenType(tokens[i].type) | |
| text = tokens[i].text | |
| value = tokens[i].value | |
| size = tokens[i].size | |
| operand = tokens[i].operand | |
| context = tokens[i].context | |
| confidence = tokens[i].confidence | |
| address = tokens[i].address | |
| result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) | |
| core.BNFreeInstructionText(tokens, count.value) | |
| return result | |
| @property | |
| def ssa_form(self): | |
| """SSA form of expression (read-only)""" | |
| return MediumLevelILInstruction(self.function.ssa_form, | |
| core.BNGetMediumLevelILSSAExprIndex(self.function.handle, self.expr_index)) | |
| @property | |
| def non_ssa_form(self): | |
| """Non-SSA form of expression (read-only)""" | |
| return MediumLevelILInstruction(self.function.non_ssa_form, | |
| core.BNGetMediumLevelILNonSSAExprIndex(self.function.handle, self.expr_index)) | |
| @property | |
| def value(self): | |
| """Value of expression if constant or a known value (read-only)""" | |
| value = core.BNGetMediumLevelILExprValue(self.function.handle, self.expr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| @property | |
| def possible_values(self): | |
| """Possible values of expression using path-sensitive static data flow analysis (read-only)""" | |
| value = core.BNGetMediumLevelILPossibleExprValues(self.function.handle, self.expr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| @property | |
| def branch_dependence(self): | |
| """Set of branching instructions that must take the true or false path to reach this instruction""" | |
| count = ctypes.c_ulonglong() | |
| deps = core.BNGetAllMediumLevelILBranchDependence(self.function.handle, self.instr_index, count) | |
| result = {} | |
| for i in xrange(0, count.value): | |
| result[deps[i].branch] = ILBranchDependence(deps[i].dependence) | |
| core.BNFreeILBranchDependenceList(deps) | |
| return result | |
| @property | |
| def low_level_il(self): | |
| """Low level IL form of this expression""" | |
| expr = self.function.get_low_level_il_expr_index(self.expr_index) | |
| if expr is None: | |
| return None | |
| return lowlevelil.LowLevelILInstruction(self.function.low_level_il.ssa_form, expr) | |
| @property | |
| def ssa_memory_version(self): | |
| """Version of active memory contents in SSA form for this instruction""" | |
| return core.BNGetMediumLevelILSSAMemoryVersionAtILInstruction(self.function.handle, self.instr_index) | |
| @property | |
| def prefix_operands(self): | |
| """All operands in the expression tree in prefix order""" | |
| result = [MediumLevelILOperationAndSize(self.operation, self.size)] | |
| for operand in self.operands: | |
| if isinstance(operand, MediumLevelILInstruction): | |
| result += operand.prefix_operands | |
| else: | |
| result.append(operand) | |
| return result | |
| @property | |
| def postfix_operands(self): | |
| """All operands in the expression tree in postfix order""" | |
| result = [] | |
| for operand in self.operands: | |
| if isinstance(operand, MediumLevelILInstruction): | |
| result += operand.postfix_operands | |
| else: | |
| result.append(operand) | |
| result.append(MediumLevelILOperationAndSize(self.operation, self.size)) | |
| return result | |
| @property | |
| def vars_written(self): | |
| """List of variables written by instruction""" | |
| if self.operation in [MediumLevelILOperation.MLIL_SET_VAR, MediumLevelILOperation.MLIL_SET_VAR_FIELD, | |
| MediumLevelILOperation.MLIL_SET_VAR_SSA, MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD, | |
| MediumLevelILOperation.MLIL_SET_VAR_ALIASED, MediumLevelILOperation.MLIL_SET_VAR_ALIASED_FIELD, | |
| MediumLevelILOperation.MLIL_VAR_PHI]: | |
| return [self.dest] | |
| elif self.operation in [MediumLevelILOperation.MLIL_SET_VAR_SPLIT, MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA]: | |
| return [self.high, self.low] | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL]: | |
| return self.output | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED, | |
| MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, | |
| MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA]: | |
| return self.output.vars_written | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL_OUTPUT, MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA]: | |
| return self.dest | |
| return [] | |
| @property | |
| def vars_read(self): | |
| """List of variables read by instruction""" | |
| if self.operation in [MediumLevelILOperation.MLIL_SET_VAR, MediumLevelILOperation.MLIL_SET_VAR_FIELD, | |
| MediumLevelILOperation.MLIL_SET_VAR_SPLIT, MediumLevelILOperation.MLIL_SET_VAR_SSA, | |
| MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA, MediumLevelILOperation.MLIL_SET_VAR_ALIASED]: | |
| return self.src.vars_read | |
| elif self.operation in [MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD, | |
| MediumLevelILOperation.MLIL_SET_VAR_ALIASED_FIELD]: | |
| return [self.prev] + self.src.vars_read | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL, MediumLevelILOperation.MLIL_SYSCALL, | |
| MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_SSA]: | |
| result = [] | |
| for param in self.params: | |
| result += param.vars_read | |
| return result | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED, | |
| MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA]: | |
| return self.params.vars_read | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL_PARAM, MediumLevelILOperation.MLIL_CALL_PARAM_SSA, | |
| MediumLevelILOperation.MLIL_VAR_PHI]: | |
| return self.src | |
| elif self.operation in [MediumLevelILOperation.MLIL_CALL_OUTPUT, MediumLevelILOperation.MLIL_CALL_OUTPUT_SSA]: | |
| return [] | |
| result = [] | |
| for operand in self.operands: | |
| if (isinstance(operand, function.Variable)) or (isinstance(operand, SSAVariable)): | |
| result.append(operand) | |
| elif isinstance(operand, MediumLevelILInstruction): | |
| result += operand.vars_read | |
| return result | |
| @property | |
| def expr_type(self): | |
| """Type of expression""" | |
| result = core.BNGetMediumLevelILExprType(self.function.handle, self.expr_index) | |
| if result.type: | |
| platform = None | |
| if self.function.source_function: | |
| platform = self.function.source_function.platform | |
| return types.Type(result.type, platform = platform, confidence = result.confidence) | |
| return None | |
| def get_ssa_var_possible_values(self, ssa_var): | |
| var_data = core.BNVariable() | |
| var_data.type = ssa_var.var.source_type | |
| var_data.index = ssa_var.var.index | |
| var_data.storage = ssa_var.var.storage | |
| value = core.BNGetMediumLevelILPossibleSSAVarValues(self.function.handle, var_data, ssa_var.version, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_ssa_var_version(self, var): | |
| var_data = core.BNVariable() | |
| var_data.type = var.source_type | |
| var_data.index = var.index | |
| var_data.storage = var.storage | |
| return core.BNGetMediumLevelILSSAVarVersionAtILInstruction(self.function.handle, var_data, self.instr_index) | |
| def get_var_for_reg(self, reg): | |
| reg = self.function.arch.get_reg_index(reg) | |
| result = core.BNGetMediumLevelILVariableForRegisterAtInstruction(self.function.handle, reg, self.instr_index) | |
| return function.Variable(self.function.source_function, result.type, result.index, result.storage) | |
| def get_var_for_flag(self, flag): | |
| flag = self.function.arch.get_flag_index(flag) | |
| result = core.BNGetMediumLevelILVariableForFlagAtInstruction(self.function.handle, flag, self.instr_index) | |
| return function.Variable(self.function.source_function, result.type, result.index, result.storage) | |
| def get_var_for_stack_location(self, offset): | |
| result = core.BNGetMediumLevelILVariableForStackLocationAtInstruction(self.function.handle, offset, self.instr_index) | |
| return function.Variable(self.function.source_function, result.type, result.index, result.storage) | |
| def get_reg_value(self, reg): | |
| reg = self.function.arch.get_reg_index(reg) | |
| value = core.BNGetMediumLevelILRegisterValueAtInstruction(self.function.handle, reg, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_reg_value_after(self, reg): | |
| reg = self.function.arch.get_reg_index(reg) | |
| value = core.BNGetMediumLevelILRegisterValueAfterInstruction(self.function.handle, reg, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_possible_reg_values(self, reg): | |
| reg = self.function.arch.get_reg_index(reg) | |
| value = core.BNGetMediumLevelILPossibleRegisterValuesAtInstruction(self.function.handle, reg, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_possible_reg_values_after(self, reg): | |
| reg = self.function.arch.get_reg_index(reg) | |
| value = core.BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(self.function.handle, reg, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_flag_value(self, flag): | |
| flag = self.function.arch.get_flag_index(flag) | |
| value = core.BNGetMediumLevelILFlagValueAtInstruction(self.function.handle, flag, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_flag_value_after(self, flag): | |
| flag = self.function.arch.get_flag_index(flag) | |
| value = core.BNGetMediumLevelILFlagValueAfterInstruction(self.function.handle, flag, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_possible_flag_values(self, flag): | |
| flag = self.function.arch.get_flag_index(flag) | |
| value = core.BNGetMediumLevelILPossibleFlagValuesAtInstruction(self.function.handle, flag, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_possible_flag_values_after(self, flag): | |
| flag = self.function.arch.get_flag_index(flag) | |
| value = core.BNGetMediumLevelILPossibleFlagValuesAfterInstruction(self.function.handle, flag, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_stack_contents(self, offset, size): | |
| value = core.BNGetMediumLevelILStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_stack_contents_after(self, offset, size): | |
| value = core.BNGetMediumLevelILStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) | |
| result = function.RegisterValue(self.function.arch, value) | |
| return result | |
| def get_possible_stack_contents(self, offset, size): | |
| value = core.BNGetMediumLevelILPossibleStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_possible_stack_contents_after(self, offset, size): | |
| value = core.BNGetMediumLevelILPossibleStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) | |
| result = function.PossibleValueSet(self.function.arch, value) | |
| core.BNFreePossibleValueSet(value) | |
| return result | |
| def get_branch_dependence(self, branch_instr): | |
| return ILBranchDependence(core.BNGetMediumLevelILBranchDependence(self.function.handle, self.instr_index, branch_instr)) | |
| def __setattr__(self, name, value): | |
| try: | |
| object.__setattr__(self, name, value) | |
| except AttributeError: | |
| raise AttributeError("attribute '%s' is read only" % name) | |
| class MediumLevelILExpr(object): | |
| """ | |
| ``class MediumLevelILExpr`` hold the index of IL Expressions. | |
| .. note:: This class shouldn't be instantiated directly. Rather the helper members of MediumLevelILFunction should be \ | |
| used instead. | |
| """ | |
| def __init__(self, index): | |
| self.index = index | |
| class MediumLevelILFunction(object): | |
| """ | |
| ``class MediumLevelILFunction`` contains the list of MediumLevelILExpr objects that make up a function. MediumLevelILExpr | |
| objects can be added to the MediumLevelILFunction by calling ``append`` and passing the result of the various class | |
| methods which return MediumLevelILExpr objects. | |
| """ | |
| def __init__(self, arch, handle = None, source_func = None): | |
| self.arch = arch | |
| self.source_function = source_func | |
| if handle is not None: | |
| self.handle = core.handle_of_type(handle, core.BNMediumLevelILFunction) | |
| else: | |
| func_handle = None | |
| if self.source_function is not None: | |
| func_handle = self.source_function.handle | |
| self.handle = core.BNCreateMediumLevelILFunction(arch.handle, func_handle) | |
| def __del__(self): | |
| core.BNFreeMediumLevelILFunction(self.handle) | |
| def __eq__(self, value): | |
| if not isinstance(value, MediumLevelILFunction): | |
| return False | |
| return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) | |
| def __ne__(self, value): | |
| if not isinstance(value, MediumLevelILFunction): | |
| return True | |
| return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) | |
| @property | |
| def current_address(self): | |
| """Current IL Address (read/write)""" | |
| return core.BNMediumLevelILGetCurrentAddress(self.handle) | |
| @current_address.setter | |
| def current_address(self, value): | |
| core.BNMediumLevelILSetCurrentAddress(self.handle, self.arch.handle, value) | |
| def set_current_address(self, value, arch = None): | |
| if arch is None: | |
| arch = self.arch | |
| core.BNMediumLevelILSetCurrentAddress(self.handle, arch.handle, value) | |
| @property | |
| def basic_blocks(self): | |
| """list of MediumLevelILBasicBlock objects (read-only)""" | |
| count = ctypes.c_ulonglong() | |
| blocks = core.BNGetMediumLevelILBasicBlockList(self.handle, count) | |
| result = [] | |
| view = None | |
| if self.source_function is not None: | |
| view = self.source_function.view | |
| for i in xrange(0, count.value): | |
| result.append(MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)) | |
| core.BNFreeBasicBlockList(blocks, count.value) | |
| return result | |
| @property | |
| def ssa_form(self): | |
| """Medium level IL in SSA form (read-only)""" | |
| result = core.BNGetMediumLevelILSSAForm(self.handle) | |
| if not result: | |
| return None | |
| return MediumLevelILFunction(self.arch, result, self.source_function) | |
| @property | |
| def non_ssa_form(self): | |
| """Medium level IL in non-SSA (default) form (read-only)""" | |
| result = core.BNGetMediumLevelILNonSSAForm(self.handle) | |
| if not result: | |
| return None | |
| return MediumLevelILFunction(self.arch, result, self.source_function) | |
| @property | |
| def low_level_il(self): | |
| """Low level IL for this function""" | |
| result = core.BNGetLowLevelILForMediumLevelIL(self.handle) | |
| if not result: | |
| return None | |
| return lowlevelil.LowLevelILFunction(self.arch, result, self.source_function) | |
| def __setattr__(self, name, value): | |
| try: | |
| object.__setattr__(self, name, value) | |
| except AttributeError: | |
| raise AttributeError("attribute '%s' is read only" % name) | |
| def __len__(self): | |
| return int(core.BNGetMediumLevelILInstructionCount(self.handle)) | |
| def __getitem__(self, i): | |
| if isinstance(i, slice) or isinstance(i, tuple): | |
| raise IndexError("expected integer instruction index") | |
| if isinstance(i, MediumLevelILExpr): | |
| return MediumLevelILInstruction(self, i.index) | |
| if (i < 0) or (i >= len(self)): | |
| raise IndexError("index out of range") | |
| return MediumLevelILInstruction(self, core.BNGetMediumLevelILIndexForInstruction(self.handle, i), i) | |
| def __setitem__(self, i, j): | |
| raise IndexError("instruction modification not implemented") | |
| def __iter__(self): | |
| count = ctypes.c_ulonglong() | |
| blocks = core.BNGetMediumLevelILBasicBlockList(self.handle, count) | |
| view = None | |
| if self.source_function is not None: | |
| view = self.source_function.view | |
| try: | |
| for i in xrange(0, count.value): | |
| yield MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self) | |
| finally: | |
| core.BNFreeBasicBlockList(blocks, count.value) | |
| def get_instruction_start(self, addr, arch = None): | |
| if arch is None: | |
| arch = self.arch | |
| result = core.BNMediumLevelILGetInstructionStart(self.handle, arch.handle, addr) | |
| if result >= core.BNGetMediumLevelILInstructionCount(self.handle): | |
| return None | |
| return result | |
| def expr(self, operation, a = 0, b = 0, c = 0, d = 0, e = 0, size = 0): | |
| if isinstance(operation, str): | |
| operation = MediumLevelILOperation[operation] | |
| elif isinstance(operation, MediumLevelILOperation): | |
| operation = operation.value | |
| return MediumLevelILExpr(core.BNMediumLevelILAddExpr(self.handle, operation, size, a, b, c, d, e)) | |
| def append(self, expr): | |
| """ | |
| ``append`` adds the MediumLevelILExpr ``expr`` to the current MediumLevelILFunction. | |
| :param MediumLevelILExpr expr: the MediumLevelILExpr to add to the current MediumLevelILFunction | |
| :return: number of MediumLevelILExpr in the current function | |
| :rtype: int | |
| """ | |
| return core.BNMediumLevelILAddInstruction(self.handle, expr.index) | |
| def goto(self, label): | |
| """ | |
| ``goto`` returns a goto expression which jumps to the provided MediumLevelILLabel. | |
| :param MediumLevelILLabel label: Label to jump to | |
| :return: the MediumLevelILExpr that jumps to the provided label | |
| :rtype: MediumLevelILExpr | |
| """ | |
| return MediumLevelILExpr(core.BNMediumLevelILGoto(self.handle, label.handle)) | |
| def if_expr(self, operand, t, f): | |
| """ | |
| ``if_expr`` returns the ``if`` expression which depending on condition ``operand`` jumps to the MediumLevelILLabel | |
| ``t`` when the condition expression ``operand`` is non-zero and ``f`` when it's zero. | |
| :param MediumLevelILExpr operand: comparison expression to evaluate. | |
| :param MediumLevelILLabel t: Label for the true branch | |
| :param MediumLevelILLabel f: Label for the false branch | |
| :return: the MediumLevelILExpr for the if expression | |
| :rtype: MediumLevelILExpr | |
| """ | |
| return MediumLevelILExpr(core.BNMediumLevelILIf(self.handle, operand.index, t.handle, f.handle)) | |
| def mark_label(self, label): | |
| """ | |
| ``mark_label`` assigns a MediumLevelILLabel to the current IL address. | |
| :param MediumLevelILLabel label: | |
| :rtype: None | |
| """ | |
| core.BNMediumLevelILMarkLabel(self.handle, label.handle) | |
| def add_label_list(self, labels): | |
| """ | |
| ``add_label_list`` returns a label list expression for the given list of MediumLevelILLabel objects. | |
| :param list(MediumLevelILLabel) lables: the list of MediumLevelILLabel to get a label list expression from | |
| :return: the label list expression | |
| :rtype: MediumLevelILExpr | |
| """ | |
| label_list = (ctypes.POINTER(core.BNMediumLevelILLabel) * len(labels))() | |
| for i in xrange(len(labels)): | |
| label_list[i] = labels[i].handle | |
| return MediumLevelILExpr(core.BNMediumLevelILAddLabelList(self.handle, label_list, len(labels))) | |
| def add_operand_list(self, operands): | |
| """ | |
| ``add_operand_list`` returns an operand list expression for the given list of integer operands. | |
| :param list(int) operands: list of operand numbers | |
| :return: an operand list expression | |
| :rtype: MediumLevelILExpr | |
| """ | |
| operand_list = (ctypes.c_ulonglong * len(operands))() | |
| for i in xrange(len(operands)): | |
| operand_list[i] = operands[i] | |
| return MediumLevelILExpr(core.BNMediumLevelILAddOperandList(self.handle, operand_list, len(operands))) | |
| def operand(self, n, expr): | |
| """ | |
| ``operand`` sets the operand number of the expression ``expr`` and passes back ``expr`` without modification. | |
| :param int n: | |
| :param MediumLevelILExpr expr: | |
| :return: returns the expression ``expr`` unmodified | |
| :rtype: MediumLevelILExpr | |
| """ | |
| core.BNMediumLevelILSetExprSourceOperand(self.handle, expr.index, n) | |
| return expr | |
| def finalize(self): | |
| """ | |
| ``finalize`` ends the function and computes the list of basic blocks. | |
| :rtype: None | |
| """ | |
| core.BNFinalizeMediumLevelILFunction(self.handle) | |
| def get_ssa_instruction_index(self, instr): | |
| return core.BNGetMediumLevelILSSAInstructionIndex(self.handle, instr) | |
| def get_non_ssa_instruction_index(self, instr): | |
| return core.BNGetMediumLevelILNonSSAInstructionIndex(self.handle, instr) | |
| def get_ssa_var_definition(self, ssa_var): | |
| var_data = core.BNVariable() | |
| var_data.type = ssa_var.var.source_type | |
| var_data.index = ssa_var.var.index | |
| var_data.storage = ssa_var.var.storage | |
| result = core.BNGetMediumLevelILSSAVarDefinition(self.handle, var_data, ssa_var.version) | |
| if result >= core.BNGetMediumLevelILInstructionCount(self.handle): | |
| return None | |
| return result | |
| def get_ssa_memory_definition(self, version): | |
| result = core.BNGetMediumLevelILSSAMemoryDefinition(self.handle, version) | |
| if result >= core.BNGetMediumLevelILInstructionCount(self.handle): | |
| return None | |
| return result | |
| def get_ssa_var_uses(self, ssa_var): | |
| count = ctypes.c_ulonglong() | |
| var_data = core.BNVariable() | |
| var_data.type = ssa_var.var.source_type | |
| var_data.index = ssa_var.var.index | |
| var_data.storage = ssa_var.var.storage | |
| instrs = core.BNGetMediumLevelILSSAVarUses(self.handle, var_data, ssa_var.version, count) | |
| result = [] | |
| for i in xrange(0, count.value): | |
| result.append(instrs[i]) | |
| core.BNFreeILInstructionList(instrs) | |
| return result | |
| def get_ssa_memory_uses(self, version): | |
| count = ctypes.c_ulonglong() | |
| instrs = core.BNGetMediumLevelILSSAMemoryUses(self.handle, version, count) | |
| result = [] | |
| for i in xrange(0, count.value): | |
| result.append(instrs[i]) | |
| core.BNFreeILInstructionList(instrs) | |
| return result | |
| def get_var_definitions(self, var): | |
| count = ctypes.c_ulonglong() | |
| var_data = core.BNVariable() | |
| var_data.type = var.source_type | |
| var_data.index = var.index | |
| var_data.storage = var.storage | |
| instrs = core.BNGetMediumLevelILVariableDefinitions(self.handle, var_data, count) | |
| result = [] | |
| for i in xrange(0, count.value): | |
| result.append(instrs[i]) | |
| core.BNFreeILInstructionList(instrs) | |
| return result | |
| def get_var_uses(self, var): | |
| count = ctypes.c_ulonglong() | |
| var_data = core.BNVariable() | |
| var_data.type = var.source_type | |
| var_data.index = var.index | |
| var_data.storage = var.storage | |
| instrs = core.BNGetMediumLevelILVariableUses(self.handle, var_data, count) | |
| result = [] | |
| for i in xrange(0, count.value): | |
| result.append(instrs[i]) | |
| core.BNFreeILInstructionList(instrs) | |
| return result | |
| def get_ssa_var_value(self, ssa_var): | |
| var_data = core.BNVariable() | |
| var_data.type = ssa_var.var.source_type | |
| var_data.index = ssa_var.var.index | |
| var_data.storage = ssa_var.var.storage | |
| value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version) | |
| result = function.RegisterValue(self.arch, value) | |
| return result | |
| def get_low_level_il_instruction_index(self, instr): | |
| low_il = self.low_level_il | |
| if low_il is None: | |
| return None | |
| low_il = low_il.ssa_form | |
| if low_il is None: | |
| return None | |
| result = core.BNGetLowLevelILInstructionIndex(self.handle, instr) | |
| if result >= core.BNGetLowLevelILInstructionCount(low_il.handle): | |
| return None | |
| return result | |
| def get_low_level_il_expr_index(self, expr): | |
| low_il = self.low_level_il | |
| if low_il is None: | |
| return None | |
| low_il = low_il.ssa_form | |
| if low_il is None: | |
| return None | |
| result = core.BNGetLowLevelILExprIndex(self.handle, expr) | |
| if result >= core.BNGetLowLevelILExprCount(low_il.handle): | |
| return None | |
| return result | |
| class MediumLevelILBasicBlock(basicblock.BasicBlock): | |
| def __init__(self, view, handle, owner): | |
| super(MediumLevelILBasicBlock, self).__init__(view, handle) | |
| self.il_function = owner | |
| def __iter__(self): | |
| for idx in xrange(self.start, self.end): | |
| yield self.il_function[idx] | |
| def __getitem__(self, idx): | |
| size = self.end - self.start | |
| if idx > size or idx < -size: | |
| raise IndexError("list index is out of range") | |
| if idx >= 0: | |
| return self.il_function[idx + self.start] | |
| else: | |
| return self.il_function[self.end + idx] | |
| def _create_instance(self, view, handle): | |
| """Internal method by super to instantiante child instances""" | |
| return MediumLevelILBasicBlock(view, handle, self.il_function) |