- Abstract
- 1. Introduction
- 2. Detection Timing: SSDT Initialization
- 3. Illusion: UEFI-Based Hypervisor
- 4. Matrix: Windows Kernel Driver-Based Hypervisor
- 5. Comparison: Illusion vs. Matrix
- 6. Detection Vectors
- 7. Appendix
- 8. Conclusion
- References
Project credits and context. These notes discuss the research prototypes illusion-rs and matrix-rs, developed by memN0ps. The code fragments are illustrative sketches, not a complete, tested implementation. Behavior depends on the CPU, Windows version, and project revision; the discussion does not guarantee invisibility or compatibility on current systems.
Abstract
This article presents two proof-of-concept Rust implementations for stealthy Windows kernel introspection using Extended Page Tables (EPT): illusion-rs (UEFI-based, early boot hooking) and matrix-rs (kernel driver-based, runtime hooking). Both leverage Second-Level Address Translation (SLAT) to redirect control flow without modifying guest memory, bypassing integrity checks like PatchGuard.
1. Introduction
Traditional kernel hooking modifies guest memory directly, making detection trivial and triggering PatchGuard on Windows. EPT-based hypervisor introspection operates outside the guest’s control plane, enabling:
- Stealth: No modification to guest virtual or physical memory
- Integrity preservation: Original code remains unchanged
- Early boot visibility (illusion-rs): Hooks before security controls initialize
- Runtime flexibility (matrix-rs): Dynamic hooking via kernel driver
Core Concepts
| Term | Definition |
|---|---|
| EPT | Intel’s Second-Level Address Translation; translates guest physical → host physical addresses |
| Shadow page | Hypervisor-controlled copy of guest memory with modified permissions/content |
| VM-exit | CPU transition from guest to hypervisor mode triggered by instructions or memory violations |
| MTF | Monitor Trap Flag; enables single-stepping for instruction replay |
2. Detection Timing: SSDT Initialization
Before installing hooks, the hypervisor must wait until the System Service Descriptor Table (SSDT) is fully initialized in ntoskrnl.exe. Installing hooks prematurely causes crashes when resolving syscall numbers through invalid memory.
Reliable Trigger Points
| Processor | Execution Path |
|---|---|
| Intel | KiInitializeKernel → KeCompactServiceTable → KiSetCacheInformation → cpuid(4, 0) |
| AMD | Conditional: If CPUID(0x80000001).ECX[22] set → cpuid(0x8000001D, 0), else fallback to cpuid(0x80000005/06) |
Implementation note: The original illusion-rs used cpuid(2, 0) as a hack that worked empirically but isn’t semantically correct. For production adaptations, use cpuid(4, 0) (Intel) or cpuid(0x8000001D, 0) (AMD).
Code Pattern
match leaf {
leaf if leaf == CpuidLeaf::CacheInformation as u32 => {
if !hook_manager.has_cpuid_cache_info_been_called {
hook_manager.manage_kernel_ept_hook(
vm,
djb2_hash("NtCreateFile"),
0x0055,
EptHookType::Function(InlineHookType::Vmcall),
true,
)?;
hook_manager.has_cpuid_cache_info_been_called = true;
}
}
}
3. Illusion: UEFI-Based Hypervisor
Architecture Overview
- Loading: UEFI firmware (Type-1 hypervisor)
- EPT Model: Per-logical-processor EPTs
- Hook Method: VMCALL + Monitor Trap Flag single-stepping
- Best for: Early boot introspection, firmware-level visibility
EPT Hook Installation Pipeline
┌─────────────────────────────────────────────────────────────┐
│ 1. Map 2MB large page to pre-allocated page table │
│ 2. Split large page → 512 × 4KB entries │
│ 3. Allocate shadow page from heap │
│ 4. Clone guest memory → shadow page │
│ 5. Insert VMCALL inline hook at function offset │
│ 6. Revoke EXECUTE permission on original page │
│ 7. Invalidate TLB/EPT caches (INVEPT All Contexts) │
│ 8. VM-exit on EPT violation → swap to shadow page │
│ 9. VMCALL triggers VM-exit → introspection │
│ 10. MTF single-step → replay displaced instructions │
│ 11. Restore original page + reapply hook │
└─────────────────────────────────────────────────────────────┘
Key Implementation Details
Memory Management
- Pre-allocated heap (default 64MB) with linked-list allocator
- Fixed-size pool avoids runtime allocation failures during VM-exit handling
- All logical processors share the same pool
Instruction Replay with MTF
// During VMCALL handler:
vm.mtf_counter = Some(instruction_count);
set_monitor_trap_flag(true);
update_guest_interrupt_flag(vm, false)?;
// MTF handler decrements counter per instruction:
*counter = counter.saturating_sub(1);
if *counter == 0 {
// Prologue fully replayed; reapply hook
swap_page(guest_pa, shadow_pa, EXECUTE);
set_monitor_trap_flag(false);
restore_guest_interrupt_flag(vm)?;
}
Hypercall Channel
User-mode control via CPUID interception—unprivileged, password-protected backdoor for enabling/disabling hooks at runtime.
4. Matrix: Windows Kernel Driver-Based Hypervisor
Architecture Overview
- Loading: Windows kernel driver (Type-2 hypervisor)
- EPT Model: Shared dual-EPT across all processors
- Hook Method: INT3 breakpoints + dynamic EPTP switching
- Best for: Runtime introspection, easier integration
Dual-EPT Design
| EPT | Permissions | Purpose |
|---|---|---|
| Primary | READ_WRITE |
Normal execution; read/write access |
| Secondary | EXECUTE only |
Shadow pages with hook logic |
Hook Installation Pipeline
┌─────────────────────────────────────────────────────────────┐
│ 1. Resolve target function (export table or SSDT) │
│ 2. Create trampoline to preserve overwritten prologue │
│ 3. Copy guest page → shadow region │
│ 4. Inject INT3 (0xCC) at function entry │
│ 5. Configure EXCEPTION_BITMAP to trap INT3 │
│ 6. Set primary EPT: remove EXECUTE from target page │
│ 7. Set secondary EPT: EXECUTE only, remap to shadow │
│ 8. Load primary_eptp into VMCS │
│ 9. On EPT violation (execute access) → switch to secondary │
│ 10. INT3 triggers VM-exit → redirect RIP to handler │
│ 11. After handler: jump via trampoline to original function │
└─────────────────────────────────────────────────────────────┘
EPTP Switching Logic
// In EPT violation handler:
if ept_violation_qualification.readable &&
ept_violation_qualification.writable &&
!ept_violation_qualification.executable {
// Execute access denied in primary → switch to secondary
vmwrite(EPTP_FULL, secondary_eptp);
}
if !ept_violation_qualification.readable &&
!ept_violation_qualification.writable &&
ept_violation_qualification.executable {
// Read/write access denied in secondary → switch back to primary
vmwrite(EPTP_FULL, primary_eptp);
}
Trampoline Design
; Trampoline stub after INT3 overwrite
push [rip+target_addr] ; Indirect jump to original function continuation
jmp qword ptr [rip+0]
Preserves registers and performs RIP-relative redirection without clobbering general-purpose registers.
5. Comparison: Illusion vs. Matrix
| Dimension | Illusion (UEFI) | Matrix (Driver) |
|---|---|---|
| Loading Stage | Early boot (firmware) | Runtime (driver load) |
| EPT Model | Per-processor EPTs | Shared dual-EPT |
| Hook Trigger | VMCALL + MTF | INT3 + breakpoint exception |
| VM-exits per hook | 2 (violation + VMCALL) + MTF steps | 2 (violation + breakpoint) |
| Control Channel | CPUID hypercalls (user-mode) | None (currently) |
| Complexity | Higher (per-processor sync) | Lower (global state) |
| Detection Risk | Firmware visibility | Driver enumeration |
| Use Case | Pre-security-control hooking | Post-boot runtime analysis |
Trade-off Summary
Choose illusion-rs if:
- Need early boot visibility before security controls load
- Require fine-grained per-processor control
- Want fully host-side introspection without guest memory allocation
Choose matrix-rs if:
- Need runtime hooking without UEFI/firmware integration
- Prefer simpler shared-state model
- Require dynamically loadable driver
6. Detection Vectors
While EPT hooks avoid guest memory modifications, they introduce detectable artifacts:
| Technique | Mechanism |
|---|---|
| Timing side-channels | RDTSC latency spikes during VM-exits |
| Thread discrepancy | Multi-core timing divergence from per-processor EPTs |
| Fault profiling | Instruction Execution Time (IET) anomalies |
| Descriptor checks | SIDT/SGDT descriptor length inconsistencies |
| MSR probing | Reads to synthetic ranges (0x40000000+) |
| Cache testing | INVD/WBINVD caching consistency checks |
| LBR inspection | Last Branch Record stack mismatches |
| Page table audit | GDT/IDT integrity validation |
Notable resources: BattlEye detection research (@vmcall, @daax), Hypervisor-Assisted Hooking Detection (@momo5502), PatchGuard introspection series (@everdox, @ajkhoury).
7. Appendix
Guest-Assisted Hooking (Deprecated in Illusion)
Early versions allocated guest memory and injected helper code. Removed due to:
- Increased complexity and synchronization requirements
- Higher detection surface
- Fragility during early kernel initialization phases
Alternative Hook Methods
| Opcode | Pros | Cons |
|---|---|---|
| INT3 | Small (1 byte); simple | Requires breakpoint exception handler |
| VMCALL | Explicit hypervisor communication | Needs dedicated handler |
JMP [rip+0] |
Single VM-exit; no exception | Larger shellcode (14 bytes) |
| CPUID | Unprivileged; user-mode accessible | Slower; not ideal for frequent hooks |
Related Projects
- barevisor - Minimal hypervisor template (Satoshi Tanda)
- vmi-rs - Modular Virtual Machine Introspection library (Petr Beneš)
- amd_hypervisor - AMD SVM-based hypervisor (not-matthias)
8. Conclusion
Both implementations demonstrate that EPT-based introspection can achieve:
- Memory integrity preservation - No direct guest memory modification
- PatchGuard compatibility - Bypasses kernel patch detection
- Fine-grained control - Per-function syscall monitoring
- Extensibility - Foundation for thread/process hiding, shellcode injection, reflective DLL loading
Production caveats:
- Virtualization-Based Security (VBS) prevents third-party hypervisor loading on modern Windows
- Intel VT-rp and nested virtualization barriers add defense layers
- Performance overhead scales with hook frequency and displaced instruction count
These techniques are well-documented in security research and game-hacking communities. The implementations serve as educational templates for advancing low-level security research, defensive instrumentation, and hypervisor-assisted threat detection.
References
- Intel® 64 and IA-32 Architectures Software Developer’s Manual - Section 29.3.2 (EPT Translation Mechanism)
- @everdox, @ajkhoury. “PatchGuard: Hypervisor-Based Introspection” (Parts 1-2)
- @momo5502. “Detecting Hypervisor-Assisted Hooking”
- @daax, @iPower, @ajkhoury, @drew. “How Anti-Cheats Detect System Emulation”
- Satoshi Tanda. “Hypervisor for Malware Analysis”
- memN0ps. illusion-rs & matrix-rs GitHub repositories