Skip to content

Commit a1b49cf

Browse files
committed
Demonstrate function bb analysis from API
1 parent 6769870 commit a1b49cf

7 files changed

+198
-8
lines changed

architecture.cpp

+67
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,15 @@ bool Architecture::GetInstructionLowLevelILCallback(
307307
}
308308

309309

310+
bool Architecture::AnalyzeBasicBlocksCallback(void *ctxt, BNFunction* function,
311+
bool incrementalUpdate, BNFunctionAnalysisSkipOverride analysisSkipOverride)
312+
{
313+
CallbackRef<Architecture> arch(ctxt);
314+
Ref<Function> func(new Function(BNNewFunctionReference(function)));
315+
return arch->AnalyzeBasicBlocks(*func, incrementalUpdate, analysisSkipOverride);
316+
}
317+
318+
310319
char* Architecture::GetRegisterNameCallback(void* ctxt, uint32_t reg)
311320
{
312321
CallbackRef<Architecture> arch(ctxt);
@@ -797,6 +806,7 @@ void Architecture::Register(Architecture* arch)
797806
callbacks.getInstructionText = GetInstructionTextCallback;
798807
callbacks.freeInstructionText = FreeInstructionTextCallback;
799808
callbacks.getInstructionLowLevelIL = GetInstructionLowLevelILCallback;
809+
callbacks.analyzeBasicBlocks = AnalyzeBasicBlocksCallback;
800810
callbacks.getRegisterName = GetRegisterNameCallback;
801811
callbacks.getFlagName = GetFlagNameCallback;
802812
callbacks.getFlagWriteTypeName = GetFlagWriteTypeNameCallback;
@@ -925,6 +935,56 @@ bool Architecture::GetInstructionLowLevelIL(const uint8_t*, uint64_t, size_t&, L
925935
}
926936

927937

938+
bool Architecture::AnalyzeBasicBlocks(Function& function, bool incrementalUpdate, BNFunctionAnalysisSkipOverride analysisSkipOverride)
939+
{
940+
auto data = function.GetView();
941+
queue<ArchAndAddr> blocksToProcess;
942+
set<ArchAndAddr> seenBlocks;
943+
944+
// TODO - we might just want to create a generic analysis settings object that includes all of these
945+
//bool tailCallTranslation = function.GetSettingsCache()->Get<bool>("core.function.translateTailCalls");
946+
bool tailCallTranslation = true;
947+
//bool disallowBranchToString = owner->IsDisallowBranchToStringEnabled();
948+
bool disallowBranchToString = true;
949+
950+
/*
951+
auto targetExceedsByteLimit = [](const BNStringReference& strRef) {
952+
size_t byteLimit = 8;
953+
if (strRef.type == Utf16String) byteLimit *= 2;
954+
else if (strRef.type == Utf32String) byteLimit *= 4;
955+
return (strRef.length >= byteLimit);
956+
};*/
957+
958+
auto funcPlatform = function.GetPlatform();
959+
auto start = function.GetStart();
960+
blocksToProcess.emplace(funcPlatform->GetArchitecture(), start);
961+
seenBlocks.emplace(funcPlatform->GetArchitecture(), start);
962+
while (blocksToProcess.size() != 0)
963+
{
964+
if (data->AnalysisIsAborted())
965+
return true;
966+
967+
// Get the next block to process
968+
ArchAndAddr location = blocksToProcess.front();
969+
ArchAndAddr instructionGroupStart = location;
970+
blocksToProcess.pop();
971+
972+
// Create a new basic block
973+
Ref<BasicBlock> block = function.CreateBasicBlock(location.arch, location.address);
974+
975+
// TODO actually compute the size of the block from the instruction info
976+
block->SetEnd(location.address + 1);
977+
978+
// Commit the basic block to the function basic block list
979+
function.AddBasicBlock(block);
980+
}
981+
982+
// Finalize the function basic block list
983+
function.FinalizeBasicBlocks();
984+
return true;
985+
}
986+
987+
928988
string Architecture::GetRegisterName(uint32_t reg)
929989
{
930990
return fmt::format("r{}", reg);
@@ -1485,6 +1545,13 @@ bool CoreArchitecture::GetInstructionLowLevelIL(const uint8_t* data, uint64_t ad
14851545
}
14861546

14871547

1548+
bool CoreArchitecture::AnalyzeBasicBlocks(Function& function, bool incrementalUpdate,
1549+
BNFunctionAnalysisSkipOverride analysisSkipOverride)
1550+
{
1551+
return BNArchitectureAnalyzeBasicBlocks(m_object, function.GetObject(), incrementalUpdate, analysisSkipOverride);
1552+
}
1553+
1554+
14881555
string CoreArchitecture::GetRegisterName(uint32_t reg)
14891556
{
14901557
char* name = BNGetArchitectureRegisterName(m_object, reg);

basicblock.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ uint64_t BasicBlock::GetStart() const
317317
}
318318

319319

320+
void BasicBlock::SetEnd(uint64_t end)
321+
{
322+
BNSetBasicBlockEnd(m_object, end);
323+
}
324+
325+
320326
uint64_t BasicBlock::GetEnd() const
321327
{
322328
return BNGetBasicBlockEnd(m_object);

binaryninjaapi.h

+39-1
Original file line numberDiff line numberDiff line change
@@ -5275,6 +5275,13 @@ namespace BinaryNinja {
52755275
*/
52765276
void AbortAnalysis();
52775277

5278+
5279+
/*! Check whether analysis is currently running
5280+
5281+
\return true if analysis is aborted, false otherwise
5282+
*/
5283+
bool AnalysisIsAborted() const;
5284+
52785285
/*! Define a DataVariable at a given address with a set type
52795286

52805287
\param addr virtual address to define the DataVariable at
@@ -8045,6 +8052,8 @@ namespace BinaryNinja {
80458052
static void FreeInstructionTextCallback(BNInstructionTextToken* tokens, size_t count);
80468053
static bool GetInstructionLowLevelILCallback(
80478054
void* ctxt, const uint8_t* data, uint64_t addr, size_t* len, BNLowLevelILFunction* il);
8055+
static bool AnalyzeBasicBlocksCallback(void *ctxt, BNFunction* function, bool incrementalUpdate,
8056+
BNFunctionAnalysisSkipOverride analysisSkipOverride);
80488057
static char* GetRegisterNameCallback(void* ctxt, uint32_t reg);
80498058
static char* GetFlagNameCallback(void* ctxt, uint32_t flag);
80508059
static char* GetFlagWriteTypeNameCallback(void* ctxt, uint32_t flags);
@@ -8215,6 +8224,9 @@ namespace BinaryNinja {
82158224
*/
82168225
virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il);
82178226

8227+
virtual bool AnalyzeBasicBlocks(Function& function, bool incrementalUpdate,
8228+
BNFunctionAnalysisSkipOverride analysisSkipOverride);
8229+
82188230
/*! Gets a register name from a register index.
82198231

82208232
\param reg Register index
@@ -8493,7 +8505,6 @@ namespace BinaryNinja {
84938505
\return Whether the conversion was successful
84948506
*/
84958507
virtual bool SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value);
8496-
84978508
void RegisterFunctionRecognizer(FunctionRecognizer* recog);
84988509
void RegisterRelocationHandler(const std::string& viewName, RelocationHandler* handler);
84998510
Ref<RelocationHandler> GetRelocationHandler(const std::string& viewName);
@@ -8609,6 +8620,8 @@ namespace BinaryNinja {
86098620
const uint8_t* data, uint64_t addr, size_t& len, std::vector<InstructionTextToken>& result) override;
86108621
virtual bool GetInstructionLowLevelIL(
86118622
const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override;
8623+
virtual bool AnalyzeBasicBlocks(Function& function, bool incrementalUpdate,
8624+
BNFunctionAnalysisSkipOverride analysisSkipOverride) override;
86128625
virtual std::string GetRegisterName(uint32_t reg) override;
86138626
virtual std::string GetFlagName(uint32_t flag) override;
86148627
virtual std::string GetFlagWriteTypeName(uint32_t flags) override;
@@ -10443,6 +10456,13 @@ namespace BinaryNinja {
1044310456
*/
1044410457
uint64_t GetStart() const;
1044510458

10459+
10460+
/*! Set the end of a basic block
10461+
10462+
\param end Ending address of the basic block
10463+
*/
10464+
void SetEnd(uint64_t end);
10465+
1044610466
/*! Ending address of the basic block
1044710467

1044810468
\return Ending address of the basic block
@@ -10870,6 +10890,24 @@ namespace BinaryNinja {
1087010890
*/
1087110891
std::vector<Ref<BasicBlock>> GetBasicBlocks() const;
1087210892

10893+
/*! Create a new basic block for this function
10894+
10895+
\param arch Architecture for the basic block
10896+
\param addr Address of the basic block
10897+
\return The new BasicBlock
10898+
*/
10899+
Ref<BasicBlock> CreateBasicBlock(Architecture* arch, uint64_t addr);
10900+
10901+
/*! Add a basic block to the function analysis basic block list
10902+
10903+
\param block The BasicBlock to add
10904+
*/
10905+
void AddBasicBlock(Ref<BasicBlock> block);
10906+
10907+
/*! Finalize basic block list for this function
10908+
*/
10909+
void FinalizeBasicBlocks();
10910+
1087310911
/*! Get the basic block an address is located in
1087410912

1087510913
\param arch Architecture for the basic block

binaryninjacore.h

+16-7
Original file line numberDiff line numberDiff line change
@@ -1842,6 +1842,13 @@ extern "C"
18421842
uint8_t confidence;
18431843
} BNTypeWithConfidence;
18441844

1845+
typedef enum BNFunctionAnalysisSkipOverride
1846+
{
1847+
DefaultFunctionAnalysisSkip,
1848+
NeverSkipFunctionAnalysis,
1849+
AlwaysSkipFunctionAnalysis
1850+
} BNFunctionAnalysisSkipOverride;
1851+
18451852
typedef struct BNCustomArchitecture
18461853
{
18471854
void* context;
@@ -1860,6 +1867,8 @@ extern "C"
18601867
void (*freeInstructionText)(BNInstructionTextToken* tokens, size_t count);
18611868
bool (*getInstructionLowLevelIL)(
18621869
void* ctxt, const uint8_t* data, uint64_t addr, size_t* len, BNLowLevelILFunction* il);
1870+
bool (*analyzeBasicBlocks)(void* ctxt, BNFunction* function,
1871+
bool incrementalUpdate, BNFunctionAnalysisSkipOverride analysisSkipOverride);
18631872
char* (*getRegisterName)(void* ctxt, uint32_t reg);
18641873
char* (*getFlagName)(void* ctxt, uint32_t flag);
18651874
char* (*getFlagWriteTypeName)(void* ctxt, uint32_t flags);
@@ -3128,13 +3137,6 @@ extern "C"
31283137
uint8_t confidence;
31293138
} BNRegisterStackAdjustment;
31303139

3131-
typedef enum BNFunctionAnalysisSkipOverride
3132-
{
3133-
DefaultFunctionAnalysisSkip,
3134-
NeverSkipFunctionAnalysis,
3135-
AlwaysSkipFunctionAnalysis
3136-
} BNFunctionAnalysisSkipOverride;
3137-
31383140
typedef enum BNReportType
31393141
{
31403142
PlainTextReportType,
@@ -4460,6 +4462,8 @@ extern "C"
44604462
BINARYNINJACOREAPI bool BNGetInstructionLowLevelIL(
44614463
BNArchitecture* arch, const uint8_t* data, uint64_t addr, size_t* len, BNLowLevelILFunction* il);
44624464
BINARYNINJACOREAPI void BNFreeInstructionText(BNInstructionTextToken* tokens, size_t count);
4465+
BINARYNINJACOREAPI bool BNArchitectureAnalyzeBasicBlocks(BNArchitecture* arch, BNFunction* function,
4466+
bool incrementalUpdate, BNFunctionAnalysisSkipOverride analysisSkipOverride);
44634467
BINARYNINJACOREAPI void BNFreeInstructionTextLines(BNInstructionTextLine* lines, size_t count);
44644468
BINARYNINJACOREAPI char* BNGetArchitectureRegisterName(BNArchitecture* arch, uint32_t reg);
44654469
BINARYNINJACOREAPI char* BNGetArchitectureFlagName(BNArchitecture* arch, uint32_t flag);
@@ -4575,6 +4579,7 @@ extern "C"
45754579
BINARYNINJACOREAPI void BNUpdateAnalysisAndWait(BNBinaryView* view);
45764580
BINARYNINJACOREAPI void BNUpdateAnalysis(BNBinaryView* view);
45774581
BINARYNINJACOREAPI void BNAbortAnalysis(BNBinaryView* view);
4582+
BINARYNINJACOREAPI bool BNAnalysisIsAborted(BNBinaryView* view);
45784583
BINARYNINJACOREAPI bool BNIsFunctionUpdateNeeded(BNFunction* func);
45794584
BINARYNINJACOREAPI void BNRequestAdvancedFunctionAnalysisData(BNFunction* func);
45804585
BINARYNINJACOREAPI void BNReleaseAdvancedFunctionAnalysisData(BNFunction* func);
@@ -4638,6 +4643,9 @@ extern "C"
46384643
BINARYNINJACOREAPI void BNFreeBasicBlock(BNBasicBlock* block);
46394644
BINARYNINJACOREAPI BNBasicBlock** BNGetFunctionBasicBlockList(BNFunction* func, size_t* count);
46404645
BINARYNINJACOREAPI void BNFreeBasicBlockList(BNBasicBlock** blocks, size_t count);
4646+
BINARYNINJACOREAPI BNBasicBlock* BNCreateFunctionBasicBlock(BNFunction* func, BNArchitecture* arch, uint64_t addr);
4647+
BINARYNINJACOREAPI void BNAddFunctionBasicBlock(BNFunction* func, BNBasicBlock* block);
4648+
BINARYNINJACOREAPI void BNFinalizeFunctionBasicBlocks(BNFunction* func);
46414649
BINARYNINJACOREAPI BNBasicBlock* BNGetFunctionBasicBlockAtAddress(
46424650
BNFunction* func, BNArchitecture* arch, uint64_t addr);
46434651
BINARYNINJACOREAPI BNBasicBlock* BNGetRecentBasicBlockForAddress(BNBinaryView* view, uint64_t addr);
@@ -4775,6 +4783,7 @@ extern "C"
47754783
BINARYNINJACOREAPI BNArchitecture* BNGetBasicBlockArchitecture(BNBasicBlock* block);
47764784
BINARYNINJACOREAPI BNBasicBlock* BNGetBasicBlockSource(BNBasicBlock* block);
47774785
BINARYNINJACOREAPI uint64_t BNGetBasicBlockStart(BNBasicBlock* block);
4786+
BINARYNINJACOREAPI void BNSetBasicBlockEnd(BNBasicBlock* block, uint64_t end);
47784787
BINARYNINJACOREAPI uint64_t BNGetBasicBlockEnd(BNBasicBlock* block);
47794788
BINARYNINJACOREAPI uint64_t BNGetBasicBlockLength(BNBasicBlock* block);
47804789
BINARYNINJACOREAPI BNBasicBlockEdge* BNGetBasicBlockOutgoingEdges(BNBasicBlock* block, size_t* count);

binaryview.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,12 @@ void BinaryView::AbortAnalysis()
21742174
}
21752175

21762176

2177+
bool BinaryView::AnalysisIsAborted() const
2178+
{
2179+
return BNAnalysisIsAborted(m_object);
2180+
}
2181+
2182+
21772183
void BinaryView::DefineDataVariable(uint64_t addr, const Confidence<Ref<Type>>& type)
21782184
{
21792185
BNTypeWithConfidence tc;

function.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,27 @@ vector<Ref<BasicBlock>> Function::GetBasicBlocks() const
319319
}
320320

321321

322+
Ref<BasicBlock> Function::CreateBasicBlock(Architecture* arch, uint64_t addr)
323+
{
324+
BNBasicBlock* block = BNCreateFunctionBasicBlock(m_object, arch->GetObject(), addr);
325+
if (!block)
326+
return nullptr;
327+
return new BasicBlock(block);
328+
}
329+
330+
331+
void Function::AddBasicBlock(Ref<BasicBlock> block)
332+
{
333+
BNAddFunctionBasicBlock(m_object, block->GetObject());
334+
}
335+
336+
337+
void Function::FinalizeBasicBlocks()
338+
{
339+
BNFinalizeFunctionBasicBlocks(m_object);
340+
}
341+
342+
322343
Ref<BasicBlock> Function::GetBasicBlockAtAddress(Architecture* arch, uint64_t addr) const
323344
{
324345
BNBasicBlock* block = BNGetFunctionBasicBlockAtAddress(m_object, arch->GetObject(), addr);

rust/src/architecture.rs

+43
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::{
3131
string::*,
3232
types::{NameAndType, Type},
3333
Endianness,
34+
function::Function,
3435
};
3536
use std::ops::Deref;
3637
use std::{
@@ -463,6 +464,15 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
463464
il: &mut MutableLiftedILFunction<Self>,
464465
) -> Option<(usize, bool)>;
465466

467+
fn analyze_basic_blocks(
468+
&self,
469+
_function: &mut Function,
470+
_incremental_update: bool,
471+
_analysis_skip_override: BNFunctionAnalysisSkipOverride,
472+
) -> bool {
473+
false
474+
}
475+
466476
/// Fallback flag value calculation path. This method is invoked when the core is unable to
467477
/// recover flag use semantics, and resorts to emitting instructions that explicitly set each
468478
/// observed flag to the value of an expression returned by this function.
@@ -1525,6 +1535,24 @@ impl Architecture for CoreArchitecture {
15251535
}
15261536
}
15271537

1538+
fn analyze_basic_blocks(
1539+
&self,
1540+
function: &mut Function,
1541+
incremental_update: bool,
1542+
analysis_skip_override: BNFunctionAnalysisSkipOverride,
1543+
) -> bool {
1544+
let success: bool = unsafe {
1545+
BNArchitectureAnalyzeBasicBlocks(
1546+
self.handle,
1547+
function.handle,
1548+
incremental_update,
1549+
analysis_skip_override,
1550+
)
1551+
};
1552+
1553+
return success;
1554+
}
1555+
15281556
fn flag_write_llil<'a>(
15291557
&self,
15301558
_flag: Self::Flag,
@@ -2234,6 +2262,20 @@ where
22342262
}
22352263
}
22362264

2265+
extern "C" fn cb_analyze_basic_blocks<A>(
2266+
ctxt: *mut c_void,
2267+
function: *mut BNFunction,
2268+
incremental_update: bool,
2269+
analysis_skip_override: BNFunctionAnalysisSkipOverride,
2270+
) -> bool
2271+
where
2272+
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
2273+
{
2274+
let custom_arch = unsafe { &*(ctxt as *mut A) };
2275+
let mut function = unsafe { Function::from_raw(function) };
2276+
return custom_arch.analyze_basic_blocks(&mut function, incremental_update, analysis_skip_override);
2277+
}
2278+
22372279
extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char
22382280
where
22392281
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
@@ -3158,6 +3200,7 @@ where
31583200
getInstructionText: Some(cb_get_instruction_text::<A>),
31593201
freeInstructionText: Some(cb_free_instruction_text),
31603202
getInstructionLowLevelIL: Some(cb_instruction_llil::<A>),
3203+
analyzeBasicBlocks: Some(cb_analyze_basic_blocks::<A>),
31613204

31623205
getRegisterName: Some(cb_reg_name::<A>),
31633206
getFlagName: Some(cb_flag_name::<A>),

0 commit comments

Comments
 (0)