Game Hacking with CheatEngine - Basic cheats, pointermaps and assembly injection

This holidays I started to take a look at game hacking. I wanted to learn a bit about the methods hackers and crackers employ to find game cheats, making this world a bit worse. The go-to tool for tasks like these is CheatEngine, so I downloaded it and after beating the tutorial they provide (which I recommend to understand a minimum of the capabilities the tool has), I was ready to hack a real game (in singleplayer mode; I'm not THAT kind of guy).

Welcome to VALHEIM

Say hello to Thor Reznos.

What I learned first was how to identify values being altered and manipulating them. The first thing we see in the screen is the health bar (left down side). If we punch, jump or run, the energy bar will appear. Let's start trying to find the energy values inside the game memory.

Perform any action that would change your energy value and pause the game.

After attaching Valheim.exe to CheatEngine, set the Value text input to 34 and click on First Scan to find where this number is stored in memory. Keep the Scan Type to Exact Value and the Value Type set to 4 bytes for now.

Spoiler: This won't work and we will have to change the value type to float.

CheatEngine found over 400k results, but we can keep searching by clicking on Next Scan after modifying the value in-game.

Let the energy go up a bit and search again!

I got 0 results :( Maybe the value type is not correct! Sometimes stats may be stored as float, so let's click on New Scan, change Value Type to float and then First Scan. You may need to perform multiple scans by letting the energy change and clicking on Next Scan.

Once you use energy in the game, and the values found in CheatEngine change, you will know that you have found the correct memory region.

Double click on those addresses to move them to the cheat table (down below). You may even change the description to remember what those address are.

As you can see, when the energy is updated in-game, the value in the cheat table is also changed:

Now, we can repeat this steps to find the player's health value. Search the float value 25 and let an enemy hit you (pause the game to avoid being killed).

In the end, I found 3 values. Add them to the cheat table and change their descriptions.

After the first epic fight, my dear Thor Reznos was low HP, so we can use the table to edit this values and make his health get back to normal! Double click on the health value to modify it:

Now you can see the HP is being restored!

You could also use the Freeze feature to avoid any change by clicking on the Active square.

Now, everytime an enemy hit us, they won't deal any damage to us (although they try a lot).

Static addresses are not efficient.

We found addresses which store the values of health and energy, but the main problem with these addresses is that they are static, so everytime we restart the game, they will change and we would need to find them again.

To avoid this, we need to find pointers to those addresses. This is known as Pointer Scanning.

Let's generate a pointermap, which we can use to compare to a new game instance. Save the game and click on the cheat table to generate a pointermap:

Save the file, close the game, reopen it and attach it to CheatEngine. As you can see, the addresses we found are not valid anymore:

Perform the first steps to find them again and let's compare them to the pointermap we created before. Click on any addresses from the cheat table, then select "Pointer scan for this address" and a new window will appear:

Select "Compare results with other saved pointermap" and find the pointermap file you saved before. Then, select the address Player energy from the scrolldown bar. The final screen should look similar to this:

Save the file and let the scanner compare. This feature will find pointers pointing to the same value in the previous save and in the current one.

After a while, I got back some results. Also, remember to change the type to float in the up-left scrolldown bar, or you will have bad times reading those values :D

It may take sometime to find the correct pointer, but once you find the correct one, double click on it to add it to the cheat table:

Repeat this process to find the pointer to the health value. I had some problems with the health pointer as it would be lost if I start moving around the map, but I removed invalid pointers using the Rescan pointerlist from the menu Pointer scanner:

In the end, I finally got the right pointers:

Now, if you restart the game and reuse this cheat table, you will see that pointers are correct as they are pointing to the current health and energy.

Cheating via assembly injection

Now that we have found the right pointers, let's create a cheat. Freezing the values or changing them to something we want is not an efficient way to hack. There must be a code that changes the energy value stored. So to find the code, click on the energy pointer, and select Find out what writes to this address.

A new window will appear, and if we jump in-game, 3 records will appear. It's a matter of observation to realize that the first instruction is a tick to check if we are wasting energy, the second one is the waste of energy produced by performing actions, and the last one is the instruction that recovers our energy.

Let's create a hack to avoid the use of any energy. Select the hit instruction and click on show disassembler:

The dissassembler window can be used to debug the process. If we toggle a breakpoint on that address and then jump (which will use 10 of energy), we can see the debugger is stopped at the address.

The assembly code will move the value inside the XMM5 register to the address [rsi + 0x628]

The value of XMM5 is 40.00, so it will put the value 40 to the current energy value. If we NOP those instructions, then we won't use energy anymore. We can simply do that by clicking the instructions and then click Replace with code that does nothing:

Now, if we perform any action, there's no waste of energy.

We can restore the original assembly code by going to the Cheat table -> advanced options , and click on "Restore with original code".

A better way to cheat would be to inject some assembly code, replacing the original, to avoid the use of any energy. We saw that everytime we perform an action, it will change [rsi + 0x628] to the new value.

On the assembler window, select the instructions which updates the energy value (movss [rsi+0x628], xmm5) and click on the menu option Tools -> Autoassemble. On the new window, click on Template -> Cheat Table Framework Code. Then, Template -> Code Injection. It should look like this:

We need to inject the cheat under the newmem tag, as shown in the comment. As we only need to set the value of [rsi + 0x628] to 50 everytime we do an action, we modify the code to this:

mov [rsi+0x628],(float)50
jmp exit

After the mov instruction, we need to add the jmp exit , or the original code will be executed, as it's right under our injected code. Another option would be to replace the xmm5 register with the value desired, but as it's an XMM register, it's needed to alloc some memory. For simplicity, I decided to avoid the original code by using the jmp.

When the code is finished, click on File-> Assign to current cheat table. It will show our cheat as a new script which we can enable or disable by clicking on the Active square.

Cheat disabled:

Cheat enabled:

Good! We created a cheat! What about the GOD MODE? As we did before, we need to find what writes to the addres of the health value. Set up the debugger and get some hits in-game.

Everytime we get hit, a mov [rax+0x4], ecx is being invoked. Looks easy to modify! We could simply set ecx to 25 , right? Let's implement the cheat as we did before.

This time, I didn't implement the jmp exit instructions as it would simply continue to the original code and set [rax+0x4] to 25, being the max health. Now, if we save the cheat and activate it, we won't get any damage:

That's all for now, but I plan to continue this blog series as I found it quite interesting reversing games.

results matching ""

    No results matching ""