vmi-os-windows 0.7.0

Windows OS specific code for VMI
Documentation
use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead, os::VmiOsModule};

use crate::{ArchAdapter, WindowsOs, WindowsOsExt as _, offset};

/// A Windows kernel module.
///
/// A module in Windows refers to a loaded executable or driver,
/// typically tracked in the kernel's module list.
///
/// # Implementation Details
///
/// Corresponds to `_KLDR_DATA_TABLE_ENTRY`.
pub struct WindowsModule<'a, Driver>
where
    Driver: VmiRead,
    Driver::Architecture: ArchAdapter<Driver>,
{
    /// The VMI state.
    vmi: VmiState<'a, WindowsOs<Driver>>,

    /// Address of the `_KLDR_DATA_TABLE_ENTRY` structure.
    va: Va,
}

impl<Driver> VmiVa for WindowsModule<'_, Driver>
where
    Driver: VmiRead,
    Driver::Architecture: ArchAdapter<Driver>,
{
    fn va(&self) -> Va {
        self.va
    }
}

impl<'a, Driver> WindowsModule<'a, Driver>
where
    Driver: VmiRead,
    Driver::Architecture: ArchAdapter<Driver>,
{
    /// Creates a new Windows kernel module.
    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
        Self { vmi, va }
    }

    /// Returns the entry point of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.EntryPoint`.
    pub fn entry_point(&self) -> Result<Va, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        self.vmi
            .read_va_native(self.va + KLDR_DATA_TABLE_ENTRY.EntryPoint.offset())
    }

    /// Returns the full name of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.FullDllName`.
    ///
    /// # Notes
    ///
    /// This operation might fail as the filename is allocated from paged pool.
    pub fn full_name(&self) -> Result<String, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        self.vmi
            .os()
            .read_unicode_string(self.va + KLDR_DATA_TABLE_ENTRY.FullDllName.offset())
    }

    /// Returns the timestamp of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.TimeDateStamp`.
    pub fn time_date_stamp(&self) -> Result<u32, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        self.vmi
            .read_u32(self.va + KLDR_DATA_TABLE_ENTRY.TimeDateStamp.offset())
    }
}

impl<'a, Driver> VmiOsModule<'a, Driver> for WindowsModule<'a, Driver>
where
    Driver: VmiRead,
    Driver::Architecture: ArchAdapter<Driver>,
{
    type Os = WindowsOs<Driver>;

    /// Returns the base address of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.DllBase`.
    fn base_address(&self) -> Result<Va, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        self.vmi
            .read_va_native(self.va + KLDR_DATA_TABLE_ENTRY.DllBase.offset())
    }

    /// Returns the size of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.SizeOfImage`.
    fn size(&self) -> Result<u64, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        Ok(self
            .vmi
            .read_u32(self.va + KLDR_DATA_TABLE_ENTRY.SizeOfImage.offset())? as u64)
    }

    /// Returns the name of the module.
    ///
    /// # Implementation Details
    ///
    /// Corresponds to `_KLDR_DATA_TABLE_ENTRY.BaseDllName`.
    ///
    /// # Notes
    ///
    /// This operation is expected to succeed as the name is allocated from
    /// non-paged pool.
    fn name(&self) -> Result<String, VmiError> {
        let KLDR_DATA_TABLE_ENTRY = offset!(self.vmi, _KLDR_DATA_TABLE_ENTRY);

        self.vmi
            .os()
            .read_unicode_string(self.va + KLDR_DATA_TABLE_ENTRY.BaseDllName.offset())
    }
}