vmi_core/os/mod.rs
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 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
#![doc = include_str!("../../docs/os.md")]
mod common;
mod struct_reader;
use vmi_macros::derive_os_wrapper;
pub use self::{
common::{
OsArchitecture, OsImageExportedSymbol, OsMapped, OsProcess, OsRegion, OsRegionKind,
ProcessId, ProcessObject, ThreadId, ThreadObject,
},
struct_reader::StructReader,
};
use crate::{
Architecture, Pa, Va, VmiCore, VmiDriver, VmiError, VmiOsContext, VmiOsContextProber,
VmiOsSession, VmiOsSessionProber,
};
/// Operating system trait.
#[derive_os_wrapper(
os_session_name = VmiOsSession,
os_context_name = VmiOsContext,
os_session_prober_name = VmiOsSessionProber,
os_context_prober_name = VmiOsContextProber
)]
pub trait VmiOs<Driver>
where
Driver: VmiDriver,
{
/// 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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> 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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<String, VmiError>;
/// Checks if Kernel Page Table Isolation (KPTI) is enabled.
fn kpti_enabled(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<bool, VmiError>;
/// Retrieves 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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<ProcessObject, VmiError>;
/// Retrieves the thread ID for a given thread object.
fn thread_id(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
thread: ThreadObject,
) -> Result<ThreadId, VmiError>;
/// Retrieves the process ID for a given process object.
fn process_id(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<ProcessId, VmiError>;
/// Retrieves the current thread object.
fn current_thread(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<ThreadObject, VmiError>;
/// Retrieves the current thread ID.
fn current_thread_id(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<ThreadId, VmiError>;
/// Retrieves the current process object.
fn current_process(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<ProcessObject, VmiError>;
/// Retrieves the current process ID.
fn current_process_id(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<ProcessId, VmiError>;
/// Retrieves a list of all processes in the system.
fn processes(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<Vec<OsProcess>, VmiError>;
/// Retrieves the parent process ID for a given process object.
fn process_parent_process_id(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<ProcessId, VmiError>;
/// Retrieves the architecture of a given process.
fn process_architecture(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<OsArchitecture, VmiError>;
/// Retrieves the translation root for a given process.
///
/// The translation root is the root of the page table hierarchy (also
/// known as the Directory Table Base (DTB) or Page Global Directory (PGD)).
///
/// # Architecture-specific
///
/// - **AMD64**: The translation root corresponds with the CR3 register
/// and PML4 table.
///
/// # Platform-specific
///
/// - **Windows**: Retrieves the `DirectoryTableBase` field from the
/// `KPROCESS` structure.
/// - **Linux**: Retrieves the `mm->pgd` field from the `task_struct`.
fn process_translation_root(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Pa, VmiError>;
/// Retrieves the base address of the user translation root for a given
/// process.
///
/// If KPTI is disabled, this function will return the same value as
/// [`VmiOs::process_translation_root`].
fn process_user_translation_root(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Pa, VmiError>;
/// Retrieves the filename of a given process.
fn process_filename(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<String, VmiError>;
/// Retrieves the base address of the process image.
fn process_image_base(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Va, VmiError>;
/// Retrieves a list of memory regions for a given process.
fn process_regions(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Vec<OsRegion>, VmiError>;
/// Checks if a given virtual address is valid in a given process.
fn process_address_is_valid(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
address: Va,
) -> Result<Option<bool>, VmiError>;
/// Finds a specific memory region in a process given an address.
fn find_process_region(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
process: ProcessObject,
address: Va,
) -> Result<Option<OsRegion>, VmiError>;
/// Retrieves the architecture of an image at a given base address.
fn image_architecture(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
image_base: Va,
) -> Result<OsArchitecture, VmiError>;
/// Retrieves a list of exported symbols from an image at a given base
/// address.
fn image_exported_symbols(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
image_base: Va,
) -> Result<Vec<OsImageExportedSymbol>, 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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> 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(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<Option<u32>, VmiError>;
}
/// Operating system extension trait.
pub trait OsExt<Driver>
where
Driver: VmiDriver,
{
/// Enumerates a linked list.
///
/// # Platform-specific
///
/// - **Windows**: Enumerates a `LIST_ENTRY` structure.
/// - **Linux**: Enumerates a `list_head` structure.
fn enumerate_list(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
list_head: Va,
callback: impl FnMut(Va) -> bool,
) -> Result<(), VmiError>;
/// Enumerates a tree structure.
///
/// # Platform-specific
///
/// - **Windows 7**: Enumerates a `MMADDRESS_NODE` structure.
/// - **Windows 10+**: Enumerates a `RTL_BALANCED_NODE` structure.
fn enumerate_tree(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
root: Va,
callback: impl FnMut(Va) -> bool,
) -> Result<(), VmiError>;
}