summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/architecture.py139
-rw-r--r--python/log.py7
2 files changed, 144 insertions, 2 deletions
diff --git a/python/architecture.py b/python/architecture.py
index 57d327c0..2d085d9e 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -41,6 +41,7 @@ from . import function
from . import binaryview
from . import variable
from . import basicblock
+from . import log
RegisterIndex = NewType('RegisterIndex', int)
RegisterStackIndex = NewType('RegisterStackIndex', int)
@@ -412,6 +413,117 @@ class BasicBlockAnalysisContext:
core.BNAnalyzeBasicBlocksContextFinalize(self._handle)
+@dataclass
+class FunctionLifterContext:
+ """Used by ``lift_function`` and contains contextual information for function-level lifting
+
+ .. note:: This class is meant to be used by Architecture plugins only
+ """
+
+ _handle: core.BNFunctionLifterContext
+ _function: "function.Function"
+ _platform: "platform.Platform"
+ _logger: "log.Logger"
+ _blocks: List["basicblock.BasicBlock"]
+ _contextual_returns: Dict["function.ArchAndAddr", bool]
+ _inline_remapping: Dict["function.ArchAndAddr", "function.ArchAndAddr"]
+ _user_indirect_branches: Dict["function.ArchAndAddr", Set["function.ArchAndAddr"]]
+ _auto_indirect_branches: Dict["function.ArchAndAddr", Set["function.ArchAndAddr"]]
+ _inlined_calls: Set[int]
+
+ @staticmethod
+ def from_core_struct(func: core.BNLowLevelILFunction,
+ bn_fl_context: core.BNFunctionLifterContext) -> "FunctionLifterContext":
+ """Create a FunctionLifterContext from a core.BNFunctionLifterContext structure."""
+
+ session_id = core.BNLoggerGetSessionId(bn_fl_context.logger)
+ name = core.BNLoggerGetName(bn_fl_context.logger)
+ logger = log.Logger(session_id, name, handle=core.BNNewLoggerReference(bn_fl_context.logger))
+
+ plat = platform.CorePlatform._from_cache(core.BNNewPlatformReference(bn_fl_context.platform))
+ blocks = []
+ for i in range(0, bn_fl_context.basicBlockCount):
+ blocks.append(
+ basicblock.BasicBlock(
+ core.BNNewBasicBlockReference(bn_fl_context.basicBlocks[i])
+ )
+ )
+
+ contextual_returns = {}
+ for i in range(0, bn_fl_context.contextualFunctionReturnCount):
+ loc = function.ArchAndAddr(
+ CoreArchitecture._from_cache(bn_fl_context.contextualFunctionReturnLocations[i].arch),
+ bn_fl_context.contextualFunctionReturnLocations[i].address,
+ )
+
+ contextual_returns[loc] = bn_fl_context._contextualFunctionReturnValues[i]
+
+ inline_remapping = {}
+ for i in range(0, bn_fl_context.inlinedRemappingEntryCount):
+ key = function.ArchAndAddr(
+ CoreArchitecture._from_cache(bn_fl_context.inlinedRemappingKeys[i].arch),
+ bn_fl_context.inlinedRemappingKeys[i].address,
+ )
+ dest = function.ArchAndAddr(
+ CoreArchitecture._from_cache(bn_fl_context.inlinedRemappingEntries[i].destination.arch),
+ bn_fl_context.inlinedRemappingEntries[i].destination.address,
+ )
+ inline_remapping[src] = dest
+
+ user_indirect_branches = {}
+ auto_indirect_branches = {}
+ for i in range(0, bn_fl_context.indirectBranchesCount):
+ src = function.ArchAndAddr(
+ CoreArchitecture._from_cache(bn_fl_context.indirectBranches[i].sourceArch),
+ bn_fl_context.indirectBranches[i].sourceAddr,
+ )
+
+ dest = function.ArchAndAddr(
+ CoreArchitecture._from_cache(bn_fl_context.indirectBranches[i].destArch),
+ bn_fl_context.indirectBranches[i].dests[j].destAddr,
+ )
+
+ if bn_fl_context.indirectBranches[i].dests[j].isAutoDefined:
+ if src not in auto_indirect_branches:
+ auto_indirect_branches[src] = set()
+ auto_indirect_branches[src].add(dest)
+ else:
+ if src not in user_indirect_branches:
+ user_indirect_branches[src] = set()
+ user_indirect_branches[src].add(dest)
+
+
+ inlined_calls = set()
+ for i in range(0, bn_fl_context.inlinedCallsCount):
+ inlined_calls.add(bn_fl_context.inlinedCalls[i])
+
+ return FunctionLifterContext(
+ _handle=bn_fl_context,
+ _function=lowlevelil.LowLevelILFunction(
+ plat.arch, core.BNNewLowLevelILFunctionReference(func)
+ ),
+ _platform=plat,
+ _logger=logger,
+ _blocks=blocks,
+ _contextual_returns=contextual_returns,
+ _inline_remapping=inline_remapping,
+ _user_indirect_branches=user_indirect_branches,
+ _auto_indirect_branches=auto_indirect_branches,
+ _inlined_calls=inlined_calls,
+ )
+
+ def prepare_block_translation(self, function, arch, address):
+ """Prepare block for translation"""
+
+ core.BNPrepareBlockTranslation(function.handle, arch.handle, address)
+
+ @property
+ def blocks(self) -> List["basicblock.BasicBlock"]:
+ """Get the list of basic blocks in this context."""
+
+ return self._blocks
+
+
@dataclass(frozen=True)
class RegisterInfo:
full_width_reg: RegisterName
@@ -611,6 +723,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
self._get_instruction_low_level_il
)
self._cb.analyzeBasicBlocks = self._cb.analyzeBasicBlocks.__class__(self._analyze_basic_blocks)
+ self._cb.liftFunction = self._cb.liftFunction.__class__(self._lift_function)
self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name)
self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name)
self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name)
@@ -1084,6 +1197,15 @@ class Architecture(metaclass=_ArchitectureMetaClass):
except:
log_error_for_exception("Unhandled Python exception in Architecture._analyze_basic_blocks")
+ def _lift_function(self, ctx, func, ptr_bn_fl_context):
+ try:
+ bn_fl_context = ptr_bn_fl_context.contents
+ context = FunctionLifterContext.from_core_struct(func, bn_fl_context)
+ return self.lift_function(lowlevelil.LowLevelILFunction(arch=self, handle=core.BNNewLowLevelILFunctionReference(func)), context)
+ except:
+ log_error_for_exception("Unhandled Python exception in Architecture._lift_function")
+ return False
+
def _get_register_name(self, ctxt, reg):
try:
if reg in self._regs_by_index:
@@ -1814,6 +1936,23 @@ class Architecture(metaclass=_ArchitectureMetaClass):
except:
log_error_for_exception("Unhandled Python exception in Architecture.analyze_basic_blocks")
+ def lift_function(self, func: "lowlevelil.LowLevelILFunction", context: FunctionLifterContext) -> bool:
+ """
+ ``lift_function`` performs lifting of the function and commits the results to the function analysis
+
+ .. note:: Architecture subclasses should only implement this method if function-level analysis is required
+
+ :param LowLevelILFunction func: the function to analyze
+ :param FunctionLifterContext context: the lifting context
+ :return: True on success, False otherwise
+ """
+
+ try:
+ return core.BNArchitectureDefaultLiftFunction(func.handle, context._handle)
+ except:
+ log_error_for_exception("Unhandled Python exception in Architecture.lift_function")
+ return False
+
def get_low_level_il_from_bytes(self, data: bytes, addr: int) -> 'lowlevelil.LowLevelILInstruction':
"""
``get_low_level_il_from_bytes`` converts the instruction in bytes to ``il`` at the given virtual address
diff --git a/python/log.py b/python/log.py
index 2f5dda49..13c65c81 100644
--- a/python/log.py
+++ b/python/log.py
@@ -365,10 +365,13 @@ def close_logs():
class Logger:
- def __init__(self, session_id: int, logger_name: str):
+ def __init__(self, session_id: int, logger_name: str, handle=None):
self.session_id = session_id
self.logger_name = logger_name
- self.handle = core.BNLogCreateLogger(logger_name, session_id)
+ if handle:
+ self.handle = handle
+ else:
+ self.handle = core.BNLogCreateLogger(logger_name, session_id)
def log(self, level: LogLevel, message: str) -> None:
log(level, message, self.logger_name, self.session_id)