- Status
- Offline
- Joined
- Mar 3, 2026
- Messages
- 142
- Reaction score
- 7
Spent the last few weeks buried in IDA Pro reversing securekernel.exe, ntoskrnl, and hvix64.exe to figure out why HyperGuard is nuking my setup with 0x18B after a few hours. Since there is basically zero public info on this, figured I would drop my findings for those of you trying to survive inside a nested position.
My current setup is a Type-1 HV parasitic inside Hyper-V with a dual-CR3 EPT split. I have the hyperv_CR3 holding shadow pages with --X (execute only), while the hook_CR3 is a deep copy with originals RW-. Currently, reads trigger an EPT violation, and my handler switches to the hook_CR3 to return clean bytes. It works against EAC, but HyperGuard is clearly running checks I haven't fully accounted for.
The 0x18B crash happens via this chain:
The issue is the flags, which are always 0x71 (ValidateRead | SetPTBits | FlushInhibit | Supervisor). At 0x14006485b, it's explicitly checking for supervisor access. Because my shadow pages are --X, the hypercall returns GPA_NO_READ_ACCESS, which triggers the bugcheck. Even if I passed that, there is a second check at 0x140064996 where it expects access rights 5 (R-X) or 6 (RWX). My --X pages return 4, failing the check and causing VTL1 to self-destruct, freeze all CPUs, and force a KeBugCheckEx.
Found that VTL1 scheduling isn't just standard VTL calls; it's handled through:
The hypercall 135 crashdump is a one-way gate, and I haven't found a way to recover once it triggers.
Has anyone here dealt with this from a nested position? I am currently leaning toward hooking HvSetEptPointer in hvix64 as the only reliable choke point for all EPTP writes. Alternatively, considering forcing writes in the VTL scheduler 0.
Anyone else doing deep-dive research into HyperGuard internals? Interested to see if anyone has a cleaner way to handle the GPA access rights without flagging the monitor. Drop your thoughts below.
My current setup is a Type-1 HV parasitic inside Hyper-V with a dual-CR3 EPT split. I have the hyperv_CR3 holding shadow pages with --X (execute only), while the hook_CR3 is a deep copy with originals RW-. Currently, reads trigger an EPT violation, and my handler switches to the hook_CR3 to return clean bytes. It works against EAC, but HyperGuard is clearly running checks I haven't fully accounted for.
The 0x18B crash happens via this chain:
- SkpgHyperguardTimerRoutine hits at a random interval.
- SkpgHyperguardRuntime (0x14000E884) kicks off the chain.
- SkpgVerifyExtents (0x14000F5A0) performs a round-robin over kernel module extents.
- SkpgVerifyMemoryExtent (0x14000EA94) calls SkpgTranslateVaWorker (0x1400645FC) to execute hypercall 0x52.
The issue is the flags, which are always 0x71 (ValidateRead | SetPTBits | FlushInhibit | Supervisor). At 0x14006485b, it's explicitly checking for supervisor access. Because my shadow pages are --X, the hypercall returns GPA_NO_READ_ACCESS, which triggers the bugcheck. Even if I passed that, there is a second check at 0x140064996 where it expects access rights 5 (R-X) or 6 (RWX). My --X pages return 4, failing the check and causing VTL1 to self-destruct, freeze all CPUs, and force a KeBugCheckEx.
Found that VTL1 scheduling isn't just standard VTL calls; it's handled through:
- Explicit hypercall 0x11.
- Synthetic timer expiry.
- Secure interrupt delivery.
- VMExit piggybacking (dispatch loop at 0x2168BA checks VTL1 events after every exit).
The hypercall 135 crashdump is a one-way gate, and I haven't found a way to recover once it triggers.
Has anyone here dealt with this from a nested position? I am currently leaning toward hooking HvSetEptPointer in hvix64 as the only reliable choke point for all EPTP writes. Alternatively, considering forcing writes in the VTL scheduler 0.
Anyone else doing deep-dive research into HyperGuard internals? Interested to see if anyone has a cleaner way to handle the GPA access rights without flagging the monitor. Drop your thoughts below.