Skip to content

Commit

Permalink
feat(core): add OsModule struct and VmiOs::modules() function
Browse files Browse the repository at this point in the history
  • Loading branch information
wbenny committed Nov 25, 2024
1 parent 659ee98 commit 78a856b
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ and this project ~~adheres to~~

### Changed

- Added Output type to the VmiHandler
- VmiHandler::finished() is renamed to VmiHandler::check_completion(),
which now returns an Option<Output> instead of a bool

### Added

- Implemented handling of PFN changes in the PageTableMonitor
- Added Output type to the VmiHandler
- vmi_core::os::OsModule + VmiOs::modules() to get the list of loaded modules

### Fixed

Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ zerocopy = "0.8"
signal-hook = "0.3"
tracing-subscriber = "0.3"

isr = "0.1.1"
isr = "0.1.2"
isr-core = "0.1.1"
isr-dl-pdb = "0.1.1"
isr-macros = "0.1.1"
isr-macros = "0.1.2"

vmi = { path = "./crates/vmi", version = "0.1.1" }
vmi-arch-amd64 = { path = "./crates/vmi-arch-amd64", version = "0.1.1" }
Expand Down
32 changes: 32 additions & 0 deletions crates/vmi-core/src/os/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,38 @@ pub enum OsArchitecture {
Amd64,
}

/// Represents information about a kernel module in the target system.
#[derive(Debug, Serialize, Deserialize)]
pub struct OsModule {
/// The base address of the module.
///
/// # Platform-specific
///
/// - **Windows**: `KLDR_DATA_TABLE_ENTRY.DllBase`
/// - **Linux**:
/// - since v6.4-rc1: `module::mem[0 /* MOD_TEXT */].base`
/// - before v6.4-rc1: `module::core_layout.base`
pub base_address: Va,

/// The size of the module.
///
/// # Platform-specific
///
/// - **Windows**: `KLDR_DATA_TABLE_ENTRY.SizeOfImage`
/// - **Linux**:
/// - since v6.4-rc1: sum of `module::mem[MOD_*].size`
/// - before v6.4-rc1: `module::init_layout.size + module::core_layout.size (+ module::data_layout.size)`
pub size: u64,

/// The short name of the module.
///
/// # Platform-specific
///
/// - **Windows**: `KLDR_DATA_TABLE_ENTRY.BaseDllName`
/// - **Linux**: `module::name`
pub name: String,
}

/// Represents information about a process in the target system.
#[derive(Debug, Serialize, Deserialize)]
pub struct OsProcess {
Expand Down
16 changes: 14 additions & 2 deletions crates/vmi-core/src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use vmi_macros::derive_os_wrapper;

pub use self::{
common::{
OsArchitecture, OsImageExportedSymbol, OsMapped, OsProcess, OsRegion, OsRegionKind,
ProcessId, ProcessObject, ThreadId, ThreadObject,
OsArchitecture, OsImageExportedSymbol, OsMapped, OsModule, OsProcess, OsRegion,
OsRegionKind, ProcessId, ProcessObject, ThreadId, ThreadObject,
},
struct_reader::StructReader,
};
Expand Down Expand Up @@ -76,6 +76,18 @@ where
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<bool, VmiError>;

/// Retrieves a list of loaded kernel modules.
///
/// # Platform-specific
///
/// - **Windows**: Retrieves information from the `PsLoadedModuleList`.
/// - **Linux**: Retrieves information from the `modules` list.
fn modules(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
) -> Result<Vec<OsModule>, VmiError>;

/// Retrieves the system process object.
///
/// The system process is the first process created by the kernel.
Expand Down
24 changes: 16 additions & 8 deletions crates/vmi-os-linux/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::cell::RefCell;
use isr_core::Profile;
use vmi_core::{
os::{
OsArchitecture, OsExt, OsImageExportedSymbol, OsMapped, OsProcess, OsRegion, OsRegionKind,
ProcessId, ProcessObject, ThreadId, ThreadObject,
OsArchitecture, OsExt, OsImageExportedSymbol, OsMapped, OsModule, OsProcess, OsRegion,
OsRegionKind, ProcessId, ProcessObject, ThreadId, ThreadObject,
},
Architecture, MemoryAccess, Pa, Registers as _, Va, VmiCore, VmiDriver, VmiError, VmiOs,
};
Expand Down Expand Up @@ -476,23 +476,31 @@ where
fn kernel_information_string(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
) -> Result<String, VmiError> {
unimplemented!()
}

fn kpti_enabled(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
) -> Result<bool, VmiError> {
unimplemented!()
}

fn modules(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
) -> Result<Vec<OsModule>, VmiError> {
unimplemented!()
}

fn system_process(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
) -> Result<ProcessObject, VmiError> {
unimplemented!()
}
Expand Down Expand Up @@ -627,7 +635,7 @@ where
fn process_translation_root(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Pa, VmiError> {
unimplemented!()
Expand All @@ -636,7 +644,7 @@ where
fn process_user_translation_root(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
process: ProcessObject,
) -> Result<Pa, VmiError> {
unimplemented!()
Expand Down Expand Up @@ -697,7 +705,7 @@ where
fn process_address_is_valid(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as crate::Architecture>::Registers,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
process: ProcessObject,
address: Va,
) -> Result<Option<bool>, VmiError> {
Expand Down
60 changes: 58 additions & 2 deletions crates/vmi-os-windows/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ use isr_core::Profile;
use vmi_arch_amd64::{Amd64, Cr3};
use vmi_core::{
os::{
OsArchitecture, OsExt, OsImageExportedSymbol, OsMapped, OsProcess, OsRegion, OsRegionKind,
ProcessId, ProcessObject, StructReader, ThreadId, ThreadObject, VmiOs,
OsArchitecture, OsExt, OsImageExportedSymbol, OsMapped, OsModule, OsProcess, OsRegion,
OsRegionKind, ProcessId, ProcessObject, StructReader, ThreadId, ThreadObject, VmiOs,
},
AccessContext, Architecture, Gfn, Hex, MemoryAccess, Pa, Registers as _, Va, VmiCore,
VmiDriver, VmiError,
Expand Down Expand Up @@ -1388,6 +1388,37 @@ where
Ok(Some(nt_build_lab_ex))
}

/// Retrieves information about a kernel module from a pointer to
/// `KLDR_DATA_TABLE_ENTRY`
pub fn kernel_module(
&self,
vmi: &VmiCore<Driver>,
registers: &<Driver::Architecture as Architecture>::Registers,
addr: Va, // _KLDR_DATA_TABLE_ENTRY*
) -> Result<OsModule, VmiError> {
let KLDR_DATA_TABLE_ENTRY = &self.offsets.common._KLDR_DATA_TABLE_ENTRY;

let base_address = vmi.read_va(
registers.address_context(addr + KLDR_DATA_TABLE_ENTRY.DllBase.offset),
registers.address_width(),
)?;

let size = vmi
.read_u32(registers.address_context(addr + KLDR_DATA_TABLE_ENTRY.SizeOfImage.offset))?
as u64;

let name = self.read_unicode_string(
vmi,
registers.address_context(addr + KLDR_DATA_TABLE_ENTRY.BaseDllName.offset),
)?;

Ok(OsModule {
base_address,
size,
name,
})
}

// endregion: Kernel

// region: Memory
Expand Down Expand Up @@ -3168,6 +3199,31 @@ where
Ok(ki_kva_shadow)
}

fn modules(
&self,
vmi: &VmiCore<Driver>,
registers: &<<Driver as VmiDriver>::Architecture as Architecture>::Registers,
) -> Result<Vec<OsModule>, VmiError> {
let mut result = Vec::new();

let PsLoadedModuleList =
self.kernel_image_base(vmi, registers)? + self.symbols.PsLoadedModuleList;

let KLDR_DATA_TABLE_ENTRY = &self.offsets.common._KLDR_DATA_TABLE_ENTRY;

self.enumerate_list(vmi, registers, PsLoadedModuleList, |entry| {
let module_entry = entry - KLDR_DATA_TABLE_ENTRY.InLoadOrderLinks.offset;

if let Ok(module) = self.kernel_module(vmi, registers, module_entry) {
result.push(module)
}

true
})?;

Ok(result)
}

fn system_process(
&self,
vmi: &VmiCore<Driver>,
Expand Down
11 changes: 11 additions & 0 deletions crates/vmi-os-windows/src/offsets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ symbols! {
pub struct Symbols {
PsActiveProcessHead: u64,
PsInitialSystemProcess: u64,
PsLoadedModuleList: u64,
KiDispatchException: Option<u64>,
DbgkpSendErrorMessage: Option<u64>,

Expand Down Expand Up @@ -100,6 +101,16 @@ offsets! {
CurrentThread: Field,
}

#[isr(alias = "_LDR_DATA_TABLE_ENTRY")]
struct _KLDR_DATA_TABLE_ENTRY {
InLoadOrderLinks: Field, // _LIST_ENTRY
DllBase: Field, // PVOID
EntryPoint: Field, // PVOID
SizeOfImage: Field, // ULONG
FullDllName: Field, // _UNICODE_STRING
BaseDllName: Field, // _UNICODE_STRING
}

struct _CLIENT_ID {
UniqueProcess: Field,
UniqueThread: Field,
Expand Down

0 comments on commit 78a856b

Please sign in to comment.