Skip to main content

vmi_core/os/
mod.rs

1#![doc = include_str!("../../docs/os.md")]
2
3mod dummy;
4mod image;
5mod macros;
6mod mapped;
7mod module;
8mod process;
9mod region;
10mod struct_reader;
11mod thread;
12mod user_module;
13
14use vmi_macros::derive_os_wrapper;
15
16use self::macros::{impl_ops, impl_predicate};
17pub use self::{
18    dummy::NoOS,
19    image::{VmiOsImage, VmiOsImageArchitecture, VmiOsImageSymbol},
20    mapped::VmiOsMapped,
21    module::{AnyModule, ModulePredicate, VmiOsModule},
22    process::{
23        AnyProcess, ProcessId, ProcessObject, ProcessPredicate, VmiOsProcess, VmiOsProcessExt,
24    },
25    region::{AnyRegion, RegionPredicate, VmiOsRegion, VmiOsRegionKind},
26    struct_reader::StructReader,
27    thread::{ThreadId, ThreadObject, VmiOsThread},
28    user_module::{AnyUserModule, UserModulePredicate, VmiOsUserModule},
29};
30use crate::{Architecture, Pa, Va, VmiDriver, VmiError, VmiOsState, VmiState};
31
32/// Operating system trait.
33#[derive_os_wrapper(VmiOsState)]
34pub trait VmiOs: Sized {
35    /// The architecture.
36    type Architecture: Architecture;
37
38    /// The driver.
39    type Driver: VmiDriver<Architecture = Self::Architecture>;
40
41    /// The process type.
42    type Process<'a>: VmiOsProcess<'a, Self::Driver, Os = Self> + 'a
43    where
44        Self: 'a;
45
46    /// The thread type.
47    type Thread<'a>: VmiOsThread<'a, Self::Driver, Os = Self> + 'a
48    where
49        Self: 'a;
50
51    /// The image type.
52    type Image<'a>: VmiOsImage<'a, Self::Driver, Os = Self> + 'a
53    where
54        Self: 'a;
55
56    /// The kernel module type.
57    type Module<'a>: VmiOsModule<'a, Self::Driver, Os = Self> + 'a
58    where
59        Self: 'a;
60
61    /// The user-mode module type.
62    type UserModule<'a>: VmiOsUserModule<'a, Self::Driver, Os = Self> + 'a
63    where
64        Self: 'a;
65
66    /// The memory region type.
67    type Region<'a>: VmiOsRegion<'a, Self::Driver, Os = Self> + 'a
68    where
69        Self: 'a;
70
71    /// The memory mapped region type.
72    type Mapped<'a>: VmiOsMapped<'a, Self::Driver, Os = Self> + 'a
73    where
74        Self: 'a;
75
76    /// Retrieves the base address of the kernel image.
77    ///
78    /// The kernel image base address is usually found using some special
79    /// CPU register - for example, a register that contains the address of
80    /// the system call handler. Such register is set by the operating system
81    /// during boot and is left unchanged (unless some rootkits are involved).
82    ///
83    /// Therefore, this function can accept the CPU registers from any point
84    /// of the VM execution (except for the early boot stage).
85    ///
86    /// For catching the exact moment when the kernel image base address is
87    /// set, you can monitor the `MSR_LSTAR` register (on AMD64) for writes.
88    ///
89    /// # Architecture-specific
90    ///
91    /// - **AMD64**: The kernel image base address is usually found using the
92    ///   `MSR_LSTAR` register.
93    ///
94    /// # Notes
95    ///
96    /// A malicious code (such as a rootkit) could modify values of the
97    /// registers, so the returned value might not be accurate.
98    fn kernel_image_base(vmi: VmiState<Self>) -> Result<Va, VmiError>;
99
100    /// Retrieves an implementation-specific string containing kernel
101    /// information.
102    ///
103    /// # Platform-specific
104    ///
105    /// - **Windows**: Retrieves the `NtBuildLab` string from the kernel image.
106    /// - **Linux**: Retrieves the `linux_banner` string from the kernel image.
107    fn kernel_information_string(vmi: VmiState<Self>) -> Result<String, VmiError>;
108
109    /// Checks if Kernel Page Table Isolation (KPTI) is enabled.
110    ///
111    /// # Platform-specific
112    ///
113    /// - **Windows**: Retrieves the `KiKvaShadow` global variable, if it exists.
114    fn kpti_enabled(vmi: VmiState<Self>) -> Result<bool, VmiError>;
115
116    /// Returns an iterator over the loaded kernel modules.
117    ///
118    /// # Platform-specific
119    ///
120    /// - **Windows**: Retrieves information from the `PsLoadedModuleList`.
121    /// - **Linux**: Retrieves information from the `modules` list.
122    fn modules<'a>(
123        vmi: VmiState<'a, Self>,
124    ) -> Result<impl Iterator<Item = Result<Self::Module<'a>, VmiError>> + use<'a, Self>, VmiError>;
125
126    /// Returns an iterator over the processes.
127    ///
128    /// # Platform-specific
129    ///
130    /// - **Windows**: Retrieves information from the `PsActiveProcessHead` list.
131    /// - **Linux**: Retrieves information from the `tasks` list.
132    fn processes<'a>(
133        vmi: VmiState<'a, Self>,
134    ) -> Result<impl Iterator<Item = Result<Self::Process<'a>, VmiError>> + use<'a, Self>, VmiError>;
135
136    /// Returns the process corresponding to the given process object.
137    fn process<'a>(
138        vmi: VmiState<'a, Self>,
139        process: ProcessObject,
140    ) -> Result<Self::Process<'a>, VmiError>;
141
142    /// Returns the currently executing process.
143    fn current_process<'a>(vmi: VmiState<'a, Self>) -> Result<Self::Process<'a>, VmiError>;
144
145    /// Returns the system process object.
146    ///
147    /// The system process is the first process created by the kernel.
148    ///
149    /// # Platform-specific
150    ///
151    /// - **Windows**: Retrieves the `PsInitialSystemProcess` global variable.
152    /// - **Linux**: Retrieves the `init_task` global variable.
153    fn system_process<'a>(vmi: VmiState<'a, Self>) -> Result<Self::Process<'a>, VmiError>;
154
155    /// Returns the thread corresponding to the given thread object.
156    fn thread<'a>(
157        vmi: VmiState<'a, Self>,
158        thread: ThreadObject,
159    ) -> Result<Self::Thread<'a>, VmiError>;
160
161    /// Returns the currently executing thread.
162    fn current_thread<'a>(vmi: VmiState<'a, Self>) -> Result<Self::Thread<'a>, VmiError>;
163
164    /// Returns the image corresponding to the given base address.
165    fn image<'a>(vmi: VmiState<'a, Self>, image_base: Va) -> Result<Self::Image<'a>, VmiError>;
166
167    /// Returns the kernel module corresponding to the given base address.
168    fn module<'a>(vmi: VmiState<'a, Self>, module: Va) -> Result<Self::Module<'a>, VmiError>;
169
170    /// Returns the user-mode module corresponding to the given base address.
171    fn user_module<'a>(
172        vmi: VmiState<'a, Self>,
173        module: Va,
174        root: Pa,
175    ) -> Result<Self::UserModule<'a>, VmiError>;
176
177    /// Returns the memory region corresponding to the given address.
178    ///
179    /// # Platform-specific
180    ///
181    /// - **Windows**: The region is represented by the `_MMVAD` structure.
182    /// - **Linux**: The region is represented by the `vm_area_struct` structure.
183    fn region<'a>(vmi: VmiState<'a, Self>, region: Va) -> Result<Self::Region<'a>, VmiError>;
184
185    /// Retrieves a specific syscall argument according to the system call ABI.
186    ///
187    /// This function assumes that it is called in the prologue of the system
188    /// call handler, i.e., the instruction pointer is pointing to the first
189    /// instruction of the function.
190    fn syscall_argument(vmi: VmiState<Self>, index: u64) -> Result<u64, VmiError>;
191
192    /// Retrieves a specific function argument according to the calling
193    /// convention of the operating system.
194    ///
195    /// This function assumes that it is called in the function prologue,
196    /// i.e., the instruction pointer is pointing to the first instruction of
197    /// the function.
198    ///
199    /// # Platform-specific
200    ///
201    /// - **Windows**: Assumes that the function is using the `stdcall`
202    ///   calling convention.
203    fn function_argument(vmi: VmiState<Self>, index: u64) -> Result<u64, VmiError>;
204
205    /// Retrieves the return value of a function.
206    ///
207    /// This function assumes that it is called immediately after the function
208    /// returns.
209    fn function_return_value(vmi: VmiState<Self>) -> Result<u64, VmiError>;
210
211    /// Retrieves the last error value.
212    ///
213    /// # Platform-specific
214    ///
215    /// - **Windows**: Retrieves the value of the `NtCurrentTeb()->LastErrorValue`
216    ///   field.
217    ///   - See also: [`WindowsOs::last_status()`](../../../../vmi_os_windows/struct.WindowsOs.html#method.last_status)
218    fn last_error(vmi: VmiState<Self>) -> Result<Option<u32>, VmiError>;
219}
220
221/// Extension methods on [`VmiOs`].
222///
223/// The blanket impl is the only impl of this trait, so implementors of
224/// [`VmiOs`] cannot override the default bodies.
225#[derive_os_wrapper(VmiOsState)]
226pub trait VmiOsExt: VmiOs {
227    /// Returns the first process matching `predicate`, or `Ok(None)`
228    /// if no live process matches.
229    fn find_process<'a>(
230        vmi: VmiState<'a, Self>,
231        predicate: impl ProcessPredicate<Self>,
232    ) -> Result<Option<Self::Process<'a>>, VmiError> {
233        for process in Self::processes(vmi)? {
234            let process = process?;
235
236            if predicate.matches(&process)? {
237                return Ok(Some(process));
238            }
239        }
240
241        Ok(None)
242    }
243
244    /// Returns an iterator over the processes matching `predicate`.
245    fn filter_processes<'a>(
246        vmi: VmiState<'a, Self>,
247        predicate: impl ProcessPredicate<Self>,
248    ) -> Result<impl Iterator<Item = Result<Self::Process<'a>, VmiError>>, VmiError> {
249        let mut processes = Self::processes(vmi)?;
250
251        Ok(std::iter::from_fn(move || {
252            for process in processes.by_ref() {
253                let process = match process {
254                    Ok(process) => process,
255                    Err(err) => return Some(Err(err)),
256                };
257
258                match predicate.matches(&process) {
259                    Ok(true) => return Some(Ok(process)),
260                    Ok(false) => continue,
261                    Err(err) => return Some(Err(err)),
262                }
263            }
264
265            None
266        }))
267    }
268
269    /// Returns the first kernel module matching `predicate`, or
270    /// `Ok(None)` if no loaded module matches.
271    fn find_module<'a>(
272        vmi: VmiState<'a, Self>,
273        predicate: impl ModulePredicate<Self>,
274    ) -> Result<Option<Self::Module<'a>>, VmiError> {
275        for module in Self::modules(vmi)? {
276            let module = module?;
277
278            if predicate.matches(&module)? {
279                return Ok(Some(module));
280            }
281        }
282
283        Ok(None)
284    }
285
286    /// Returns an iterator over the kernel modules matching `predicate`.
287    fn filter_modules<'a>(
288        vmi: VmiState<'a, Self>,
289        predicate: impl ModulePredicate<Self>,
290    ) -> Result<impl Iterator<Item = Result<Self::Module<'a>, VmiError>>, VmiError> {
291        let mut modules = Self::modules(vmi)?;
292
293        Ok(std::iter::from_fn(move || {
294            for module in modules.by_ref() {
295                let module = match module {
296                    Ok(module) => module,
297                    Err(err) => return Some(Err(err)),
298                };
299
300                match predicate.matches(&module) {
301                    Ok(true) => return Some(Ok(module)),
302                    Ok(false) => continue,
303                    Err(err) => return Some(Err(err)),
304                }
305            }
306
307            None
308        }))
309    }
310}
311
312impl<T> VmiOsExt for T where T: VmiOs {}