Skip to main content

vmi_os_windows/comps/
peb.rs

1use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, VmiVa, driver::VmiRead};
2
3use super::{
4    LdrDataTableEntry, LdrDataTableEntryLayout, PebLdrData, PebLdrDataLayout, WindowsPebLdrData,
5    WindowsPebLdrDataBase, WindowsProcessParameters, WindowsProcessParametersBase,
6    WindowsWow64Kind,
7    process_parameters::{
8        CurDir, CurDirLayout, RtlUserProcessParameters, RtlUserProcessParametersLayout,
9    },
10};
11use crate::{
12    ListEntry, WindowsOs,
13    arch::{ArchAdapter, StructLayout, StructLayout32, StructLayout64},
14    iter::ListEntryLayout,
15};
16
17/// Field offsets for a `_PEB` structure.
18pub trait Peb<Layout>
19where
20    Layout: StructLayout,
21{
22    /// Offset of the `Ldr` field.
23    const OFFSET_LDR: u64;
24
25    /// Offset of the `ProcessParameters` field.
26    const OFFSET_PROCESS_PARAMETERS: u64;
27}
28
29/// `_PEB` structure layout.
30pub struct PebLayout;
31
32impl Peb<StructLayout32> for PebLayout {
33    const OFFSET_LDR: u64 = 0x0c;
34    const OFFSET_PROCESS_PARAMETERS: u64 = 0x10;
35}
36
37impl Peb<StructLayout64> for PebLayout {
38    const OFFSET_LDR: u64 = 0x18;
39    const OFFSET_PROCESS_PARAMETERS: u64 = 0x20;
40}
41
42/// PEB accessor with a compile-time pointer width.
43///
44/// # Implementation Details
45///
46/// Corresponds to `_PEB`.
47pub struct WindowsPebBase<'a, Driver, Layout>
48where
49    Driver: VmiRead,
50    Driver::Architecture: ArchAdapter<Driver>,
51    Layout: StructLayout,
52    PebLayout: Peb<Layout>,
53{
54    /// The VMI state.
55    vmi: VmiState<'a, WindowsOs<Driver>>,
56
57    /// The virtual address of the `_PEB` structure.
58    va: Va,
59
60    /// The translation root.
61    root: Pa,
62
63    _marker: std::marker::PhantomData<Layout>,
64}
65
66impl<'a, Driver, Layout> WindowsPebBase<'a, Driver, Layout>
67where
68    Driver: VmiRead,
69    Driver::Architecture: ArchAdapter<Driver>,
70    Layout: StructLayout,
71    PebLayout: Peb<Layout>,
72{
73    /// Creates a new PEB accessor.
74    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
75        Self {
76            vmi,
77            va,
78            root,
79            _marker: std::marker::PhantomData,
80        }
81    }
82
83    /// Returns the PEB loader data.
84    pub fn ldr(&self) -> Result<WindowsPebLdrDataBase<'a, Driver, Layout>, VmiError>
85    where
86        ListEntryLayout: ListEntry<Layout>,
87        PebLdrDataLayout: PebLdrData<Layout>,
88        LdrDataTableEntryLayout: LdrDataTableEntry<Layout>,
89    {
90        let va = Layout::read_va(self.vmi, (self.va + PebLayout::OFFSET_LDR, self.root))?;
91        Ok(WindowsPebLdrDataBase::new(self.vmi, va, self.root))
92    }
93
94    /// Returns the process parameters.
95    pub fn process_parameters(
96        &self,
97    ) -> Result<WindowsProcessParametersBase<'a, Driver, Layout>, VmiError>
98    where
99        RtlUserProcessParametersLayout: RtlUserProcessParameters<Layout>,
100        CurDirLayout: CurDir<Layout>,
101    {
102        let va = Layout::read_va(
103            self.vmi,
104            (self.va + PebLayout::OFFSET_PROCESS_PARAMETERS, self.root),
105        )?;
106        Ok(WindowsProcessParametersBase::new(self.vmi, va, self.root))
107    }
108}
109
110enum WindowsPebWrapper<'a, Driver>
111where
112    Driver: VmiRead,
113    Driver::Architecture: ArchAdapter<Driver>,
114{
115    W32(WindowsPebBase<'a, Driver, StructLayout32>),
116    W64(WindowsPebBase<'a, Driver, StructLayout64>),
117}
118
119impl<'a, Driver> WindowsPebWrapper<'a, Driver>
120where
121    Driver: VmiRead,
122    Driver::Architecture: ArchAdapter<Driver>,
123{
124    fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
125        Self::W32(WindowsPebBase::new(vmi, va, root))
126    }
127
128    fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
129        Self::W64(WindowsPebBase::new(vmi, va, root))
130    }
131
132    fn native(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
133        match vmi.registers().address_width() {
134            4 => Self::w32(vmi, va, root),
135            8 => Self::w64(vmi, va, root),
136            _ => panic!("Unsupported address width"),
137        }
138    }
139
140    fn ldr(&self) -> Result<WindowsPebLdrData<'a, Driver>, VmiError> {
141        match self {
142            Self::W32(inner) => Ok(WindowsPebLdrData::from(inner.ldr()?)),
143            Self::W64(inner) => Ok(WindowsPebLdrData::from(inner.ldr()?)),
144        }
145    }
146
147    fn process_parameters(&self) -> Result<WindowsProcessParameters<'a, Driver>, VmiError> {
148        match self {
149            Self::W32(inner) => Ok(WindowsProcessParameters::from(inner.process_parameters()?)),
150            Self::W64(inner) => Ok(WindowsProcessParameters::from(inner.process_parameters()?)),
151        }
152    }
153}
154
155/// PEB accessor with a runtime pointer width.
156///
157/// The PEB is a user-mode structure that stores process-wide information,
158/// such as loaded modules, heap data, and environment settings.
159///
160/// # Implementation Details
161///
162/// Corresponds to `_PEB`.
163pub struct WindowsPeb<'a, Driver>
164where
165    Driver: VmiRead,
166    Driver::Architecture: ArchAdapter<Driver>,
167{
168    inner: WindowsPebWrapper<'a, Driver>,
169}
170
171impl<Driver> VmiVa for WindowsPeb<'_, Driver>
172where
173    Driver: VmiRead,
174    Driver::Architecture: ArchAdapter<Driver>,
175{
176    fn va(&self) -> Va {
177        match &self.inner {
178            WindowsPebWrapper::W32(inner) => inner.va,
179            WindowsPebWrapper::W64(inner) => inner.va,
180        }
181    }
182}
183
184impl<'a, Driver> From<WindowsPebBase<'a, Driver, StructLayout32>> for WindowsPeb<'a, Driver>
185where
186    Driver: VmiRead,
187    Driver::Architecture: ArchAdapter<Driver>,
188{
189    fn from(value: WindowsPebBase<'a, Driver, StructLayout32>) -> Self {
190        Self {
191            inner: WindowsPebWrapper::W32(value),
192        }
193    }
194}
195
196impl<'a, Driver> From<WindowsPebBase<'a, Driver, StructLayout64>> for WindowsPeb<'a, Driver>
197where
198    Driver: VmiRead,
199    Driver::Architecture: ArchAdapter<Driver>,
200{
201    fn from(value: WindowsPebBase<'a, Driver, StructLayout64>) -> Self {
202        Self {
203            inner: WindowsPebWrapper::W64(value),
204        }
205    }
206}
207
208impl<Driver> std::fmt::Debug for WindowsPeb<'_, Driver>
209where
210    Driver: VmiRead,
211    Driver::Architecture: ArchAdapter<Driver>,
212{
213    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
214        let process_parameters = self.process_parameters();
215
216        f.debug_struct("WindowsPeb")
217            .field("process_parameters", &process_parameters)
218            .finish()
219    }
220}
221
222impl<'a, Driver> WindowsPeb<'a, Driver>
223where
224    Driver: VmiRead,
225    Driver::Architecture: ArchAdapter<Driver>,
226{
227    /// Creates a new PEB accessor.
228    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
229        Self::with_kind(vmi, va, vmi.translation_root(va), WindowsWow64Kind::Native)
230    }
231
232    /// Creates a new PEB accessor with an explicit address space root and
233    /// pointer width.
234    pub fn with_kind(
235        vmi: VmiState<'a, WindowsOs<Driver>>,
236        va: Va,
237        root: Pa,
238        kind: WindowsWow64Kind,
239    ) -> Self {
240        let inner = match kind {
241            WindowsWow64Kind::Native => WindowsPebWrapper::native(vmi, va, root),
242            WindowsWow64Kind::X86 => WindowsPebWrapper::w32(vmi, va, root),
243        };
244
245        Self { inner }
246    }
247
248    /// Returns the PEB loader data.
249    ///
250    /// The loader data contains the three module lists maintained
251    /// by the Windows loader.
252    ///
253    /// # Implementation Details
254    ///
255    /// Corresponds to `_PEB.Ldr`.
256    pub fn ldr(&self) -> Result<WindowsPebLdrData<'a, Driver>, VmiError> {
257        self.inner.ldr()
258    }
259
260    /// Returns the process parameters of the process.
261    ///
262    /// # Implementation Details
263    ///
264    /// Corresponds to `_PEB.ProcessParameters`.
265    pub fn process_parameters(&self) -> Result<WindowsProcessParameters<'a, Driver>, VmiError> {
266        self.inner.process_parameters()
267    }
268
269    /// Returns the current directory.
270    ///
271    /// Shortcut for [`self.process_parameters()?.current_directory()`].
272    ///
273    /// [`self.process_parameters()?.current_directory()`]: WindowsProcessParameters::current_directory
274    pub fn current_directory(&self) -> Result<String, VmiError> {
275        self.process_parameters()?.current_directory()
276    }
277
278    /// Returns the DLL search path.
279    ///
280    /// Shortcut for [`self.process_parameters()?.dll_path()`].
281    ///
282    /// [`self.process_parameters()?.dll_path()`]: WindowsProcessParameters::dll_path
283    pub fn dll_path(&self) -> Result<String, VmiError> {
284        self.process_parameters()?.dll_path()
285    }
286
287    /// Returns the full path of the executable image.
288    ///
289    /// Shortcut for [`self.process_parameters()?.image_path_name()`].
290    ///
291    /// [`self.process_parameters()?.image_path_name()`]: WindowsProcessParameters::image_path_name
292    pub fn image_path_name(&self) -> Result<String, VmiError> {
293        self.process_parameters()?.image_path_name()
294    }
295
296    /// Returns the command line used to launch the process.
297    ///
298    /// Shortcut for [`self.process_parameters()?.command_line()`].
299    ///
300    /// [`self.process_parameters()?.command_line()`]: WindowsProcessParameters::command_line
301    pub fn command_line(&self) -> Result<String, VmiError> {
302        self.process_parameters()?.command_line()
303    }
304}