Skip to content

Commit 3c47579

Browse files
zznopemesare
authored andcommitted
[Rust] Bindings for custom basic block analysis
1 parent 25f8d40 commit 3c47579

File tree

6 files changed

+429
-13
lines changed

6 files changed

+429
-13
lines changed

rust/src/architecture.rs

Lines changed: 228 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,13 @@ use crate::{
3838
calling_convention::CoreCallingConvention,
3939
data_buffer::DataBuffer,
4040
disassembly::InstructionTextToken,
41-
function::Function,
41+
function::{ArchAndAddr, Function, NativeBlock},
4242
platform::Platform,
4343
rc::*,
4444
relocation::CoreRelocationHandler,
45-
string::IntoCStr,
46-
string::*,
45+
string::{IntoCStr, *},
4746
types::{NameAndType, Type},
48-
Endianness,
47+
BranchType, Endianness,
4948
};
5049

5150
pub mod basic_block;
@@ -135,13 +134,13 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
135134
il: &LowLevelILMutableFunction,
136135
) -> Option<(usize, bool)>;
137136

138-
unsafe fn analyze_basic_blocks(
137+
fn analyze_basic_blocks(
139138
&self,
140139
function: &mut Function,
141-
context: *mut BNBasicBlockAnalysisContext,
140+
context: &mut BasicBlockAnalysisContext,
142141
) {
143142
unsafe {
144-
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context);
143+
BNArchitectureDefaultAnalyzeBasicBlocks(function.handle, context.handle);
145144
}
146145
}
147146

@@ -484,13 +483,13 @@ impl Architecture for CoreArchitecture {
484483
}
485484
}
486485

487-
unsafe fn analyze_basic_blocks(
486+
fn analyze_basic_blocks(
488487
&self,
489488
function: &mut Function,
490-
context: *mut BNBasicBlockAnalysisContext,
489+
context: &mut BasicBlockAnalysisContext,
491490
) {
492491
unsafe {
493-
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context);
492+
BNArchitectureAnalyzeBasicBlocks(self.handle, function.handle, context.handle);
494493
}
495494
}
496495

@@ -862,6 +861,222 @@ impl Architecture for CoreArchitecture {
862861
}
863862
}
864863

864+
pub struct BasicBlockAnalysisContext {
865+
pub(crate) handle: *mut BNBasicBlockAnalysisContext,
866+
contextual_returns_dirty: bool,
867+
868+
// In
869+
pub indirect_branches: Vec<IndirectBranchInfo>,
870+
pub indirect_no_return_calls: HashSet<ArchAndAddr>,
871+
pub analysis_skip_override: BNFunctionAnalysisSkipOverride,
872+
pub translate_tail_calls: bool,
873+
pub disallow_branch_to_string: bool,
874+
pub max_function_size: u64,
875+
pub halt_on_invalid_instruction: bool,
876+
pub max_size_reached: bool,
877+
878+
// In/Out
879+
contextual_returns: HashMap<ArchAndAddr, bool>,
880+
881+
// Out
882+
direct_code_references: HashMap<u64, ArchAndAddr>,
883+
direct_no_return_calls: HashSet<ArchAndAddr>,
884+
halted_disassembly_addresses: HashSet<ArchAndAddr>,
885+
}
886+
887+
impl BasicBlockAnalysisContext {
888+
pub unsafe fn from_raw(handle: *mut BNBasicBlockAnalysisContext) -> Self {
889+
debug_assert!(!handle.is_null());
890+
891+
let ctx_ref = &*handle;
892+
893+
let indirect_branches = (0..ctx_ref.indirectBranchesCount)
894+
.map(|i| {
895+
let raw: BNIndirectBranchInfo =
896+
unsafe { std::ptr::read(ctx_ref.indirectBranches.add(i)) };
897+
IndirectBranchInfo::from(raw)
898+
})
899+
.collect::<Vec<_>>();
900+
901+
let indirect_no_return_calls = (0..ctx_ref.indirectNoReturnCallsCount)
902+
.map(|i| {
903+
let raw = unsafe { std::ptr::read(ctx_ref.indirectNoReturnCalls.add(i)) };
904+
ArchAndAddr::from(raw)
905+
})
906+
.collect::<HashSet<_>>();
907+
908+
let contextual_returns = (0..ctx_ref.contextualFunctionReturnCount)
909+
.map(|i| {
910+
let loc = unsafe {
911+
let raw = std::ptr::read(ctx_ref.contextualFunctionReturnLocations.add(i));
912+
ArchAndAddr::from(raw)
913+
};
914+
let val = unsafe { *ctx_ref.contextualFunctionReturnValues.add(i) };
915+
(loc, val)
916+
})
917+
.collect::<HashMap<_, _>>();
918+
919+
let direct_code_references = (0..ctx_ref.directRefCount)
920+
.map(|i| {
921+
let src = unsafe {
922+
let raw = std::ptr::read(ctx_ref.directRefSources.add(i));
923+
ArchAndAddr::from(raw)
924+
};
925+
let tgt = unsafe { *ctx_ref.directRefTargets.add(i) };
926+
(tgt, src)
927+
})
928+
.collect::<HashMap<_, _>>();
929+
930+
let direct_no_return_calls = (0..ctx_ref.directNoReturnCallsCount)
931+
.map(|i| {
932+
let raw = unsafe { std::ptr::read(ctx_ref.directNoReturnCalls.add(i)) };
933+
ArchAndAddr::from(raw)
934+
})
935+
.collect::<HashSet<_>>();
936+
937+
let halted_disassembly_addresses = (0..ctx_ref.haltedDisassemblyAddressesCount)
938+
.map(|i| {
939+
let raw = unsafe { std::ptr::read(ctx_ref.haltedDisassemblyAddresses.add(i)) };
940+
ArchAndAddr::from(raw)
941+
})
942+
.collect::<HashSet<_>>();
943+
944+
BasicBlockAnalysisContext {
945+
handle,
946+
contextual_returns_dirty: false,
947+
indirect_branches,
948+
indirect_no_return_calls,
949+
analysis_skip_override: ctx_ref.analysisSkipOverride,
950+
translate_tail_calls: ctx_ref.translateTailCalls,
951+
disallow_branch_to_string: ctx_ref.disallowBranchToString,
952+
max_function_size: ctx_ref.maxFunctionSize,
953+
halt_on_invalid_instruction: ctx_ref.haltOnInvalidInstructions,
954+
max_size_reached: ctx_ref.maxSizeReached,
955+
contextual_returns,
956+
direct_code_references,
957+
direct_no_return_calls,
958+
halted_disassembly_addresses,
959+
}
960+
}
961+
962+
pub fn add_contextual_return(&mut self, loc: ArchAndAddr, value: bool) {
963+
if !self.contextual_returns.contains_key(&loc) {
964+
self.contextual_returns_dirty = true;
965+
}
966+
967+
self.contextual_returns.insert(loc, value);
968+
}
969+
970+
pub fn add_direct_code_reference(&mut self, target: u64, src: ArchAndAddr) {
971+
self.direct_code_references.entry(target).or_insert(src);
972+
}
973+
974+
pub fn add_direct_no_return_call(&mut self, loc: ArchAndAddr) {
975+
self.direct_no_return_calls.insert(loc);
976+
}
977+
978+
pub fn add_halted_disassembly_address(&mut self, loc: ArchAndAddr) {
979+
self.halted_disassembly_addresses.insert(loc);
980+
}
981+
982+
pub fn create_basic_block(
983+
&self,
984+
arch: CoreArchitecture,
985+
start: u64,
986+
) -> Option<Ref<BasicBlock<NativeBlock>>> {
987+
let raw_block =
988+
unsafe { BNAnalyzeBasicBlocksContextCreateBasicBlock(self.handle, arch.handle, start) };
989+
990+
if raw_block.is_null() {
991+
return None;
992+
}
993+
994+
unsafe { Some(BasicBlock::ref_from_raw(raw_block, NativeBlock::new())) }
995+
}
996+
997+
pub fn add_basic_block(&self, block: Ref<BasicBlock<NativeBlock>>) {
998+
unsafe {
999+
BNAnalyzeBasicBlocksContextAddBasicBlockToFunction(self.handle, block.handle);
1000+
}
1001+
}
1002+
1003+
pub fn add_temp_outgoing_reference(&self, target: &Function) {
1004+
unsafe {
1005+
BNAnalyzeBasicBlocksContextAddTempReference(self.handle, target.handle);
1006+
}
1007+
}
1008+
1009+
pub fn finalize(&mut self) {
1010+
if !self.direct_code_references.is_empty() {
1011+
let total = self.direct_code_references.len();
1012+
let mut sources: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
1013+
let mut targets: Vec<u64> = Vec::with_capacity(total);
1014+
for (target, src) in &self.direct_code_references {
1015+
sources.push(src.into_raw());
1016+
targets.push(*target);
1017+
}
1018+
unsafe {
1019+
BNAnalyzeBasicBlocksContextSetDirectCodeReferences(
1020+
self.handle,
1021+
sources.as_mut_ptr(),
1022+
targets.as_mut_ptr(),
1023+
total,
1024+
);
1025+
}
1026+
}
1027+
1028+
if !self.direct_no_return_calls.is_empty() {
1029+
let total = self.direct_no_return_calls.len();
1030+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
1031+
for loc in &self.direct_no_return_calls {
1032+
locations.push(loc.into_raw());
1033+
}
1034+
unsafe {
1035+
BNAnalyzeBasicBlocksContextSetDirectNoReturnCalls(
1036+
self.handle,
1037+
locations.as_mut_ptr(),
1038+
total,
1039+
);
1040+
}
1041+
}
1042+
1043+
if !self.halted_disassembly_addresses.is_empty() {
1044+
let total = self.halted_disassembly_addresses.len();
1045+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
1046+
for loc in &self.halted_disassembly_addresses {
1047+
locations.push(loc.into_raw());
1048+
}
1049+
unsafe {
1050+
BNAnalyzeBasicBlocksContextSetHaltedDisassemblyAddresses(
1051+
self.handle,
1052+
locations.as_mut_ptr(),
1053+
total,
1054+
);
1055+
}
1056+
}
1057+
1058+
if self.contextual_returns_dirty {
1059+
let total = self.contextual_returns.len();
1060+
let mut locations: Vec<BNArchitectureAndAddress> = Vec::with_capacity(total);
1061+
let mut values: Vec<bool> = Vec::with_capacity(total);
1062+
for (loc, value) in &self.contextual_returns {
1063+
locations.push(loc.into_raw());
1064+
values.push(*value);
1065+
}
1066+
unsafe {
1067+
BNAnalyzeBasicBlocksContextSetContextualFunctionReturns(
1068+
self.handle,
1069+
locations.as_mut_ptr(),
1070+
values.as_mut_ptr(),
1071+
total,
1072+
);
1073+
}
1074+
}
1075+
1076+
unsafe { BNAnalyzeBasicBlocksContextFinalize(self.handle) };
1077+
}
1078+
}
1079+
8651080
impl Debug for CoreArchitecture {
8661081
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
8671082
f.debug_struct("CoreArchitecture")
@@ -1204,9 +1419,9 @@ where
12041419
{
12051420
let custom_arch = unsafe { &*(ctxt as *mut A) };
12061421
let mut function = unsafe { Function::from_raw(function) };
1207-
unsafe {
1208-
custom_arch.analyze_basic_blocks(&mut function, context);
1209-
}
1422+
let mut context: BasicBlockAnalysisContext =
1423+
unsafe { BasicBlockAnalysisContext::from_raw(context) };
1424+
custom_arch.analyze_basic_blocks(&mut function, &mut context);
12101425
}
12111426

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

0 commit comments

Comments
 (0)