D
DioProcess

Register Interception

Ring -1

Intercept and modify CPU control register access (CR0, CR3, CR4, DR*) from the hypervisor.

Overview

Control registers govern critical CPU behavior. The hypervisor can trap access to these registers, allowing interception and modification of OS behavior invisibly.

Intercepted Registers

RegisterPurposeUse Case
CR0System control (WP, PE, PG)Disable write protection
CR3Page table base (PDBR)Track context switches
CR4Extended features (SMEP, SMAP)Disable SMEP/SMAP
DR0-DR3Debug breakpoint addressesInvisible breakpoints
DR6Debug statusHide debug events
DR7Debug controlInvisible debug control

CR0 Write Protection Bypass

CR0.WP (Write Protect) prevents ring 0 code from writing to read-only pages. The hypervisor can intercept CR0 writes to keep WP disabled:

CR0 WP Bypass
// When guest writes CR0, hypervisor intercepts
VOID VmExitHandler_MovToCr0(PVCPU_CONTEXT Vcpu, ULONG64 NewValue) {
    // Force WP bit to 0 (disable write protection)
    NewValue &= ~CR0_WP;
    
    // Allow other bits through
    Vcpu->GuestCr0 = NewValue;
    
    // Update shadow CR0 (what OS thinks it set)
    Vcpu->ShadowCr0 = NewValue | CR0_WP;  // Lie to OS
}

// When guest reads CR0, return shadow value
VOID VmExitHandler_MovFromCr0(PVCPU_CONTEXT Vcpu) {
    // Return shadow (with WP bit showing as set)
    Vcpu->Rax = Vcpu->ShadowCr0;
}

CR3 Context Tracking

Track process context switches by intercepting CR3 loads:

CR3 Tracking
// Map of CR3 values to process info
std::map<ULONG64, ProcessInfo> Cr3ToProcess;

VOID VmExitHandler_MovToCr3(PVCPU_CONTEXT Vcpu, ULONG64 NewCr3) {
    ULONG64 OldCr3 = Vcpu->GuestCr3;
    
    // Log context switch
    if (Cr3ToProcess.count(NewCr3)) {
        auto& Proc = Cr3ToProcess[NewCr3];
        LogEvent("Switched to PID %d (%s)", Proc.Pid, Proc.Name);
        
        // Apply per-process hooks if registered
        if (HasHooksForProcess(Proc.Pid)) {
            ApplyEptHooks(Proc.Pid);
        }
    }
    
    // Allow CR3 load to proceed
    Vcpu->GuestCr3 = NewCr3;
}

Invisible Debug Registers

Set hardware breakpoints that are invisible to the guest OS:

Hidden DR Breakpoints
// Hypervisor maintains its own debug register state
struct HiddenDebugState {
    ULONG64 Dr0, Dr1, Dr2, Dr3;  // Breakpoint addresses
    ULONG64 Dr6;                  // Status
    ULONG64 Dr7;                  // Control
};

HiddenDebugState HvDebugState;
HiddenDebugState GuestDebugState;  // What OS set

// When guest reads DR, return guest's (shadow) value
VOID VmExitHandler_MovFromDr(PVCPU_CONTEXT Vcpu, ULONG DrNum) {
    switch (DrNum) {
        case 0: Vcpu->Rax = GuestDebugState.Dr0; break;
        case 1: Vcpu->Rax = GuestDebugState.Dr1; break;
        // ... etc
    }
}

// When guest writes DR, save to guest state but don't apply
VOID VmExitHandler_MovToDr(PVCPU_CONTEXT Vcpu, ULONG DrNum, ULONG64 Value) {
    // Save what guest thinks it set
    switch (DrNum) {
        case 0: GuestDebugState.Dr0 = Value; break;
        // ... etc
    }
    
    // Actual hardware breakpoints are HvDebugState, not visible to guest
    // Guest's breakpoints are never actually set in hardware
}

// Set hypervisor's own invisible breakpoint
VOID HvSetBreakpoint(ULONG Slot, ULONG64 Address, ULONG Type) {
    switch (Slot) {
        case 0: HvDebugState.Dr0 = Address; break;
        // ... etc
    }
    
    // Configure DR7 for the breakpoint
    HvDebugState.Dr7 |= (1 << (Slot * 2));  // Enable
    HvDebugState.Dr7 |= (Type << (16 + Slot * 4));  // Condition
    
    // Apply to actual hardware
    ApplyHvDebugState();
}

IOCTLs

IOCTLCodeDescription
HV_SET_BREAKPOINT0x820Set invisible breakpoint
HV_CLEAR_BREAKPOINT0x821Remove breakpoint
HV_DISABLE_SMEP0x822Disable SMEP via CR4 intercept
HV_SET_CR3_CALLBACK0x823Register CR3 change callback

Use Cases

  • Disable write protection — Allow writing to read-only kernel memory
  • Process tracking — Monitor context switches via CR3
  • Invisible breakpoints — Debug without detection
  • Disable SMEP/SMAP — Execute user pages from kernel
  • Anti-anti-debug — Hide debug state from targets

Detection Considerations

  • • Timing attacks can detect CR exit latency
  • • Side-channel analysis of instruction timing
  • • CPUID leaf analysis for hypervisor detection
  • • TSC offset manipulation detection