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}