leviathan-driver 0.1.0

Windows kernel-mode EDR/XDR driver framework in Rust - callbacks, filters, detection, forensics
//! Integrity Verification and Anti-Tampering
//!
//! Protects the driver and monitored data from tampering attacks.
//!
//! # Protection Mechanisms
//! - Kernel Data Protection (KDP) via VBS
//! - Callback registration verification
//! - Driver integrity monitoring
//! - Hook detection and prevention
//!
//! # Attack Detection
//! - DKOM (Direct Kernel Object Manipulation)
//! - Callback removal/modification
//! - Driver patching
//! - PatchGuard bypass attempts
//!
//! # VBS Integration
//! When VBS is enabled, critical data structures can be protected
//! using the Secure Kernel at VTL1.

use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use wdk::println;
use wdk_sys::{
    ntddk::MmIsAddressValid,
    NTSTATUS, PVOID, STATUS_SUCCESS,
};

/// Flag indicating if integrity monitoring is active
static MONITORING_ACTIVE: AtomicBool = AtomicBool::new(false);

/// Counter for detected tampering attempts
static TAMPERING_ATTEMPTS: AtomicU64 = AtomicU64::new(0);

/// Callback registration record
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CallbackRecord {
    /// Type of callback
    pub callback_type: CallbackType,
    /// Original callback address
    pub original_address: usize,
    /// Current callback address (for comparison)
    pub current_address: usize,
    /// Is callback still registered
    pub registered: bool,
}

/// Types of kernel callbacks we monitor
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CallbackType {
    ProcessNotify = 0,
    ThreadNotify = 1,
    ImageNotify = 2,
    RegistryCallback = 3,
    ObjectCallback = 4,
    MinifilterCallback = 5,
    WfpCallout = 6,
}

/// Maximum number of callbacks to track
const MAX_CALLBACKS: usize = 32;

/// Storage for callback records
static mut CALLBACK_RECORDS: [CallbackRecord; MAX_CALLBACKS] = [CallbackRecord {
    callback_type: CallbackType::ProcessNotify,
    original_address: 0,
    current_address: 0,
    registered: false,
}; MAX_CALLBACKS];

static CALLBACK_COUNT: AtomicU64 = AtomicU64::new(0);

/// Initialize integrity monitoring
///
/// # Safety
/// Must be called from PASSIVE_LEVEL after callbacks are registered
pub unsafe fn init_integrity_monitoring() -> Result<(), NTSTATUS> {
    if MONITORING_ACTIVE.load(Ordering::SeqCst) {
        return Ok(());
    }

    println!("[Leviathan] Initializing integrity monitoring");

    // Check if VBS/HVCI is enabled
    if is_vbs_enabled() {
        println!("[Leviathan] VBS/HVCI is enabled - enhanced protection available");
    }

    MONITORING_ACTIVE.store(true, Ordering::SeqCst);
    Ok(())
}

/// Register a callback for integrity monitoring
///
/// Records the callback address so we can detect if it's modified.
///
/// # Safety
/// Callback address must be valid
pub unsafe fn register_callback_for_monitoring(
    callback_type: CallbackType,
    callback_address: usize,
) {
    let count = CALLBACK_COUNT.load(Ordering::SeqCst) as usize;
    if count >= MAX_CALLBACKS {
        println!("[Leviathan] Warning: Callback monitoring limit reached");
        return;
    }

    unsafe {
        CALLBACK_RECORDS[count] = CallbackRecord {
            callback_type,
            original_address: callback_address,
            current_address: callback_address,
            registered: true,
        };
    }

    CALLBACK_COUNT.store((count + 1) as u64, Ordering::SeqCst);

    println!(
        "[Leviathan] Registered callback {:?} at {:#x} for monitoring",
        callback_type, callback_address
    );
}

/// Verify all registered callbacks are intact
///
/// Returns the number of tampered callbacks detected.
pub fn verify_callbacks() -> u32 {
    let count = CALLBACK_COUNT.load(Ordering::SeqCst) as usize;
    let mut tampered = 0u32;

    for i in 0..count {
        let record = unsafe { &CALLBACK_RECORDS[i] };
        if !record.registered {
            continue;
        }

        // Check if callback address is still valid
        if !unsafe { MmIsAddressValid(record.original_address as PVOID) } != 0 {
            println!(
                "[Leviathan] TAMPERING: Callback {:?} address invalid!",
                record.callback_type
            );
            tampered += 1;
            TAMPERING_ATTEMPTS.fetch_add(1, Ordering::SeqCst);
        }

        // In production, would also:
        // 1. Read current callback from kernel structures
        // 2. Compare against original_address
        // 3. Verify callback code hasn't been patched
    }

    tampered
}

/// Check if VBS (Virtualization Based Security) is enabled
///
/// When VBS is enabled, we can use Kernel Data Protection (KDP)
/// to protect critical data structures.
pub fn is_vbs_enabled() -> bool {
    // Use NtQuerySystemInformation with SystemCodeIntegrityInformation
    // Check for CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED flag (0x400)

    // Simplified check - in production would query system info
    false
}

/// Check if HVCI (Hypervisor-protected Code Integrity) is enabled
pub fn is_hvci_enabled() -> bool {
    // Similar to VBS check, but specifically for HVCI
    is_vbs_enabled()
}

/// Driver code integrity verification
pub mod code_integrity {
    use super::*;

    /// Stored hash of our driver's code sections
    static mut DRIVER_CODE_HASH: [u8; 32] = [0u8; 32];

    /// Compute hash of driver code sections
    ///
    /// # Safety
    /// Must be called during driver initialization
    pub unsafe fn compute_driver_hash(
        _driver_base: usize,
        _driver_size: usize,
    ) -> [u8; 32] {
        // In production:
        // 1. Find .text and .rdata sections
        // 2. Compute SHA-256 hash
        // 3. Store for later verification

        [0u8; 32] // Placeholder
    }

    /// Verify driver code hasn't been modified
    pub fn verify_driver_integrity() -> bool {
        // In production:
        // 1. Re-compute hash of code sections
        // 2. Compare against stored hash
        // 3. Return false if mismatch

        true // Placeholder
    }

    /// Check for inline hooks in driver functions
    ///
    /// Detects if any of our functions have been hooked.
    pub fn detect_inline_hooks(_function_address: usize) -> bool {
        // Check first bytes of function for:
        // - JMP instructions (0xE9, 0xEB)
        // - CALL instructions (0xE8)
        // - MOV + JMP patterns

        false // Placeholder
    }
}

/// Kernel Data Protection (KDP) support
///
/// Uses VBS Secure Kernel to protect critical data.
pub mod kdp {
    use super::*;

    /// Mark a memory region as read-only via KDP
    ///
    /// Protected memory cannot be modified even by kernel code.
    ///
    /// # Safety
    /// - Region must be properly aligned
    /// - VBS must be enabled
    #[allow(dead_code)]
    pub unsafe fn protect_memory(
        _address: PVOID,
        _size: usize,
    ) -> Result<(), NTSTATUS> {
        if !is_vbs_enabled() {
            return Err(wdk_sys::STATUS_NOT_SUPPORTED);
        }

        // In production:
        // Use MmProtectMdlSystemAddress or KDP APIs

        Ok(())
    }

    /// Allocate memory from secure pool
    ///
    /// Memory from secure pool is protected by the hypervisor.
    #[allow(dead_code)]
    pub unsafe fn allocate_secure(_size: usize) -> Option<PVOID> {
        if !is_vbs_enabled() {
            return None;
        }

        // In production:
        // Use ExAllocatePool with appropriate flags for KDP

        None // Placeholder
    }
}

/// DKOM detection
///
/// Detect Direct Kernel Object Manipulation attacks.
pub mod dkom_detection {
    use super::*;

    /// Check if process list has been manipulated
    ///
    /// Compares process enumeration methods to detect unlinking.
    pub fn detect_hidden_processes() -> Vec<usize> {
        let mut hidden = Vec::new();

        // Detection methods:
        // 1. Compare PsActiveProcessHead walking vs PspCidTable
        // 2. Check thread->process links for orphan threads
        // 3. Verify handle table entries
        // 4. Compare against scheduler's ready queue

        // In production, would implement multiple enumeration
        // techniques and cross-reference results

        hidden
    }

    /// Check if driver list has been manipulated
    pub fn detect_hidden_drivers() -> Vec<usize> {
        let mut hidden = Vec::new();

        // Detection methods:
        // 1. Compare PsLoadedModuleList walking vs pool tag scanning
        // 2. Verify module headers match pool allocations
        // 3. Check MmUnloadedDrivers for anomalies

        hidden
    }

    /// Verify EPROCESS linked list integrity
    pub fn verify_process_list() -> bool {
        // Walk EPROCESS.ActiveProcessLinks in both directions
        // Verify FLINK->BLINK == current entry

        true // Placeholder
    }
}

/// Hook detection for system structures
pub mod hook_detection {
    use super::*;

    /// Check SSDT for modifications
    ///
    /// Note: This is historical - modern Windows has PatchGuard
    #[allow(dead_code)]
    pub fn check_ssdt_integrity() -> bool {
        // Compare SSDT entries against known good values
        // On x64, check relative offsets

        true // Placeholder
    }

    /// Check IDT for modifications
    #[allow(dead_code)]
    pub fn check_idt_integrity() -> bool {
        // Verify IDT entries point to expected handlers

        true // Placeholder
    }

    /// Detect MSR hooks
    #[allow(dead_code)]
    pub fn check_msr_hooks() -> bool {
        // Check LSTAR, SYSCALL_MASK for modifications

        true // Placeholder
    }
}

/// Get tampering attempt count
pub fn get_tampering_attempts() -> u64 {
    TAMPERING_ATTEMPTS.load(Ordering::SeqCst)
}

/// Report tampering to security event log
pub fn report_tampering(description: &str) {
    TAMPERING_ATTEMPTS.fetch_add(1, Ordering::SeqCst);

    println!(
        "[Leviathan] SECURITY ALERT: Tampering detected - {}",
        description
    );

    // In production:
    // 1. Log to ETW security channel
    // 2. Send alert to user-mode service
    // 3. Consider defensive action (terminate, crash, alert)
}