1use binaryninjacore_sys::*;
2use std::ffi::CStr;
3
4use crate::architecture::CoreArchitecture;
5use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
6use crate::string::IntoCStr;
7use std::num::NonZeroU32;
8use std::ptr::NonNull;
9
10pub type BaseAddressDetectionPOISetting = BNBaseAddressDetectionPOISetting;
11pub type BaseAddressDetectionConfidence = BNBaseAddressDetectionConfidence;
12pub type BaseAddressDetectionPOIType = BNBaseAddressDetectionPOIType;
13pub type BaseAddressDetectionAnalysisMode = BNBaseAddressDetectionAnalysisMode;
14
15const BASE_ADDRESS_AUTO_DETECTION_ARCH: &str = "auto detect";
17
18pub enum BaseAddressDetectionAnalysis {
19 Basic,
20 ControlFlow,
21 Full,
22}
23
24impl BaseAddressDetectionAnalysis {
25 pub fn as_raw(&self) -> &'static CStr {
26 match self {
27 BaseAddressDetectionAnalysis::Basic => c"basic",
28 BaseAddressDetectionAnalysis::ControlFlow => c"controlFlow",
29 BaseAddressDetectionAnalysis::Full => c"full",
30 }
31 }
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub struct BaseAddressDetectionResult {
36 pub scores: Vec<BaseAddressDetectionScore>,
37 pub confidence: BaseAddressDetectionConfidence,
38 pub last_base: u64,
39}
40
41#[repr(C)]
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
43pub struct BaseAddressDetectionScore {
44 pub score: usize,
45 pub base_address: u64,
46}
47
48#[repr(C)]
49#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
50pub struct BaseAddressDetectionReason {
51 pub pointer: u64,
52 pub poi_offset: u64,
53 pub poi_type: BaseAddressDetectionPOIType,
54}
55
56impl CoreArrayProvider for BaseAddressDetectionReason {
57 type Raw = BNBaseAddressDetectionReason;
58 type Context = ();
59 type Wrapped<'a> = &'a Self;
60}
61
62unsafe impl CoreArrayProviderInner for BaseAddressDetectionReason {
63 unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
64 BNFreeBaseAddressDetectionReasons(raw)
65 }
66
67 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
68 std::mem::transmute::<&BNBaseAddressDetectionReason, &BaseAddressDetectionReason>(raw)
71 }
72}
73
74pub struct BaseAddressDetection {
75 handle: NonNull<BNBaseAddressDetection>,
76}
77
78impl BaseAddressDetection {
79 pub(crate) unsafe fn from_raw(handle: NonNull<BNBaseAddressDetection>) -> Self {
80 Self { handle }
81 }
82
83 #[allow(clippy::mut_from_ref)]
84 pub(crate) unsafe fn as_raw(&self) -> &mut BNBaseAddressDetection {
85 &mut *self.handle.as_ptr()
86 }
87
88 pub fn aborted(&self) -> bool {
90 unsafe { BNIsBaseAddressDetectionAborted(self.as_raw()) }
91 }
92
93 pub fn abort(&self) {
98 unsafe { BNAbortBaseAddressDetection(self.as_raw()) }
99 }
100
101 pub fn get_reasons(&self, base_address: u64) -> Array<BaseAddressDetectionReason> {
104 let mut count = 0;
105 let reasons =
106 unsafe { BNGetBaseAddressDetectionReasons(self.as_raw(), base_address, &mut count) };
107 unsafe { Array::new(reasons, count, ()) }
108 }
109
110 pub fn scores(&self, max_candidates: usize) -> BaseAddressDetectionResult {
111 let mut scores = vec![BNBaseAddressDetectionScore::default(); max_candidates];
112 let mut confidence = BNBaseAddressDetectionConfidence::NoConfidence;
113 let mut last_base = 0;
114 let num_candidates = unsafe {
115 BNGetBaseAddressDetectionScores(
116 self.as_raw(),
117 scores.as_mut_ptr(),
118 scores.len(),
119 &mut confidence,
120 &mut last_base,
121 )
122 };
123 scores.truncate(num_candidates);
124 let scores = unsafe {
127 std::mem::transmute::<Vec<BNBaseAddressDetectionScore>, Vec<BaseAddressDetectionScore>>(
128 scores,
129 )
130 };
131 BaseAddressDetectionResult {
132 scores,
133 confidence,
134 last_base,
135 }
136 }
137
138 pub fn detect(&self, settings: &BaseAddressDetectionSettings) -> bool {
143 let mut raw_settings = BaseAddressDetectionSettings::into_raw(settings);
144 unsafe { BNDetectBaseAddress(self.handle.as_ptr(), &mut raw_settings) }
145 }
146
147 pub fn detect_with_instruction_analysis(
149 &self,
150 settings: &BaseAddressDetectionInstructionAnalysisSettings,
151 ) -> bool {
152 let mut raw_settings = BaseAddressDetectionInstructionAnalysisSettings::into_raw(settings);
153 unsafe {
154 BNDetectBaseAddressWithInstructionAnalysis(self.handle.as_ptr(), &mut raw_settings)
155 }
156 }
157
158 pub fn detect_with_sampling(&self, settings: &BaseAddressDetectionSamplingSettings) -> bool {
160 let mut raw_settings = BaseAddressDetectionSamplingSettings::into_raw(settings);
161 unsafe { BNDetectBaseAddressWithSampling(self.handle.as_ptr(), &mut raw_settings) }
162 }
163}
164
165impl Drop for BaseAddressDetection {
166 fn drop(&mut self) {
167 unsafe { BNFreeBaseAddressDetection(self.as_raw()) }
168 }
169}
170
171pub struct BaseAddressDetectionSettings {
173 arch: Option<CoreArchitecture>,
174 analysis: BaseAddressDetectionAnalysis,
176 min_string_len: u32,
178 alignment: NonZeroU32,
180 lower_boundary: u64,
182 upper_boundary: u64,
184 poi_analysis: BaseAddressDetectionPOISetting,
186 max_pointers: u32,
188 analysis_mode: BaseAddressDetectionAnalysisMode,
190}
191
192impl BaseAddressDetectionSettings {
193 pub(crate) fn into_raw(value: &Self) -> BNBaseAddressDetectionSettings {
194 let arch_name = value
195 .arch
196 .map(|a| a.name())
197 .unwrap_or(BASE_ADDRESS_AUTO_DETECTION_ARCH.to_string());
198 let c_arch_name = arch_name.to_cstr();
199 BNBaseAddressDetectionSettings {
200 Architecture: c_arch_name.into_raw(),
201 Analysis: value.analysis.as_raw().as_ptr(),
202 MinStrlen: value.min_string_len,
203 Alignment: value.alignment.get(),
204 LowerBoundary: value.lower_boundary,
205 UpperBoundary: value.upper_boundary,
206 POIAnalysis: value.poi_analysis,
207 MaxPointersPerCluster: value.max_pointers,
208 AnalysisMode: value.analysis_mode,
209 }
210 }
211
212 pub fn arch(mut self, value: CoreArchitecture) -> Self {
213 self.arch = Some(value);
214 self
215 }
216
217 pub fn analysis(mut self, value: BaseAddressDetectionAnalysis) -> Self {
218 self.analysis = value;
219 self
220 }
221
222 pub fn min_strlen(mut self, value: u32) -> Self {
223 self.min_string_len = value;
224 self
225 }
226
227 pub fn alignment(mut self, value: NonZeroU32) -> Self {
228 self.alignment = value;
229 self
230 }
231
232 pub fn low_boundary(mut self, value: u64) -> Self {
236 assert!(
237 self.upper_boundary >= value,
238 "upper boundary must be greater than lower boundary"
239 );
240 self.lower_boundary = value;
241 self
242 }
243
244 pub fn high_boundary(mut self, value: u64) -> Self {
248 assert!(
249 self.lower_boundary <= value,
250 "upper boundary must be greater than lower boundary"
251 );
252 self.upper_boundary = value;
253 self
254 }
255
256 pub fn poi_analysis(mut self, value: BaseAddressDetectionPOISetting) -> Self {
257 self.poi_analysis = value;
258 self
259 }
260
261 pub fn max_pointers(mut self, value: u32) -> Self {
265 assert!(value > 2, "max pointers must be at least 2");
266 self.max_pointers = value;
267 self
268 }
269
270 pub fn analysis_mode(mut self, value: BaseAddressDetectionAnalysisMode) -> Self {
271 self.analysis_mode = value;
272 self
273 }
274}
275
276impl Default for BaseAddressDetectionSettings {
277 fn default() -> Self {
278 BaseAddressDetectionSettings {
279 arch: None,
280 analysis: BaseAddressDetectionAnalysis::Full,
281 min_string_len: 10,
282 alignment: 1024.try_into().unwrap(),
283 lower_boundary: u64::MIN,
284 upper_boundary: u64::MAX,
285 poi_analysis: BaseAddressDetectionPOISetting::POIAnalysisAll,
286 max_pointers: 128,
287 analysis_mode:
288 BaseAddressDetectionAnalysisMode::InstructionAnalysisBaseAddressDetection,
289 }
290 }
291}
292
293pub struct BaseAddressDetectionCommonSettings {
295 arch: Option<CoreArchitecture>,
296 min_string_len: u32,
298 lower_boundary: u64,
300 upper_boundary: u64,
302}
303
304impl BaseAddressDetectionCommonSettings {
305 fn into_raw(value: &Self) -> BNBaseAddressDetectionCommonSettings {
306 let arch_name = value
307 .arch
308 .map(|a| a.name())
309 .unwrap_or(BASE_ADDRESS_AUTO_DETECTION_ARCH.to_string());
310 let c_arch_name = arch_name.to_cstr();
311 BNBaseAddressDetectionCommonSettings {
312 Architecture: c_arch_name.into_raw(),
313 MinStrlen: value.min_string_len,
314 LowerBoundary: value.lower_boundary,
315 UpperBoundary: value.upper_boundary,
316 }
317 }
318
319 pub fn arch(mut self, value: CoreArchitecture) -> Self {
320 self.arch = Some(value);
321 self
322 }
323
324 pub fn min_strlen(mut self, value: u32) -> Self {
325 self.min_string_len = value;
326 self
327 }
328
329 pub fn low_boundary(mut self, value: u64) -> Self {
333 assert!(
334 self.upper_boundary >= value,
335 "upper boundary must be greater than lower boundary"
336 );
337 self.lower_boundary = value;
338 self
339 }
340
341 pub fn high_boundary(mut self, value: u64) -> Self {
345 assert!(
346 self.lower_boundary <= value,
347 "upper boundary must be greater than lower boundary"
348 );
349 self.upper_boundary = value;
350 self
351 }
352}
353
354impl Default for BaseAddressDetectionCommonSettings {
355 fn default() -> Self {
356 Self {
357 arch: None,
358 min_string_len: 10,
359 lower_boundary: u64::MIN,
360 upper_boundary: u64::MAX,
361 }
362 }
363}
364
365pub struct BaseAddressDetectionInstructionAnalysisSettings {
367 common: BaseAddressDetectionCommonSettings,
368 analysis: BaseAddressDetectionAnalysis,
370 alignment: NonZeroU32,
372 poi_analysis: BaseAddressDetectionPOISetting,
374 max_pointers: u32,
376}
377
378impl BaseAddressDetectionInstructionAnalysisSettings {
379 pub(crate) fn into_raw(value: &Self) -> BNBaseAddressDetectionInstructionAnalysisSettings {
380 BNBaseAddressDetectionInstructionAnalysisSettings {
381 Common: BaseAddressDetectionCommonSettings::into_raw(&value.common),
382 Analysis: value.analysis.as_raw().as_ptr(),
383 Alignment: value.alignment.get(),
384 POIAnalysis: value.poi_analysis,
385 MaxPointersPerCluster: value.max_pointers,
386 }
387 }
388
389 pub fn common(mut self, value: BaseAddressDetectionCommonSettings) -> Self {
390 self.common = value;
391 self
392 }
393
394 pub fn arch(mut self, value: CoreArchitecture) -> Self {
395 self.common = self.common.arch(value);
396 self
397 }
398
399 pub fn analysis(mut self, value: BaseAddressDetectionAnalysis) -> Self {
400 self.analysis = value;
401 self
402 }
403
404 pub fn min_strlen(mut self, value: u32) -> Self {
405 self.common = self.common.min_strlen(value);
406 self
407 }
408
409 pub fn alignment(mut self, value: NonZeroU32) -> Self {
410 self.alignment = value;
411 self
412 }
413
414 pub fn low_boundary(mut self, value: u64) -> Self {
415 self.common = self.common.low_boundary(value);
416 self
417 }
418
419 pub fn high_boundary(mut self, value: u64) -> Self {
420 self.common = self.common.high_boundary(value);
421 self
422 }
423
424 pub fn poi_analysis(mut self, value: BaseAddressDetectionPOISetting) -> Self {
425 self.poi_analysis = value;
426 self
427 }
428
429 pub fn max_pointers(mut self, value: u32) -> Self {
433 assert!(value >= 2, "max pointers must be at least 2");
434 self.max_pointers = value;
435 self
436 }
437}
438
439impl Default for BaseAddressDetectionInstructionAnalysisSettings {
440 fn default() -> Self {
441 Self {
442 common: BaseAddressDetectionCommonSettings::default(),
443 analysis: BaseAddressDetectionAnalysis::Full,
444 alignment: 1024.try_into().unwrap(),
445 poi_analysis: BaseAddressDetectionPOISetting::POIAnalysisAll,
446 max_pointers: 128,
447 }
448 }
449}
450
451pub struct BaseAddressDetectionSamplingSettings {
453 common: BaseAddressDetectionCommonSettings,
454 alignment: NonZeroU32,
456}
457
458impl BaseAddressDetectionSamplingSettings {
459 pub(crate) fn into_raw(value: &Self) -> BNBaseAddressDetectionSamplingSettings {
460 BNBaseAddressDetectionSamplingSettings {
461 Common: BaseAddressDetectionCommonSettings::into_raw(&value.common),
462 Alignment: value.alignment.get(),
463 }
464 }
465
466 pub fn common(mut self, value: BaseAddressDetectionCommonSettings) -> Self {
467 self.common = value;
468 self
469 }
470
471 pub fn arch(mut self, value: CoreArchitecture) -> Self {
472 self.common = self.common.arch(value);
473 self
474 }
475
476 pub fn min_strlen(mut self, value: u32) -> Self {
477 self.common = self.common.min_strlen(value);
478 self
479 }
480
481 pub fn alignment(mut self, value: NonZeroU32) -> Self {
482 self.alignment = value;
483 self
484 }
485
486 pub fn low_boundary(mut self, value: u64) -> Self {
487 self.common = self.common.low_boundary(value);
488 self
489 }
490
491 pub fn high_boundary(mut self, value: u64) -> Self {
492 self.common = self.common.high_boundary(value);
493 self
494 }
495}
496
497impl Default for BaseAddressDetectionSamplingSettings {
498 fn default() -> Self {
499 Self {
500 common: BaseAddressDetectionCommonSettings::default(),
501 alignment: 4096.try_into().unwrap(),
502 }
503 }
504}