1use binaryninjacore_sys::*;
2use std::ffi::{c_char, CStr};
3
4use crate::architecture::CoreArchitecture;
5use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
6use std::num::NonZeroU32;
7use std::ptr::NonNull;
8
9pub type BaseAddressDetectionPOISetting = BNBaseAddressDetectionPOISetting;
10pub type BaseAddressDetectionConfidence = BNBaseAddressDetectionConfidence;
11pub type BaseAddressDetectionPOIType = BNBaseAddressDetectionPOIType;
12
13const BASE_ADDRESS_AUTO_DETECTION_ARCH: &CStr = c"auto detect";
15
16pub enum BaseAddressDetectionAnalysis {
17 Basic,
18 ControlFlow,
19 Full,
20}
21
22impl BaseAddressDetectionAnalysis {
23 pub fn as_raw(&self) -> &'static CStr {
24 match self {
25 BaseAddressDetectionAnalysis::Basic => c"basic",
26 BaseAddressDetectionAnalysis::ControlFlow => c"controlFlow",
27 BaseAddressDetectionAnalysis::Full => c"full",
28 }
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct BaseAddressDetectionResult {
34 pub scores: Vec<BaseAddressDetectionScore>,
35 pub confidence: BaseAddressDetectionConfidence,
36 pub last_base: u64,
37}
38
39#[repr(C)]
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
41pub struct BaseAddressDetectionScore {
42 pub score: usize,
43 pub base_address: u64,
44}
45
46#[repr(C)]
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
48pub struct BaseAddressDetectionReason {
49 pub pointer: u64,
50 pub poi_offset: u64,
51 pub poi_type: BaseAddressDetectionPOIType,
52}
53
54impl CoreArrayProvider for BaseAddressDetectionReason {
55 type Raw = BNBaseAddressDetectionReason;
56 type Context = ();
57 type Wrapped<'a> = &'a Self;
58}
59
60unsafe impl CoreArrayProviderInner for BaseAddressDetectionReason {
61 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
62 BNFreeBaseAddressDetectionReasons(raw)
63 }
64
65 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
66 std::mem::transmute::<&BNBaseAddressDetectionReason, &BaseAddressDetectionReason>(raw)
69 }
70}
71
72pub struct BaseAddressDetection {
73 handle: NonNull<BNBaseAddressDetection>,
74}
75
76impl BaseAddressDetection {
77 pub(crate) unsafe fn from_raw(handle: NonNull<BNBaseAddressDetection>) -> Self {
78 Self { handle }
79 }
80
81 #[allow(clippy::mut_from_ref)]
82 pub(crate) unsafe fn as_raw(&self) -> &mut BNBaseAddressDetection {
83 &mut *self.handle.as_ptr()
84 }
85
86 pub fn aborted(&self) -> bool {
88 unsafe { BNIsBaseAddressDetectionAborted(self.as_raw()) }
89 }
90
91 pub fn abort(&self) {
96 unsafe { BNAbortBaseAddressDetection(self.as_raw()) }
97 }
98
99 pub fn get_reasons(&self, base_address: u64) -> Array<BaseAddressDetectionReason> {
102 let mut count = 0;
103 let reasons =
104 unsafe { BNGetBaseAddressDetectionReasons(self.as_raw(), base_address, &mut count) };
105 unsafe { Array::new(reasons, count, ()) }
106 }
107
108 pub fn scores(&self, max_candidates: usize) -> BaseAddressDetectionResult {
109 let mut scores = vec![BNBaseAddressDetectionScore::default(); max_candidates];
110 let mut confidence = BNBaseAddressDetectionConfidence::NoConfidence;
111 let mut last_base = 0;
112 let num_candidates = unsafe {
113 BNGetBaseAddressDetectionScores(
114 self.as_raw(),
115 scores.as_mut_ptr(),
116 scores.len(),
117 &mut confidence,
118 &mut last_base,
119 )
120 };
121 scores.truncate(num_candidates);
122 let scores = unsafe {
125 std::mem::transmute::<Vec<BNBaseAddressDetectionScore>, Vec<BaseAddressDetectionScore>>(
126 scores,
127 )
128 };
129 BaseAddressDetectionResult {
130 scores,
131 confidence,
132 last_base,
133 }
134 }
135
136 pub fn detect(&self, settings: &BaseAddressDetectionSettings) -> bool {
141 let mut raw_settings = BaseAddressDetectionSettings::into_raw(settings);
142 unsafe { BNDetectBaseAddress(self.handle.as_ptr(), &mut raw_settings) }
143 }
144}
145
146impl Drop for BaseAddressDetection {
147 fn drop(&mut self) {
148 unsafe { BNFreeBaseAddressDetection(self.as_raw()) }
149 }
150}
151
152pub struct BaseAddressDetectionSettings {
162 arch: Option<CoreArchitecture>,
163 analysis: BaseAddressDetectionAnalysis,
164 min_string_len: u32,
165 alignment: NonZeroU32,
166 lower_boundary: u64,
167 upper_boundary: u64,
168 poi_analysis: BaseAddressDetectionPOISetting,
169 max_pointers: u32,
170}
171
172impl BaseAddressDetectionSettings {
173 pub(crate) fn into_raw(value: &Self) -> BNBaseAddressDetectionSettings {
174 let arch_name = value
175 .arch
176 .map(|a| a.name().as_ptr())
177 .unwrap_or(BASE_ADDRESS_AUTO_DETECTION_ARCH.as_ptr() as *const u8);
178 BNBaseAddressDetectionSettings {
179 Architecture: arch_name as *const c_char,
180 Analysis: value.analysis.as_raw().as_ptr(),
181 MinStrlen: value.min_string_len,
182 Alignment: value.alignment.get(),
183 LowerBoundary: value.lower_boundary,
184 UpperBoundary: value.upper_boundary,
185 POIAnalysis: value.poi_analysis,
186 MaxPointersPerCluster: value.max_pointers,
187 }
188 }
189
190 pub fn arch(mut self, value: CoreArchitecture) -> Self {
191 self.arch = Some(value);
192 self
193 }
194
195 pub fn analysis(mut self, value: BaseAddressDetectionAnalysis) -> Self {
196 self.analysis = value;
197 self
198 }
199
200 pub fn min_strlen(mut self, value: u32) -> Self {
201 self.min_string_len = value;
202 self
203 }
204
205 pub fn alignment(mut self, value: NonZeroU32) -> Self {
206 self.alignment = value;
207 self
208 }
209
210 pub fn low_boundary(mut self, value: u64) -> Self {
211 assert!(
212 self.upper_boundary >= value,
213 "upper boundary must be greater than lower boundary"
214 );
215 self.lower_boundary = value;
216 self
217 }
218
219 pub fn high_boundary(mut self, value: u64) -> Self {
220 assert!(
221 self.lower_boundary <= value,
222 "upper boundary must be greater than lower boundary"
223 );
224 self.upper_boundary = value;
225 self
226 }
227
228 pub fn poi_analysis(mut self, value: BaseAddressDetectionPOISetting) -> Self {
229 self.poi_analysis = value;
230 self
231 }
232
233 pub fn max_pointers(mut self, value: u32) -> Self {
234 assert!(value > 2, "max pointers must be at least 2");
235 self.max_pointers = value;
236 self
237 }
238}
239
240impl Default for BaseAddressDetectionSettings {
241 fn default() -> Self {
242 BaseAddressDetectionSettings {
243 arch: None,
244 analysis: BaseAddressDetectionAnalysis::Full,
245 min_string_len: 10,
246 alignment: 1024.try_into().unwrap(),
247 lower_boundary: u64::MIN,
248 upper_boundary: u64::MAX,
249 poi_analysis: BaseAddressDetectionPOISetting::POIAnalysisAll,
250 max_pointers: 128,
251 }
252 }
253}