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