Windows draws a hard line between ring 3 and ring 0, and that line is asymmetric by design. Ring 0 code sees every page of every ring 3 process. Ring 3 code, even code running inside a signed anti-cheat service, cannot read so much as a byte of kernel memory without asking the kernel through a syscall the kernel is free to lie about. That asymmetry is the entire mechanical reason a well-written kernel cheat bypass anti cheat scheme works against a user-mode anti-cheat, and it is the reason every serious anti-cheat vendor shipped their own driver years ago.
This post walks through the exact primitives a ring 0 cheat uses, why the reads it performs are essentially invisible to a ring 3 observer, what changed in Windows 11 24H2 that killed a whole category of shortcut, and what user-mode anti-cheats can still reasonably expect to catch. It is not an operational guide. There is no driver-loading trick or vulnerable-driver name here, because the interesting question is architectural, not operational.
The privilege inversion at the heart of Windows security
The x86-64 privilege ring model is straightforward on paper: CPL 0 is the kernel, CPL 3 is everything else, and the transitions between them go through a small set of hardware-defined gates (SYSCALL, IRET, interrupts, exceptions). What people forget is how one-sided the visibility rules are.
At CPL 0 the CPU respects the page tables the kernel itself set up, and the kernel is the process that set them up. It can walk PsActiveProcessHead and enumerate every EPROCESS, hand its own CR3 to a mapper routine, or KeStackAttachProcess into any target address space it chooses. The CR0.WP bit that stops kernel code from writing user read-only pages is a bit the kernel owns. There is no ring above ring 0 asking Windows for permission (the hypervisor changes that story on VBS boxes, and we will get there).
At CPL 3, a process sees the tiny keyhole of its own virtual address space, plus whatever handles the kernel has been kind enough to give it. NtReadVirtualMemory on another process requires PROCESS_VM_READ on a handle that the kernel granted or refused. If a driver installed an ObRegisterCallbacks filter, that handle may have been stripped of PROCESS_VM_READ before the call ever returned:
// Anti-cheat driver, pre-operation callback
OB_PREOP_CALLBACK_STATUS PreOpen(
PVOID ctx, POB_PRE_OPERATION_INFORMATION info)
{
if (IsGameProcess(info->Object)) {
// Strip the ability to read game memory before the handle
// is even returned to the opener. Ring 3 sees a valid HANDLE
// and an ACCESS_DENIED on every subsequent NtReadVirtualMemory.
info->Parameters->CreateHandleInformation.DesiredAccess
&= ~PROCESS_VM_READ;
}
return OB_PREOP_SUCCESS;
}
From ring 3 you cannot tell the difference between "no such process" and "the kernel is hiding this process from you."
That is the ring 0 cheat / ring 3 anti-cheat asymmetry. The kernel driver has full read of the game's address space by default. The user-mode anti-cheat has read of the kernel by permission only, and the permissions it needs to detect a kernel driver bypass eac scheme are exactly the permissions the kernel does not hand out.
How a ring 0 cheat reads game memory
The mechanical core of almost every kernel reader is two documented Windows APIs. First, resolve the target process by PID:
PEPROCESS gameProcess = nullptr;
NTSTATUS status = PsLookupProcessByProcessId(
(HANDLE)gamePid,
&gameProcess);
if (!NT_SUCCESS(status)) return status;
// gameProcess now holds a referenced pointer to the game's EPROCESS
PsLookupProcessByProcessId returns a referenced pointer to the target's EPROCESS. There is no handle, no ACL, and no PROCESS_VM_READ check. It is a kernel-only export that takes a PID and hands you the kernel object. ObDereferenceObject releases the reference when you are done.
Then read the memory:
SIZE_T bytesTransferred = 0;
uint64_t viewMatrix[16];
status = MmCopyVirtualMemory(
gameProcess, // source: game's EPROCESS
(PVOID)0x7FF6B4C2A000, // source VA in the game
IoGetCurrentProcess(), // destination: our driver's process
&viewMatrix, // destination buffer in system space
sizeof(viewMatrix),
KernelMode, // <-- this is the important part
&bytesTransferred);
The last mode argument is the entire trick. MmCopyVirtualMemory performs its address probes in the requested mode. Passing KernelMode tells the routine to skip the probes that would normally reject a user pointer with the wrong permissions. The routine attaches to the source process, resolves the VA through that process's page tables, copies the bytes into your driver's buffer, detaches, and returns. There is no notification anywhere in ring 3 that this happened. The game's page tables were not modified. The game's threads were not suspended. No handle was ever opened against the game process, so any ObRegisterCallbacks filter installed by an anti-cheat driver never fires.
An mmcopyvirtualmemory cheat that only reads (positions, view matrix, entity lists, bone arrays) leaves no ring 3 artifact at all. The game code that computed those values does not run any differently after the read. From the game's perspective, and from any user-mode anti-cheat sharing that perspective, nothing happened.
Why reads are silent and writes are loud
The temptation is always to write. Aimbots need to steer the crosshair; ESP boxes want to hook the renderer; wall-hacks want to disable occlusion tests. A driver that writes into game memory picks up an entirely different threat profile from one that only reads.
Modern engines hash their own .text sections. Some do it on a timer inside a worker thread; some do it inline before hot code paths run; a few use hardware performance counters to notice unexpected branches. Any driver that patches a game function to inject aim logic is racing that hash. Even if the anti-cheat driver is not looking, the game's own integrity code will trip on a checksum mismatch minutes later, and the resulting telemetry ships home whenever the process next talks to the auth server.
Writes into kernel-owned code are worse. PatchGuard (KPP) rolls dice against the SSDT, MSR_LSTAR, the IDT, the KdDebuggerData block, and a growing set of other structures on random intervals measured in minutes. A driver that hooks NtReadVirtualMemory to hide a cheat process is signing its own bugcheck: KPP fires KERNEL_SECURITY_CHECK_FAILURE (STOP 0x139) or CRITICAL_STRUCTURE_CORRUPTION (STOP 0x109) on the next check pass, and the machine bluescreens with a stack that names the offending pointer.
This is why a well-designed ring 0 cheat is architecturally biased toward pure reads. It moves as much logic as possible into a user-mode overlay process (rendering ESP over the game window from an unrelated process, or over a second monitor) and only asks the kernel driver for the smallest set of primitives: read a struct, translate a coordinate, resolve a pointer chain. The overlay is loud but does nothing sensitive; the driver is quiet and does everything sensitive.
Driver Signature Enforcement and the signed-third-party-driver problem
None of the above helps if you cannot load your driver. 64-bit Windows has required DSE since Vista: a driver whose IMAGE_DIRECTORY_ENTRY_SECURITY block does not chain to a Microsoft-cross-signed leaf refuses to load. Since 2015 that leaf has to be an attestation-signed or WHQL-signed certificate issued through the Hardware Dev Center, tied to a real EV code-signing cert.
Test-signing mode exists (bcdedit /set testsigning on) but the resulting watermark on the desktop and the boot policy change is trivially fingerprinted, and any anti-cheat worth its salt refuses to run on a test-signed box.
For years the workaround was the signed-third-party-driver approach: find a legitimately signed driver with an exploitable primitive (arbitrary physical read, arbitrary MSR write, unchecked MmMapIoSpace, unfiltered IOCTL that takes a kernel pointer), install it, and use it as a signed foothold to do whatever you would have done with a homemade driver. Microsoft's response is the signed third-party driver Blocklist (DriverSiPolicy.p7b), enforced by the code integrity subsystem and updated with Windows Update. On a machine with HVCI enabled the blocklist is enforced by the hypervisor, which means the standard trick of writing to CI!g_CiOptions from ring 0 to disable enforcement no longer works, because that memory is guarded by SLAT permissions the hypervisor owns and the NT kernel does not.
The practical result is that a signed-third-party-driver chain on a modern HVCI-enabled Windows 11 box is fighting three separate layers: the blocklist itself, the SLAT-enforced code integrity policy, and the fact that even a successful load runs inside a VBS-hardened kernel where large chunks of the memory manager refuse to cooperate.
The Windows 11 24H2 wall: MiShowBadMapper
Windows 11 24H2 shipped a quiet but consequential change in MiShowBadMapper, the memory manager routine that vets MmMapIoSpace requests. On 24H2 kernels, requesting a MmNonCached alias of a physical range that overlaps a WriteBack-cached kernel page is refused outright. The routine bugchecks the offender with BAD_POOL_CALLER or ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, depending on how the caller misuses the returned pointer.
That single change killed a large class of signed-third-party-driver readers that had been shipping since the Windows 7 era. Their trick was to walk a target process's page tables from a signed driver's MmMapIoSpace primitive, then translate any user VA to a physical address and alias that physical page as NonCached in the driver's own virtual space. The alias let them read the game process without ever attaching to it and without ever touching a documented API that could be hooked by an anti-cheat.
On 23H2 and earlier the alias returned a valid pointer. On 24H2 the same call path bugchecks. The workaround is nontrivial because the entire attraction of the pattern was that it did not require a documented cross-process read; changing the caching type back to WriteBack (the only way MiShowBadMapper returns success on a WB-backed page) reintroduces the coherency and TLB issues the alias existed to solve. This is a real, easily-verifiable change in the 24H2 memory manager, and it is one of the reasons the manual mapped driver community has been unusually quiet since October 2024.
What ring 3 anti-cheats can theoretically detect
The list is short and it gets shorter every year.
| Signal | Reliability | Blocked by |
|---|---|---|
| SSDT / shadow SSDT hooks | Historically strong | PatchGuard (KPP) forbids these anyway |
MSR_LSTAR redirection |
Detectable via RDMSR from a driver |
KPP checks it every scan pass |
Unlinked EPROCESS in ActiveProcessLinks |
Real signal | Requires ring 0 to walk, so useless from ring 3 |
| Unsigned or test-signed drivers loaded | Trivial from ring 3 (EnumDeviceDrivers) |
Attacker rides a legitimately-signed third-party driver |
Handle enumeration showing PROCESS_VM_READ |
Fires on ring 3 cheats, not ring 0 | Kernel reads never open a handle |
| Timing anomalies (frame pacing, syscall latency) | Very weak; huge false-positive rate | Anything else on the box |
| ETW / kernel callback telemetry | Requires the AC to have a driver | If it has a driver, this is no longer user mode |
The honest read of this table is that a user-mode anti-cheat looking for a well-behaved kernel reader has almost nothing to work with. It can look at handles (the cheat did not open one), at modules loaded in the game process (the cheat is not loaded in the game process), at threads (the cheat has no thread in the game), and at API integrity in its own address space (the cheat did not touch it). Everything a ring 0 driver bypass eac scheme does happens in an address space the anti-cheat cannot see.
This is why the ring 0 versus ring 3 debate is not a preference, it is an architectural requirement. We covered the vendor-side of that argument in our user-mode vs kernel vs hybrid anti-cheat breakdown; this post is the attacker-side view of the same equation. KyTech's product line assumes the target is running a ring 0 anti-cheat, because on any competitive title in 2026 it is.
DMA hardware readers: a different threat model
The furthest end of the spectrum drops the driver entirely. A DMA setup is a second physical machine (the reader) connected to the target box over PCIe, usually via an FPGA card in an M.2 or PCIe slot. The FPGA presents itself to the target as an ordinary bus master device. Bus mastering means it can issue reads and writes to system memory without CPU involvement, so the target's OS never sees a driver load, a syscall, or a process open.
The reader machine runs an unrelated OS (usually Linux), parses the target's page tables out of physical memory, resolves the game's virtual addresses, and either overlays ESP on a second monitor or forwards mouse input through a hardware KMBox that speaks USB HID to the target. From the target's perspective there is no cheat; there is a PCIe card and a mouse.
The defense is the IOMMU. Intel VT-d and AMD-Vi were designed exactly to stop unauthorized DMA, and Windows 11's Kernel DMA Protection (enabled by default on machines that support it and expose it through firmware) restricts bus masters to a per-device address window until a driver explicitly maps memory into it. In practice, IOMMU coverage of internal PCIe slots is uneven; laptops with Thunderbolt tend to enforce it strictly, and desktop motherboards range from fully-enforcing to functionally-off depending on firmware and chipset generation. This is why the DMA scene tends to publish compatibility tables by motherboard SKU: they are effectively tracking which boards have IOMMU coverage a bus-master card can slip around.
For KyTech's purposes the DMA path is a separate product category with a separate risk profile. Every cheat we currently ship is a software kernel driver, not a hardware reader.
How KyTech handles this
KyTech was founded in 2025 by two engineers with backgrounds in Windows internals and reverse engineering. Every product we ship (kytech-apex, kytech-cs2, kytech-ow2, kytech-bo7, kytech-fh6, and kytech-roblox) uses a signed kernel driver to perform the read primitives described above.
The choice is architectural. A signed-third-party-driver chain looks cheap right up until the third-party driver hits the blocklist, at which point every customer's install breaks on the next Windows Update. A properly signed kernel driver survives the blocklist by construction, and on Windows 11 24H2 it survives the MiShowBadMapper change because it never needed the physical-memory-alias trick that change was designed to kill.
The user-facing consequence is that our drivers do not require test-signing mode, do not require disabling HVCI on machines that ship with it enabled, and do not require the customer to load a suspicious third-party driver alongside them. The internal consequence is that we spend significantly more engineering time on signing infrastructure and on staying inside the documented MmCopyVirtualMemory primitive than we would if we cut corners with a manual mapper.
The HWID spoofer that ships in beta with kytech-apex is the only place we currently touch anything close to system state, and it is deliberately scoped to Apex Legends until we have enough hardware coverage data to broaden it. Everything else is pure read primitives feeding a user-mode overlay, exactly the design the ring 0 / ring 3 asymmetry rewards.
If you understood this post, you are the reader we build for. KyTech Apex is the flagship of this ring 0 driver architecture in production, and the reference every other title in the lineup inherits its read primitives from. Product listings and current stock are at /purchase.
Enough theory. get in.
The loader is one click away. Ring-0 kernel driver, polymorphic per download, memory-only injection. Six games across VAC, EAC, Ricochet, Byfron, and Warden.
Get in ›