Skip to main content

vmi_core/os/
process.rs

1use super::{
2    RegionPredicate, UserModulePredicate, VmiOs, VmiOsImageArchitecture, impl_ops, impl_predicate,
3};
4use crate::{Pa, Va, VmiDriver, VmiError, VmiVa};
5
6impl_ops! {
7    /// A process ID within a system.
8    pub struct ProcessId(pub u32);
9}
10
11impl_ops! {
12    /// A process object within a system.
13    ///
14    /// Equivalent to `EPROCESS*` on Windows or `task_struct*` on Linux.
15    pub struct ProcessObject(pub Va);
16}
17
18impl VmiVa for ProcessObject {
19    fn va(&self) -> Va {
20        self.0
21    }
22}
23
24impl ProcessObject {
25    /// Checks if the process object is a null reference.
26    pub fn is_null(&self) -> bool {
27        self.0.0 == 0
28    }
29
30    /// Converts the process object to a 64-bit unsigned integer.
31    pub fn to_u64(&self) -> u64 {
32        self.0.0
33    }
34}
35
36impl_predicate! {
37    /// Predicate used by [`VmiOsExt::find_process`].
38    ///
39    /// [`VmiOsExt::find_process`]: super::VmiOsExt::find_process
40    pub trait ProcessPredicate & impl for &str {
41        fn matches(&self, process: &Os::Process<'_>) -> Result<bool, VmiError> {
42            Ok(process.name()?.eq_ignore_ascii_case(self))
43        }
44    }
45
46    #[any]
47    pub struct AnyProcess;
48}
49
50impl<Os> ProcessPredicate<Os> for ProcessId
51where
52    Os: VmiOs,
53{
54    fn matches(&self, process: &Os::Process<'_>) -> Result<bool, VmiError> {
55        Ok(process.id()? == *self)
56    }
57}
58
59/// A trait for process objects.
60///
61/// This trait provides an abstraction over processes within a guest OS.
62pub trait VmiOsProcess<'a, Driver>: VmiVa + 'a
63where
64    Driver: VmiDriver,
65{
66    /// The VMI OS type.
67    type Os: VmiOs<Driver = Driver, Process<'a> = Self>;
68
69    /// Returns the process ID.
70    fn id(&self) -> Result<ProcessId, VmiError>;
71
72    /// Returns the process object.
73    fn object(&self) -> Result<ProcessObject, VmiError>;
74
75    /// Returns the name of the process.
76    ///
77    /// # Platform-specific
78    ///
79    /// - **Windows**: `_EPROCESS.ImageFileName` (limited to 16 characters).
80    /// - **Linux**: `_task_struct.comm` (limited to 16 characters).
81    fn name(&self) -> Result<String, VmiError>;
82
83    /// Returns the parent process ID.
84    fn parent_id(&self) -> Result<ProcessId, VmiError>;
85
86    /// Returns the architecture of the process.
87    fn architecture(&self) -> Result<VmiOsImageArchitecture, VmiError>;
88
89    /// Returns the process's page table translation root.
90    fn translation_root(&self) -> Result<Pa, VmiError>;
91
92    /// Returns the user-mode page table translation root.
93    ///
94    /// If KPTI is disabled, this function will return the same value as
95    /// [`translation_root`](Self::translation_root).
96    fn user_translation_root(&self) -> Result<Pa, VmiError>;
97
98    /// Returns the base address of the process image.
99    fn image_base(&self) -> Result<Va, VmiError>;
100
101    /// Returns an iterator over the process's memory regions.
102    fn regions(
103        &self,
104    ) -> Result<
105        impl Iterator<Item = Result<<Self::Os as VmiOs>::Region<'a>, VmiError>> + use<'a, Driver, Self>,
106        VmiError,
107    >;
108
109    /// Returns the memory region containing the given address.
110    fn lookup_region(
111        &self,
112        address: Va,
113    ) -> Result<Option<<Self::Os as VmiOs>::Region<'a>>, VmiError>;
114
115    /// Returns an iterator over the process's user modules.
116    ///
117    /// The list matches the process's [`architecture`](Self::architecture).
118    ///
119    /// # Platform-specific
120    ///
121    /// - **Windows**: `_PEB.Ldr.InLoadOrderModuleList` of the native PEB
122    ///   (`_EPROCESS.Peb`), and of the 32-bit PEB (from `_EPROCESS.WoW64Process`)
123    ///   for a WoW64 process.
124    fn user_modules(
125        &self,
126    ) -> Result<
127        impl Iterator<Item = Result<<Self::Os as VmiOs>::UserModule<'a>, VmiError>>
128        + use<'a, Driver, Self>,
129        VmiError,
130    >;
131
132    /// Returns the user module containing the given address.
133    fn lookup_user_module(
134        &self,
135        address: Va,
136    ) -> Result<Option<<Self::Os as VmiOs>::UserModule<'a>>, VmiError>;
137
138    /// Returns an iterator over the threads in the process.
139    ///
140    /// # Platform-specific
141    ///
142    /// - **Windows**: `_EPROCESS.ThreadListHead`.
143    fn threads(
144        &self,
145    ) -> Result<
146        impl Iterator<Item = Result<<Self::Os as VmiOs>::Thread<'a>, VmiError>> + use<'a, Driver, Self>,
147        VmiError,
148    >;
149
150    /// Checks whether the given virtual address is valid in the process.
151    ///
152    /// This method checks if page-faulting on the address would result in
153    /// a successful access.
154    fn is_valid_address(&self, address: Va) -> Result<Option<bool>, VmiError>;
155}
156
157/// Extension methods on [`VmiOsProcess`].
158///
159/// The blanket impl is the only impl of this trait, so implementors of
160/// [`VmiOsProcess`] cannot override the default bodies.
161pub trait VmiOsProcessExt<'a, Driver>: VmiOsProcess<'a, Driver>
162where
163    Driver: VmiDriver,
164{
165    /// Returns the first memory region matching `predicate`, or
166    /// `Ok(None)` if no region in the process matches.
167    fn find_region(
168        &self,
169        predicate: impl RegionPredicate<Self::Os>,
170    ) -> Result<Option<<Self::Os as VmiOs>::Region<'a>>, VmiError> {
171        for region in self.regions()? {
172            let region = region?;
173
174            if predicate.matches(&region)? {
175                return Ok(Some(region));
176            }
177        }
178
179        Ok(None)
180    }
181
182    /// Returns an iterator over the memory regions matching `predicate`.
183    fn filter_regions(
184        &self,
185        predicate: impl RegionPredicate<Self::Os>,
186    ) -> Result<impl Iterator<Item = Result<<Self::Os as VmiOs>::Region<'a>, VmiError>>, VmiError>
187    {
188        let mut regions = self.regions()?;
189
190        Ok(std::iter::from_fn(move || {
191            for region in regions.by_ref() {
192                let region = match region {
193                    Ok(region) => region,
194                    Err(err) => return Some(Err(err)),
195                };
196
197                match predicate.matches(&region) {
198                    Ok(true) => return Some(Ok(region)),
199                    Ok(false) => continue,
200                    Err(err) => return Some(Err(err)),
201                }
202            }
203
204            None
205        }))
206    }
207
208    /// Returns the first user module matching `predicate`, or
209    /// `Ok(None)` if no user module in the process matches.
210    fn find_user_module(
211        &self,
212        predicate: impl UserModulePredicate<Self::Os>,
213    ) -> Result<Option<<Self::Os as VmiOs>::UserModule<'a>>, VmiError> {
214        for module in self.user_modules()? {
215            let module = module?;
216
217            if predicate.matches(&module)? {
218                return Ok(Some(module));
219            }
220        }
221
222        Ok(None)
223    }
224
225    /// Returns an iterator over the user modules matching `predicate`.
226    fn filter_user_modules(
227        &self,
228        predicate: impl UserModulePredicate<Self::Os>,
229    ) -> Result<impl Iterator<Item = Result<<Self::Os as VmiOs>::UserModule<'a>, VmiError>>, VmiError>
230    {
231        let mut modules = self.user_modules()?;
232
233        Ok(std::iter::from_fn(move || {
234            for module in modules.by_ref() {
235                let module = match module {
236                    Ok(module) => module,
237                    Err(err) => return Some(Err(err)),
238                };
239
240                match predicate.matches(&module) {
241                    Ok(true) => return Some(Ok(module)),
242                    Ok(false) => continue,
243                    Err(err) => return Some(Err(err)),
244                }
245            }
246
247            None
248        }))
249    }
250}
251
252impl<'a, Driver, T> VmiOsProcessExt<'a, Driver> for T
253where
254    Driver: VmiDriver,
255    T: VmiOsProcess<'a, Driver>,
256{
257}