One of the tactics widely used by cheaters in multiplayer games is modifying the software loaded into memory by overwriting the original code of the process, or by injecting their own code. Anti-cheat software is trying to detect such modifications and decide whether they are a cheat or just expected variations. But what happens when the operating system itself starts to modify memory in an unexpected way?
Puzzled by the observation of runtime modification to Windows kernel components, our developers investigated the origins of these alterations. What we discovered are artifacts of Windows mitigations for well-known CPU side-channel vulnerabilities. Understanding these memory patches is crucial for an anti-cheat solution. This article explores the technical background, so be prepared for a dense read.
How does CPU instruction scheduling work?
Every CPU instruction is executed by a sequence of elementary operations in a pipeline. The instruction is fetched from memory, decoded and then the logical operation is executed. The result is written and the instruction counter is increased. Processors reach for the next instruction when the first step of the previous instruction is performed. That way several instructions can be executed in parallel, each one at a different step in the pipeline at a given time. Modern CPUs can sequence up to 100 instructions at a time in the pipeline and use several tricks to improve performance:
- Out-of-order execution is where the CPU switches the order of the instructions in the pipeline. The CPU may execute later instructions if they do not depend on results of earlier instructions.
- Branch prediction tries to execute the most likely path based on its execution history when two potential instructions can be loaded into the pipeline, and the processor cannot decide which should be loaded into memory first.
- Speculative execution improves performance by executing instructions ahead of time to minimize latency. The CPU takes a snapshot of its state before executing a potential instruction sequence so that it can discard all instruction results and restore the previous processor state. Without speculative execution the processor would need to wait for prior instructions to be resolved before executing the next one.
What are Meltdown and Spectre?
Meltdown allows a user-mode process to reach kernel-mode without any permissions to do so. Since mode separation is assured at the hardware level, an instruction reaching kernel-mode raises an exception that immediately prevents a data leak. This is perfectly safe for a processor running instructions sequentially, but due to pipelining and speculative execution, instructions that are eventually rolled back are executed and may alter and leak information to the CPU’s architectural state.
The processor will later raise an exception, prompting the snapshot to be restored from before the privileged instruction execution. The attacker can employ a side-channel attack on the cache to retrieve information from kernel space that should not be reachable.
Spectre v1 and v2
Spectre v1 specifically trains the branch predictor in a way that it allows for speculative execution, that would otherwise not be reached in the regular flow.
Spectre v2 on the other hand relies on exploiting the branch target predictor. The attacker may use the branch target predictor to choose the indirect jump to the part of the memory otherwise unreachable. The code then accesses the sensitive data and buffers it. The rest of the attack pattern is the same as Meltdown – the speculative execution is rejected and through cache probing, the attacker can obtain sensitive data.
How to protect against Spectre and Meltdown attacks?
There are several ways to mitigate the risks of Spectre and Meltdown attacks, many of which are provided by the CPU manufacturers through microcode updates. But depending on the type of attack, a different approach may be used. Meltdown has a few viable solutions, one of which is Kernel Page Table Isolation (KPTI). Spectre v1 can be solved with a LFENCE instruction which stops speculative execution, but for Spectre v2, the solution is more complex as there is a greater performance impact. A more promising solution however is to implement a retpoline mechanism on the operating system level.
What are retpoline and DVRT?
Retpoline is a mechanism proposed by Google engineers that replaces an indirect call or jump with a sequence that has safe speculation behavior. A potentially unsafe indirect call is overwritten by a jump to that safe isolated space, followed by an interruption that breaks the speculative injection. Retpoline changes are done ad-hoc when loading a kernel module into memory. How does Windows accomplish these patches?
Dynamic Value Relocation Table (DVRT) refers to metadata that builds into the Load Config directory of the binary file during the compilation phase. DVRT was introduced in the past but has been extended to contain information for mitigating Spectre v2. The compiler keeps all the metadata about indirect jumps and stores them under the .reloc section, repurposed for DVRT. During the runtime, the kernel parses the DVRT metadata and applies the retpoline patches for each reference.
This can be enabled on OS level, using registry key System\CurrentControlSet\Control\Session Manager\Memory Management\FeatureSettings.
The code of the retpoline sequence is stored in the RETPOL section of the kernel image where it is mapped to the page right at the end of each kernel module. All the replacements of the indirect calls and jumps then refer to the same page with the retpoline code, which in turn executes the control flow in a safe manner, free from speculative execution attacks.
Are you interested in learning more?
Analyzing differences between executable images causes the developers of anti-cheat software great headaches. Windows kernel patches more places to redirect calls and jumps to the retpoline section to mitigate Spectre v2. DVRT is the structure stored in the .reloc section that describes these patch locations. We have dissected and documented this data structure.
Feel free to check out our blog for more details and learn how anti-cheat helps keep gaming experiences fun and fair!