- Status
- Offline
- Joined
- Mar 3, 2026
- Messages
- 170
- Reaction score
- 7
Been grinding through the internals of HyperGuard for a while now. Since there is basically zero public info on this, I spent the last few weeks buried in IDA analyzing securekernel.exe, ntoskrnl, and hvix64.exe.
My current setup is a type-1 hypervisor parasiting inside Hyper-V using a dual-CR3 EPT split. I have hyperv_CR3 running shadow pages with --X (execute only) permissions, while the hook_CR3 is a deep copy with originals kept as RW-. Any execution attempt hits the shadow pages, while standard reads trigger an EPT violation. The handler then switches to the hook_CR3 to return clean bytes. This bypasses EAC without a hitch.
The problem: HyperGuard hits me with a 0x18B bugcheck after a few hours of runtime. I traced the full chain in IDA and found the trigger point:
The flags are consistently 0x71. At 0x14006485b:
The kill happens at 0x140064960. Because my --X pages force Hyper-V to deny reads, the ResultCode comes back as 5 (GpaNoReadAccess), leading straight to a SkpgBugCheck. Even if you get past that, there is a second check at 0x140064996 that validates access rights. My --X setup returns 4, which fails because it requires 5 (R-X) or 6 (RWX).
Once that happens, VTL1 self-destructs, freezes all CPUs, kills timers, and overwrites VTL0 RIP to KeBugCheckEx(0x18B). Hvix64.exe hypercall 0x52 performs a software EPT walk reading the same page table pages as the VMCS EPTP, which is why my EPT modifications are getting flagged.
I also mapped out that VTL1 gets scheduled in four ways, not just through explicit VTL calls:
Hypercall 135 crashdump is a one-way street; once triggered, VPs spin in a barrier and time out, causing a secondary bugcheck.
Has anyone dealt with this from a nested position? I am debating hooking HvSetEptPointer in hvix64 as the only viable choke point for all EPTP writes. Or are we looking at forcing writes into the VTL scheduler 0 to keep parity? Drop your thoughts if you've been reversing this lately.
My current setup is a type-1 hypervisor parasiting inside Hyper-V using a dual-CR3 EPT split. I have hyperv_CR3 running shadow pages with --X (execute only) permissions, while the hook_CR3 is a deep copy with originals kept as RW-. Any execution attempt hits the shadow pages, while standard reads trigger an EPT violation. The handler then switches to the hook_CR3 to return clean bytes. This bypasses EAC without a hitch.
The problem: HyperGuard hits me with a 0x18B bugcheck after a few hours of runtime. I traced the full chain in IDA and found the trigger point:
Code:
SkpgHyperguardTimerRoutine (random interval)
→ SkpgHyperguardRuntime (0x14000E884)
→ SkpgVerifyExtents (0x14000F5A0) — round-robin over kernel module extents
→ SkpgVerifyMemoryExtent (0x14000EA94)
→ SkpgTranslateVaWorker (0x1400645FC)
→ hypercall 0x52 (HvTranslateVirtualAddress)
The flags are consistently 0x71. At 0x14006485b:
Code:
mov rdx, cs:ShvlTranslateGvaGenericSupervisorAccess ; 0x40
or rdx, 31h ; = 0x71
The kill happens at 0x140064960. Because my --X pages force Hyper-V to deny reads, the ResultCode comes back as 5 (GpaNoReadAccess), leading straight to a SkpgBugCheck. Even if you get past that, there is a second check at 0x140064996 that validates access rights. My --X setup returns 4, which fails because it requires 5 (R-X) or 6 (RWX).
Once that happens, VTL1 self-destructs, freezes all CPUs, kills timers, and overwrites VTL0 RIP to KeBugCheckEx(0x18B). Hvix64.exe hypercall 0x52 performs a software EPT walk reading the same page table pages as the VMCS EPTP, which is why my EPT modifications are getting flagged.
I also mapped out that VTL1 gets scheduled in four ways, not just through explicit VTL calls:
- Hypercall 0x11: Standard VTL call.
- Synthetic Timer: Expiry at sub_FFFFF8000020F180.
- Secure Interrupts: Delivery via sub_FFFFF800002BA524.
- VMExit Piggybacking: Dispatch loop at 0x2168BA checks pending VTL1 events after every exit.
Hypercall 135 crashdump is a one-way street; once triggered, VPs spin in a barrier and time out, causing a secondary bugcheck.
Has anyone dealt with this from a nested position? I am debating hooking HvSetEptPointer in hvix64 as the only viable choke point for all EPTP writes. Or are we looking at forcing writes into the VTL scheduler 0 to keep parity? Drop your thoughts if you've been reversing this lately.