summaryrefslogtreecommitdiff
path: root/python/architecture.py
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2025-04-25 13:30:45 -0400
committerRyan Snyder <ryan@vector35.com>2025-06-23 13:44:12 -0400
commitb079d1a1e19151f5c39de84c2e1e6cc6a91abc74 (patch)
tree8cf27224630b690fcfdfd490ee43ec1cd56fc9b6 /python/architecture.py
parent76215b86ff629da58aa94d4cf4093d2e67017412 (diff)
Perform BB analysis from Architecture C++ API
This commit moves AnalyzeBasicBlocks from the binary ninja core to the API and allows architecture plugins to optionally override AnalyzeBasicBlocks for a custom implementation Supply ABB inputs in BNBasicBlockAnalysisContext Register default analyze basic blocks callback This allows the nanomips and rust core architecture plugins to work again while using the C++ API DefaultAnalyzeBasicBlocks Use default ABB from Python plugins Fix bug in API ArchAndAddr operator overload Python APIs for basic block analysis
Diffstat (limited to 'python/architecture.py')
-rw-r--r--python/architecture.py59
1 files changed, 59 insertions, 0 deletions
diff --git a/python/architecture.py b/python/architecture.py
index 29a393a8..8ce4b4f6 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -40,6 +40,7 @@ from . import typelibrary
from . import function
from . import binaryview
from . import deprecation
+from .variable import IndirectBranchInfo
RegisterIndex = NewType('RegisterIndex', int)
RegisterStackIndex = NewType('RegisterStackIndex', int)
@@ -66,6 +67,16 @@ IntrinsicType = Union[IntrinsicName, 'lowlevelil.ILIntrinsic', IntrinsicIndex]
@dataclass(frozen=True)
+class BasicBlockAnalysisContext:
+ """Used by ``analyze_basic_blocks`` and contains analysis settings and other contextual information."""
+ indirect_branches: List[IndirectBranchInfo]
+ analysis_skip_override: core.FunctionAnalysisSkipOverrideEnum
+ translate_tail_calls: bool
+ disallow_branch_to_string: bool
+ max_function_size: int
+
+
+@dataclass(frozen=True)
class RegisterInfo:
full_width_reg: RegisterName
size: int
@@ -246,6 +257,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__(
self._get_instruction_low_level_il
)
+ self._cb.analyzeBasicBlocks = self._cb.analyzeBasicBlocks.__class__(self._analyze_basic_blocks)
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)
@@ -711,6 +723,25 @@ class Architecture(metaclass=_ArchitectureMetaClass):
log_error(traceback.format_exc())
return False
+ def _analyze_basic_blocks(self, ctx, func, ptr_bn_bb_context):
+ try:
+ bn_bb_context = ptr_bn_bb_context.contents
+ indirect_branches = []
+ for i in range(0, bn_bb_context.indirectBranchesCount):
+ ibi = IndirectBranchInfo()
+ ibi.source_arch = CoreArchitecture._from_cache(bn_bb_context.indirectBranches[i].sourceArch)
+ ibi.source_addr = bn_bb_context.indirectBranches[i].sourceAddr
+ ibi.dest_arch = CoreArchitecture._from_cache(bn_bb_context.indirectBranches[i].destArch)
+ ibi.dest_addr = bn_bb_context.indirectBranches[i].destAddr
+ ibi.auto_defined = bn_bb_context.indirectBranches[i].autoDefined
+ indirect_branches.append(ibi)
+
+ context = BasicBlockAnalysisContext(indirect_branches, bn_bb_context.analysisSkipOverride,
+ bn_bb_context.translateTailCalls, bn_bb_context.disallowBranchToString, bn_bb_context.maxFunctionSize)
+ self.analyze_basic_blocks(function.Function(handle=core.BNNewFunctionReference(func)), context)
+ except:
+ log_error(traceback.format_exc())
+
def _get_register_name(self, ctxt, reg):
try:
if reg in self._regs_by_index:
@@ -1426,6 +1457,34 @@ class Architecture(metaclass=_ArchitectureMetaClass):
"""
raise NotImplementedError
+ def analyze_basic_blocks(self, func: 'function.Function', context: BasicBlockAnalysisContext) -> None:
+ """
+ ``analyze_basic_blocks`` performs basic block recovery and commits the results to the function analysis
+
+ .. note:: Architecture subclasses should only implement this method if function-level analysis is required
+
+ :param Function func: the function to analyze
+ :param BNBasicBlockAnalysisContext context: the analysis context
+ """
+
+ try:
+ bn_bb_context = core.BNBasicBlockAnalysisContext()
+ bn_bb_context.indirectBranchesCount = len(context.indirect_branches)
+ bn_bb_context.analysisSkipOverride = context.analysis_skip_override
+ bn_bb_context.translateTailCalls = context.translate_tail_calls
+ bn_bb_context.disallowBranchToString = context.disallow_branch_to_string
+ bn_bb_context.maxFunctionSize = context.max_function_size
+ bn_bb_context.indirectBranches = (core.BNIndirectBranchInfo * len(context.indirect_branches))()
+ for i in range(0, len(context.indirect_branches)):
+ bn_bb_context.indirectBranches[i].sourceArch = context.indirect_branches[i].source_arch.handle
+ bn_bb_context.indirectBranches[i].sourceAddr = context.indirect_branches[i].source_addr
+ bn_bb_context.indirectBranches[i].destArch = context.indirect_branches[i].dest_arch.handle
+ bn_bb_context.indirectBranches[i].destAddr = context.indirect_branches[i].dest_addr
+ bn_bb_context.indirectBranches[i].autoDefined = context.indirect_branches[i].auto_defined
+ core.BNArchitectureDefaultAnalyzeBasicBlocks(func.handle, ctypes.byref(bn_bb_context))
+ except:
+ log_error(traceback.format_exc())
+
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