Skip to main content

vmi_os_windows/comps/
peb_ldr_data.rs

1use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, VmiVa, driver::VmiRead};
2
3use super::{WindowsUserModule, WindowsWow64Kind};
4use crate::{
5    ArchAdapter, ListEntry, ListEntryIterator, ListEntryIteratorBase, WindowsOs,
6    arch::{StructLayout, StructLayout32, StructLayout64},
7    iter::ListEntryLayout,
8};
9
10/// Field offsets for a `_PEB_LDR_DATA` structure.
11pub trait PebLdrData<Layout>
12where
13    Layout: StructLayout,
14{
15    /// Offset of the `InLoadOrderModuleList` field.
16    const OFFSET_IN_LOAD_ORDER_MODULE_LIST: u64;
17
18    /// Offset of the `InMemoryOrderModuleList` field.
19    const OFFSET_IN_MEMORY_ORDER_MODULE_LIST: u64;
20
21    /// Offset of the `InInitializationOrderModuleList` field.
22    const OFFSET_IN_INITIALIZATION_ORDER_MODULE_LIST: u64;
23}
24
25/// `_PEB_LDR_DATA` structure layout.
26pub struct PebLdrDataLayout;
27
28impl PebLdrData<StructLayout32> for PebLdrDataLayout {
29    const OFFSET_IN_LOAD_ORDER_MODULE_LIST: u64 = 0x0c;
30    const OFFSET_IN_MEMORY_ORDER_MODULE_LIST: u64 = 0x14;
31    const OFFSET_IN_INITIALIZATION_ORDER_MODULE_LIST: u64 = 0x1c;
32}
33
34impl PebLdrData<StructLayout64> for PebLdrDataLayout {
35    const OFFSET_IN_LOAD_ORDER_MODULE_LIST: u64 = 0x10;
36    const OFFSET_IN_MEMORY_ORDER_MODULE_LIST: u64 = 0x20;
37    const OFFSET_IN_INITIALIZATION_ORDER_MODULE_LIST: u64 = 0x30;
38}
39
40/// Field offsets for a `_LDR_DATA_TABLE_ENTRY` structure.
41pub trait LdrDataTableEntry<Layout>
42where
43    Layout: StructLayout,
44{
45    /// Offset of the `InLoadOrderLinks` field.
46    const OFFSET_IN_LOAD_ORDER_LINKS: u64;
47
48    /// Offset of the `InMemoryOrderLinks` field.
49    const OFFSET_IN_MEMORY_ORDER_LINKS: u64;
50
51    /// Offset of the `InInitializationOrderLinks` field.
52    const OFFSET_IN_INITIALIZATION_ORDER_LINKS: u64;
53}
54
55/// `_LDR_DATA_TABLE_ENTRY` structure layout.
56pub struct LdrDataTableEntryLayout;
57
58impl LdrDataTableEntry<StructLayout32> for LdrDataTableEntryLayout {
59    const OFFSET_IN_LOAD_ORDER_LINKS: u64 = 0x00;
60    const OFFSET_IN_MEMORY_ORDER_LINKS: u64 = 0x08;
61    const OFFSET_IN_INITIALIZATION_ORDER_LINKS: u64 = 0x10;
62}
63
64impl LdrDataTableEntry<StructLayout64> for LdrDataTableEntryLayout {
65    const OFFSET_IN_LOAD_ORDER_LINKS: u64 = 0x00;
66    const OFFSET_IN_MEMORY_ORDER_LINKS: u64 = 0x10;
67    const OFFSET_IN_INITIALIZATION_ORDER_LINKS: u64 = 0x20;
68}
69
70/// PEB loader data accessor with a compile-time pointer width.
71///
72/// # Implementation Details
73///
74/// Corresponds to `_PEB_LDR_DATA`.
75pub struct WindowsPebLdrDataBase<'a, Driver, Layout>
76where
77    Driver: VmiRead,
78    Driver::Architecture: ArchAdapter<Driver>,
79    Layout: StructLayout,
80    PebLdrDataLayout: PebLdrData<Layout>,
81{
82    /// The VMI state.
83    vmi: VmiState<'a, WindowsOs<Driver>>,
84
85    /// The virtual address of the `_PEB_LDR_DATA` structure.
86    va: Va,
87
88    /// The translation root.
89    root: Pa,
90
91    _marker: std::marker::PhantomData<Layout>,
92}
93
94impl<'a, Driver, Layout> WindowsPebLdrDataBase<'a, Driver, Layout>
95where
96    Driver: VmiRead,
97    Driver::Architecture: ArchAdapter<Driver>,
98    Layout: StructLayout,
99    ListEntryLayout: ListEntry<Layout>,
100    PebLdrDataLayout: PebLdrData<Layout>,
101    LdrDataTableEntryLayout: LdrDataTableEntry<Layout>,
102{
103    /// Creates a new PEB loader data accessor.
104    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
105        Self {
106            vmi,
107            va,
108            root,
109            _marker: std::marker::PhantomData,
110        }
111    }
112
113    /// Returns an iterator over modules in load order.
114    ///
115    /// # Implementation Details
116    ///
117    /// Corresponds to `_PEB_LDR_DATA.InLoadOrderModuleList`.
118    pub fn in_load_order_modules(
119        &self,
120    ) -> Result<
121        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver, Layout>,
122        VmiError,
123    > {
124        let vmi = self.vmi;
125        let root = self.root;
126        Ok(self
127            .in_load_order_modules_inner()
128            .map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
129    }
130
131    /// Returns an iterator over modules in memory order.
132    ///
133    /// # Implementation Details
134    ///
135    /// Corresponds to `_PEB_LDR_DATA.InMemoryOrderModuleList`.
136    pub fn in_memory_order_modules(
137        &self,
138    ) -> Result<
139        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver, Layout>,
140        VmiError,
141    > {
142        let vmi = self.vmi;
143        let root = self.root;
144        Ok(self
145            .in_memory_order_modules_inner()
146            .map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
147    }
148
149    /// Returns an iterator over modules in initialization order.
150    ///
151    /// # Implementation Details
152    ///
153    /// Corresponds to `_PEB_LDR_DATA.InInitializationOrderModuleList`.
154    pub fn in_initialization_order_modules(
155        &self,
156    ) -> Result<
157        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver, Layout>,
158        VmiError,
159    > {
160        let vmi = self.vmi;
161        let root = self.root;
162        Ok(self
163            .in_initialization_order_modules_inner()
164            .map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
165    }
166
167    fn in_load_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
168        self.make_iterator(
169            self.va + PebLdrDataLayout::OFFSET_IN_LOAD_ORDER_MODULE_LIST,
170            LdrDataTableEntryLayout::OFFSET_IN_LOAD_ORDER_LINKS,
171        )
172    }
173
174    fn in_memory_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
175        self.make_iterator(
176            self.va + PebLdrDataLayout::OFFSET_IN_MEMORY_ORDER_MODULE_LIST,
177            LdrDataTableEntryLayout::OFFSET_IN_MEMORY_ORDER_LINKS,
178        )
179    }
180
181    fn in_initialization_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
182        self.make_iterator(
183            self.va + PebLdrDataLayout::OFFSET_IN_INITIALIZATION_ORDER_MODULE_LIST,
184            LdrDataTableEntryLayout::OFFSET_IN_INITIALIZATION_ORDER_LINKS,
185        )
186    }
187
188    fn make_iterator(
189        &self,
190        list_head: Va,
191        link_offset: u64,
192    ) -> ListEntryIteratorBase<'a, Driver, Layout> {
193        ListEntryIteratorBase::new(self.vmi, list_head, link_offset, self.root)
194    }
195}
196
197enum WindowsPebLdrDataWrapper<'a, Driver>
198where
199    Driver: VmiRead,
200    Driver::Architecture: ArchAdapter<Driver>,
201{
202    W32(WindowsPebLdrDataBase<'a, Driver, StructLayout32>),
203    W64(WindowsPebLdrDataBase<'a, Driver, StructLayout64>),
204}
205
206impl<'a, Driver> WindowsPebLdrDataWrapper<'a, Driver>
207where
208    Driver: VmiRead,
209    Driver::Architecture: ArchAdapter<Driver>,
210{
211    fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
212        Self::W32(WindowsPebLdrDataBase::new(vmi, va, root))
213    }
214
215    fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
216        Self::W64(WindowsPebLdrDataBase::new(vmi, va, root))
217    }
218
219    fn native(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
220        match vmi.registers().address_width() {
221            4 => Self::w32(vmi, va, root),
222            8 => Self::w64(vmi, va, root),
223            _ => panic!("Unsupported address width"),
224        }
225    }
226
227    fn in_load_order_modules(
228        &self,
229    ) -> Result<
230        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
231        VmiError,
232    > {
233        let (iter, vmi, root) = match self {
234            Self::W32(inner) => (
235                ListEntryIterator::from(inner.in_load_order_modules_inner()),
236                inner.vmi,
237                inner.root,
238            ),
239            Self::W64(inner) => (
240                ListEntryIterator::from(inner.in_load_order_modules_inner()),
241                inner.vmi,
242                inner.root,
243            ),
244        };
245
246        Ok(iter.map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
247    }
248
249    fn in_memory_order_modules(
250        &self,
251    ) -> Result<
252        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
253        VmiError,
254    > {
255        let (iter, vmi, root) = match self {
256            Self::W32(inner) => (
257                ListEntryIterator::from(inner.in_memory_order_modules_inner()),
258                inner.vmi,
259                inner.root,
260            ),
261            Self::W64(inner) => (
262                ListEntryIterator::from(inner.in_memory_order_modules_inner()),
263                inner.vmi,
264                inner.root,
265            ),
266        };
267
268        Ok(iter.map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
269    }
270
271    fn in_initialization_order_modules(
272        &self,
273    ) -> Result<
274        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
275        VmiError,
276    > {
277        let (iter, vmi, root) = match self {
278            Self::W32(inner) => (
279                ListEntryIterator::from(inner.in_initialization_order_modules_inner()),
280                inner.vmi,
281                inner.root,
282            ),
283            Self::W64(inner) => (
284                ListEntryIterator::from(inner.in_initialization_order_modules_inner()),
285                inner.vmi,
286                inner.root,
287            ),
288        };
289
290        Ok(iter.map(move |result| result.map(|va| WindowsUserModule::new(vmi, va, root))))
291    }
292}
293
294/// PEB loader data accessor with a runtime pointer width.
295///
296/// # Implementation Details
297///
298/// Corresponds to `_PEB_LDR_DATA`.
299pub struct WindowsPebLdrData<'a, Driver>
300where
301    Driver: VmiRead,
302    Driver::Architecture: ArchAdapter<Driver>,
303{
304    inner: WindowsPebLdrDataWrapper<'a, Driver>,
305}
306
307impl<'a, Driver> From<WindowsPebLdrDataBase<'a, Driver, StructLayout32>>
308    for WindowsPebLdrData<'a, Driver>
309where
310    Driver: VmiRead,
311    Driver::Architecture: ArchAdapter<Driver>,
312{
313    fn from(value: WindowsPebLdrDataBase<'a, Driver, StructLayout32>) -> Self {
314        Self {
315            inner: WindowsPebLdrDataWrapper::W32(value),
316        }
317    }
318}
319
320impl<'a, Driver> From<WindowsPebLdrDataBase<'a, Driver, StructLayout64>>
321    for WindowsPebLdrData<'a, Driver>
322where
323    Driver: VmiRead,
324    Driver::Architecture: ArchAdapter<Driver>,
325{
326    fn from(value: WindowsPebLdrDataBase<'a, Driver, StructLayout64>) -> Self {
327        Self {
328            inner: WindowsPebLdrDataWrapper::W64(value),
329        }
330    }
331}
332
333impl<Driver> VmiVa for WindowsPebLdrData<'_, Driver>
334where
335    Driver: VmiRead,
336    Driver::Architecture: ArchAdapter<Driver>,
337{
338    fn va(&self) -> Va {
339        match &self.inner {
340            WindowsPebLdrDataWrapper::W32(inner) => inner.va,
341            WindowsPebLdrDataWrapper::W64(inner) => inner.va,
342        }
343    }
344}
345
346impl<'a, Driver> WindowsPebLdrData<'a, Driver>
347where
348    Driver: VmiRead,
349    Driver::Architecture: ArchAdapter<Driver>,
350{
351    /// Creates a new PEB loader data accessor.
352    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
353        Self::with_kind(vmi, va, vmi.translation_root(va), WindowsWow64Kind::Native)
354    }
355
356    /// Creates a new PEB loader data accessor with an explicit address space
357    /// root and pointer width.
358    pub fn with_kind(
359        vmi: VmiState<'a, WindowsOs<Driver>>,
360        va: Va,
361        root: Pa,
362        kind: WindowsWow64Kind,
363    ) -> Self {
364        let inner = match kind {
365            WindowsWow64Kind::Native => WindowsPebLdrDataWrapper::native(vmi, va, root),
366            WindowsWow64Kind::X86 => WindowsPebLdrDataWrapper::w32(vmi, va, root),
367        };
368
369        Self { inner }
370    }
371
372    /// Returns an iterator over modules in load order.
373    ///
374    /// # Implementation Details
375    ///
376    /// Corresponds to `_PEB_LDR_DATA.InLoadOrderModuleList`.
377    pub fn in_load_order_modules(
378        &self,
379    ) -> Result<
380        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
381        VmiError,
382    > {
383        self.inner.in_load_order_modules()
384    }
385
386    /// Returns an iterator over modules in memory order.
387    ///
388    /// # Implementation Details
389    ///
390    /// Corresponds to `_PEB_LDR_DATA.InMemoryOrderModuleList`.
391    pub fn in_memory_order_modules(
392        &self,
393    ) -> Result<
394        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
395        VmiError,
396    > {
397        self.inner.in_memory_order_modules()
398    }
399
400    /// Returns an iterator over modules in initialization order.
401    ///
402    /// # Implementation Details
403    ///
404    /// Corresponds to `_PEB_LDR_DATA.InInitializationOrderModuleList`.
405    pub fn in_initialization_order_modules(
406        &self,
407    ) -> Result<
408        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
409        VmiError,
410    > {
411        self.inner.in_initialization_order_modules()
412    }
413}