Skip to content

Commit d381cab

Browse files
committed
Python APIs for basic block analysis
1 parent 290f183 commit d381cab

File tree

8 files changed

+412
-30
lines changed

8 files changed

+412
-30
lines changed

architecture.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ void Architecture::AnalyzeBasicBlocksCallback(void *ctxt, BNFunction* function,
313313
{
314314
CallbackRef<Architecture> arch(ctxt);
315315
Ref<Function> func(new Function(BNNewFunctionReference(function)));
316-
arch->AnalyzeBasicBlocks(*func, context);
316+
arch->AnalyzeBasicBlocks(*func, *context);
317317
}
318318

319319

@@ -936,7 +936,7 @@ bool Architecture::GetInstructionLowLevelIL(const uint8_t*, uint64_t, size_t&, L
936936
}
937937

938938

939-
void Architecture::AnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context)
939+
void Architecture::AnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context)
940940
{
941941
DefaultAnalyzeBasicBlocks(function, context);
942942
}
@@ -1502,9 +1502,9 @@ bool CoreArchitecture::GetInstructionLowLevelIL(const uint8_t* data, uint64_t ad
15021502
}
15031503

15041504

1505-
void CoreArchitecture::AnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context)
1505+
void CoreArchitecture::AnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context)
15061506
{
1507-
BNArchitectureAnalyzeBasicBlocks(m_object, function.GetObject(), context);
1507+
BNArchitectureAnalyzeBasicBlocks(m_object, function.GetObject(), &context);
15081508
}
15091509

15101510

binaryninjaapi.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8064,6 +8064,7 @@ namespace BinaryNinja {
80648064
class RelocationHandler;
80658065

80668066
typedef size_t ExprId;
8067+
typedef BNBasicBlockAnalysisContext BasicBlockAnalysisContext;
80678068

80688069
/*! The Architecture class is the base class for all CPU architectures. This provides disassembly, assembly,
80698070
patching, and IL translation lifting for a given architecture.
@@ -8172,7 +8173,7 @@ namespace BinaryNinja {
81728173
\param function Function to analyze
81738174
\param context Context for the analysis
81748175
*/
8175-
static void DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context);
8176+
static void DefaultAnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context);
81768177

81778178
/*! Get an Architecture by name
81788179

@@ -8277,7 +8278,7 @@ namespace BinaryNinja {
82778278
\param function Function to analyze
82788279
\param context Context for the analysis
82798280
*/
8280-
virtual void AnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context);
8281+
virtual void AnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context);
82818282

82828283
/*! Gets a register name from a register index.
82838284

@@ -8672,7 +8673,7 @@ namespace BinaryNinja {
86728673
const uint8_t* data, uint64_t addr, size_t& len, std::vector<InstructionTextToken>& result) override;
86738674
virtual bool GetInstructionLowLevelIL(
86748675
const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override;
8675-
virtual void AnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context) override;
8676+
virtual void AnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context) override;
86768677
virtual std::string GetRegisterName(uint32_t reg) override;
86778678
virtual std::string GetFlagName(uint32_t flag) override;
86788679
virtual std::string GetFlagWriteTypeName(uint32_t flags) override;

binaryninjacore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
// Current ABI version for linking to the core. This is incremented any time
3838
// there are changes to the API that affect linking, including new functions,
3939
// new types, or modifications to existing functions or types.
40-
#define BN_CURRENT_CORE_ABI_VERSION 105
40+
#define BN_CURRENT_CORE_ABI_VERSION 106
4141

4242
// Minimum ABI version that is supported for loading of plugins. Plugins that
4343
// are linked to an ABI version less than this will not be able to load and
@@ -4811,7 +4811,7 @@ extern "C"
48114811
BINARYNINJACOREAPI BNBasicBlockEdge* BNGetBasicBlockIncomingEdges(BNBasicBlock* block, size_t* count);
48124812
BINARYNINJACOREAPI void BNFreeBasicBlockEdgeList(BNBasicBlockEdge* edges, size_t count);
48134813
BINARYNINJACOREAPI bool BNBasicBlockHasUndeterminedOutgoingEdges(BNBasicBlock* block);
4814-
BINARYNINJACOREAPI void BNBasicBlockAddPendingOutgoingEdge(BNBasicBlock* block, BNBranchType type,
4814+
BINARYNINJACOREAPI void BNBasicBlockAddPendingOutgoingEdge(BNBasicBlock* block, BNBranchType type,
48154815
uint64_t addr, BNArchitecture* arch, bool fallThrough);
48164816
BINARYNINJACOREAPI BNPendingBasicBlockEdge* BNGetBasicBlockPendingOutgoingEdges(BNBasicBlock* block, size_t* count);
48174817
BINARYNINJACOREAPI void BNFreePendingBasicBlockEdgeList(BNPendingBasicBlockEdge* edges);

defaultabb.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,19 @@ static bool GetNextFunctionAfterAddress(Ref<BinaryView> data, Ref<Platform> plat
5656
}
5757

5858

59-
void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAnalysisContext* context)
59+
void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BasicBlockAnalysisContext& context)
6060
{
6161
auto data = function.GetView();
6262
queue<ArchAndAddr> blocksToProcess;
6363
map<ArchAndAddr, Ref<BasicBlock>> instrBlocks;
6464
set<ArchAndAddr> seenBlocks;
6565
map<ArchAndAddr, set<ArchAndAddr>> indirectBranches;
66-
for (size_t i = 0; i < context->indirectBranchesCount; i++)
66+
for (size_t i = 0; i < context.indirectBranchesCount; i++)
6767
{
68-
auto sourceLocation = ArchAndAddr(new CoreArchitecture(context->indirectBranches[i].sourceArch),
69-
context->indirectBranches[i].sourceAddr);
70-
auto destLocation = ArchAndAddr(new CoreArchitecture(context->indirectBranches[i].destArch),
71-
context->indirectBranches[i].destAddr);
68+
auto sourceLocation = ArchAndAddr(new CoreArchitecture(context.indirectBranches[i].sourceArch),
69+
context.indirectBranches[i].sourceAddr);
70+
auto destLocation = ArchAndAddr(new CoreArchitecture(context.indirectBranches[i].destArch),
71+
context.indirectBranches[i].destAddr);
7272
indirectBranches[sourceLocation].insert(destLocation);
7373
}
7474

@@ -148,7 +148,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
148148
}
149149

150150
uint64_t totalSize = 0;
151-
uint64_t maxSize = context->maxFunctionSize;
151+
uint64_t maxSize = context.maxFunctionSize;
152152
while (blocksToProcess.size() != 0)
153153
{
154154
if (data->AnalysisIsAborted())
@@ -356,7 +356,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
356356
function.AddDirectCodeReference(location, info.branchTarget[i]);
357357

358358
auto otherFunc = function.GetCalleeForAnalysis(targetPlatform, target.address, true);
359-
if (context->translateTailCalls && targetPlatform && otherFunc && (otherFunc->GetStart() != function.GetStart()))
359+
if (context.translateTailCalls && targetPlatform && otherFunc && (otherFunc->GetStart() != function.GetStart()))
360360
{
361361
calledFunctions.insert(otherFunc);
362362
if (info.branchType[i] == UnconditionalBranch)
@@ -371,7 +371,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
371371
break;
372372
}
373373
}
374-
else if (context->disallowBranchToString && data->GetStringAtAddress(location.address, strRef) && targetExceedsByteLimit(strRef))
374+
else if (context.disallowBranchToString && data->GetStringAtAddress(location.address, strRef) && targetExceedsByteLimit(strRef))
375375
{
376376
BNLogInfo("Not adding branch target from 0x%" PRIx64 " to string at 0x%" PRIx64
377377
" length:%zu",
@@ -503,7 +503,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
503503
targetPlatform = funcPlatform->GetRelatedPlatform(branch.arch);
504504

505505
// Normal analysis should not inline indirect targets that are function starts
506-
if (context->translateTailCalls && data->GetAnalysisFunction(targetPlatform, branch.address))
506+
if (context.translateTailCalls && data->GetAnalysisFunction(targetPlatform, branch.address))
507507
continue;
508508

509509
block->AddPendingOutgoingEdge(IndirectBranch, branch.address, branch.arch);
@@ -590,10 +590,10 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
590590
// We prefer to allow disassembly when function analysis is disabled, but only up to the maximum size.
591591
// The log message and tag are generated in ProcessAnalysisSkip
592592
totalSize += info.length;
593-
if (context->analysisSkipOverride == NeverSkipFunctionAnalysis)
593+
if (context.analysisSkipOverride == NeverSkipFunctionAnalysis)
594594
maxSize = 0;
595-
else if (!maxSize && (context->analysisSkipOverride == AlwaysSkipFunctionAnalysis))
596-
maxSize = context->maxFunctionSize;
595+
else if (!maxSize && (context.analysisSkipOverride == AlwaysSkipFunctionAnalysis))
596+
maxSize = context.maxFunctionSize;
597597
if (maxSize && (totalSize > maxSize))
598598
break;
599599

@@ -609,7 +609,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
609609
delayInstructionEndsBlock = endsBlock;
610610
}
611611

612-
if (block->CanExit() && context->translateTailCalls && !delaySlotCount && hasNextFunc && (location.address == nextFuncAddr))
612+
if (block->CanExit() && context.translateTailCalls && !delaySlotCount && hasNextFunc && (location.address == nextFuncAddr))
613613
{
614614
// Falling through into another function. Don't consider this a tail call if the current block
615615
// called the function, as this indicates a get PC construct.
@@ -644,5 +644,5 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function& function, BNBasicBlockAna
644644
void Architecture::DefaultAnalyzeBasicBlocksCallback(BNFunction* function, BNBasicBlockAnalysisContext* context)
645645
{
646646
Ref<Function> func(new Function(BNNewFunctionReference(function)));
647-
Architecture::DefaultAnalyzeBasicBlocks(*func, context);
647+
Architecture::DefaultAnalyzeBasicBlocks(*func, *context);
648648
}

python/architecture.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from . import function
4141
from . import binaryview
4242
from . import deprecation
43+
from .variable import IndirectBranchInfo
4344

4445
RegisterIndex = NewType('RegisterIndex', int)
4546
RegisterStackIndex = NewType('RegisterStackIndex', int)
@@ -65,6 +66,16 @@
6566
IntrinsicType = Union[IntrinsicName, 'lowlevelil.ILIntrinsic', IntrinsicIndex]
6667

6768

69+
@dataclass(frozen=True)
70+
class BasicBlockAnalysisContext:
71+
"""Used by ``analyze_basic_blocks`` and contains analysis settings and other contextual information."""
72+
indirect_branches: List[IndirectBranchInfo]
73+
analysis_skip_override: core.FunctionAnalysisSkipOverrideEnum
74+
translate_tail_calls: bool
75+
disallow_branch_to_string: bool
76+
max_function_size: int
77+
78+
6879
@dataclass(frozen=True)
6980
class RegisterInfo:
7081
full_width_reg: RegisterName
@@ -711,8 +722,21 @@ def _get_instruction_low_level_il(self, ctxt, data, addr, length, il):
711722
log_error(traceback.format_exc())
712723
return False
713724

714-
def _analyze_basic_blocks(self, ctx, func, context):
725+
def _analyze_basic_blocks(self, ctx, func, ptr_bn_bb_context):
715726
try:
727+
bn_bb_context = ptr_bn_bb_context.contents
728+
indirect_branches = []
729+
for i in range(0, bn_bb_context.indirectBranchesCount):
730+
ibi = IndirectBranchInfo()
731+
ibi.source_arch = CoreArchitecture._from_cache(bn_bb_context.indirectBranches[i].sourceArch)
732+
ibi.source_addr = bn_bb_context.indirectBranches[i].sourceAddr
733+
ibi.dest_arch = CoreArchitecture._from_cache(bn_bb_context.indirectBranches[i].destArch)
734+
ibi.dest_addr = bn_bb_context.indirectBranches[i].destAddr
735+
ibi.auto_defined = bn_bb_context.indirectBranches[i].autoDefined
736+
indirect_branches.append(ibi)
737+
738+
context = BasicBlockAnalysisContext(indirect_branches, bn_bb_context.analysisSkipOverride,
739+
bn_bb_context.translateTailCalls, bn_bb_context.disallowBranchToString, bn_bb_context.maxFunctionSize)
716740
self.analyze_basic_blocks(function.Function(handle=core.BNNewFunctionReference(func)), context)
717741
except:
718742
log_error(traceback.format_exc())
@@ -1432,18 +1456,31 @@ def get_instruction_low_level_il(self, data: bytes, addr: int, il: lowlevelil.Lo
14321456
"""
14331457
raise NotImplementedError
14341458

1435-
def analyze_basic_blocks(self, func, context):
1459+
def analyze_basic_blocks(self, func: 'function.Function', context: BasicBlockAnalysisContext) -> None:
14361460
"""
1437-
``analyze_basic_blocks`` performs function-level basic block recovery and commits the blocks to analysis
1461+
``analyze_basic_blocks`` performs basic block recovery and commits the results to the function analysis
14381462
1439-
.. note:: Architecture subclasses should not implement this method unless function-level lifting is required
1463+
.. note:: Architecture subclasses should only implement this method if function-level analysis is required
14401464
14411465
:param Function func: the function to analyze
14421466
:param BNBasicBlockAnalysisContext context: the analysis context
14431467
"""
14441468

14451469
try:
1446-
core.BNArchitectureDefaultAnalyzeBasicBlocks(func.handle, context)
1470+
bn_bb_context = core.BNBasicBlockAnalysisContext()
1471+
bn_bb_context.indirectBranchesCount = len(context.indirect_branches)
1472+
bn_bb_context.analysisSkipOverride = context.analysis_skip_override
1473+
bn_bb_context.translateTailCalls = context.translate_tail_calls
1474+
bn_bb_context.disallowBranchToString = context.disallow_branch_to_string
1475+
bn_bb_context.maxFunctionSize = context.max_function_size
1476+
bn_bb_context.indirectBranches = (core.BNIndirectBranchInfo * len(context.indirect_branches))()
1477+
for i in range(0, len(context.indirect_branches)):
1478+
bn_bb_context.indirectBranches[i].sourceArch = context.indirect_branches[i].source_arch.handle
1479+
bn_bb_context.indirectBranches[i].sourceAddr = context.indirect_branches[i].source_addr
1480+
bn_bb_context.indirectBranches[i].destArch = context.indirect_branches[i].dest_arch.handle
1481+
bn_bb_context.indirectBranches[i].destAddr = context.indirect_branches[i].dest_addr
1482+
bn_bb_context.indirectBranches[i].autoDefined = context.indirect_branches[i].auto_defined
1483+
core.BNArchitectureDefaultAnalyzeBasicBlocks(func.handle, ctypes.byref(bn_bb_context))
14471484
except:
14481485
log_error(traceback.format_exc())
14491486

0 commit comments

Comments
 (0)