Source code for binaryninja.mediumlevelil

# Copyright (c) 2019 Vector 35 Inc
#
# 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
import struct

# Binary Ninja components
import binaryninja
from binaryninja import _binaryninjacore as core
from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence
from binaryninja import basicblock #required for MediumLevelILBasicBlock argument
from binaryninja import function
from binaryninja import types
from binaryninja import lowlevelil

# 2-3 compatibility
from binaryninja import range


[docs]class SSAVariable(object):
[docs] 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 isinstance(other, SSAVariable) and ( (self.var, self.version) == (other.var, other.version) ) def __hash__(self): return hash((self.var, self.version))
[docs]class MediumLevelILLabel(object):
[docs] def __init__(self, handle = None): if handle is None: self.handle = (core.BNMediumLevelILLabel * 1)() core.BNMediumLevelILInitLabel(self.handle) else: self.handle = handle
[docs]class MediumLevelILOperationAndSize(object):
[docs] 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) def __eq__(self, other): if isinstance(other, MediumLevelILOperation): return other == self.operation if isinstance(other, MediumLevelILOperationAndSize): return other.size == self.size and other.operation == self.operation else: return False
[docs]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_VAR_SPLIT: [("high", "var"), ("low", "var")], 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_EXTERN_PTR: [("constant", "int"), ("offset", "int")], MediumLevelILOperation.MLIL_FLOAT_CONST: [("constant", "float")], 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: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_DIVS: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_DIVS_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODU: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODU_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODS: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODS_DP: [("left", "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_RET_HINT: [("dest", "expr")], 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_TAILCALL: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")], MediumLevelILOperation.MLIL_TAILCALL_UNTYPED: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")], MediumLevelILOperation.MLIL_BP: [], MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], MediumLevelILOperation.MLIL_INTRINSIC: [("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], MediumLevelILOperation.MLIL_INTRINSIC_SSA: [("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], MediumLevelILOperation.MLIL_FREE_VAR_SLOT: [("dest", "var")], MediumLevelILOperation.MLIL_FREE_VAR_SLOT_SSA: [("prev", "var_ssa_dest_and_src")], MediumLevelILOperation.MLIL_UNDEF: [], MediumLevelILOperation.MLIL_UNIMPL: [], MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], MediumLevelILOperation.MLIL_FADD: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FSUB: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FMUL: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FDIV: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FSQRT: [("src", "expr")], MediumLevelILOperation.MLIL_FNEG: [("src", "expr")], MediumLevelILOperation.MLIL_FABS: [("src", "expr")], MediumLevelILOperation.MLIL_FLOAT_TO_INT: [("src", "expr")], MediumLevelILOperation.MLIL_INT_TO_FLOAT: [("src", "expr")], MediumLevelILOperation.MLIL_FLOAT_CONV: [("src", "expr")], MediumLevelILOperation.MLIL_ROUND_TO_INT: [("src", "expr")], MediumLevelILOperation.MLIL_FLOOR: [("src", "expr")], MediumLevelILOperation.MLIL_CEIL: [("src", "expr")], MediumLevelILOperation.MLIL_FTRUNC: [("src", "expr")], MediumLevelILOperation.MLIL_FCMP_E: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_NE: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_LT: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_LE: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_GE: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_GT: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_O: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_FCMP_UO: [("left", "expr"), ("right", "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_VAR_SPLIT_SSA: [("high", "var_ssa"), ("low", "var_ssa")], 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_TAILCALL_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int")], MediumLevelILOperation.MLIL_TAILCALL_UNTYPED_SSA: [("output", "expr"), ("dest", "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")] }
[docs] 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] value = (value & ((1 << 63) - 1)) - (value & (1 << 63)) elif operand_type == "float": if instr.size == 4: value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0] elif instr.size == 8: value = struct.unpack("d", struct.pack("Q", instr.operands[i]))[0] else: value = instr.operands[i] elif operand_type == "expr": value = MediumLevelILInstruction(func, instr.operands[i]) elif operand_type == "intrinsic": value = lowlevelil.ILIntrinsic(func.arch, 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 range(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 range(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 range(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 range(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 = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result @property def il_basic_block(self): """IL basic block object containing this expression (read-only) (only available on finalized functions)""" return MediumLevelILBasicBlock(self.function.source_function.view, core.BNGetMediumLevelILBasicBlockForInstruction(self.function.handle, self.instr_index), self.function) @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 range(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 llil(self): """Alias for low_level_il""" return self.low_level_il @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, MediumLevelILOperation.MLIL_TAILCALL]: return self.output elif self.operation in [MediumLevelILOperation.MLIL_CALL_UNTYPED, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED, MediumLevelILOperation.MLIL_TAILCALL_UNTYPED, MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_TAILCALL_SSA, MediumLevelILOperation.MLIL_TAILCALL_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_TAILCALL, MediumLevelILOperation.MLIL_CALL_SSA, MediumLevelILOperation.MLIL_SYSCALL_SSA, MediumLevelILOperation.MLIL_TAILCALL_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_TAILCALL_UNTYPED, MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_SYSCALL_UNTYPED_SSA, MediumLevelILOperation.MLIL_TAILCALL_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
[docs] 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
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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)
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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
[docs] 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)
[docs]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. """
[docs] def __init__(self, index): self.index = index
[docs]class MediumLevelILFunction(object): """ ``class MediumLevelILFunction`` contains the list of MediumLevelILExpr objects that make up a binaryninja.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. """
[docs] def __init__(self, arch = None, 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) if self.source_function is None: self.source_function = binaryninja.function.Function(handle = core.BNGetMediumLevelILOwnerFunction(self.handle)) if self.arch is None: self.arch = self.source_function.arch else: if self.source_function is None: self.handle = None raise ValueError("IL functions must be created with an associated function") if self.arch is None: self.arch = self.source_function.arch func_handle = self.source_function.handle self.handle = core.BNCreateMediumLevelILFunction(arch.handle, func_handle)
def __del__(self): if self.handle is not None: 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)
[docs] 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 range(0, count.value): result.append(MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self)) core.BNFreeBasicBlockList(blocks, count.value) return result @property def instructions(self): """A generator of mlil instructions of the current function""" for block in self.basic_blocks: for i in block: yield i @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) @property def llil(self): """Alias for low_level_il""" return self.low_level_il 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 range(0, count.value): yield MediumLevelILBasicBlock(view, core.BNNewBasicBlockReference(blocks[i]), self) finally: core.BNFreeBasicBlockList(blocks, count.value)
[docs] 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
[docs] 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))
[docs] 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)
[docs] 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))
[docs] 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))
[docs] 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)
[docs] def add_label_list(self, labels): """ ``add_label_list`` returns a label list expression for the given list of MediumLevelILLabel objects. :param list(MediumLevelILLabel) labels: 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 range(len(labels)): label_list[i] = labels[i].handle return MediumLevelILExpr(core.BNMediumLevelILAddLabelList(self.handle, label_list, len(labels)))
[docs] 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 range(len(operands)): operand_list[i] = operands[i] return MediumLevelILExpr(core.BNMediumLevelILAddOperandList(self.handle, operand_list, len(operands)))
[docs] 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
[docs] def finalize(self): """ ``finalize`` ends the function and computes the list of basic blocks. :rtype: None """ core.BNFinalizeMediumLevelILFunction(self.handle)
[docs] def get_ssa_instruction_index(self, instr): return core.BNGetMediumLevelILSSAInstructionIndex(self.handle, instr)
[docs] def get_non_ssa_instruction_index(self, instr): return core.BNGetMediumLevelILNonSSAInstructionIndex(self.handle, instr)
[docs] 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
[docs] def get_ssa_memory_definition(self, version): result = core.BNGetMediumLevelILSSAMemoryDefinition(self.handle, version) if result >= core.BNGetMediumLevelILInstructionCount(self.handle): return None return result
[docs] 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 range(0, count.value): result.append(instrs[i]) core.BNFreeILInstructionList(instrs) return result
[docs] def get_ssa_memory_uses(self, version): count = ctypes.c_ulonglong() instrs = core.BNGetMediumLevelILSSAMemoryUses(self.handle, version, count) result = [] for i in range(0, count.value): result.append(instrs[i]) core.BNFreeILInstructionList(instrs) return result
[docs] def is_ssa_var_live(self, ssa_var): """ ``is_ssa_var_live`` determines if ``ssa_var`` is live at any point in the function :param SSAVariable ssa_var: the SSA variable to query :return: whether the variable is live at any point in the function :rtype: bool """ 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 return core.BNIsMediumLevelILSSAVarLive(self.handle, var_data, ssa_var.version)
[docs] 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 range(0, count.value): result.append(instrs[i]) core.BNFreeILInstructionList(instrs) return result
[docs] 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 range(0, count.value): result.append(instrs[i]) core.BNFreeILInstructionList(instrs) return result
[docs] 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
[docs] 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
[docs] 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
[docs] def create_graph(self, settings = None): if settings is not None: settings_obj = settings.handle else: settings_obj = None return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateMediumLevelILFunctionGraph(self.handle, settings_obj))
[docs]class MediumLevelILBasicBlock(basicblock.BasicBlock):
[docs] def __init__(self, view, handle, owner): super(MediumLevelILBasicBlock, self).__init__(handle, view) self.il_function = owner
def __iter__(self): for idx in range(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, handle, view): """Internal method by super to instantiate child instances""" return MediumLevelILBasicBlock(view, handle, self.il_function) def __hash__(self): return hash((self.start, self.end, self.il_function))