Skip to main content

vmi_os_windows/comps/
user_module.rs

1use vmi_core::{Pa, Va, VmiError, VmiState, VmiVa, driver::VmiRead, os::VmiOsUserModule};
2
3use super::macros::impl_offsets;
4use crate::{ArchAdapter, WindowsOs, WindowsOsExt as _};
5
6/// A Windows user-mode module.
7///
8/// Represents a module loaded into a process address space, as enumerated
9/// from the PEB loader data (`_LDR_DATA_TABLE_ENTRY`). Reads are performed
10/// through a user-mode translation root, so the module's PE image and
11/// metadata are accessible even on KPTI-enabled systems.
12///
13/// # Implementation Details
14///
15/// Corresponds to `_LDR_DATA_TABLE_ENTRY`.
16pub struct WindowsUserModule<'a, Driver>
17where
18    Driver: VmiRead,
19    Driver::Architecture: ArchAdapter<Driver>,
20{
21    /// The VMI state.
22    vmi: VmiState<'a, WindowsOs<Driver>>,
23
24    /// The virtual address of the `_LDR_DATA_TABLE_ENTRY` structure.
25    va: Va,
26
27    /// The user-mode translation root.
28    root: Pa,
29}
30
31impl<Driver> VmiVa for WindowsUserModule<'_, Driver>
32where
33    Driver: VmiRead,
34    Driver::Architecture: ArchAdapter<Driver>,
35{
36    fn va(&self) -> Va {
37        self.va
38    }
39}
40
41impl<'a, Driver> WindowsUserModule<'a, Driver>
42where
43    Driver: VmiRead,
44    Driver::Architecture: ArchAdapter<Driver>,
45{
46    impl_offsets!();
47
48    /// Creates a new Windows user-mode module.
49    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
50        Self { vmi, va, root }
51    }
52
53    /// Returns the entry point of the module.
54    ///
55    /// # Implementation Details
56    ///
57    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.EntryPoint`.
58    pub fn entry_point(&self) -> Result<Va, VmiError> {
59        let offsets = self.offsets();
60        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
61
62        self.vmi.read_va_native_in((
63            self.va + LDR_DATA_TABLE_ENTRY.EntryPoint.offset(),
64            self.root,
65        ))
66    }
67
68    /// Returns the full name of the module.
69    ///
70    /// # Implementation Details
71    ///
72    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.FullDllName`.
73    pub fn full_name(&self) -> Result<String, VmiError> {
74        let offsets = self.offsets();
75        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
76
77        self.vmi.os().read_unicode_string_in((
78            self.va + LDR_DATA_TABLE_ENTRY.FullDllName.offset(),
79            self.root,
80        ))
81    }
82
83    /// Returns the timestamp of the module.
84    ///
85    /// # Implementation Details
86    ///
87    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.TimeDateStamp`.
88    pub fn time_date_stamp(&self) -> Result<u32, VmiError> {
89        let offsets = self.offsets();
90        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
91
92        self.vmi.read_u32_in((
93            self.va + LDR_DATA_TABLE_ENTRY.TimeDateStamp.offset(),
94            self.root,
95        ))
96    }
97}
98
99impl<'a, Driver> VmiOsUserModule<'a, Driver> for WindowsUserModule<'a, Driver>
100where
101    Driver: VmiRead,
102    Driver::Architecture: ArchAdapter<Driver>,
103{
104    type Os = WindowsOs<Driver>;
105
106    /// Returns the base address of the module.
107    ///
108    /// # Implementation Details
109    ///
110    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.DllBase`.
111    fn base_address(&self) -> Result<Va, VmiError> {
112        let offsets = self.offsets();
113        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
114
115        self.vmi
116            .read_va_native_in((self.va + LDR_DATA_TABLE_ENTRY.DllBase.offset(), self.root))
117    }
118
119    /// Returns the size of the module.
120    ///
121    /// # Implementation Details
122    ///
123    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.SizeOfImage`.
124    fn size(&self) -> Result<u64, VmiError> {
125        let offsets = self.offsets();
126        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
127
128        Ok(self.vmi.read_u32_in((
129            self.va + LDR_DATA_TABLE_ENTRY.SizeOfImage.offset(),
130            self.root,
131        ))? as u64)
132    }
133
134    /// Returns the name of the module.
135    ///
136    /// # Implementation Details
137    ///
138    /// Corresponds to `_LDR_DATA_TABLE_ENTRY.BaseDllName`.
139    fn name(&self) -> Result<String, VmiError> {
140        let offsets = self.offsets();
141        let LDR_DATA_TABLE_ENTRY = &offsets._LDR_DATA_TABLE_ENTRY;
142
143        self.vmi.os().read_unicode_string_in((
144            self.va + LDR_DATA_TABLE_ENTRY.BaseDllName.offset(),
145            self.root,
146        ))
147    }
148}