Game Hacking in C#

In this blog post, I’ll guide you through scanning for memory values in games using Cheat Engine and show you how to create cheat scripts in C#. Additionally, I’ll teach you how to build reliable cheats using AOB (Array of Bytes) scripting techniques.

GAME HACKING

Lorenzo Meacci

12/1/20247 min read

What is game Hacking?

Game hacking involves altering a game’s code, data, or mechanics to modify gameplay, access hidden content, or gain an unfair advantage. While some individuals hack games as a creative hobby or for personal enjoyment, others use it to cheat in online multiplayer games, potentially disrupting the experience and fairness for other players.

PS. Sorry to my IT teacher for making this blog. He hates cheaters in games (me too). Hope he does't penalize me next test :p

Why Cheat?

There are several reasons why a game hacker would cheat, this is my personal list:

1) To Gain Money or Rewards

2) To Troll Other Player

3) To Climb Leaderboards Quickly

4)To Exploit Pay-to-Win Systems

5) For the fun of it

Syllabus

  • Identify Structures in the game

  • AOB (Array of Bytes) scripting

Identify Structures in the game

Firstly you need to target a game, in this example I will be hacking the Assault Cube FPS. The game can be downloaded here. Now we need to install the cheating software suite, Cheat Engine, It is a comprehensive Game Hacking toolkit that offers functionality for every scenario. Its main functionality is the ability to scan and filter through memory addresses. Go to the Cheat Engine page for the download.

Now that we have everything installed, we can open both Cheat Engine and the game.

The first step would be to attach the game to Cheat engine from the "Monitor Icon" in the top left corner of the GUI

After you have selected the game process, Cheat Engine will be able to scan for memory values in the game memory space. Now we can start scanning for memory values like health and ammo. To scan for ammo in a game, start by checking the current ammo count (e.g., 12). Use this value as your initial search in the memory scanner. Then, shoot to decrease the ammo and scan again using the updated ammo value. Repeat this process until the memory scanner narrows it down to a single memory address representing the ammo.

Shoot some bullets and scan again

Nice, We now have found the memory address of the ammo!! We can add it to the address table and modify its value

Addresses Theory

Nice now we could technically do the same thing with the health value making us effectively immortal. But as always things are not so easy. Yes, this might work for one game, but after the game is closed and opened again the health value will not be present in the same memory address, this is because Address Space Layout Randomisation (ASLR) is in place. The main principle of ASLR is quite simple: it randomizes the location where program executables are loaded into memory.

However, the internal memory layout (structures and offsets) typically remains consistent. By locating the game's base address and using a pointer chain, we can dynamically calculate the ammo address/health.

To do this, we can right-click on the value and select (Pointer scan for this address):

Next we can configure the following scanning options

Click "ok" and save the file.

Now you will probably receive a huge amount of pointers, these are all the pointers related to the ammo memory address, some of this remain static after game restarts other not. We need to filter out the static ones. To do so, we have to restart the game and attach cheat engine to it once again, after that use the Rescan option in the PointerScan window

After clicking that we will need to put the value of the ammo that is in the game now e.g (20):

We still have some false pointers, so we need to restart the game and repeat the scanning process until the number of values is reduced further.

Once we have fewer and more consistent values, select one of them and add it to the address table.

Now we need to write down the values somewhere to use them later in our C# program:

These are the values ("ac_client.exe"+00183828 , 8 , 96C , 288)

When learning these techniques, I found that there is an awesome NuGet developed by "swedz c#", it is a simple add-on for the ReadProcessMemory and WriteProcessMemory functions.

First thing to do is to create a Visual Studio C# console app project.

Next step is to know the architecture of the game (x64 or x86), to do that we can open the task manager and show the “details”:

and we can see that the application is x86:

Now we can install the x32 bit swed NuGet, to do this go to Project > Manage NuGet Packages

Now we need to change the Architecture of our External program to x86:

First, create an instance of the Swed class, specifying the program name in the constructor. Next, obtain the game's moduleBase address and the ammo address using the values gathered earlier in Cheat Engine. Then, within a while loop to verify that the code works, print the current ammo value to the console.

How does it work?

Remember that ASLR randomizes where the game is loaded in memory, so we need to get the base address of the game and then compute the ammo memory address using the pointer found earlier. For debugging, the ammo value is then printed to the console to verify if the script is correctly locating the memory address.

Cool, now we can read the ammo address after the game restarts, but the script currently doesn't write the new ammo value to memory. To fix this, we can modify the while loop in the script and insert a WriteInt method, specifying the ammo address and the value we want to write.

AOB scripting

As we saw earlier, it is possible to scan in-memory for specific values. Once the parameter is identified, we can change its value. However, when the game is restarted, the memory location of the previously found value becomes useless. This is where AOB comes into play. Game hackers can use an array of bytes (or 'byte pattern') to identify unique code sequences associated with the variable of interest. These sequences are often code segments that read from or write to the variable.

This time the game I will target is called "Cave Crawler" and it can be downloaded here

Locating the health value of the game is the same process as in Assault Cube, just keep scanning for the value as it changes:

After identifying the life value, we can add it to the address table, right-click on it and select > "What access this adress". After loosing another life, we will see what is access the address:

We can view this in the disassembler and examine the series of operations associated with health loss:

We can see that there is a 'sub' operation, where the rbx register is used as the base address, and an offset of 08 is added to get the effective memory address. Then, the value stored in the rax register is subtracted. We can now right-click and replace this with a NOP (No Operation) instruction, which will be ignored by the CPU and prevent our health from decrementing:

After replacing the instructions with NOP bytes (0x90), you'll notice that we no longer lose health because we've overwritten the instructions that are executed when we take damage.

These instructions, or series of bytes, are always the same and can be scanned and overwritten. Instead of using Cheat Engine, which has a built-in scanner, we can use the C# memory scanner from this GitHub repository.

At a high level, this is how the code of the scanner works:

1) P/Invoke: Imports Windows API functions to read/write another process's memory.

2) Pattern Matching: Scans memory for a specific byte pattern using FindPattern.

3) Backup: Saves original bytes at a target address for restoration if needed.

4) Memory Writing: Writes new bytes or patterns to memory via WriteProcessMemory.

5) Encapsulation: Wraps functionality in a reusable, modular Scanner class.

If you want to learn more on how to create a memory scanner, "swedz C#" created an awesome video about it.

To get the bytes sequence in Cheat engine, we can click-shift on the memory address and drag down:

Now it's time to code again! Now create a C# console application in VS. Once that is done, navigate to Project > Add class and copy-paste the class from the GitHub repo.

In our Program.cs file, we need to create a `Process` instance specifying the target process name and then initialize the scanner with the pattern of bytes found earlier:

Now let's find the byte pattern using FindPattern. If the pattern is found, we write new bytes (90 90 90 90) to the address and confirms success. We also retrieve and display the original bytes for backup. If the pattern isn’t found, we notify the user of the failure.

Final Code:

Remember to ALWAYS compile the projects in the same architecture of the game, in our example is x64.

Now once we run the script and the NOP bytes are written, you will notice that we don't take damage anymore: