Skip to main content

Command Palette

Search for a command to run...

At the Root of Trust: Kernel Anti-Cheats

A deep dive into kernel level anti-cheats and how to build them

Updated
At the Root of Trust: Kernel Anti-Cheats

What are Anti-Cheats

An anti-cheat is a piece of software designed to prevent users from cheating in games, particularly online games. It’s an essential component of most games these days to keep the playing field even and as fair as possible.

If you've ever wondered why a game like Valorant boots up with a driver or why Easy Anti-Cheat nags you at launch, you’re in the right place. In this article we’ll do a deep dive into how modern kernel level anti-cheats work, what kernel-mode actually means, and why some of these drivers are indistinguishable from rootkits.

Rings of Trust: Kernel vs User Mode

Before we get into cheat detection, we need to first get clear about privilege levels on your system. On x86 processors, the CPU operates in "rings". Ring 3 is where regular user-mode applications run — they don’t get direct hardware access but rather must rely on system calls. Ring 0, the kernel, has full privileges to interact with memory, devices, and other hardware resources.

The kernel is what sits at the core of your OS, acting as the central interface between hardware and software applications.

Anti-cheat drivers work at Ring 0 because that’s where most of the cheats now live. A user-mode anti-cheat running in Ring 3 can’t effectively monitor or block a cheat operating at Ring 0.

Cheat developers eventually started exploiting vulnerable drivers and abusing legitimate but poorly secured driver interfaces to gain kernel access. Some of these techniques even involve writing your own unsigned drivers and then using techniques like Driver Signature Enforcement (DSE) bypass, Test Signing Mode abuse, or vulnerable driver mapping (via tools like KDMapper) to load them without detection.

Why Kernel Anti-Cheats Exist

As cheats started to evolve beyond just simple DLL injection or memory patching, it became clear to anti-cheat developers that they need to up the ante too. Let’s briefly go over what a more advanced cheat might use.

  • Manual Driver Mapping: This bypasses the windows driver loader, which normally verifies driver signatures. A manually parsed PE file of the .sys driver is copied directly into kernel space, resolving imports and relocations yourself and jumping directly into the driver’s DriverEntry. Since this isn’t loaded by the OS “officially”, it won’t be listed under the NtQuerySystemInformation.

  • Syscall Hooking: System calls are the lowest-level interface between user mode and the kernel. By using techniques SSDT or trampoline hooking, you can intercept and alter system calls to hide handles and block anti-cheat scans entirely.

  • Direct Kernel Object Manipulation (DKOM): The windows kernel has numerous data structures that tell us what’s running and what kind of access it has.

    • _EPROCESS: Represents the actual process in memory

    • _ETHREAD: Represents the actual thread in memory

    • ActiveProcessLinks: A doubly linked list of currently active processes

    • _TOKEN: An object that holds key information for security

By manually editing these structures, cheats can acheive stealth or privilege escalation without triggering kernel APIs.

  • Page Table Entry (PTE) tampering: Paging is a memory management technique that divides processes into equal sized segments called pages and maps them to equal sized memory blocks called frames. A page table is essentially just a table holding page attributes like weather it’s writable or executable or present. Flipping the NX(non-executable) bit for example will turn a non-executable process into an executable one. This is a common technique to run shellcode or payloads in restricted pages.

  • VAD (Virtual Address Descriptor) Modification: VADs are kernel-mode structures that define the memory layout of a user-mode process. In windows, each process had it’s own VAD tree that tracks all its memory allocations. You can easily add new entries to this tree using VirtualAllocEx() + WriteProcessMemory(). However this is easily detectable. But you could tamper with the VADs to hide those memory regions completely (e.g., remove their VAD entry) or modify the permissions to make RWX memory look like RX or even NOACCESS or even Re-label memory to look like it’s backed by a file or part of a legitimate DLL. This is VAD tampering and it’s not easily detectable.

These methods are very difficult — if not impossible — to detect from user-mode. Hence, kernel-level anti-cheats had to step in.

Technical Breakdown: Key Kernel Detection Techniques

Let’s dive a bit deeper into these detection techniques.

ObRegisterCallbacks

The Windows kernel exposes ObRegisterCallbacks to allow kernel modules to register callbacks for process/thread handle creation or duplication. Anti-cheats can use this to:

  • Prevent debuggers and suspicious processes from accessing the game.

  • Monitor the creation of high-privilege handles to the game process (like PROCESS_VM_READ/WRITE for example).

  • Deny any suspicious access patterns that show up (e.g., a random process requesting PROCESS_ALL_ACCESS).

The callbacks could also check the calling PID and apply rules such as whitelisting trusted PIDs or limiting cross-process access.

MmCopyMemory

MmCopyMemory is a pretty secure way to copy memory across processes in kernel mode. It basically avoids common exceptions that are raised by user-mode anti-debug checks. Anti-cheats use this to scan target process memory, compare hash digests, detect known byte signatures, or look for shellcode patterns (like NOP sleds, call stubs, etc.).

Handle Table Validation

Using ZwQuerySystemInformation (with SystemHandleInformation), anti-cheats enumerate system-wide handles and validate whether suspicious processes have:

  • Unexpected access rights.

  • Duplicate handles to protected processes.

  • Handle spoofing artifacts (e.g., ghost handles not linked to valid PIDs).

Memory Integrity Checks

A hypervisor is a low-level virtual machine monitor that can be used to validate code as it’s being loaded to prevent execution from modified pages or ones that are not properly signed. It can also:This is an effective way to block out any cheats that use manual driver mapping as mentioned above. However, this does not account for cheats that use vulnerabilities in verified and signed drivers that are already present in your system.

The most famous case came a few years ago when a malicious actor used a vulnerable driver, the anti cheat used by Genshin Impact to get escalated privileges.

Riot’s Vanguard

Vanguard’s driver (vgk.sys) loads at boot and is signed with Microsoft’s kernel signing certificate via the WHQL process. It:

  • Hooks early system initialization routines to gain a privileged execution context.

  • Implements secure callbacks to prevent even the earliest driver loads from being malicious.

  • Monitors the PCI bus for DMA devices and unrecognized hardware.

  • Performs PE section hashing, NT header validation, and cross-verification of memory with disk images.

  • Implements live process memory validation using checksum-based comparisons.

Additionally, it monitors IRP_MJ_CREATE and IRP_MJ_DEVICE_CONTROL for IOCTL abuse and device access from ring-3 malware. Vanguard is designed to be persistent, preemptive, and capable of self-healing (via reboot-triggered reinstalls).

BattlEye: Adaptive Kernel Protection

BattlEye is the anti-cheat used by PUBG. dynamically adapts its behavior based on the game and environment. It utilizes a lightweight hypervisor layer built on virtualization technologies such as Intel VT-x or AMD-V to watch page access and memory execution flows while at the same time capturing kernel call stacks and return addresses to detect rogue drivers.

At the core of BattlEye’s protection is its ability to monitor kernel-level operations with precision. The system can capture kernel call stacks and examines return addresses to identify rogue drivers that might attempt to manipulate game processes. By maintaining a detailed view of kernel activities, BattlEye can pinpoint anomalies that suggest the presence of malicious drivers designed to bypass game security

Thread injection is a common technique used by cheats to insert malicious code into a game’s process. Battleye’s system tracks the use of functions like NtCreateThreadEx, which can create new threads in a target process, and monitors remote Asynchronous Procedure Call (APC) queues, which can be exploited to execute code covertly. By closely observing these mechanisms, BattlEye ensures that unauthorized code execution is detected and blocked before it can compromise the game environment

BattlEye also frequently hashes memory sections, walk module lists manually (bypassing LdrLoadDll), and even tracks floating point state to catch silent aimbots.

Building Your Own Kernel Anti-Cheat

1. Write a KMDF Driver (.sys)

Use the Windows Driver Kit (WDK) and KMDF (Kernel-Mode Driver Framework).

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    UNREFERENCED_PARAMETER(RegistryPath);
    DriverObject->DriverUnload = DriverUnload;
    // Register callbacks and hooks here
    return STATUS_SUCCESS;
}

2. Filter Handle Access: ObRegisterCallbacks

Monitor and block handle access to processes, threads, etc. The goal here is to block any other process (like a cheat engine) from opening handles to your game process with dangerous permissions.

OB_CALLBACK_REGISTRATION obReg = { 0 };
OB_OPERATION_REGISTRATION opReg = { 0 };

opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opReg.PreOperation = MyPreOpCallback;
opReg.PostOperation = MyPostOpCallback;

obReg.OperationRegistrationCount = 1;
obReg.OperationRegistration = &opReg;
obReg.RegistrationContext = NULL;
obReg.Version = OB_FLT_REGISTRATION_VERSION;

ObRegisterCallbacks(&obReg, &g_ObHandle);

The above code registers a callback (ObRegisterCallbacks) that will be called every time a handle to a process or thread is created or duplicated.

OB_PREOP_CALLBACK_STATUS MyPreOpCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info) {
    UNREFERENCED_PARAMETER(RegistrationContext);

    if (Info->ObjectType == *PsProcessType) {
        HANDLE pid = PsGetProcessId((PEPROCESS)Info->Object);
        if (pid == g_GamePID && Info->Operation == OB_OPERATION_HANDLE_CREATE) {
            Info->Parameters->CreateHandleInformation.OriginalDesiredAccess &= ~(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION);
        }
    }

    return OB_PREOP_SUCCESS;
}

MyPreOpCallback inspects the handle request and strips away any permissions if it's targeting your game process (g_GamePID).

3. Scan Memory from Kernel Space

Use MmCopyMemory to read user-mode memory to do basic signature scanning or behavior scanning.

MM_COPY_ADDRESS source = { 0 };
source.VirtualAddress = (PVOID)target_address;

SIZE_T bytesRead = 0;
UCHAR buffer[64] = { 0 };

NTSTATUS status = MmCopyMemory(buffer, source, sizeof(buffer), MM_COPY_MEMORY_VIRTUAL, &bytesRead);

4. Detect Loaded Drivers: PsSetLoadImageNotifyRoutine

Track .sys file loading and verify against whitelists or digital signatures. This helps detect kernel-mode cheats trying to sneak in silently. You could compare each new driver against a whitelist or calculate a hash and check against known malicious ones.

VOID ImageLoadCallback(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo) {
    if (ImageInfo->SystemModeImage && FullImageName) {
        DbgPrint("Loaded: %wZ | Base: %p\n", FullImageName, ImageInfo->ImageBase);
        // Check against whitelist or signature database
    }
}

PsSetLoadImageNotifyRoutine(ImageLoadCallback);

5. Track Kernel Threads: PsSetCreateThreadNotifyRoutine

Detect suspicious kernel-mode threads:

VOID CreateThreadNotify(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN Create) {
    if (Create) {
        DbgPrint("Thread Created: PID %d TID %d\n", (int)(ULONG_PTR)ProcessId, (int)(ULONG_PTR)ThreadId);
    }
}

PsSetCreateThreadNotifyRoutine(CreateThreadNotify);

You could either flag it or kill it.

6. Generate a Unique HWID

This is to create a consistent fingerprint for a user’s physical machine. Use BIOS UUID, CPU ID, MAC address, and disk serials that can be used to track Identify players uniquely, even if they create new accounts, Detect ban evasion, by recognizing the same machine under different user accounts.

User-mode BIOS UUID (via WMI):

IEnumWbemClassObject* pEnumerator = NULL;
pSvc->ExecQuery(L"WQL", L"SELECT UUID FROM Win32_ComputerSystemProduct", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator);

Kernel-mode disk serials would require sending IOCTLs.

Finally hash all the components to generate the HWID (e.g., SHA-256).

7. Telemetry + Secure Upload

Batch collected data and send it over HTTPS:

[Driver] --> [User-mode Helper] --> [HTTPS POST JSON to API]

Use WinHttpSendRequest or libcurl to securely transmit data.

8. Self-Protection Measures

Basic measures against detection or tampering of your driver.

  • Driver Hiding: Unlink from PsLoadedModuleList ( it’s pretty unstable and unsafe).

  • Integrity Checks: Shadow copies, verify memory contents periodically.

  • Watchdog Threads: Background kernel threads that constantly re-check memory, handle access, and driver integrity.

void WatchdogThread(PVOID Context) {
    while (TRUE) {
        // Recheck memory signatures, driver list, etc.
        LARGE_INTEGER interval;
        interval.QuadPart = -10 * 1000 * 1000; // 1 second
        KeDelayExecutionThread(KernelMode, FALSE, &interval);
    }
}

Denuvo: The Anti-Tamper Fortress

Denuvo is not technically an anti-cheat but rather an Anti-Tamper protection used to prevent cracks, piracy, and reverse engineering of PC games. It’s a runtime protection system — meaning it protects the application while it is running, not just through static encryption.

The first thing it does is Executable Encryption and Obfuscation. Meaning the original game executable is first encrypted and obfuscated. During runtime Denuvo decrypts and loads small sections of the code dynamically, usually right before they’re needed. This kind of decryption makes static analysis or dumping the whole exe extremely hard. If you try to dump the running game from memory (e.g., with Scylla or PE-sieve), the dump is either Incomplete or Corrupted or missing decrypted sections.

Another major step is Code Virtualization & Mutation. This transforms critical functions into virtual opcodes that run on Denuvo’s own custom VMs**,** which themselves use a non-standard instruction set allowing it to “mutate” the function every time you run the game. So even if you reverse one part of the code, the next part might look completely different**.**

The next layer of tamper proofing comes from Anti-Debugging techniques like detection of debuggers and crashing, timing checks to detect breakpoints, interrupt hooking, detection of hardware breakpoints etc. If Denuvo notices any tampering, it may silently crash the game later — making debugging frustrating. Alongside this, it also performs integrity checks on it’s own binary, game memory and the code flow to patches.

What Kernel Anti-Cheats Can’t Stop

  • AI Aim Assist Tools: These use an external camera and object detection models (YOLO, OpenCV) to recognize enemies and move the mouse. To the system, they behave like a regular mouse input.

  • Stream-Proof ESPs: Render overlays on a second monitor or use HDMI intercepts. Nothing is injected into the game.

  • UEFI Rootkits: Modify BIOS/firmware to inject persistent drivers before the OS boots. Nearly invisible without forensic tools.

  • AI-driven Human-like Bots: Simulate player inputs with enough variability to evade statistical detection.

Conclusion: Anti-Cheats Are Basically Rootkits in Suits

The next time a game loads a kernel driver, remember: it’s not paranoia — it’s protection. It’s a technical arms race where both sides are using every tool available. Whether it’s hooking system callbacks, scanning virtual memory, or detecting rogue PCIe traffic, anti-cheats today operate on a level that tracks basically everything about your system which is why they’re so controversial. As for weather they’re really worth the risk, it’s up to you to decide.

Artemis

Part 1 of 12

The May '25 series marks our first public showcase—an inside look at the ideas, experiments, and projects we're building. These blogs are dense, thoughtful, and a signal to the world: NTL is here, and we’re just getting started.

Up next

Host discovery and port scanning through Network-Mapper (Nmap)

Basic guide to mapping network infrastructure