Skip to main content

vmi_os_windows/comps/
process_parameters.rs

1use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, VmiVa, driver::VmiRead};
2
3use super::WindowsWow64Kind;
4use crate::{
5    WindowsOs,
6    arch::{ArchAdapter, StructLayout, StructLayout32, StructLayout64},
7};
8
9/// Field offsets for a `_RTL_USER_PROCESS_PARAMETERS` structure.
10pub trait RtlUserProcessParameters<Layout>
11where
12    Layout: StructLayout,
13{
14    /// Offset of the `CurrentDirectory` field.
15    const OFFSET_CURRENT_DIRECTORY: u64;
16
17    /// Offset of the `DllPath` field.
18    const OFFSET_DLL_PATH: u64;
19
20    /// Offset of the `ImagePathName` field.
21    const OFFSET_IMAGE_PATH_NAME: u64;
22
23    /// Offset of the `CommandLine` field.
24    const OFFSET_COMMAND_LINE: u64;
25}
26
27/// `_RTL_USER_PROCESS_PARAMETERS` structure layout.
28pub struct RtlUserProcessParametersLayout;
29
30impl RtlUserProcessParameters<StructLayout32> for RtlUserProcessParametersLayout {
31    const OFFSET_CURRENT_DIRECTORY: u64 = 0x24;
32    const OFFSET_DLL_PATH: u64 = 0x30;
33    const OFFSET_IMAGE_PATH_NAME: u64 = 0x38;
34    const OFFSET_COMMAND_LINE: u64 = 0x40;
35}
36
37impl RtlUserProcessParameters<StructLayout64> for RtlUserProcessParametersLayout {
38    const OFFSET_CURRENT_DIRECTORY: u64 = 0x38;
39    const OFFSET_DLL_PATH: u64 = 0x50;
40    const OFFSET_IMAGE_PATH_NAME: u64 = 0x60;
41    const OFFSET_COMMAND_LINE: u64 = 0x70;
42}
43
44/// Field offsets for a `_CURDIR` structure.
45pub trait CurDir<Layout>
46where
47    Layout: StructLayout,
48{
49    /// Offset of the `DosPath` field.
50    const OFFSET_DOS_PATH: u64;
51}
52
53/// `_CURDIR` structure layout.
54pub struct CurDirLayout;
55
56impl CurDir<StructLayout32> for CurDirLayout {
57    const OFFSET_DOS_PATH: u64 = 0x00;
58}
59
60impl CurDir<StructLayout64> for CurDirLayout {
61    const OFFSET_DOS_PATH: u64 = 0x00;
62}
63
64/// Process parameters accessor with a compile-time pointer width.
65///
66/// # Implementation Details
67///
68/// Corresponds to `_RTL_USER_PROCESS_PARAMETERS`.
69pub struct WindowsProcessParametersBase<'a, Driver, Layout>
70where
71    Driver: VmiRead,
72    Driver::Architecture: ArchAdapter<Driver>,
73    Layout: StructLayout,
74    RtlUserProcessParametersLayout: RtlUserProcessParameters<Layout>,
75{
76    /// The VMI state.
77    vmi: VmiState<'a, WindowsOs<Driver>>,
78
79    /// The virtual address of the `_RTL_USER_PROCESS_PARAMETERS` structure.
80    va: Va,
81
82    /// The translation root.
83    root: Pa,
84
85    _marker: std::marker::PhantomData<Layout>,
86}
87
88impl<'a, Driver, Layout> WindowsProcessParametersBase<'a, Driver, Layout>
89where
90    Driver: VmiRead,
91    Driver::Architecture: ArchAdapter<Driver>,
92    Layout: StructLayout,
93    RtlUserProcessParametersLayout: RtlUserProcessParameters<Layout>,
94    CurDirLayout: CurDir<Layout>,
95{
96    /// Creates a new process parameters accessor.
97    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
98        Self {
99            vmi,
100            va,
101            root,
102            _marker: std::marker::PhantomData,
103        }
104    }
105
106    /// Returns the current directory.
107    ///
108    /// # Implementation Details
109    ///
110    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.CurrentDirectory.DosPath`.
111    pub fn current_directory(&self) -> Result<String, VmiError> {
112        Layout::read_unicode_string(
113            self.vmi,
114            (
115                self.va
116                    + RtlUserProcessParametersLayout::OFFSET_CURRENT_DIRECTORY
117                    + CurDirLayout::OFFSET_DOS_PATH,
118                self.root,
119            ),
120        )
121    }
122
123    /// Returns the DLL search path.
124    ///
125    /// # Implementation Details
126    ///
127    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.DllPath`.
128    pub fn dll_path(&self) -> Result<String, VmiError> {
129        Layout::read_unicode_string(
130            self.vmi,
131            (
132                self.va + RtlUserProcessParametersLayout::OFFSET_DLL_PATH,
133                self.root,
134            ),
135        )
136    }
137
138    /// Returns the full path of the executable image.
139    ///
140    /// # Implementation Details
141    ///
142    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.ImagePathName`.
143    pub fn image_path_name(&self) -> Result<String, VmiError> {
144        Layout::read_unicode_string(
145            self.vmi,
146            (
147                self.va + RtlUserProcessParametersLayout::OFFSET_IMAGE_PATH_NAME,
148                self.root,
149            ),
150        )
151    }
152
153    /// Returns the command line used to launch the process.
154    ///
155    /// # Implementation Details
156    ///
157    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.CommandLine`.
158    pub fn command_line(&self) -> Result<String, VmiError> {
159        Layout::read_unicode_string(
160            self.vmi,
161            (
162                self.va + RtlUserProcessParametersLayout::OFFSET_COMMAND_LINE,
163                self.root,
164            ),
165        )
166    }
167}
168
169enum WindowsProcessParametersWrapper<'a, Driver>
170where
171    Driver: VmiRead,
172    Driver::Architecture: ArchAdapter<Driver>,
173{
174    W32(WindowsProcessParametersBase<'a, Driver, StructLayout32>),
175    W64(WindowsProcessParametersBase<'a, Driver, StructLayout64>),
176}
177
178impl<'a, Driver> WindowsProcessParametersWrapper<'a, Driver>
179where
180    Driver: VmiRead,
181    Driver::Architecture: ArchAdapter<Driver>,
182{
183    fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
184        Self::W32(WindowsProcessParametersBase::new(vmi, va, root))
185    }
186
187    fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
188        Self::W64(WindowsProcessParametersBase::new(vmi, va, root))
189    }
190
191    fn native(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
192        match vmi.registers().address_width() {
193            4 => Self::w32(vmi, va, root),
194            8 => Self::w64(vmi, va, root),
195            _ => panic!("Unsupported address width"),
196        }
197    }
198
199    fn current_directory(&self) -> Result<String, VmiError> {
200        match self {
201            Self::W32(inner) => inner.current_directory(),
202            Self::W64(inner) => inner.current_directory(),
203        }
204    }
205
206    fn dll_path(&self) -> Result<String, VmiError> {
207        match self {
208            Self::W32(inner) => inner.dll_path(),
209            Self::W64(inner) => inner.dll_path(),
210        }
211    }
212
213    fn image_path_name(&self) -> Result<String, VmiError> {
214        match self {
215            Self::W32(inner) => inner.image_path_name(),
216            Self::W64(inner) => inner.image_path_name(),
217        }
218    }
219
220    fn command_line(&self) -> Result<String, VmiError> {
221        match self {
222            Self::W32(inner) => inner.command_line(),
223            Self::W64(inner) => inner.command_line(),
224        }
225    }
226}
227
228/// Process parameters accessor with a runtime pointer width.
229///
230/// Contains command-line arguments, environment variables, and other
231/// startup information for a process.
232///
233/// # Implementation Details
234///
235/// Corresponds to `_RTL_USER_PROCESS_PARAMETERS`.
236pub struct WindowsProcessParameters<'a, Driver>
237where
238    Driver: VmiRead,
239    Driver::Architecture: ArchAdapter<Driver>,
240{
241    inner: WindowsProcessParametersWrapper<'a, Driver>,
242}
243
244impl<'a, Driver> From<WindowsProcessParametersBase<'a, Driver, StructLayout32>>
245    for WindowsProcessParameters<'a, Driver>
246where
247    Driver: VmiRead,
248    Driver::Architecture: ArchAdapter<Driver>,
249{
250    fn from(value: WindowsProcessParametersBase<'a, Driver, StructLayout32>) -> Self {
251        Self {
252            inner: WindowsProcessParametersWrapper::W32(value),
253        }
254    }
255}
256
257impl<'a, Driver> From<WindowsProcessParametersBase<'a, Driver, StructLayout64>>
258    for WindowsProcessParameters<'a, Driver>
259where
260    Driver: VmiRead,
261    Driver::Architecture: ArchAdapter<Driver>,
262{
263    fn from(value: WindowsProcessParametersBase<'a, Driver, StructLayout64>) -> Self {
264        Self {
265            inner: WindowsProcessParametersWrapper::W64(value),
266        }
267    }
268}
269
270impl<Driver> VmiVa for WindowsProcessParameters<'_, Driver>
271where
272    Driver: VmiRead,
273    Driver::Architecture: ArchAdapter<Driver>,
274{
275    fn va(&self) -> Va {
276        match &self.inner {
277            WindowsProcessParametersWrapper::W32(inner) => inner.va,
278            WindowsProcessParametersWrapper::W64(inner) => inner.va,
279        }
280    }
281}
282
283impl<Driver> std::fmt::Debug for WindowsProcessParameters<'_, Driver>
284where
285    Driver: VmiRead,
286    Driver::Architecture: ArchAdapter<Driver>,
287{
288    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
289        let current_directory = self.current_directory();
290        let dll_path = self.dll_path();
291        let image_path_name = self.image_path_name();
292        let command_line = self.command_line();
293
294        f.debug_struct("WindowsProcessParameters")
295            .field("current_directory", &current_directory)
296            .field("dll_path", &dll_path)
297            .field("image_path_name", &image_path_name)
298            .field("command_line", &command_line)
299            .finish()
300    }
301}
302
303impl<'a, Driver> WindowsProcessParameters<'a, Driver>
304where
305    Driver: VmiRead,
306    Driver::Architecture: ArchAdapter<Driver>,
307{
308    /// Creates a new process parameters accessor.
309    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
310        Self::with_kind(vmi, va, vmi.translation_root(va), WindowsWow64Kind::Native)
311    }
312
313    /// Creates a new process parameters accessor with an explicit address
314    /// space root and pointer width.
315    pub fn with_kind(
316        vmi: VmiState<'a, WindowsOs<Driver>>,
317        va: Va,
318        root: Pa,
319        kind: WindowsWow64Kind,
320    ) -> Self {
321        let inner = match kind {
322            WindowsWow64Kind::Native => WindowsProcessParametersWrapper::native(vmi, va, root),
323            WindowsWow64Kind::X86 => WindowsProcessParametersWrapper::w32(vmi, va, root),
324        };
325
326        Self { inner }
327    }
328
329    /// Returns the current directory.
330    ///
331    /// # Implementation Details
332    ///
333    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.CurrentDirectory.DosPath`.
334    pub fn current_directory(&self) -> Result<String, VmiError> {
335        self.inner.current_directory()
336    }
337
338    /// Returns the DLL search path.
339    ///
340    /// # Implementation Details
341    ///
342    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.DllPath`.
343    pub fn dll_path(&self) -> Result<String, VmiError> {
344        self.inner.dll_path()
345    }
346
347    /// Returns the full path of the executable image.
348    ///
349    /// # Implementation Details
350    ///
351    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.ImagePathName`.
352    pub fn image_path_name(&self) -> Result<String, VmiError> {
353        self.inner.image_path_name()
354    }
355
356    /// Returns the command line used to launch the process.
357    ///
358    /// # Implementation Details
359    ///
360    /// Corresponds to `_RTL_USER_PROCESS_PARAMETERS.CommandLine`.
361    pub fn command_line(&self) -> Result<String, VmiError> {
362        self.inner.command_line()
363    }
364}