While playing video games with leaderboards you might notice that sometimes there are players with enormous, impossible scores.

lbhack

Impossible scores!

As you probably guess those ones weren’t scored by playing a game the fair way.
There are three (known to me) ways to do such a terrible thing:

  1. By modifying the save files or the shared preferences. Better not to use any kind of shared preferences to store vulnerable values, while the save files should be encrypted and has a checksum for checking if someone was trying to modify them.
  2. By using a proxy to perform a-man-in-the-middle attack (in other words – by modifying the request that was sent to the leaderboards system). Sensitivity to this type of attack depends of the leaderboards’ vendor you use. If you have your own leaderboard system make sure you communicate with it via SSL with public key infrastructure.
  3. By modifying the memory during the game runtime with such programs like GameGuardian.

We will talk about the 3rd way to cheat.

For the sake of simplycity I will use a CheatManager to demonstrate how memory hacking works (the process is very similar to the GameGuardian’s one).

Of course, if someone want to hack a game very much, they will find a way anyway. The goal is to make it a little harder than it would be without any kind of security.

Let’s run a simple program, that will increment scores in each second:

Run this program and pause it using CheatManager (set the hotkey in Edit->Settings->Hotkeys->”Pause the selected process”.

beforehack

Application with scores before memory hack.

Now search for the current score value which is 130.

mem1

Memory values and addresses.

As you can see there are three values in this process that are equal to 130. Which one is the one we are looking for? Unpause tha application and check which one is changing:

mem2

Highlighted changing value.

Now, when we’ve got the address of the value we’re looking for, we can change it by right-clicking on the address and selecting “Change value of selected address”:

1SX7pZOAm2x21N5noNnhdIaP4pmvoB1kZ6nqHiA

Changing value for the address.

At this moment, when you unpause the application, you will see that the score value was truely changed:

afterhack

Application running after memory hack.

As you can see the memory hacking is based on searching the specific values in the memory and then changing them to receive better scores. To make life more difficult for swindler the value must not be represented in the memory as itself.

One of the easiest and the fastest way to encrypt the value is to xor it by a random key. Because we’re planning to use many types and floating points types can’t be xored they have to be casted and stored in the biggest available chunks of data. The uint64_t will be just fine.

Let’s create a new class which will be our safe type.

As you can see there are three values.
The idea is very straightforward:

  • When creating and modyfying the value the new key is generated.
  • The value is encrypted by this key.
  • Both of them – the encrypted value and the key are saved in the memory.
  • The unencrypted value is used to create a check copy, which is created by xoring it with a static, random number.

The whole constructor should look like this:

The tricky bit-level casting is a casting to another type without conversion. That means all bits from, for example, float will be moved to the int untouched.

The check copy will be used as the final defence line for cheaters, who somehow find the encrypted value.

When the safe_type is called it has to decrypt saved value, check it and return as the normal type.

The most of Sunday cheaters won’t find the proper value to change. If the cheater will find it somehow he will have to know how to change all three used values to not cause an assertion (and they can’t blame programmer for an application crash in this situation).

This is, of course, only a suggestion how to do this kind of obfuscation. The trickier the encryption will be, the better.

The only thing that has left is to overload operators, so the whole class will be easy to use.

In the solution here there is a complete code with all necessary operators and the simple application that shows how to use safe_type class.