Skip to content
Permalink
dev
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
# Copyright (c) 2018-2022 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.
from abc import abstractmethod
import ctypes
import struct
from typing import Optional, List, Union, Mapping, Generator, NewType, Tuple, ClassVar, Dict
from dataclasses import dataclass
# Binary Ninja components
from . import _binaryninjacore as core
from .enums import MediumLevelILOperation, ILBranchDependence, DataFlowQueryOption, FunctionGraphType, DeadStoreElimination
from . import basicblock
from . import function
from . import types
from . import lowlevelil
from . import highlevelil
from . import flowgraph
from . import variable
from . import architecture
from . import binaryview
from .interaction import show_graph_report
from .commonil import (
BaseILInstruction, Constant, BinaryOperation, UnaryOperation, Comparison, SSA, Phi, FloatingPoint, ControlFlow,
Terminal, Call, Localcall, Syscall, Tailcall, Return, Signed, Arithmetic, Carry, DoublePrecision, Memory, Load,
Store, RegisterStack, SetVar, Intrinsic
)
TokenList = List['function.InstructionTextToken']
ExpressionIndex = NewType('ExpressionIndex', int)
InstructionIndex = NewType('InstructionIndex', int)
MLILInstructionsType = Generator['MediumLevelILInstruction', None, None]
MLILBasicBlocksType = Generator['MediumLevelILBasicBlock', None, None]
OperandsType = Tuple[ExpressionIndex, ExpressionIndex, ExpressionIndex, ExpressionIndex, ExpressionIndex]
MediumLevelILOperandType = Union[int, float, 'MediumLevelILOperationAndSize', 'MediumLevelILInstruction',
'lowlevelil.ILIntrinsic', 'variable.Variable', 'SSAVariable', List[int],
List['variable.Variable'], List['SSAVariable'], List['MediumLevelILInstruction'],
Mapping[int, int]]
@dataclass(frozen=True, repr=False, order=True)
class SSAVariable:
var: 'variable.Variable'
version: int
def __repr__(self):
return f"<ssa {self.var} version {self.version}>"
@property
def name(self) -> str:
return self.var.name
@property
def type(self) -> 'types.Type':
return self.var.type
@property
def function(self) -> 'function.Function':
return self.var.function
@property
def dead_store_elimination(self) -> DeadStoreElimination:
return self.var.dead_store_elimination
class MediumLevelILLabel:
def __init__(self, handle: Optional[core.BNMediumLevelILLabel] = None):
if handle is None:
self.handle = (core.BNMediumLevelILLabel * 1)()
core.BNMediumLevelILInitLabel(self.handle)
else:
self.handle = handle
@dataclass(frozen=True, repr=False)
class MediumLevelILOperationAndSize:
operation: MediumLevelILOperation
size: int
def __repr__(self):
if self.size == 0:
return f"<{self.operation.name}>"
return f"<{self.operation.name} {self.size}>"
@dataclass(frozen=True)
class CoreMediumLevelILInstruction:
operation: MediumLevelILOperation
source_operand: int
size: int
operands: OperandsType
address: int
@classmethod
def from_BNMediumLevelILInstruction(cls, instr: core.BNMediumLevelILInstruction) -> 'CoreMediumLevelILInstruction':
operands: OperandsType = tuple([ExpressionIndex(instr.operands[i]) for i in range(5)]) # type: ignore
return cls(MediumLevelILOperation(instr.operation), instr.sourceOperand, instr.size, operands, instr.address)
@dataclass(frozen=True)
class MediumLevelILInstruction(BaseILInstruction):
"""
``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``).
"""
function: 'MediumLevelILFunction'
expr_index: ExpressionIndex
instr: CoreMediumLevelILInstruction
instr_index: InstructionIndex
ILOperations: ClassVar[Mapping[MediumLevelILOperation, List[Tuple[str, str]]]] = {
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", "target_map")
], 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")]
}
@staticmethod
def show_mlil_hierarchy():
graph = flowgraph.FlowGraph()
nodes = {}
for instruction in ILInstruction.values():
instruction.add_subgraph(graph, nodes)
show_graph_report("MLIL Class Hierarchy Graph", graph)
@classmethod
def create(
cls, func: 'MediumLevelILFunction', expr_index: ExpressionIndex, instr_index: Optional[InstructionIndex] = None
) -> 'MediumLevelILInstruction':
assert func.arch is not None, "Attempted to create IL instruction with function missing an Architecture"
inst = core.BNGetMediumLevelILByIndex(func.handle, expr_index)
assert inst is not None, "core.BNGetMediumLevelILByIndex returned None"
if instr_index is None:
instr_index = core.BNGetMediumLevelILInstructionForExpr(func.handle, expr_index)
assert instr_index is not None, "core.BNGetMediumLevelILInstructionForExpr returned None"
instr = CoreMediumLevelILInstruction.from_BNMediumLevelILInstruction(inst)
return ILInstruction[instr.operation](func, expr_index, instr, instr_index) # type: ignore
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 f"<mlil: {self}>"
def __eq__(self, other: 'MediumLevelILInstruction') -> bool:
if not isinstance(other, MediumLevelILInstruction):
return NotImplemented
return self.function == other.function and self.expr_index == other.expr_index
def __lt__(self, other: 'MediumLevelILInstruction') -> bool:
if not isinstance(other, MediumLevelILInstruction):
return NotImplemented
return self.function == other.function and self.expr_index < other.expr_index
def __le__(self, other: 'MediumLevelILInstruction') -> bool:
if not isinstance(other, MediumLevelILInstruction):
return NotImplemented
return self.function == other.function and self.expr_index <= other.expr_index
def __gt__(self, other: 'MediumLevelILInstruction') -> bool:
if not isinstance(other, MediumLevelILInstruction):
return NotImplemented
return self.function == other.function and self.expr_index > other.expr_index
def __ge__(self, other: 'MediumLevelILInstruction') -> bool:
if not isinstance(other, MediumLevelILInstruction):
return NotImplemented
return self.function == other.function and self.expr_index >= other.expr_index
def __hash__(self):
return hash((self.function, self.expr_index))
@property
def tokens(self) -> TokenList:
"""MLIL tokens (read-only)"""
count = ctypes.c_ulonglong()
tokens = ctypes.POINTER(core.BNInstructionTextToken)()
assert self.function.arch is not None, f"type(self.function): {type(self.function)} "
result = core.BNGetMediumLevelILExprText(
self.function.handle, self.function.arch.handle, self.expr_index, tokens, count, None
)
assert result, "core.BNGetMediumLevelILExprText returned False"
try:
return function.InstructionTextToken._from_core_struct(tokens, count.value)
finally:
core.BNFreeInstructionText(tokens, count.value)
@property
def il_basic_block(self) -> 'MediumLevelILBasicBlock':
"""IL basic block object containing this expression (read-only) (only available on finalized functions)"""
core_block = core.BNGetMediumLevelILBasicBlockForInstruction(self.function.handle, self.instr_index)
assert core_block is not None
assert self.function.source_function is not None
return MediumLevelILBasicBlock(core_block, self.function, self.function.source_function.view)
@property
def ssa_form(self) -> 'MediumLevelILInstruction':
"""SSA form of expression (read-only)"""
ssa_func = self.function.ssa_form
assert ssa_func is not None
return MediumLevelILInstruction.create(
ssa_func, ExpressionIndex(core.BNGetMediumLevelILSSAExprIndex(self.function.handle, self.expr_index))
)
@property
def non_ssa_form(self) -> 'MediumLevelILInstruction':
"""Non-SSA form of expression (read-only)"""
non_ssa_func = self.function.non_ssa_form
assert non_ssa_func is not None
return MediumLevelILInstruction.create(
non_ssa_func,
ExpressionIndex(core.BNGetMediumLevelILNonSSAExprIndex(self.function.handle, self.expr_index))
)
@property
def value(self) -> variable.RegisterValue:
"""Value of expression if constant or a known value (read-only)"""
value = core.BNGetMediumLevelILExprValue(self.function.handle, self.expr_index)
result = variable.RegisterValue.from_BNRegisterValue(value, self.function.arch)
return result
@property
def possible_values(self) -> variable.PossibleValueSet:
"""Possible values of expression using path-sensitive static data flow analysis (read-only)"""
value = core.BNGetMediumLevelILPossibleExprValues(self.function.handle, self.expr_index, None, 0)