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