Ever wondered how Cheat Engine works? (Extended)

This article is a deeper dive into how the Cheat Engine works behind the scenes. It builds on the previous article and focuses on more technical depth and what developers should be aware of.

By Tim Uhlott|Last updated: January 31, 2026|15 minutes read
game developmentcheat enginehacking
Ever wondered how Cheat Engine works? (Extended)
Cheat Engine is often introduced to developers through the lens of “game hacking,” but that framing undersells what it actually represents. At its core, Cheat Engine is a sophisticated Windows process-introspection framework that combines user-mode API usage, kernel-mode escalation, runtime metadata analysis, and even hardware-level virtualization. Understanding that provides a valuable case study in how applications are observed, modified, and controlled from outside their own trust boundary. This article breaks down how Cheat Engine works technically, and why those mechanisms are particularly effective against Unity games. The intent is not to teach exploitation, but to demystify the architecture so developers can better reason about debugging, tooling, performance, and security trade-offs in their own engines and projects.

Process Interrogation on Windows: Owning Another Address Space

Every memory manipulation workflow begins with one prerequisite: access to a target process’s virtual address space. On Windows, this is mediated by the Win32 API and enforced by the kernel’s object security model. The typical entry point is OpenProcess, which returns a handle representing the kernel’s authorization to interact with another process. What matters is not the function itself, but the access mask requested. Tools like Cheat Engine usually ask for combinations of:
  • PROCESS_VM_READ and PROCESS_VM_WRITE to copy memory across address spaces
  • PROCESS_VM_OPERATION to change page protections
  • PROCESS_QUERY_INFORMATION to enumerate threads, modules, and metadata
  • PROCESS_CREATE_THREAD for remote execution or DLL injection
Once granted, the handle becomes a capability token. Every subsequent operation like ReadProcessMemory, WriteProcessMemory, VirtualProtectEx is validated against it. From the kernel’s perspective, this is all legitimate behavior; Windows was explicitly designed to allow debuggers and profilers to do exactly this. The key architectural point is that no code runs “inside” the target process at this stage. The kernel temporarily maps the target’s physical pages into the scanner’s context during reads and writes, providing a consistent snapshot of memory without violating isolation guarantees.

Mapping the Virtual Address Space

A modern Windows process does not expose a flat block of usable memory. Instead, it sees a sparse virtual address space composed of regions with different states, protections, and backing stores. Cheat Engine navigates this space using VirtualQueryEx, which returns MEMORY_BASIC_INFORMATION structures describing each region. This metadata drives nearly all higher-level behavior:
  • State (MEM_COMMIT, MEM_RESERVE, MEM_FREE) determines whether data actually exists
  • Protection (PAGE_READWRITE, PAGE_EXECUTE_READ, etc.) distinguishes variables from code
  • Type (MEM_PRIVATE, MEM_IMAGE) separates heap allocations from modules and DLLs
For a Unity game, this distinction is important. Gameplay variables tend to live in MEM_PRIVATE heap regions, while engine logic and static data reside in MEM_IMAGE regions belonging to UnityPlayer.dll, GameAssembly.dll, or managed runtime libraries. By walking the address space region by region, the scanner builds a working map of “where things can possibly be,” which dramatically reduces noise before any value scanning even begins.

Value Scanning: Reducing Gigabytes to One Address

The classic Cheat Engine workflow, scan for a value, change it, scan again, is an exercise in algorithmic filtering. A first scan for a common value (say, an int with value 100) can easily return tens of thousands of candidates. Subsequent scans compare the current contents of those same addresses against new constraints:
  • Increased / Decreased when the direction of change is known
  • Changed / Unchanged to eliminate static or unrelated data
  • Range-based scans for obfuscated or scaled values
From a systems perspective, the important detail is how scanning is performed efficiently. Instead of issuing thousands of small kernel calls, Cheat Engine reads large contiguous regions into local buffers and scans them in user space. Alignment heuristics (e.g., stepping by 4 bytes for 32-bit integers) further reduce workload without missing likely candidates. The result is an address that appears to correspond to a gameplay variable, but only for the current session.

ASLR, Heap Allocation, and the Need for Pointers

Modern applications make heavy use of dynamic allocation, and Windows enforces Address Space Layout Randomization (ASLR) across process restarts. As a result, absolute addresses are ephemeral. To survive restarts, Cheat Engine resolves pointer paths: chains of dereferences that begin at a static base (often a module + offset) and walk through heap-allocated objects to reach the final value. Conceptually, this mirrors how the game itself accesses data:
ModuleBase
  → GlobalManager*
      → Player*
          → Stats*
              → health
Each arrow represents a pointer read plus a fixed offset. Cheat Engine’s pointer scanner automates discovery of these paths by identifying values in memory that look like pointers, that is, integers which themselves point to valid committed regions. By generating pointer maps across multiple sessions and comparing them, the tool can identify stable chains that remain valid even as individual allocations move. These chains are what ultimately get serialized into reusable cheat tables. For developers, this is a reminder that even heavily abstracted object graphs still collapse down into predictable memory layouts once compiled.

Debugging the Target: Who Writes This Value?

Finding a variable answers what to modify. Debugging answers how it’s modified. Cheat Engine supports several breakpoint mechanisms, each with different trade-offs:

Software Breakpoints (INT3)

These overwrite the first byte of an instruction with 0xCC. When executed, the CPU raises an exception that the debugger intercepts. This is simple and flexible, but noisy: it modifies code pages and is trivial to detect.

Hardware Breakpoints (Debug Registers)

Modern CPUs expose debug registers (DR0–DR7) that can monitor execution or memory access without altering code. These breakpoints operate at the hardware level and can trigger on reads or writes to a specific address. For reverse engineering gameplay logic “what writes to health?” hardware breakpoints are invaluable, because they reveal the exact instruction and register state responsible for a change.

VEH Debugging

Vectored Exception Handling (VEH) avoids attaching as a traditional debugger. Instead, injected code inside the target process registers its own exception handler, intercepting breakpoints before Windows’ standard handlers run. From the target’s point of view, no debugger is attached. From the researcher’s point of view, full breakpoint telemetry is available. This technique highlights how much flexibility Windows provides to in-process exception routing.

Crossing into Kernel Space (and Beyond)

As anti-cheat systems increasingly operate in kernel mode, user-mode memory tools face structural limits. Cheat Engine addresses this with optional kernel drivers and, at the extreme end, a custom hypervisor.

Kernel Drivers

A Ring-0 driver can bypass user-mode API hooks, access physical memory directly, and set breakpoints invisible to user-mode detection. It effectively re-implements parts of the memory manager from a more privileged vantage point.

Hypervisor (DBVM)

DBVM pushes this idea further by running beneath Windows itself, using Intel VT-x or AMD-V. In this configuration, Windows becomes a guest OS, and Cheat Engine operates at a higher privilege level. This enables:
  • Breakpoints that never surface to the OS
  • Page-level access control via Extended Page Tables (EPT)
  • Concealment from kernel self-protection mechanisms like PatchGuard
From an architectural standpoint, this demonstrates a blunt truth: the highest privilege layer always wins. Security is about raising cost, not achieving absolute prevention.

Unity-Specific Analysis: Mono vs. IL2CPP

Unity’s scripting backend choice fundamentally defines how observable and malleable a game is from outside the process. Mono and IL2CPP do not merely differ in performance characteristics; they expose very different reverse-engineering surfaces.

Mono: Rich Metadata as Both Feature and Liability

In Mono-based Unity builds, C# assemblies are loaded largely intact. Class names, field names, method signatures, inheritance hierarchies, and field offsets remain discoverable at runtime. This metadata exists to support reflection, debugging, serialization, and garbage collection, and it is exposed through the Mono embedding API. Cheat Engine’s Mono Dissector leverages this directly by injecting a helper module that queries the runtime via functions such as mono_class_get_fields() and mono_field_get_offset(). The result is effectively a live, structured view of the managed heap: developers’ conceptual object models rendered directly into a memory inspection tool.

Where Obfuscation Helps in Mono

Code obfuscation does meaningfully raise the cost of analysis in Mono builds, for example:
  • Symbol obfuscation (renaming classes, fields, and methods) destroys semantic clarity. A field named PlayerHealth becoming a1b2c3 removes intent and slows manual exploration.
  • Control-flow obfuscation complicates method-level reasoning when breakpoints hit managed code paths.
  • String encryption prevents trivial discovery of logic tied to configuration keys, events, or debug output.
However, obfuscation does not eliminate structural visibility. Even fully renamed fields still:
  • Exist at fixed offsets within objects
  • Are enumerable via the Mono API
  • Can be observed changing over time
From a memory tool’s perspective, Player.currentHealth and a.b.c are equally writable once their offset is known. Obfuscation increases analyst effort, but it does not meaningfully restrict capability. In short: Mono obfuscation protects meaning, not access.

IL2CPP: Native Code, Reduced Introspection Surface

IL2CPP fundamentally alters the analysis model by converting managed code into native C++ ahead of time. The managed runtime disappears, taking with it reflection, JIT compilation, and most high-level metadata. Instead, Unity emits:
  • A native binary (GameAssembly.dll)
  • A serialized metadata file (global-metadata.dat) describing types, methods, and fields
At runtime, objects still exist on the heap, but there is no longer a managed API that cleanly exposes their structure. Cheat Engine cannot simply “ask the runtime” for field offsets or instances. This forces attackers into:
  • Metadata dumping and reconstruction
  • Static analysis of native code
  • API hooking of IL2CPP runtime functions
  • Traditional pointer and code analysis
The barrier to entry is significantly higher.

Where Obfuscation Helps in IL2CPP

Obfuscation is materially more effective in IL2CPP builds because it compounds existing opacity rather than merely renaming exposed metadata. Effective IL2CPP obfuscation strategies include:
  • Metadata obfuscation Renaming types and fields which then are requested inside global-metadata.dat breaking automated dumpers’ ability to produce meaningful headers.
  • Layout randomization Reordering fields within classes invalidates previously discovered offsets, forcing re-analysis after every build.
  • Control-flow flattening in native code Makes static disassembly of GameAssembly.dll significantly harder, even with full symbols reconstructed.
  • Dead-code and fake-type injection Pollutes metadata with unused or misleading structures, increasing noise during reverse engineering.
Unlike Mono, where tooling can query live runtime truth, IL2CPP attackers must reconstruct intent from binaries. Obfuscation directly targets this reconstruction phase. That said, obfuscation still does not make manipulation impossible. Once offsets and code paths are rediscovered, the same fundamental techniques apply:
  • Objects are still heap-allocated
  • Fields still live at deterministic offsets
  • Native instructions still mutate memory
What changes is time-to-capability, not end capability.

Temporal Manipulation: How Speed Hacks Work

Cheat Engine’s speed hack does not accelerate the CPU or alter the system clock. Instead, it manipulates time perception inside the target process by intercepting Windows timing APIs such as QueryPerformanceCounter, GetTickCount64, and timeGetTime. Most game engines, including Unity, advance simulation based on per-frame delta time derived from these APIs. By scaling the reported elapsed time with a multiplier, the speed hack convinces the engine that more (or less) time has passed than actually has. Physics, animation, cooldowns, and AI logic then evolve faster or slower accordingly. The transformation is conceptually simple: real time is sampled once, and all subsequent time queries are linearly scaled before being returned to the game. Unity’s Time.deltaTime ultimately traces back to QueryPerformanceCounter, making it the primary interception point in modern titles.

Anti-Cheat Detection Strategies

Because speed hacks do not modify kernel or hardware clocks, anti-cheat systems focus on inconsistencies rather than prevention. Common detection approaches include:
  • Cross-clock validation Comparing user-mode timing results (e.g., QueryPerformanceCounter) against kernel-level timers or CPU counters (RDTSC). Diverging rates indicate manipulation.
  • Kernel-time verification Sampling time directly in Ring 0, bypassing user-mode hooks entirely. Any mismatch between kernel-observed time and client-reported deltas is grounds for suspicion.
  • Behavioral validation Detecting impossible outcomes: movement speed, cooldown completion, or simulation progress exceeding what authoritative time allows, especially in multiplayer environments.
  • API integrity checks Verifying that timing functions are unhooked, reside on image-backed pages, and match expected instruction signatures.
In server-authoritative multiplayer architectures, speed hacks are largely neutralized by design, as the server’s clock defines reality. In single-player or client-authoritative games, detection becomes a probabilistic arms race rather than a guarantee. Developer Takeaway Speed hacks demonstrate that time, like memory, is untrusted input on the client. Anti-cheat systems respond by validating time across multiple authority layers like user mode, kernel mode, hardware counters, and servers - until manipulation becomes detectable or irrelevant.

What This Means for Game Developers

Cheat Engine is not magic. It is a systematic exploitation of documented operating system features, runtime metadata, and hardware capabilities. For developers, the takeaways are practical:
  • Client-side state is never authoritative
  • Metadata is a trade-off between productivity and observability
  • Security features raise effort, not guarantees
  • Debugging infrastructure is indistinguishable from attack surface
Understanding these tools does not weaken your games, it strengthens your mental model of how software actually runs on player machines. In the end, whoever controls the highest privilege layer controls reality. Everything else is policy.
Newsletter

Stay in the Loop.

Subscribe to our newsletter to receive the latest news, updates, and special offers directly in your inbox. Don't miss out!