Skip to content

Commit 604a22a

Browse files
committed
Rust bindings for custom basic block analysis
1 parent 288edd3 commit 604a22a

File tree

7 files changed

+482
-16
lines changed

7 files changed

+482
-16
lines changed

binaryninjacore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7607,11 +7607,11 @@ extern "C"
76077607

76087608
// LLVM Services APIs
76097609
BINARYNINJACOREAPI void BNLlvmServicesInit(void);
7610-
76117610
BINARYNINJACOREAPI int BNLlvmServicesAssemble(const char* src, int dialect, const char* triplet, int codeModel,
76127611
int relocMode, char** outBytes, int* outBytesLen, char** err, int* errLen);
7613-
76147612
BINARYNINJACOREAPI void BNLlvmServicesAssembleFree(char* outBytes, char* err);
7613+
BINARYNINJACOREAPI int BNLlvmServicesDisasmInstruction(const char *triplet, uint8_t *src, int srcLen,
7614+
uint64_t addr, char *result, size_t resultMaxSize);
76157615

76167616
// Filesystem functionality
76177617
BINARYNINJACOREAPI bool BNDeleteFile(const char* path);

rust/src/architecture.rs

Lines changed: 276 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ use crate::{
2323
calling_convention::CoreCallingConvention,
2424
data_buffer::DataBuffer,
2525
disassembly::InstructionTextToken,
26-
function::Function,
26+
function::{ArchAndAddr, Function, NativeBlock},
2727
platform::Platform,
2828
rc::*,
2929
relocation::CoreRelocationHandler,
30-
string::IntoCStr,
31-
string::*,
30+
string::{IntoCStr, *},
3231
types::{NameAndType, Type},
33-
Endianness,
32+
BranchType, Endianness,
3433
};
3534
use std::ops::Deref;
3635
use std::{
@@ -42,8 +41,10 @@ use std::{
4241
mem::MaybeUninit,
4342
};
4443

44+
use crate::basic_block::BasicBlock;
4545
use crate::function_recognizer::FunctionRecognizer;
4646
use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler};
47+
use crate::variable::IndirectBranchInfo;
4748

4849
use crate::confidence::Conf;
4950
use crate::low_level_il::expression::ValueExpr;
@@ -54,6 +55,7 @@ use crate::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction
5455
pub use binaryninjacore_sys::BNFlagRole as FlagRole;
5556
pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend;
5657
pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition;
58+
use std::collections::HashSet;
5759

5860
macro_rules! newtype {
5961
($name:ident, $inner_type:ty) => {
@@ -171,6 +173,23 @@ impl From<BranchKind> for BranchInfo {
171173
}
172174
}
173175

176+
impl From<BranchKind> for BranchType {
177+
fn from(value: BranchKind) -> Self {
178+
match value {
179+
BranchKind::Unresolved => BranchType::UnresolvedBranch,
180+
BranchKind::Unconditional(_) => BranchType::UnconditionalBranch,
181+
BranchKind::True(_) => BranchType::TrueBranch,
182+
BranchKind::False(_) => BranchType::FalseBranch,
183+
BranchKind::Call(_) => BranchType::CallDestination,
184+
BranchKind::FunctionReturn => BranchType::FunctionReturn,
185+
BranchKind::SystemCall => BranchType::SystemCall,
186+
BranchKind::Indirect => BranchType::IndirectBranch,
187+
BranchKind::Exception => BranchType::ExceptionBranch,
188+
BranchKind::UserDefined => BranchType::UserDefinedBranch,
189+
}
190+
}
191+
}
192+
174193
/// This is the number of branches that can be specified in an [`InstructionInfo`].
175194
pub const NUM_BRANCH_INFO: usize = 3;
176195

@@ -471,13 +490,13 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
471490
il: &LowLevelILMutableFunction,
472491
) -> Option<(usize, bool)>;
473492

474-
unsafe fn analyze_basic_blocks(
493+
fn analyze_basic_blocks(
475494
&self,
476495
function: &mut Function,
477-
context: *mut BNBasicBlockAnalysisContext,
496+
context: &mut BasicBlockAnalysisContext,
478497
) {
479498
unsafe {
480-
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context);
499+
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context.handle);
481500
}
482501
}
483502

@@ -1544,13 +1563,13 @@ impl Architecture for CoreArchitecture {
15441563
}
15451564
}
15461565

1547-
unsafe fn analyze_basic_blocks(
1566+
fn analyze_basic_blocks(
15481567
&self,
15491568
function: &mut Function,
1550-
context: *mut BNBasicBlockAnalysisContext,
1569+
context: &mut BasicBlockAnalysisContext,
15511570
) {
15521571
unsafe {
1553-
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context);
1572+
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context.handle);
15541573
}
15551574
}
15561575

@@ -1922,6 +1941,250 @@ impl Architecture for CoreArchitecture {
19221941
}
19231942
}
19241943

1944+
pub struct BasicBlockAnalysisContext {
1945+
pub(crate) handle: *mut BNBasicBlockAnalysisContext,
1946+
contextual_returns_dirty: bool,
1947+
1948+
// In
1949+
pub indirect_branches: Vec<IndirectBranchInfo>,
1950+
pub indirect_no_return_calls: HashSet<ArchAndAddr>,
1951+
pub analysis_skip_override: BNFunctionAnalysisSkipOverride,
1952+
pub translate_tail_calls: bool,
1953+
pub disallow_branch_to_string: bool,
1954+
pub max_function_size: u64,
1955+
pub max_size_reached: bool,
1956+
1957+
// In/Out
1958+
contextual_returns: HashMap<ArchAndAddr, bool>,
1959+
1960+
// Out
1961+
direct_code_references: HashMap<u64, ArchAndAddr>,
1962+
direct_no_return_calls: HashSet<ArchAndAddr>,
1963+
halted_disassembly_addresses: HashSet<ArchAndAddr>,
1964+
inlined_unresolved_indirect_branches: HashSet<ArchAndAddr>,
1965+
}
1966+
1967+
impl BasicBlockAnalysisContext {
1968+
pub unsafe fn from_raw(handle: *mut BNBasicBlockAnalysisContext) -> Self {
1969+
debug_assert!(!handle.is_null());
1970+
1971+
let ctx_ref = &*handle;
1972+
1973+
let indirect_branches = (0..ctx_ref.indirectBranchesCount)
1974+
.map(|i| {
1975+
let raw: BNIndirectBranchInfo =
1976+
unsafe { std::ptr::read(ctx_ref.indirectBranches.add(i)) };
1977+
IndirectBranchInfo::from(raw)
1978+
})
1979+
.collect::<Vec<_>>();
1980+
1981+
let indirect_no_return_calls = (0..ctx_ref.indirectNoReturnCallsCount)
1982+
.map(|i| {
1983+
let raw = unsafe { std::ptr::read(ctx_ref.indirectNoReturnCalls.add(i)) };
1984+
ArchAndAddr::from(raw)
1985+
})
1986+
.collect::<HashSet<_>>();
1987+
1988+
let contextual_returns = (0..ctx_ref.contextualFunctionReturnCount)
1989+
.map(|i| {
1990+
let loc = unsafe {
1991+
let raw = std::ptr::read(ctx_ref.contextualFunctionReturnLocations.add(i));
1992+
ArchAndAddr::from(raw)
1993+
};
1994+
let val = unsafe { *ctx_ref.contextualFunctionReturnValues.add(i) };
1995+
(loc, val)
1996+
})
1997+
.collect::<HashMap<_, _>>();
1998+
1999+
let direct_code_references = (0..ctx_ref.directRefCount)
2000+
.map(|i| {
2001+
let src = unsafe {
2002+
let raw = std::ptr::read(ctx_ref.directRefSources.add(i));
2003+
ArchAndAddr::from(raw)
2004+
};
2005+
let tgt = unsafe { *ctx_ref.directRefTargets.add(i) };
2006+
(tgt, src)
2007+
})
2008+
.collect::<HashMap<_, _>>();
2009+
2010+
let direct_no_return_calls = (0..ctx_ref.directNoReturnCallsCount)
2011+
.map(|i| {
2012+
let raw = unsafe { std::ptr::read(ctx_ref.directNoReturnCalls.add(i)) };
2013+
ArchAndAddr::from(raw)
2014+
})
2015+
.collect::<HashSet<_>>();
2016+
2017+
let halted_disassembly_addresses = (0..ctx_ref.haltedDisassemblyAddressesCount)
2018+
.map(|i| {
2019+
let raw = unsafe { std::ptr::read(ctx_ref.haltedDisassemblyAddresses.add(i)) };
2020+
ArchAndAddr::from(raw)
2021+
})
2022+
.collect::<HashSet<_>>();
2023+
2024+
let inlined_unresolved_indirect_branches = (0..ctx_ref
2025+
.inlinedUnresolvedIndirectBranchCount)
2026+
.map(|i| {
2027+
let raw =
2028+
unsafe { std::ptr::read(ctx_ref.inlinedUnresolvedIndirectBranches.add(i)) };
2029+
ArchAndAddr::from(raw)
2030+
})
2031+
.collect::<HashSet<_>>();
2032+
2033+
BasicBlockAnalysisContext {
2034+
handle,
2035+
contextual_returns_dirty: false,
2036+
indirect_branches,
2037+
indirect_no_return_calls,
2038+
analysis_skip_override: ctx_ref.analysisSkipOverride,
2039+
translate_tail_calls: ctx_ref.translateTailCalls,
2040+
disallow_branch_to_string: ctx_ref.disallowBranchToString,
2041+
max_function_size: ctx_ref.maxFunctionSize,
2042+
max_size_reached: ctx_ref.maxSizeReached,
2043+
contextual_returns,
2044+
direct_code_references,
2045+
direct_no_return_calls,
2046+
halted_disassembly_addresses,
2047+
inlined_unresolved_indirect_branches,
2048+
}
2049+
}
2050+
2051+
pub fn add_contextual_return(&mut self, loc: ArchAndAddr, value: bool) {
2052+
if !self.contextual_returns.contains_key(&loc) {
2053+
self.contextual_returns_dirty = true;
2054+
}
2055+
2056+
self.contextual_returns.insert(loc, value);
2057+
}
2058+
2059+
pub fn add_direct_code_reference(&mut self, target: u64, src: ArchAndAddr) {
2060+
self.direct_code_references.entry(target).or_insert(src);
2061+
}
2062+
2063+
pub fn add_direct_no_return_call(&mut self, loc: ArchAndAddr) {
2064+
self.direct_no_return_calls.insert(loc);
2065+
}
2066+
2067+
pub fn add_halted_disassembly_address(&mut self, loc: ArchAndAddr) {
2068+
self.halted_disassembly_addresses.insert(loc);
2069+
}
2070+
2071+
pub fn add_inlined_unresolved_indirect_branch(&mut self, loc: ArchAndAddr) {
2072+
self.inlined_unresolved_indirect_branches.insert(loc);
2073+
}
2074+
2075+
pub fn create_basic_block(
2076+
&self,
2077+
arch: CoreArchitecture,
2078+
start: u64,
2079+
) -> Option<Ref<BasicBlock<NativeBlock>>> {
2080+
let raw_block =
2081+
unsafe { BNAnalyzeBasicBlocksContextCreateBasicBlock(self.handle, arch.handle, start) };
2082+
2083+
if raw_block.is_null() {
2084+
return None;
2085+
}
2086+
2087+
unsafe { Some(BasicBlock::ref_from_raw(raw_block, NativeBlock::new())) }
2088+
}
2089+
2090+
pub fn add_basic_block(&self, block: Ref<BasicBlock<NativeBlock>>) {
2091+
unsafe {
2092+
BNAnalyzeBasicBlocksContextAddBasicBlockToFunction(self.handle, block.handle);
2093+
}
2094+
}
2095+
2096+
pub fn add_temp_outgoing_reference(&self, target: &Function) {
2097+
unsafe {
2098+
BNAnalyzeBasicBlocksContextAddTempReference(self.handle, target.handle);
2099+
}
2100+
}
2101+
2102+
pub fn finalize(&mut self) {
2103+
if !self.direct_code_references.is_empty() {
2104+
let total = self.direct_code_references.len();
2105+
let mut sources: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2106+
let mut targets: Vec<u64> = Vec::with_capacity(total);
2107+
for (target, src) in &self.direct_code_references {
2108+
sources.push(src.into_raw());
2109+
targets.push(*target);
2110+
}
2111+
unsafe {
2112+
BNAnalyzeBasicBlocksContextSetDirectCodeReferences(
2113+
self.handle,
2114+
sources.as_mut_ptr(),
2115+
targets.as_mut_ptr(),
2116+
total,
2117+
);
2118+
}
2119+
}
2120+
2121+
if !self.direct_no_return_calls.is_empty() {
2122+
let total = self.direct_no_return_calls.len();
2123+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2124+
for loc in &self.direct_no_return_calls {
2125+
locations.push(loc.into_raw());
2126+
}
2127+
unsafe {
2128+
BNAnalyzeBasicBlocksContextSetDirectNoReturnCalls(
2129+
self.handle,
2130+
locations.as_mut_ptr(),
2131+
total,
2132+
);
2133+
}
2134+
}
2135+
2136+
if !self.halted_disassembly_addresses.is_empty() {
2137+
let total = self.halted_disassembly_addresses.len();
2138+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2139+
for loc in &self.halted_disassembly_addresses {
2140+
locations.push(loc.into_raw());
2141+
}
2142+
unsafe {
2143+
BNAnalyzeBasicBlocksContextSetHaltedDisassemblyAddresses(
2144+
self.handle,
2145+
locations.as_mut_ptr(),
2146+
total,
2147+
);
2148+
}
2149+
}
2150+
2151+
if !self.inlined_unresolved_indirect_branches.is_empty() {
2152+
let total = self.inlined_unresolved_indirect_branches.len();
2153+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2154+
for loc in &self.inlined_unresolved_indirect_branches {
2155+
locations.push(loc.into_raw());
2156+
}
2157+
unsafe {
2158+
BNAnalyzeBasicBlocksContextSetInlinedUnresolvedIndirectBranches(
2159+
self.handle,
2160+
locations.as_mut_ptr(),
2161+
total,
2162+
);
2163+
}
2164+
}
2165+
2166+
if self.contextual_returns_dirty {
2167+
let total = self.contextual_returns.len();
2168+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2169+
let mut values: Vec<bool> = Vec::with_capacity(total);
2170+
for (loc, value) in &self.contextual_returns {
2171+
locations.push(loc.into_raw());
2172+
values.push(*value);
2173+
}
2174+
unsafe {
2175+
BNAnalyzeBasicBlocksContextSetContextualFunctionReturns(
2176+
self.handle,
2177+
locations.as_mut_ptr(),
2178+
values.as_mut_ptr(),
2179+
total,
2180+
);
2181+
}
2182+
}
2183+
2184+
unsafe { BNAnalyzeBasicBlocksContextFinalize(self.handle) };
2185+
}
2186+
}
2187+
19252188
impl Debug for CoreArchitecture {
19262189
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19272190
f.debug_struct("CoreArchitecture")
@@ -2264,9 +2527,9 @@ where
22642527
{
22652528
let custom_arch = unsafe { &*(ctxt as *mut A) };
22662529
let mut function = unsafe { Function::from_raw(function) };
2267-
unsafe {
2268-
custom_arch.analyze_basic_blocks(&mut function, context);
2269-
}
2530+
let mut context: BasicBlockAnalysisContext =
2531+
unsafe { BasicBlockAnalysisContext::from_raw(context) };
2532+
custom_arch.analyze_basic_blocks(&mut function, &mut context);
22702533
}
22712534

22722535
extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char

0 commit comments

Comments
 (0)