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 {}