Game Hacking #0: Runtime Function Patching

c++ binary cracking reverse-engineering gamehacking

When it comes to patching certain functions of a binary on ASM level, it’s often performed by modifying the binary itself. This post shows a different approach to accomplish the same thing: Removing game cheat protections using runtime function patching.

The Target

This is being shown in the following context: Quake3 based multiplayer games include certain settings (CVars) which are disabled for players to prevent cheating. These settings would enable clients to disable fog and shadows and use different camera angles. Using these settings would bring an advantage over clients not being able to use them, hence the protection mechanism. However, it would be convenient to use these settings anyway and remove the protection mechanism on the client side – that’s what function patching is being used for.

Looking for the Code

The first step is to locate the code segment which is being used to implement the client side protection. An easy way to do this is to search for error messages. There’s an error message being displayed in case a client tries to use an illegal CVar which would remove all shadows from the current map:

Error message

This can be used to locate the relevant code segment in IDA:

IDA String search

Navigate to the machine code by clicking on the cross reference (XRef) of the first search result:

IDA Xref

The code in this particular segment prevents the usage of illegal CVar settings and values by calling an error handling method based on a cmp operation resulting in a conditional jump:

Conditional Jump

Observing the code on runtime suggests that to remove the protection, it’s enough to always perform the conditional jump – making it a jmp instead of a jnz to skip the error handling. This can also be seen in the corresponding graph view:

Conditional Jump

Checking the hex view of the conditional shows that the jnz has opcode 75 (jnz rel 8). This results in the requirement of patching exactly one byte - making it a jmp (rel 8) with opcode EB.

Now this could be patched directly in the binary but it would be way more elegant to patch it in the memory after executing the binary. This is what the Windows API method WriteProcessMemory can be used for. You can see this implemented in this proof of concept. Take note of the following things:

After executing the code, the graph view in memory looks like this, making the error handling code unreachable:

View After Removing the Protection

Let’s verify the memory patching worked by using an illegal CVar:

Using an Illegal CVar

This hack could now be distributed as executable file, making it possible to use it in combination with other modifications which work in-memory.

BinaryGolf 2023: Building A GameBoy-Bash Polyglot

binary ctf

ShhPlunk: Muting the Splunk Forwarder

reverse-engineering c++ linux

Game Hacking #5: Hacking Walls and Particles

reverse-engineering c++ binary gamehacking