Context
The traditional arms race between kernel-mode cheat drivers and anti-cheat detection agents is fundamentally constrained by the x64 privilege model. Once an untrusted driver executes at Ring 0, client-side software verification cannot provide absolute guarantees. Both parties operate at the same privilege level, and the attacker has equal access to the same hooks, callbacks, and memory the defender relies on.
The industry response to this ceiling has been to move security enforcement below Ring 0 entirely, leveraging hardware-enforced isolation boundaries: HVCI, TPM 2.0, Secure Boot, and critically for this post, the IOMMU. This is the shift that makes Direct Memory Access (DMA) hardware cheats an interesting problem.
DMA cheats have evolved significantly. The original generation of PCIe cards were detectable through firmware signatures and PCIe configuration space analysis. Anti-cheat systems across the industry have implemented firmware detection pipelines to address this. In response, the attack surface evolved again, modern DMA implementations emulate legitimate virtual filesystems to appear as real disk devices, or go further and use real NVMe controllers into their DMA cards as a MITM, bypassing any runtime filesystem checks. At this point, detection becomes an arms race with no clear winner. The correct response is to stop trying to detect and start preventing access altogether!
This post traces the exact mechanism Windows provides for doing exactly that, stripping a PCIe device's IOMMU page table access to specific physical memory regions, enforced entirely in silicon. Every function address and behaviour described here was verified through static analysis of a Windows 10 system image. This research was done primarily to develop a deeper understanding of DMA as a domain, and to build the foundational knowledge needed to reverse device firmware in the future, as firmware analysis is increasingly relevant to understanding how modern DMA implementations operate below the OS.
Why SATA/NVMe Firmware is Popular
Before tracing how the prevention mechanism works, it is worth understanding why DMA-based memory reading, specifically for SATA/NVMe firmware still functions on most systems with IOMMU enabled.
Having IOMMU enabled in the BIOS does not mean Windows uses it to restrict device memory access. The feature that actually sets up IOMMU page tables in a restrictive way is Kernel DMA Protection. When KDP is active and a new PCIe device is enumerated, Windows attempts to bind a driver to it. If the driver declares support for DMA remapping, it loads normally and cooperates with the OS to declare exactly which physical memory ranges it needs access to. The IOMMU page tables for that device are then populated to allow only those specific ranges. If the driver does not declare remapping support, the device is either restricted or the load is refused entirely.
The critical word is "if". Not all drivers support DMA remapping as requiring it universally would break compatibility with a large portion of the device ecosystem, so enforcement is selective. This is the gap that firmware-based DMA cheats exploit. A device spoofing an NVMe SSD will trigger the inbox Microsoft storage driver, which does support DMA remapping. The IOMMU page tables will be populated to allow only what a legitimate storage device needs, which does not include game process memory. However, if the firmware spoof is imperfect or the driver binding does not occur as expected, the device may end up in an unrestricted domain with broad physical memory access.
The Secure Kernel Bridge
When the operating system decides to unmap a DMA device from a physical memory region, the request originates not from ntoskrnl but from the Secure Kernel, which manages Virtual Trust Level 1. Normal kernel code cannot perform this operation directly. The teardown entry point, recoverable from the Secure Kernel's public PDB symbols, is SkhalpDmaDeleteMapping.
void __fastcall SkhalpDmaDeleteMapping(__int64 *BugCheckParameter4)
{
__int64 v1 = *BugCheckParameter4;
if ( *BugCheckParameter4 )
{
ULONG_PTR BugCheckParameter2;
LODWORD(BugCheckParameter2) = *((_DWORD *)BugCheckParameter4 + 6);
int result = ShvlUnmapDeviceGpaPages(
*(_QWORD *)(v1 + 24),
BugCheckParameter4[2],
(unsigned int *)&BugCheckParameter2);
if ( result < 0 ||
(_DWORD)BugCheckParameter2 != *((_DWORD *)BugCheckParameter4 + 6) )
{
SkeBugCheckEx(0x121u, result, ...);
}
SkhalpLaDelete(v1 + 48, BugCheckParameter4[2]);
SkFreePool(512, BugCheckParameter4[4]);
SkobpDereferenceObject(BugCheckParameter4[1] - 32);
SkobpDereferenceObject(*BugCheckParameter4 - 32);
}
}
The critical call is ShvlUnmapDeviceGpaPages. If the hypercall returns an error or the page count does not match, the system bug checks immediately. The OS treats a failed DMA unmap as a fatal condition.
ShvlUnmapDeviceGpaPages is implemented as a retry loop:
__int64 __fastcall ShvlUnmapDeviceGpaPages(__int64 a1, __int64 a2, unsigned int *p_PageCount)
{
unsigned int PageCount = *p_PageCount;
unsigned int completed = 0;
unsigned int n4095 = 4095;
_QWORD input[4];
input[0] = -1;
input[1] = 0;
input[2] = a1;
do
{
if ( !PageCount ) break;
input[3] = a2;
if ( n4095 <= PageCount ) PageCount = n4095;
n4095 = PageCount;
int status = ShvlpInitiateFastHypercall(
180, (unsigned int)input, 32, PageCount, &v10, 0, 0);
completed += v10;
PageCount = *p_PageCount - v10;
a2 += (unsigned int)(v10 << 12);
*p_PageCount = PageCount;
}
while ( status >= 0 );
*p_PageCount = completed;
return (unsigned int)status;
}
The loop exists to handle preemption. If the hypervisor exceeds its time quota mid-operation, it returns HV_STATUS_TIMEOUT (0x1016). The Secure Kernel resumes from the last completed page on the next iteration. Hypercall 180 (0xB4) is HvCallUnmapDeviceGpaPages, part of the Hyper-V device domain family:
| Code | Hypercall |
|---|---|
| 0xB1 | HvCallCreateDeviceDomain |
| 0xB2 | HvCallAttachDeviceDomain |
| 0xB3 | HvCallMapDeviceGpaPages |
| 0xB4 | HvCallUnmapDeviceGpaPages |
One architectural detail worth making explicit here: when Hyper-V is active, these hypercalls map IOVAs (I/O Virtual Addresses) to GPAs (Guest Physical Addresses), not HPAs (Host Physical Addresses). The only constraint Hyper-V enforces unconditionally is that no device can ever be mapped to hypervisor memory (HPAs belonging to the hypervisor itself, the Secure Kernel, and related VTL1 structures). All other GPA mappings are under kernel control and can be set, modified, or cleared by any kernel-mode driver with access to the appropriate APIs, including anti-cheat drivers.
Locating the Dispatch Table in hvix64.exe
Microsoft does not provide public symbols for hvix64.exe. Hyper-V dispatches hypercalls via a global table in the CONST section, indexed by hypercall code. Each entry is an 0x18-byte structure containing a function pointer followed by a metadata field encoding the hypercall ID and flags.
The sibling hypercall 0xB3 (HvCallMapDeviceGpaPages) leaves a debug string in the binary:
.rdata:FFFFF80000407304 "Failed to map device domain page"
Tracing the reference chain from this string upward through the call hierarchy leads to the 0xB3 dispatch table entry:
CONST:FFFFF80000C010C8 dq offset <HvCallMapDeviceGpaPages handler>
The 0xB4 entry follows immediately at +0x18:
CONST:FFFFF80000C010E0 dq offset sub_FFFFF8000028FA80 ; HvCallUnmapDeviceGpaPages
CONST:FFFFF80000C010E8 dq 20000100B4h ; metadata: ID=0xB4
sub_FFFFF8000028FA80 is the verified entry point for HvCallUnmapDeviceGpaPages in this build.
The Handler Internals
The dispatch handler validates the hypercall input, acquires a reference on the device domain object, and locates the GPA mapping context before delegating to the outer unmap loop. The outer loop handles the page range with alignment validation, bounds checking, and a preemption check via rdtsc comparison against a time quota.
The per-page unmap operation clears the page table entry and flushes the IOTLB. Two implementation details are worth noting. First, the preemption mechanism is why the Secure Kernel's retry loop exists: the hypervisor can abort partway through a large unmap operation and report how many pages it completed. Second, the loop advances by either 4096 bytes or 2097152 bytes depending on a flag returned by the per-page function, meaning the hypervisor natively handles both standard 4KB pages and 2MB huge pages.
The Bare Metal Path: Direct HAL Manipulation
Although most modern anti-cheat deployments require HVCI and therefore operate in a Hyper-V environment, the IOMMU manipulation stack also has a complete bare metal path that bypasses the hypervisor entirely. This is relevant both for understanding the full architecture and for systems where Hyper-V is not active.
The HAL function HalpIommuDomainUnmapLogicalRange acts as the abstraction layer that selects between the two paths at runtime:
__int64 __fastcall HalpIommuDomainUnmapLogicalRange(
ULONG_PTR domainCtx,
ULONG_PTR targetAddr,
unsigned __int64 *size,
char remap)
{
if ( HalpHvIommu ) // is a Hyper-V IOMMU active?
{
if ( !HalpHvIommuDeviceDomain )
return STATUS_UNSUCCESSFUL;
// This is the 0xB4 path we traced above
BugCheckParameter2 = IommupHvMapDeviceLogicalRange(...);
}
else
{
HalpIommuUnmapLogicalRange(*(_QWORD *)(domainCtx + 24), size, targetAddr);
// Flush TLB in chunks of 1024 pages after clearing entries
while ( pageCount )
{
chunk = min(pageCount, 1024);
HalpIommuFlushDmaDomain(domainCtx, ...);
pageCount -= chunk;
addr += chunk << 12;
}
}
}
When running without Hyper-V, HalpIommuUnmapLogicalRange performs the actual page table manipulation directly in memory:
// zero out IOMMU page table structure to the target entries
memset(v17, 0, Size);
// flush CPU cache lines to ensure the hardware sees the zeroes
if ( !HalpIommuPageTableCacheCoherent )
KeInvalidateRangeAllCachesNoIpi(v17, Size);
KeInvalidateRangeAllCachesNoIpi issues a flush across the modified address range, or falls back to a full cache invalidation if the range exceeds the largest cache size. This is necessary because the IOMMU reads its page tables from memory, and without an explicit flush the CPU cache may still hold the old valid translations while the hardware sees stale data.
The result is identical to the hypervisor path: page table entries zeroed, translations invalidated, subsequent DMA transactions to those addresses blocked at the silicon level. The difference is only in who performs the operation and through what interface.
Hardware Enforcement
When the page table entries are cleared and the IOTLB or CPU cache is flushed, any subsequent read or write by the PCIe device to those addresses is blocked at the silicon level. The IOMMU hardware intercepts the transaction before it reaches RAM. The device receives a PCIe Unsupported Request or Completer Abort response, reads return 0xFF, and the IOMMU logs a translation fault that can be queried through hardware registers.
This enforcement is performed by the motherboard's memory controller and is completely outside the control of the PCIe device. No firmware modification on the card itself can bypass it, because the restriction is imposed by hardware the card does not own or communicate with directly. A device spoofing an NVMe SSD is still subject to an IOMMU whose page tables say it cannot read a given address range.
Dynamic Shielding as the Answer to Firmware DMA
This research was revisited following a Vanguard update pushed recently that appears to involve changes to how DMA device access is handled as devices are seemingly revoked access for the whole session, or even the whole boot? Most stuff online has been speculations such as them bricking hardware, so I cannot give my full view on this. The exact mechanism Vanguard uses is not confirmed by me personally, but it seems like some form of device remapping is being applied. Whether they invoke HvCallUnmapDeviceGpaPages directly or reach the same hardware outcome through a different path is an open question. The reason I haven't confirmed it myself, is that Vanguard is not currently my focus and is not the point of this blog whatsoever.
The correct approach to verify this would be to hook HvlInvokeHypercall and observe whether hypercall code 0xB4 appears during game initialisation. If Vanguard routes through an alternative mechanism rather than the standard kernel export, no 0xB4 traffic would show up at that hook site and further analysis of their driver would be needed.
No commercial anti-cheat is currently confirmed to be using runtime dynamic unmapping on a per-region basis, of which I will not name the one's that I have confirmed it on. However, cheaters can and have confirmed this themselves by simply testing their firmware. The infrastructure to do so already exists. The Windows kernel exports HvlInvokeHypercall, accessible from a kernel-mode driver. A driver could call HvCallUnmapDeviceGpaPages dynamically to strip IOMMU access to specific physical pages at runtime. The correct scope for this is the memory regions that matter most, like for an Unreal Engine title, restricting access to the pages backing UWorld should be sufficient to blind a DMA cheat entirely. The system pagefile and filesystem pages remain untouched, so there is no stability risk.
This approach directly addresses the firmware evolution problem. A DMA device using a real NVMe controller with modified firmware is still subject to IOMMU enforcement, and it does not matter how legitimate the device appears in PCIe configuration space, what filesystem it exposes, or what driver the OS loads for it. The IOMMU page table is managed either by the hypervisor at VTL1 or by the HAL directly on bare metal, and neither is accessible to code running on the PCIe bus.
Detection has been losing this race for several years, but page isolation is how prevention wins it.
Conclusion
The Hyper-V device domain hypercall family, implemented through the Secure Kernel and dispatched through the hypervisor, provides a hardware-enforced method for making physical memory regions inaccessible to PCIe devices at the IOMMU level. On bare metal systems without a hypervisor, the HAL achieves the same result through direct page table manipulation via HalpIommuUnmapLogicalRange, zeroing entries and issuing clflush to push the changes through to hardware. The HalpHvIommu global flag in the HAL selects between these two paths at runtime.
The current window in which firmware-spoofing DMA devices operate successfully exists because KDP enforcement is not yet universal. That window is closing as Microsoft extends mandatory remapping to more device classes. An anti-cheat that actively unmaps its game's physical pages from device domains does not need to wait for that process to complete. All that is left, is to prevent and detect local IOMMU workarounds.
Feel free to contact me if you wish to discuss this, or I made any errors as most of what I found here was actively learnt during the analysis.