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, WindowsUserModuleBase, 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    /// Offset of the `DllBase` field.
55    const OFFSET_DLL_BASE: u64;
56
57    /// Offset of the `EntryPoint` field.
58    const OFFSET_ENTRY_POINT: u64;
59
60    /// Offset of the `SizeOfImage` field.
61    const OFFSET_SIZE_OF_IMAGE: u64;
62
63    /// Offset of the `FullDllName` field.
64    const OFFSET_FULL_DLL_NAME: u64;
65
66    /// Offset of the `BaseDllName` field.
67    const OFFSET_BASE_DLL_NAME: u64;
68
69    /// Offset of the `TimeDateStamp` field.
70    const OFFSET_TIME_DATE_STAMP: u64;
71}
72
73/// `_LDR_DATA_TABLE_ENTRY` structure layout.
74pub struct LdrDataTableEntryLayout;
75
76impl LdrDataTableEntry<StructLayout32> for LdrDataTableEntryLayout {
77    const OFFSET_IN_LOAD_ORDER_LINKS: u64 = 0x00;
78    const OFFSET_IN_MEMORY_ORDER_LINKS: u64 = 0x08;
79    const OFFSET_IN_INITIALIZATION_ORDER_LINKS: u64 = 0x10;
80    const OFFSET_DLL_BASE: u64 = 0x18;
81    const OFFSET_ENTRY_POINT: u64 = 0x1c;
82    const OFFSET_SIZE_OF_IMAGE: u64 = 0x20;
83    const OFFSET_FULL_DLL_NAME: u64 = 0x24;
84    const OFFSET_BASE_DLL_NAME: u64 = 0x2c;
85    const OFFSET_TIME_DATE_STAMP: u64 = 0x44;
86}
87
88impl LdrDataTableEntry<StructLayout64> for LdrDataTableEntryLayout {
89    const OFFSET_IN_LOAD_ORDER_LINKS: u64 = 0x00;
90    const OFFSET_IN_MEMORY_ORDER_LINKS: u64 = 0x10;
91    const OFFSET_IN_INITIALIZATION_ORDER_LINKS: u64 = 0x20;
92    const OFFSET_DLL_BASE: u64 = 0x30;
93    const OFFSET_ENTRY_POINT: u64 = 0x38;
94    const OFFSET_SIZE_OF_IMAGE: u64 = 0x40;
95    const OFFSET_FULL_DLL_NAME: u64 = 0x48;
96    const OFFSET_BASE_DLL_NAME: u64 = 0x58;
97    const OFFSET_TIME_DATE_STAMP: u64 = 0x80;
98}
99
100/// PEB loader data accessor with a compile-time pointer width.
101///
102/// # Implementation Details
103///
104/// Corresponds to `_PEB_LDR_DATA`.
105pub struct WindowsPebLdrDataBase<'a, Driver, Layout>
106where
107    Driver: VmiRead,
108    Driver::Architecture: ArchAdapter<Driver>,
109    Layout: StructLayout,
110    PebLdrDataLayout: PebLdrData<Layout>,
111{
112    /// The VMI state.
113    vmi: VmiState<'a, WindowsOs<Driver>>,
114
115    /// Address of the `_PEB_LDR_DATA` structure.
116    va: Va,
117
118    /// The translation root.
119    root: Pa,
120
121    _marker: std::marker::PhantomData<Layout>,
122}
123
124impl<'a, Driver, Layout> WindowsPebLdrDataBase<'a, Driver, Layout>
125where
126    Driver: VmiRead,
127    Driver::Architecture: ArchAdapter<Driver>,
128    Layout: StructLayout,
129    ListEntryLayout: ListEntry<Layout>,
130    PebLdrDataLayout: PebLdrData<Layout>,
131    LdrDataTableEntryLayout: LdrDataTableEntry<Layout>,
132{
133    /// Creates a new PEB loader data accessor.
134    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
135        Self {
136            vmi,
137            va,
138            root,
139            _marker: std::marker::PhantomData,
140        }
141    }
142
143    /// Returns an iterator over modules in load order.
144    ///
145    /// # Implementation Details
146    ///
147    /// Corresponds to `_PEB_LDR_DATA.InLoadOrderModuleList`.
148    pub fn in_load_order_modules(
149        &self,
150    ) -> Result<
151        impl Iterator<Item = Result<WindowsUserModuleBase<'a, Driver, Layout>, VmiError>>
152        + use<'a, Driver, Layout>,
153        VmiError,
154    > {
155        let vmi = self.vmi;
156        let root = self.root;
157        Ok(self
158            .in_load_order_modules_inner()
159            .map(move |result| result.map(|va| WindowsUserModuleBase::new(vmi, va, root))))
160    }
161
162    /// Returns an iterator over modules in memory order.
163    ///
164    /// # Implementation Details
165    ///
166    /// Corresponds to `_PEB_LDR_DATA.InMemoryOrderModuleList`.
167    pub fn in_memory_order_modules(
168        &self,
169    ) -> Result<
170        impl Iterator<Item = Result<WindowsUserModuleBase<'a, Driver, Layout>, VmiError>>
171        + use<'a, Driver, Layout>,
172        VmiError,
173    > {
174        let vmi = self.vmi;
175        let root = self.root;
176        Ok(self
177            .in_memory_order_modules_inner()
178            .map(move |result| result.map(|va| WindowsUserModuleBase::new(vmi, va, root))))
179    }
180
181    /// Returns an iterator over modules in initialization order.
182    ///
183    /// # Implementation Details
184    ///
185    /// Corresponds to `_PEB_LDR_DATA.InInitializationOrderModuleList`.
186    pub fn in_initialization_order_modules(
187        &self,
188    ) -> Result<
189        impl Iterator<Item = Result<WindowsUserModuleBase<'a, Driver, Layout>, VmiError>>
190        + use<'a, Driver, Layout>,
191        VmiError,
192    > {
193        let vmi = self.vmi;
194        let root = self.root;
195        Ok(self
196            .in_initialization_order_modules_inner()
197            .map(move |result| result.map(|va| WindowsUserModuleBase::new(vmi, va, root))))
198    }
199
200    fn in_load_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
201        self.make_iterator(
202            self.va + PebLdrDataLayout::OFFSET_IN_LOAD_ORDER_MODULE_LIST,
203            LdrDataTableEntryLayout::OFFSET_IN_LOAD_ORDER_LINKS,
204        )
205    }
206
207    fn in_memory_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
208        self.make_iterator(
209            self.va + PebLdrDataLayout::OFFSET_IN_MEMORY_ORDER_MODULE_LIST,
210            LdrDataTableEntryLayout::OFFSET_IN_MEMORY_ORDER_LINKS,
211        )
212    }
213
214    fn in_initialization_order_modules_inner(&self) -> ListEntryIteratorBase<'a, Driver, Layout> {
215        self.make_iterator(
216            self.va + PebLdrDataLayout::OFFSET_IN_INITIALIZATION_ORDER_MODULE_LIST,
217            LdrDataTableEntryLayout::OFFSET_IN_INITIALIZATION_ORDER_LINKS,
218        )
219    }
220
221    fn make_iterator(
222        &self,
223        list_head: Va,
224        link_offset: u64,
225    ) -> ListEntryIteratorBase<'a, Driver, Layout> {
226        ListEntryIteratorBase::new(self.vmi, list_head, link_offset, self.root)
227    }
228}
229
230enum WindowsPebLdrDataWrapper<'a, Driver>
231where
232    Driver: VmiRead,
233    Driver::Architecture: ArchAdapter<Driver>,
234{
235    W32(WindowsPebLdrDataBase<'a, Driver, StructLayout32>),
236    W64(WindowsPebLdrDataBase<'a, Driver, StructLayout64>),
237}
238
239impl<'a, Driver> WindowsPebLdrDataWrapper<'a, Driver>
240where
241    Driver: VmiRead,
242    Driver::Architecture: ArchAdapter<Driver>,
243{
244    fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
245        Self::W32(WindowsPebLdrDataBase::new(vmi, va, root))
246    }
247
248    fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
249        Self::W64(WindowsPebLdrDataBase::new(vmi, va, root))
250    }
251
252    fn native(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
253        match vmi.registers().address_width() {
254            4 => Self::w32(vmi, va, root),
255            8 => Self::w64(vmi, va, root),
256            _ => panic!("Unsupported address width"),
257        }
258    }
259
260    fn in_load_order_modules(
261        &self,
262    ) -> Result<
263        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
264        VmiError,
265    > {
266        let (iter, vmi, root, kind) = match self {
267            Self::W32(inner) => (
268                ListEntryIterator::from(inner.in_load_order_modules_inner()),
269                inner.vmi,
270                inner.root,
271                WindowsWow64Kind::X86,
272            ),
273            Self::W64(inner) => (
274                ListEntryIterator::from(inner.in_load_order_modules_inner()),
275                inner.vmi,
276                inner.root,
277                WindowsWow64Kind::Native,
278            ),
279        };
280
281        Ok(iter
282            .map(move |result| result.map(|va| WindowsUserModule::with_kind(vmi, va, root, kind))))
283    }
284
285    fn in_memory_order_modules(
286        &self,
287    ) -> Result<
288        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
289        VmiError,
290    > {
291        let (iter, vmi, root, kind) = match self {
292            Self::W32(inner) => (
293                ListEntryIterator::from(inner.in_memory_order_modules_inner()),
294                inner.vmi,
295                inner.root,
296                WindowsWow64Kind::X86,
297            ),
298            Self::W64(inner) => (
299                ListEntryIterator::from(inner.in_memory_order_modules_inner()),
300                inner.vmi,
301                inner.root,
302                WindowsWow64Kind::Native,
303            ),
304        };
305
306        Ok(iter
307            .map(move |result| result.map(|va| WindowsUserModule::with_kind(vmi, va, root, kind))))
308    }
309
310    fn in_initialization_order_modules(
311        &self,
312    ) -> Result<
313        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
314        VmiError,
315    > {
316        let (iter, vmi, root, kind) = match self {
317            Self::W32(inner) => (
318                ListEntryIterator::from(inner.in_initialization_order_modules_inner()),
319                inner.vmi,
320                inner.root,
321                WindowsWow64Kind::X86,
322            ),
323            Self::W64(inner) => (
324                ListEntryIterator::from(inner.in_initialization_order_modules_inner()),
325                inner.vmi,
326                inner.root,
327                WindowsWow64Kind::Native,
328            ),
329        };
330
331        Ok(iter
332            .map(move |result| result.map(|va| WindowsUserModule::with_kind(vmi, va, root, kind))))
333    }
334}
335
336/// PEB loader data accessor with a runtime pointer width.
337///
338/// # Implementation Details
339///
340/// Corresponds to `_PEB_LDR_DATA`.
341pub struct WindowsPebLdrData<'a, Driver>
342where
343    Driver: VmiRead,
344    Driver::Architecture: ArchAdapter<Driver>,
345{
346    inner: WindowsPebLdrDataWrapper<'a, Driver>,
347}
348
349impl<'a, Driver> From<WindowsPebLdrDataBase<'a, Driver, StructLayout32>>
350    for WindowsPebLdrData<'a, Driver>
351where
352    Driver: VmiRead,
353    Driver::Architecture: ArchAdapter<Driver>,
354{
355    fn from(value: WindowsPebLdrDataBase<'a, Driver, StructLayout32>) -> Self {
356        Self {
357            inner: WindowsPebLdrDataWrapper::W32(value),
358        }
359    }
360}
361
362impl<'a, Driver> From<WindowsPebLdrDataBase<'a, Driver, StructLayout64>>
363    for WindowsPebLdrData<'a, Driver>
364where
365    Driver: VmiRead,
366    Driver::Architecture: ArchAdapter<Driver>,
367{
368    fn from(value: WindowsPebLdrDataBase<'a, Driver, StructLayout64>) -> Self {
369        Self {
370            inner: WindowsPebLdrDataWrapper::W64(value),
371        }
372    }
373}
374
375impl<Driver> VmiVa for WindowsPebLdrData<'_, Driver>
376where
377    Driver: VmiRead,
378    Driver::Architecture: ArchAdapter<Driver>,
379{
380    fn va(&self) -> Va {
381        match &self.inner {
382            WindowsPebLdrDataWrapper::W32(inner) => inner.va,
383            WindowsPebLdrDataWrapper::W64(inner) => inner.va,
384        }
385    }
386}
387
388impl<'a, Driver> WindowsPebLdrData<'a, Driver>
389where
390    Driver: VmiRead,
391    Driver::Architecture: ArchAdapter<Driver>,
392{
393    /// Creates a new PEB loader data accessor.
394    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
395        Self::with_kind(vmi, va, vmi.translation_root(va), WindowsWow64Kind::Native)
396    }
397
398    /// Creates a new PEB loader data accessor with an explicit address space
399    /// root and pointer width.
400    pub fn with_kind(
401        vmi: VmiState<'a, WindowsOs<Driver>>,
402        va: Va,
403        root: Pa,
404        kind: WindowsWow64Kind,
405    ) -> Self {
406        let inner = match kind {
407            WindowsWow64Kind::Native => WindowsPebLdrDataWrapper::native(vmi, va, root),
408            WindowsWow64Kind::X86 => WindowsPebLdrDataWrapper::w32(vmi, va, root),
409        };
410
411        Self { inner }
412    }
413
414    /// Returns an iterator over modules in load order.
415    ///
416    /// # Implementation Details
417    ///
418    /// Corresponds to `_PEB_LDR_DATA.InLoadOrderModuleList`.
419    pub fn in_load_order_modules(
420        &self,
421    ) -> Result<
422        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
423        VmiError,
424    > {
425        self.inner.in_load_order_modules()
426    }
427
428    /// Returns an iterator over modules in memory order.
429    ///
430    /// # Implementation Details
431    ///
432    /// Corresponds to `_PEB_LDR_DATA.InMemoryOrderModuleList`.
433    pub fn in_memory_order_modules(
434        &self,
435    ) -> Result<
436        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
437        VmiError,
438    > {
439        self.inner.in_memory_order_modules()
440    }
441
442    /// Returns an iterator over modules in initialization order.
443    ///
444    /// # Implementation Details
445    ///
446    /// Corresponds to `_PEB_LDR_DATA.InInitializationOrderModuleList`.
447    pub fn in_initialization_order_modules(
448        &self,
449    ) -> Result<
450        impl Iterator<Item = Result<WindowsUserModule<'a, Driver>, VmiError>> + use<'a, Driver>,
451        VmiError,
452    > {
453        self.inner.in_initialization_order_modules()
454    }
455}