summaryrefslogtreecommitdiff
path: root/python/function.py
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2017-04-21 23:29:16 -0400
committerRusty Wagner <rusty@vector35.com>2017-04-21 23:29:16 -0400
commit87990dd2043a6234003620b6a408e5ae17c4eade (patch)
treea77daf0d96f27aa037e76ea2ba868ce968271638 /python/function.py
parent93020159006b68c5e0e5b1eafeef11d1df72da1a (diff)
parent66c7accacdbc73ed4edb7e9bada54085a3272426 (diff)
Merge branch 'mlil' into dev
Diffstat (limited to 'python/function.py')
-rw-r--r--python/function.py292
1 files changed, 191 insertions, 101 deletions
diff --git a/python/function.py b/python/function.py
index 9e58c47d..18856ff2 100644
--- a/python/function.py
+++ b/python/function.py
@@ -26,13 +26,14 @@ import ctypes
import _binaryninjacore as core
from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType,
HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend,
- DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext)
+ DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType)
import architecture
import highlight
import associateddatastore
import types
import basicblock
import lowlevelil
+import mediumlevelil
import binaryview
import log
@@ -50,93 +51,158 @@ class RegisterValue(object):
def __init__(self, arch, value):
self.type = RegisterValueType(value.state)
if value.state == RegisterValueType.EntryValue:
- self.reg = arch.get_reg_name(value.reg)
- elif value.state == RegisterValueType.OffsetFromEntryValue:
- self.reg = arch.get_reg_name(value.reg)
+ self.reg = arch.get_reg_name(value.value)
+ elif value.state == RegisterValueType.ConstantValue:
+ self.value = value.value
+ elif value.state == RegisterValueType.StackFrameOffset:
self.offset = value.value
+
+ def __repr__(self):
+ if self.type == RegisterValueType.EntryValue:
+ return "<entry %s>" % self.reg
+ if self.type == RegisterValueType.ConstantValue:
+ return "<const %#x>" % self.value
+ if self.type == RegisterValueType.StackFrameOffset:
+ return "<stack frame offset %#x>" % self.offset
+ if self.type == RegisterValueType.ReturnAddressValue:
+ return "<return address>"
+ return "<undetermined>"
+
+
+class ValueRange(object):
+ def __init__(self, start, end, step):
+ self.start = start
+ self.end = end
+ self.step = step
+
+ def __repr__(self):
+ if self.step == 1:
+ return "<range: %#x to %#x>" % (self.start, self.end)
+ return "<range: %#x to %#x, step %#x>" % (self.start, self.end, self.step)
+
+
+class PossibleValueSet(object):
+ def __init__(self, arch, value):
+ self.type = RegisterValueType(value.state)
+ if value.state == RegisterValueType.EntryValue:
+ self.reg = arch.get_reg_name(value.value)
elif value.state == RegisterValueType.ConstantValue:
self.value = value.value
elif value.state == RegisterValueType.StackFrameOffset:
self.offset = value.value
elif value.state == RegisterValueType.SignedRangeValue:
self.offset = value.value
- self.start = value.rangeStart
- self.end = value.rangeEnd
- self.step = value.rangeStep
- if self.start & (1 << 63):
- self.start |= ~((1 << 63) - 1)
- if self.end & (1 << 63):
- self.end |= ~((1 << 63) - 1)
+ self.ranges = []
+ for i in xrange(0, value.count):
+ start = value.ranges[i].start
+ end = value.ranges[i].end
+ step = value.ranges[i].step
+ if start & (1 << 63):
+ start |= ~((1 << 63) - 1)
+ if end & (1 << 63):
+ end |= ~((1 << 63) - 1)
+ self.ranges.append(ValueRange(start, end, step))
elif value.state == RegisterValueType.UnsignedRangeValue:
self.offset = value.value
- self.start = value.rangeStart
- self.end = value.rangeEnd
- self.step = value.rangeStep
+ self.ranges = []
+ for i in xrange(0, value.count):
+ start = value.ranges[i].start
+ end = value.ranges[i].end
+ step = value.ranges[i].step
+ self.ranges.append(ValueRange(start, end, step))
elif value.state == RegisterValueType.LookupTableValue:
self.table = []
self.mapping = {}
- for i in xrange(0, value.rangeEnd):
+ for i in xrange(0, value.count):
from_list = []
for j in xrange(0, value.table[i].fromCount):
from_list.append(value.table[i].fromValues[j])
self.mapping[value.table[i].fromValues[j]] = value.table[i].toValue
self.table.append(LookupTableEntry(from_list, value.table[i].toValue))
- elif value.state == RegisterValueType.OffsetFromUndeterminedValue:
- self.offset = value.value
+ elif (value.state == RegisterValueType.InSetOfValues) or (value.state == RegisterValueType.NotInSetOfValues):
+ self.values = set()
+ for i in xrange(0, value.count):
+ self.values.add(value.valueSet[i])
def __repr__(self):
if self.type == RegisterValueType.EntryValue:
return "<entry %s>" % self.reg
- if self.type == RegisterValueType.OffsetFromEntryValue:
- return "<entry %s + %#x>" % (self.reg, self.offset)
if self.type == RegisterValueType.ConstantValue:
return "<const %#x>" % self.value
if self.type == RegisterValueType.StackFrameOffset:
return "<stack frame offset %#x>" % self.offset
- if (self.type == RegisterValueType.SignedRangeValue) or (self.type == RegisterValueType.UnsignedRangeValue):
- if self.step == 1:
- return "<range: %#x to %#x>" % (self.start, self.end)
- return "<range: %#x to %#x, step %#x>" % (self.start, self.end, self.step)
+ if self.type == RegisterValueType.SignedRangeValue:
+ return "<signed ranges: %s>" % repr(self.ranges)
+ if self.type == RegisterValueType.UnsignedRangeValue:
+ return "<unsigned ranges: %s>" % repr(self.ranges)
if self.type == RegisterValueType.LookupTableValue:
return "<table: %s>" % ', '.join([repr(i) for i in self.table])
- if self.type == RegisterValueType.OffsetFromUndeterminedValue:
- return "<undetermined with offset %#x>" % self.offset
+ if self.type == RegisterValueType.InSetOfValues:
+ return "<in %s>" % repr(self.values)
+ if self.type == RegisterValueType.NotInSetOfValues:
+ return "<not in %s>" % repr(self.values)
+ if self.type == RegisterValueType.ReturnAddressValue:
+ return "<return address>"
return "<undetermined>"
-class StackVariable(object):
- def __init__(self, ofs, name, t):
- self.offset = ofs
- self.name = name
- self.type = t
-
- def __repr__(self):
- return "<var@%x: %s %s>" % (self.offset, self.type, self.name)
-
- def __str__(self):
- return self.name
-
-
class StackVariableReference(object):
- def __init__(self, src_operand, t, name, start_ofs, ref_ofs):
+ def __init__(self, src_operand, t, name, var, ref_ofs):
self.source_operand = src_operand
self.type = t
self.name = name
- self.starting_offset = start_ofs
+ self.var = var
self.referenced_offset = ref_ofs
if self.source_operand == 0xffffffff:
self.source_operand = None
def __repr__(self):
if self.source_operand is None:
- if self.referenced_offset != self.starting_offset:
- return "<ref to %s%+#x>" % (self.name, self.referenced_offset - self.starting_offset)
+ if self.referenced_offset != self.var.storage:
+ return "<ref to %s%+#x>" % (self.name, self.referenced_offset - self.var.storage)
return "<ref to %s>" % self.name
- if self.referenced_offset != self.starting_offset:
- return "<operand %d ref to %s%+#x>" % (self.source_operand, self.name, self.referenced_offset)
+ if self.referenced_offset != self.var.storage:
+ return "<operand %d ref to %s%+#x>" % (self.source_operand, self.name, self.var.storage)
return "<operand %d ref to %s>" % (self.source_operand, self.name)
+class Variable(object):
+ def __init__(self, func, source_type, index, storage, name = None, var_type = None):
+ self.function = func
+ self.source_type = VariableSourceType(source_type)
+ self.index = index
+ self.storage = storage
+
+ var = core.BNVariable()
+ var.type = source_type
+ var.index = index
+ var.storage = storage
+ self.identifier = core.BNToVariableIdentifier(var)
+
+ if name is None:
+ name = core.BNGetVariableName(func.handle, var)
+ if var_type is None:
+ var_type = core.BNGetVariableType(func.handle, var)
+ if var_type:
+ var_type = types.Type(var_type)
+
+ self.name = name
+ self.type = var_type
+
+ @classmethod
+ def from_identifier(self, func, identifier, name = None, var_type = None):
+ var = core.BNFromVariableIdentifier(identifier)
+ return Variable(func, VariableSourceType(var.type), var.index, var.storage, name, var_type)
+
+ def __repr__(self):
+ if self.type is None:
+ return "<var %s>" % self.name
+ return "<var %s %s%s>" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name())
+
+ def __str__(self):
+ return self.name
+
+
class ConstantReference(object):
def __init__(self, val, size):
self.value = val
@@ -298,6 +364,11 @@ class Function(object):
return lowlevelil.LowLevelILFunction(self.arch, core.BNGetFunctionLiftedIL(self.handle), self)
@property
+ def medium_level_il(self):
+ """Function medium level IL (read-only)"""
+ return mediumlevelil.MediumLevelILFunction(self.arch, core.BNGetFunctionMediumLevelIL(self.handle), self)
+
+ @property
def function_type(self):
"""Function type object"""
return types.Type(core.BNGetFunctionType(self.handle))
@@ -308,14 +379,28 @@ class Function(object):
@property
def stack_layout(self):
- """List of function stack (read-only)"""
+ """List of function stack variables (read-only)"""
count = ctypes.c_ulonglong()
v = core.BNGetStackLayout(self.handle, count)
result = []
for i in xrange(0, count.value):
- result.append(StackVariable(v[i].offset, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type))))
- result.sort(key = lambda x: x.offset)
- core.BNFreeStackLayout(v, count.value)
+ result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
+ types.Type(handle = core.BNNewTypeReference(v[i].type))))
+ result.sort(key = lambda x: x.identifier)
+ core.BNFreeVariableList(v, count.value)
+ return result
+
+ @property
+ def vars(self):
+ """List of function variables (read-only)"""
+ count = ctypes.c_ulonglong()
+ v = core.BNGetFunctionVariables(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
+ types.Type(handle = core.BNNewTypeReference(v[i].type))))
+ result.sort(key = lambda x: x.identifier)
+ core.BNFreeVariableList(v, count.value)
return result
@property
@@ -396,7 +481,7 @@ class Function(object):
result = []
for i in xrange(0, count.value):
result.append(exits[i])
- core.BNFreeLowLevelILInstructionList(exits)
+ core.BNFreeILInstructionList(exits)
return result
def get_reg_value_at(self, addr, reg, arch=None):
@@ -418,7 +503,6 @@ class Function(object):
reg = arch.regs[reg].index
value = core.BNGetRegisterValueAtInstruction(self.handle, arch.handle, addr, reg)
result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_reg_value_after(self, addr, reg, arch=None):
@@ -440,37 +524,6 @@ class Function(object):
reg = arch.regs[reg].index
value = core.BNGetRegisterValueAfterInstruction(self.handle, arch.handle, addr, reg)
result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
- return result
-
- def get_reg_value_at_low_level_il_instruction(self, i, reg, arch=None):
- """
- ``get_reg_value_at_low_level_il_instruction`` returns the value of the specified register ``reg`` at the il address
- i
-
- :param int i: il address of instruction to query
- :param Architecture arch: (optional) Architecture for the given function
- :rtype: function.RegisterValue
- :Example:
-
- >>> func.get_reg_value_at_low_level_il_instruction(15, 'rdi')
- <const 0x2>
- """
- if arch is None:
- arch = self.arch
- if isinstance(reg, str):
- reg = self.arch.regs[reg].index
- value = core.BNGetRegisterValueAtLowLevelILInstruction(self.handle, i, reg)
- result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
- return result
-
- def get_reg_value_after_low_level_il_instruction(self, i, reg):
- if isinstance(reg, str):
- reg = self.arch.regs[reg].index
- value = core.BNGetRegisterValueAfterLowLevelILInstruction(self.handle, i, reg)
- result = RegisterValue(self.arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_stack_contents_at(self, addr, offset, size, arch=None):
@@ -496,7 +549,6 @@ class Function(object):
arch = self.arch
value = core.BNGetStackContentsAtInstruction(self.handle, arch.handle, addr, offset, size)
result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_stack_contents_after(self, addr, offset, size, arch=None):
@@ -504,19 +556,6 @@ class Function(object):
arch = self.arch
value = core.BNGetStackContentsAfterInstruction(self.handle, arch.handle, addr, offset, size)
result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
- return result
-
- def get_stack_contents_at_low_level_il_instruction(self, i, offset, size):
- value = core.BNGetStackContentsAtLowLevelILInstruction(self.handle, i, offset, size)
- result = RegisterValue(self.arch, value)
- core.BNFreeRegisterValue(value)
- return result
-
- def get_stack_contents_after_low_level_il_instruction(self, i, offset, size):
- value = core.BNGetStackContentsAfterInstruction(self.handle, i, offset, size)
- result = RegisterValue(self.arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_parameter_at(self, addr, func_type, i, arch=None):
@@ -526,7 +565,6 @@ class Function(object):
func_type = func_type.handle
value = core.BNGetParameterValueAtInstruction(self.handle, arch.handle, addr, func_type, i)
result = RegisterValue(arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_parameter_at_low_level_il_instruction(self, instr, func_type, i):
@@ -534,7 +572,6 @@ class Function(object):
func_type = func_type.handle
value = core.BNGetParameterValueAtLowLevelILInstruction(self.handle, instr, func_type, i)
result = RegisterValue(self.arch, value)
- core.BNFreeRegisterValue(value)
return result
def get_regs_read_by(self, addr, arch=None):
@@ -566,8 +603,10 @@ class Function(object):
refs = core.BNGetStackVariablesReferencedByInstruction(self.handle, arch.handle, addr, count)
result = []
for i in xrange(0, count.value):
- result.append(StackVariableReference(refs[i].sourceOperand, types.Type(core.BNNewTypeReference(refs[i].type)),
- refs[i].name, refs[i].startingOffset, refs[i].referencedOffset))
+ var_type = types.Type(core.BNNewTypeReference(refs[i].type))
+ result.append(StackVariableReference(refs[i].sourceOperand, var_type,
+ refs[i].name, Variable.from_identifier(self, refs[i].varIdentifier, refs[i].name, var_type),
+ refs[i].referencedOffset))
core.BNFreeStackVariableReferenceList(refs, count.value)
return result
@@ -595,7 +634,7 @@ class Function(object):
result = []
for i in xrange(0, count.value):
result.append(instrs[i])
- core.BNFreeLowLevelILInstructionList(instrs)
+ core.BNFreeILInstructionList(instrs)
return result
def get_lifted_il_flag_definitions_for_use(self, i, flag):
@@ -606,7 +645,7 @@ class Function(object):
result = []
for i in xrange(0, count.value):
result.append(instrs[i])
- core.BNFreeLowLevelILInstructionList(instrs)
+ core.BNFreeILInstructionList(instrs)
return result
def get_flags_read_by_lifted_il_instruction(self, i):
@@ -802,6 +841,57 @@ class Function(object):
color = highlight.HighlightColor(color)
core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct())
+ def create_auto_stack_var(self, offset, var_type, name):
+ core.BNCreateAutoStackVariable(self.handle, offset, var_type.handle, name)
+
+ def create_user_stack_var(self, offset, var_type, name):
+ core.BNCreateUserStackVariable(self.handle, offset, var_type.handle, name)
+
+ def delete_auto_stack_var(self, offset):
+ core.BNDeleteAutoStackVariable(self.handle, offset)
+
+ def delete_user_stack_var(self, offset):
+ core.BNDeleteUserStackVariable(self.handle, offset)
+
+ def create_auto_var(self, var, var_type, name, ignore_disjoint_uses = False):
+ var_data = core.BNVariable()
+ var_data.type = var.source_type
+ var_data.index = var.index
+ var_data.storage = var.storage
+ core.BNCreateAutoVariable(self.handle, var_data, var_type.handle, name, ignore_disjoint_uses)
+
+ def create_user_var(self, var, var_type, name, ignore_disjoint_uses = False):
+ var_data = core.BNVariable()
+ var_data.type = var.source_type
+ var_data.index = var.index
+ var_data.storage = var.storage
+ core.BNCreateUserVariable(self.handle, var_data, var_type.handle, name, ignore_disjoint_uses)
+
+ def delete_auto_var(self, var):
+ var_data = core.BNVariable()
+ var_data.type = var.source_type
+ var_data.index = var.index
+ var_data.storage = var.storage
+ core.BNDeleteAutoVariable(self.handle, var_data)
+
+ def delete_user_var(self, var):
+ var_data = core.BNVariable()
+ var_data.type = var.source_type
+ var_data.index = var.index
+ var_data.storage = var.storage
+ core.BNDeleteUserVariable(self.handle, var_data)
+
+ def get_stack_var_at_frame_offset(self, offset, addr, arch=None):
+ if arch is None:
+ arch = self.arch
+ found_var = core.BNVariableNameAndType()
+ if not core.BNGetStackVariableAtFrameOffset(self.handle, arch.handle, addr, offset, found_var):
+ return None
+ result = Variable(self, found_var.var.type, found_var.var.index, found_var.var.storage,
+ found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type)))
+ core.BNFreeVariableNameAndType(found_var)
+ return result
+
class AdvancedFunctionAnalysisDataRequestor(object):
def __init__(self, func = None):