memflow_win32/win32/kernel_builder.rs
1use std::prelude::v1::*;
2
3use super::{Win32Kernel, Win32KernelInfo};
4use crate::offsets::Win32Offsets;
5
6#[cfg(feature = "symstore")]
7use crate::offsets::SymbolStore;
8
9use crate::offsets::offset_builder_with_kernel_info;
10
11use memflow::architecture::ArchitectureIdent;
12use memflow::cglue::forward::ForwardMut;
13use memflow::error::Result;
14use memflow::mem::{
15 phys_mem::CachedPhysicalMemory, virt_translate::CachedVirtualTranslate, DirectTranslate,
16 PhysicalMemory, VirtualTranslate2,
17};
18use memflow::types::{Address, DefaultCacheValidator};
19
20/// Builder for a Windows Kernel structure.
21///
22/// This function encapsulates the entire setup process for a Windows target
23/// and will make sure the user gets a properly initialized object at the end.
24///
25/// This function is a high level abstraction over the individual parts of initialization a Windows target:
26/// - Scanning for the ntoskrnl and retrieving the `Win32KernelInfo` struct.
27/// - Retrieving the Offsets for the target Windows version.
28/// - Creating a struct which implements `VirtualTranslate2` for virtual to physical address translations.
29/// - Optionally wrapping the Connector or the `VirtualTranslate2` object into a cached object.
30/// - Initialization of the Kernel structure itself.
31///
32/// # Examples
33///
34/// Using the builder with default values:
35/// ```
36/// use memflow::mem::PhysicalMemory;
37/// use memflow_win32::win32::Win32Kernel;
38///
39/// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
40/// let _kernel = Win32Kernel::builder(connector)
41/// .build()
42/// .unwrap();
43/// }
44/// ```
45///
46/// Using the builder with default cache configurations:
47/// ```
48/// use memflow::mem::PhysicalMemory;
49/// use memflow_win32::win32::Win32Kernel;
50///
51/// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
52/// let _kernel = Win32Kernel::builder(connector)
53/// .build_default_caches()
54/// .build()
55/// .unwrap();
56/// }
57/// ```
58///
59/// Customizing the caches:
60/// ```
61/// use memflow::mem::{PhysicalMemory, CachedPhysicalMemory, CachedVirtualTranslate};
62/// use memflow_win32::win32::Win32Kernel;
63///
64/// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
65/// let _kernel = Win32Kernel::builder(connector)
66/// .build_page_cache(|connector, arch| {
67/// CachedPhysicalMemory::builder(connector)
68/// .arch(arch)
69/// .build()
70/// .unwrap()
71/// })
72/// .build_vat_cache(|vat, arch| {
73/// CachedVirtualTranslate::builder(vat)
74/// .arch(arch)
75/// .build()
76/// .unwrap()
77/// })
78/// .build()
79/// .unwrap();
80/// }
81/// ```
82///
83/// # Remarks
84///
85/// Manual initialization of the above examples would look like the following:
86/// ```
87/// use memflow::prelude::v1::*;
88/// use memflow_win32::prelude::{
89/// Win32KernelInfo,
90/// Win32Offsets,
91/// Win32Kernel,
92/// offset_builder_with_kernel_info
93/// };
94///
95/// fn test<T: 'static + PhysicalMemory + Clone>(mut connector: T) {
96/// // Use the ntoskrnl scanner to find the relevant KernelInfo (start_block, arch, dtb, ntoskrnl, etc)
97/// let kernel_info = Win32KernelInfo::scanner(connector.forward_mut()).scan().unwrap();
98/// // Download the corresponding pdb from the default symbol store
99/// let offsets = offset_builder_with_kernel_info(&kernel_info).build().unwrap();
100///
101/// // Create a struct for doing virtual to physical memory translations
102/// let vat = DirectTranslate::new();
103///
104/// // Create a Page Cache layer with default values
105/// let mut connector_cached = CachedPhysicalMemory::builder(connector)
106/// .arch(kernel_info.os_info.arch)
107/// .build()
108/// .unwrap();
109///
110/// // Create a Tlb Cache layer with default values
111/// let vat_cached = CachedVirtualTranslate::builder(vat)
112/// .arch(kernel_info.os_info.arch)
113/// .build()
114/// .unwrap();
115///
116/// // Initialize the final Kernel object
117/// let _kernel = Win32Kernel::new(connector_cached, vat_cached, offsets, kernel_info);
118/// }
119/// ```
120pub struct Win32KernelBuilder<T, TK, VK> {
121 connector: T,
122
123 arch: Option<ArchitectureIdent>,
124 kernel_hint: Option<Address>,
125 dtb: Option<Address>,
126
127 #[cfg(feature = "symstore")]
128 symbol_store: Option<SymbolStore>,
129
130 build_page_cache: Box<dyn FnOnce(T, ArchitectureIdent) -> TK>,
131 build_vat_cache: Box<dyn FnOnce(DirectTranslate, ArchitectureIdent) -> VK>,
132}
133
134impl<T> Win32KernelBuilder<T, T, DirectTranslate>
135where
136 T: PhysicalMemory,
137{
138 pub fn new(connector: T) -> Win32KernelBuilder<T, T, DirectTranslate> {
139 Win32KernelBuilder {
140 connector,
141
142 arch: None,
143 kernel_hint: None,
144 dtb: None,
145
146 #[cfg(feature = "symstore")]
147 symbol_store: Some(SymbolStore::default()),
148
149 build_page_cache: Box::new(|connector, _| connector),
150 build_vat_cache: Box::new(|vat, _| vat),
151 }
152 }
153}
154
155impl<'a, T, TK, VK> Win32KernelBuilder<T, TK, VK>
156where
157 T: PhysicalMemory,
158 TK: 'static + PhysicalMemory + Clone,
159 VK: 'static + VirtualTranslate2 + Clone,
160{
161 pub fn build(mut self) -> Result<Win32Kernel<TK, VK>> {
162 // find kernel_info
163 let mut kernel_scanner = Win32KernelInfo::scanner(self.connector.forward_mut());
164 if let Some(arch) = self.arch {
165 kernel_scanner = kernel_scanner.arch(arch);
166 }
167 if let Some(kernel_hint) = self.kernel_hint {
168 kernel_scanner = kernel_scanner.kernel_hint(kernel_hint);
169 }
170 if let Some(dtb) = self.dtb {
171 kernel_scanner = kernel_scanner.dtb(dtb);
172 }
173 let kernel_info = kernel_scanner.scan()?;
174
175 // acquire offsets from the symbol store
176 let offsets = self.build_offsets(&kernel_info)?;
177
178 // TODO: parse memory maps
179
180 // create a vat object
181 let vat = DirectTranslate::new();
182
183 // create caches
184 let kernel_connector = (self.build_page_cache)(self.connector, kernel_info.os_info.arch);
185 let kernel_vat = (self.build_vat_cache)(vat, kernel_info.os_info.arch);
186
187 // create the final kernel object
188 Ok(Win32Kernel::new(
189 kernel_connector,
190 kernel_vat,
191 offsets,
192 kernel_info,
193 ))
194 }
195
196 #[cfg(feature = "symstore")]
197 fn build_offsets(&self, kernel_info: &Win32KernelInfo) -> Result<Win32Offsets> {
198 let mut builder = offset_builder_with_kernel_info(kernel_info);
199 if let Some(store) = &self.symbol_store {
200 builder = builder.symbol_store(store.clone());
201 } else {
202 builder = builder.no_symbol_store();
203 }
204 builder.build()
205 }
206
207 #[cfg(not(feature = "symstore"))]
208 fn build_offsets(&self, kernel_info: &Win32KernelInfo) -> Result<Win32Offsets> {
209 offset_builder_with_kernel_info(&kernel_info).build()
210 }
211
212 pub fn arch(mut self, arch: ArchitectureIdent) -> Self {
213 self.arch = Some(arch);
214 self
215 }
216
217 pub fn kernel_hint(mut self, kernel_hint: Address) -> Self {
218 self.kernel_hint = Some(kernel_hint);
219 self
220 }
221
222 pub fn dtb(mut self, dtb: Address) -> Self {
223 self.dtb = Some(dtb);
224 self
225 }
226
227 /// Configures the symbol store to be used when constructing the Kernel.
228 /// This will override the default symbol store that is being used if no other setting is configured.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use memflow::mem::PhysicalMemory;
234 /// use memflow_win32::prelude::{Win32Kernel, SymbolStore};
235 ///
236 /// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
237 /// let _kernel = Win32Kernel::builder(connector)
238 /// .symbol_store(SymbolStore::new().no_cache())
239 /// .build()
240 /// .unwrap();
241 /// }
242 /// ```
243 #[cfg(feature = "symstore")]
244 pub fn symbol_store(mut self, symbol_store: SymbolStore) -> Self {
245 self.symbol_store = Some(symbol_store);
246 self
247 }
248
249 /// Disables the symbol store when constructing the Kernel.
250 /// By default a default symbol store will be used when constructing a kernel.
251 /// This option allows the user to disable the symbol store alltogether
252 /// and fall back to the built-in offsets table.
253 ///
254 /// # Examples
255 ///
256 /// ```
257 /// use memflow::mem::PhysicalMemory;
258 /// use memflow_win32::win32::Win32Kernel;
259 /// use memflow_win32::offsets::SymbolStore;
260 ///
261 /// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
262 /// let _kernel = Win32Kernel::builder(connector)
263 /// .no_symbol_store()
264 /// .build()
265 /// .unwrap();
266 /// }
267 /// ```
268 #[cfg(feature = "symstore")]
269 pub fn no_symbol_store(mut self) -> Self {
270 self.symbol_store = None;
271 self
272 }
273
274 /// Creates the Kernel structure with default caching enabled.
275 ///
276 /// If this option is specified, the Kernel structure is generated
277 /// with a (page level cache)[../index.html] with default settings.
278 /// On top of the page level cache a [vat cache](../index.html) will be setupped.
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use memflow::mem::PhysicalMemory;
284 /// use memflow_win32::win32::Win32Kernel;
285 ///
286 /// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
287 /// let _kernel = Win32Kernel::builder(connector)
288 /// .build_default_caches()
289 /// .build()
290 /// .unwrap();
291 /// }
292 /// ```
293 pub fn build_default_caches(
294 self,
295 ) -> Win32KernelBuilder<
296 T,
297 CachedPhysicalMemory<'a, T, DefaultCacheValidator>,
298 CachedVirtualTranslate<DirectTranslate, DefaultCacheValidator>,
299 > {
300 Win32KernelBuilder {
301 connector: self.connector,
302
303 arch: self.arch,
304 kernel_hint: self.kernel_hint,
305 dtb: self.dtb,
306
307 #[cfg(feature = "symstore")]
308 symbol_store: self.symbol_store,
309
310 build_page_cache: Box::new(|connector, arch| {
311 CachedPhysicalMemory::builder(connector)
312 .arch(arch)
313 .build()
314 .unwrap()
315 }),
316 build_vat_cache: Box::new(|vat, arch| {
317 CachedVirtualTranslate::builder(vat)
318 .arch(arch)
319 .build()
320 .unwrap()
321 }),
322 }
323 }
324
325 /// Creates a Kernel structure by constructing the page cache from the given closure.
326 ///
327 /// This function accepts a `FnOnce` closure that is being evaluated
328 /// after the ntoskrnl has been found.
329 ///
330 /// # Examples
331 ///
332 /// ```
333 /// use memflow::mem::{PhysicalMemory, CachedPhysicalMemory};
334 /// use memflow_win32::win32::Win32Kernel;
335 ///
336 /// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
337 /// let _kernel = Win32Kernel::builder(connector)
338 /// .build_page_cache(|connector, arch| {
339 /// CachedPhysicalMemory::builder(connector)
340 /// .arch(arch)
341 /// .build()
342 /// .unwrap()
343 /// })
344 /// .build()
345 /// .unwrap();
346 /// }
347 /// ```
348 pub fn build_page_cache<TKN, F: FnOnce(T, ArchitectureIdent) -> TKN + 'static>(
349 self,
350 func: F,
351 ) -> Win32KernelBuilder<T, TKN, VK>
352 where
353 TKN: PhysicalMemory,
354 {
355 Win32KernelBuilder {
356 connector: self.connector,
357
358 arch: self.arch,
359 kernel_hint: self.kernel_hint,
360 dtb: self.dtb,
361
362 #[cfg(feature = "symstore")]
363 symbol_store: self.symbol_store,
364
365 build_page_cache: Box::new(func),
366 build_vat_cache: self.build_vat_cache,
367 }
368 }
369
370 /// Creates a Kernel structure by constructing the vat cache from the given closure.
371 ///
372 /// This function accepts a `FnOnce` closure that is being evaluated
373 /// after the ntoskrnl has been found.
374 ///
375 /// # Examples
376 ///
377 /// ```
378 /// use memflow::mem::{PhysicalMemory, CachedVirtualTranslate};
379 /// use memflow_win32::win32::Win32Kernel;
380 ///
381 /// fn test<T: 'static + PhysicalMemory + Clone>(connector: T) {
382 /// let _kernel = Win32Kernel::builder(connector)
383 /// .build_vat_cache(|vat, arch| {
384 /// CachedVirtualTranslate::builder(vat)
385 /// .arch(arch)
386 /// .build()
387 /// .unwrap()
388 /// })
389 /// .build()
390 /// .unwrap();
391 /// }
392 /// ```
393 pub fn build_vat_cache<VKN, F: FnOnce(DirectTranslate, ArchitectureIdent) -> VKN + 'static>(
394 self,
395 func: F,
396 ) -> Win32KernelBuilder<T, TK, VKN>
397 where
398 VKN: VirtualTranslate2,
399 {
400 Win32KernelBuilder {
401 connector: self.connector,
402
403 arch: self.arch,
404 kernel_hint: self.kernel_hint,
405 dtb: self.dtb,
406
407 #[cfg(feature = "symstore")]
408 symbol_store: self.symbol_store,
409
410 build_page_cache: self.build_page_cache,
411 build_vat_cache: Box::new(func),
412 }
413 }
414
415 // TODO: more builder configurations
416 // kernel_info_builder()
417 // offset_builder()
418}