Skip to content

Commit b97cfa6

Browse files
committed
Rust bindings for custom basic block analysis
1 parent f4068c2 commit b97cfa6

File tree

4 files changed

+287
-16
lines changed

4 files changed

+287
-16
lines changed

rust/src/architecture.rs

Lines changed: 230 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@ 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},
3332
Endianness,
3433
};
@@ -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) => {
@@ -471,13 +473,13 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
471473
il: &LowLevelILMutableFunction,
472474
) -> Option<(usize, bool)>;
473475

474-
unsafe fn analyze_basic_blocks(
476+
fn analyze_basic_blocks(
475477
&self,
476478
function: &mut Function,
477-
context: *mut BNBasicBlockAnalysisContext,
479+
context: &mut BasicBlockAnalysisContext,
478480
) {
479481
unsafe {
480-
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context);
482+
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context.handle);
481483
}
482484
}
483485

@@ -1544,13 +1546,13 @@ impl Architecture for CoreArchitecture {
15441546
}
15451547
}
15461548

1547-
unsafe fn analyze_basic_blocks(
1549+
fn analyze_basic_blocks(
15481550
&self,
15491551
function: &mut Function,
1550-
context: *mut BNBasicBlockAnalysisContext,
1552+
context: &mut BasicBlockAnalysisContext,
15511553
) {
15521554
unsafe {
1553-
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context);
1555+
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context.handle);
15541556
}
15551557
}
15561558

@@ -1925,6 +1927,222 @@ impl Architecture for CoreArchitecture {
19251927
}
19261928
}
19271929

1930+
pub struct BasicBlockAnalysisContext {
1931+
pub(crate) handle: *mut BNBasicBlockAnalysisContext,
1932+
contextual_returns_dirty: bool,
1933+
1934+
// In
1935+
pub indirect_branches: Vec<IndirectBranchInfo>,
1936+
pub indirect_no_return_calls: HashSet<ArchAndAddr>,
1937+
pub analysis_skip_override: BNFunctionAnalysisSkipOverride,
1938+
pub translate_tail_calls: bool,
1939+
pub disallow_branch_to_string: bool,
1940+
pub max_function_size: u64,
1941+
pub halt_on_invalid_instruction: bool,
1942+
pub max_size_reached: bool,
1943+
1944+
// In/Out
1945+
contextual_returns: HashMap<ArchAndAddr, bool>,
1946+
1947+
// Out
1948+
direct_code_references: HashMap<u64, ArchAndAddr>,
1949+
direct_no_return_calls: HashSet<ArchAndAddr>,
1950+
halted_disassembly_addresses: HashSet<ArchAndAddr>,
1951+
}
1952+
1953+
impl BasicBlockAnalysisContext {
1954+
pub unsafe fn from_raw(handle: *mut BNBasicBlockAnalysisContext) -> Self {
1955+
debug_assert!(!handle.is_null());
1956+
1957+
let ctx_ref = &*handle;
1958+
1959+
let indirect_branches = (0..ctx_ref.indirectBranchesCount)
1960+
.map(|i| {
1961+
let raw: BNIndirectBranchInfo =
1962+
unsafe { std::ptr::read(ctx_ref.indirectBranches.add(i)) };
1963+
IndirectBranchInfo::from(raw)
1964+
})
1965+
.collect::<Vec<_>>();
1966+
1967+
let indirect_no_return_calls = (0..ctx_ref.indirectNoReturnCallsCount)
1968+
.map(|i| {
1969+
let raw = unsafe { std::ptr::read(ctx_ref.indirectNoReturnCalls.add(i)) };
1970+
ArchAndAddr::from(raw)
1971+
})
1972+
.collect::<HashSet<_>>();
1973+
1974+
let contextual_returns = (0..ctx_ref.contextualFunctionReturnCount)
1975+
.map(|i| {
1976+
let loc = unsafe {
1977+
let raw = std::ptr::read(ctx_ref.contextualFunctionReturnLocations.add(i));
1978+
ArchAndAddr::from(raw)
1979+
};
1980+
let val = unsafe { *ctx_ref.contextualFunctionReturnValues.add(i) };
1981+
(loc, val)
1982+
})
1983+
.collect::<HashMap<_, _>>();
1984+
1985+
let direct_code_references = (0..ctx_ref.directRefCount)
1986+
.map(|i| {
1987+
let src = unsafe {
1988+
let raw = std::ptr::read(ctx_ref.directRefSources.add(i));
1989+
ArchAndAddr::from(raw)
1990+
};
1991+
let tgt = unsafe { *ctx_ref.directRefTargets.add(i) };
1992+
(tgt, src)
1993+
})
1994+
.collect::<HashMap<_, _>>();
1995+
1996+
let direct_no_return_calls = (0..ctx_ref.directNoReturnCallsCount)
1997+
.map(|i| {
1998+
let raw = unsafe { std::ptr::read(ctx_ref.directNoReturnCalls.add(i)) };
1999+
ArchAndAddr::from(raw)
2000+
})
2001+
.collect::<HashSet<_>>();
2002+
2003+
let halted_disassembly_addresses = (0..ctx_ref.haltedDisassemblyAddressesCount)
2004+
.map(|i| {
2005+
let raw = unsafe { std::ptr::read(ctx_ref.haltedDisassemblyAddresses.add(i)) };
2006+
ArchAndAddr::from(raw)
2007+
})
2008+
.collect::<HashSet<_>>();
2009+
2010+
BasicBlockAnalysisContext {
2011+
handle,
2012+
contextual_returns_dirty: false,
2013+
indirect_branches,
2014+
indirect_no_return_calls,
2015+
analysis_skip_override: ctx_ref.analysisSkipOverride,
2016+
translate_tail_calls: ctx_ref.translateTailCalls,
2017+
disallow_branch_to_string: ctx_ref.disallowBranchToString,
2018+
max_function_size: ctx_ref.maxFunctionSize,
2019+
halt_on_invalid_instruction: ctx_ref.haltOnInvalidInstructions,
2020+
max_size_reached: ctx_ref.maxSizeReached,
2021+
contextual_returns,
2022+
direct_code_references,
2023+
direct_no_return_calls,
2024+
halted_disassembly_addresses,
2025+
}
2026+
}
2027+
2028+
pub fn add_contextual_return(&mut self, loc: ArchAndAddr, value: bool) {
2029+
if !self.contextual_returns.contains_key(&loc) {
2030+
self.contextual_returns_dirty = true;
2031+
}
2032+
2033+
self.contextual_returns.insert(loc, value);
2034+
}
2035+
2036+
pub fn add_direct_code_reference(&mut self, target: u64, src: ArchAndAddr) {
2037+
self.direct_code_references.entry(target).or_insert(src);
2038+
}
2039+
2040+
pub fn add_direct_no_return_call(&mut self, loc: ArchAndAddr) {
2041+
self.direct_no_return_calls.insert(loc);
2042+
}
2043+
2044+
pub fn add_halted_disassembly_address(&mut self, loc: ArchAndAddr) {
2045+
self.halted_disassembly_addresses.insert(loc);
2046+
}
2047+
2048+
pub fn create_basic_block(
2049+
&self,
2050+
arch: CoreArchitecture,
2051+
start: u64,
2052+
) -> Option<BasicBlock<NativeBlock>> {
2053+
let raw_block =
2054+
unsafe { BNAnalyzeBasicBlocksContextCreateBasicBlock(self.handle, arch.handle, start) };
2055+
2056+
if raw_block.is_null() {
2057+
return None;
2058+
}
2059+
2060+
unsafe { Some(BasicBlock::from_raw(raw_block, NativeBlock::new())) }
2061+
}
2062+
2063+
pub fn add_basic_block(&self, block: &BasicBlock<NativeBlock>) {
2064+
unsafe {
2065+
BNAnalyzeBasicBlocksContextAddBasicBlockToFunction(self.handle, block.handle);
2066+
}
2067+
}
2068+
2069+
pub fn add_temp_outgoing_reference(&self, target: &Function) {
2070+
unsafe {
2071+
BNAnalyzeBasicBlocksContextAddTempReference(self.handle, target.handle);
2072+
}
2073+
}
2074+
2075+
pub fn finalize(&mut self) {
2076+
if !self.direct_code_references.is_empty() {
2077+
let total = self.direct_code_references.len();
2078+
let mut sources: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2079+
let mut targets: Vec<u64> = Vec::with_capacity(total);
2080+
for (target, src) in &self.direct_code_references {
2081+
sources.push(src.into_raw());
2082+
targets.push(*target);
2083+
}
2084+
unsafe {
2085+
BNAnalyzeBasicBlocksContextSetDirectCodeReferences(
2086+
self.handle,
2087+
sources.as_mut_ptr(),
2088+
targets.as_mut_ptr(),
2089+
total,
2090+
);
2091+
}
2092+
}
2093+
2094+
if !self.direct_no_return_calls.is_empty() {
2095+
let total = self.direct_no_return_calls.len();
2096+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2097+
for loc in &self.direct_no_return_calls {
2098+
locations.push(loc.into_raw());
2099+
}
2100+
unsafe {
2101+
BNAnalyzeBasicBlocksContextSetDirectNoReturnCalls(
2102+
self.handle,
2103+
locations.as_mut_ptr(),
2104+
total,
2105+
);
2106+
}
2107+
}
2108+
2109+
if !self.halted_disassembly_addresses.is_empty() {
2110+
let total = self.halted_disassembly_addresses.len();
2111+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2112+
for loc in &self.halted_disassembly_addresses {
2113+
locations.push(loc.into_raw());
2114+
}
2115+
unsafe {
2116+
BNAnalyzeBasicBlocksContextSetHaltedDisassemblyAddresses(
2117+
self.handle,
2118+
locations.as_mut_ptr(),
2119+
total,
2120+
);
2121+
}
2122+
}
2123+
2124+
if self.contextual_returns_dirty {
2125+
let total = self.contextual_returns.len();
2126+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
2127+
let mut values: Vec<bool> = Vec::with_capacity(total);
2128+
for (loc, value) in &self.contextual_returns {
2129+
locations.push(loc.into_raw());
2130+
values.push(*value);
2131+
}
2132+
unsafe {
2133+
BNAnalyzeBasicBlocksContextSetContextualFunctionReturns(
2134+
self.handle,
2135+
locations.as_mut_ptr(),
2136+
values.as_mut_ptr(),
2137+
total,
2138+
);
2139+
}
2140+
}
2141+
2142+
unsafe { BNAnalyzeBasicBlocksContextFinalize(self.handle) };
2143+
}
2144+
}
2145+
19282146
impl Debug for CoreArchitecture {
19292147
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
19302148
f.debug_struct("CoreArchitecture")
@@ -2267,9 +2485,9 @@ where
22672485
{
22682486
let custom_arch = unsafe { &*(ctxt as *mut A) };
22692487
let mut function = unsafe { Function::from_raw(function) };
2270-
unsafe {
2271-
custom_arch.analyze_basic_blocks(&mut function, context);
2272-
}
2488+
let mut context: BasicBlockAnalysisContext =
2489+
unsafe { BasicBlockAnalysisContext::from_raw(context) };
2490+
custom_arch.analyze_basic_blocks(&mut function, &mut context);
22732491
}
22742492

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

rust/src/basic_block.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,22 @@ impl<C: BlockContext> BasicBlock<C> {
160160
C::InstructionIndex::from(unsafe { BNGetBasicBlockEnd(self.handle) })
161161
}
162162

163+
pub fn set_end(&self, end: u64) {
164+
unsafe {
165+
BNSetBasicBlockEnd(self.handle, end);
166+
}
167+
}
168+
169+
pub fn add_instruction_data(&self, data: &[u8]) {
170+
unsafe {
171+
BNBasicBlockAddInstructionData(
172+
self.handle,
173+
data.as_ptr() as *const _,
174+
data.len(),
175+
);
176+
}
177+
}
178+
163179
pub fn raw_length(&self) -> u64 {
164180
unsafe { BNGetBasicBlockLength(self.handle) }
165181
}
@@ -194,6 +210,18 @@ impl<C: BlockContext> BasicBlock<C> {
194210
}
195211
}
196212

213+
pub fn add_pending_outgoing_edge(
214+
&self,
215+
typ: BranchType,
216+
addr: u64,
217+
arch: CoreArchitecture,
218+
fallthrough: bool,
219+
) {
220+
unsafe {
221+
BNBasicBlockAddPendingOutgoingEdge(self.handle, typ, addr, arch.handle, fallthrough);
222+
}
223+
}
224+
197225
// is this valid for il blocks? (it looks like up to MLIL it is)
198226
pub fn has_undetermined_outgoing_edges(&self) -> bool {
199227
unsafe { BNBasicBlockHasUndeterminedOutgoingEdges(self.handle) }

rust/src/function.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2906,3 +2906,28 @@ unsafe impl CoreArrayProviderInner for Comment {
29062906
}
29072907
}
29082908
}
2909+
2910+
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
2911+
pub struct ArchAndAddr {
2912+
pub arch: CoreArchitecture,
2913+
pub addr: u64,
2914+
}
2915+
2916+
impl From<BNArchitectureAndAddress> for ArchAndAddr {
2917+
fn from(raw: BNArchitectureAndAddress) -> Self {
2918+
unsafe {
2919+
let arch = CoreArchitecture::from_raw(raw.arch);
2920+
let addr = raw.address;
2921+
ArchAndAddr { arch, addr }
2922+
}
2923+
}
2924+
}
2925+
2926+
impl ArchAndAddr {
2927+
pub fn into_raw(self) -> BNArchitectureAndAddress {
2928+
BNArchitectureAndAddress {
2929+
arch: self.arch.handle,
2930+
address: self.addr,
2931+
}
2932+
}
2933+
}

0 commit comments

Comments
 (0)