Developing Game in Unity? Check Template Projects, Tools, VFX & many more!

Unity 3D Obfuscation Methods & Anti-Cheat Protection

645

So, you finally released your game which you've been working so hard on and maybe even added some leaderboard to spice things up. But days go by and you notice some players popping up on top of scoreboard with unrealistically high scores. Your first thought is of course they're hacking, but how do they do that?

The answer is, they're most likely using a program to inject their own values into the memory, with the most popular of such programs being Cheat Engine. Now, in single-player games the hacking doesn't really matter that much, but it becomes a problem when it's a multiplayer game where the other players are involved.

In this post I will be showing how to make your game more secure against such attacks, which in turn will improve the experience for non-hacking players.

NOTE: This article only briefly covers the most common attacks and a basic protection against them. If you need more out-of-the-box solution feel free to check this Asset Store package.

When it comes to hacking with Cheat Engine there are 2 most common attacks used by novice hackers, the Speed Hack and Value Scanning.

Speed Hack

Being the easiest to execute (only requires 2 clicks), the Speed Hack is usually the first choice for the novice users.

Speed hack works by speeding up the game's update rate, making everything faster, thus giving hackers an edge over the players who play at the normal speed.

Fortunately there is a way to detect this hack in Unity. Check the script below:

SC_SpeedhackDetector.cs

using UnityEngine;
using System;

public class SC_SpeedhackDetector : MonoBehaviour
{
    //Speed hack protection
    public int timeDiff = 0; 
    int previousTime = 0;
    int realTime = 0;
    float gameTime = 0;
    bool detected = false;

    // Use this for initialization
    void Start()
    {
        previousTime = DateTime.Now.Second;
        gameTime = 1;
    }

    // Update is called once per frame 
    void FixedUpdate()
    {
        if (previousTime != DateTime.Now.Second)
        {
            realTime++;
            previousTime = DateTime.Now.Second;

            timeDiff = (int)gameTime - realTime;
            if (timeDiff > 7)
            {
                if (!detected)
                {
                    detected = true;
                    SpeedhackDetected();
                }
            }
            else
            {
                detected = false;
            }
        }
        gameTime += Time.deltaTime;
    }

    void SpeedhackDetected()
    {
        //Speedhack was detected, do something here (kick player from the game etc.)
        print("Speedhack detected.");
    }
}

The script above compares the in-game time with a computer's (system) time. Normally both times are updated at the same rate (assuming the Time.timeScale is set to 1), but when the SpeedHack is activated, it accelerates the in-game update frequency, making the in-game time accumulate faster.

Once the difference between both times becomes too great (in this case 7 seconds, but you can choose any value, just make sure it's not too small to avoid false positives) the script calls the SpeedhackDetected() method which signalizes the presence of SpeedHack.

To use the script make sure it's attached to any Object in the Scene.

Value Scanning

Value scanning is a process of finding relevant values in game's allocated memory and overwriting them with different values. Most commonly used to increase player Health, Weapon Ammo or basically any value that would give a hacker an unfair advantage over other players.

Technically speaking every value in the game can be overwritten/changed, but does it mean all of them need to be protected? Not necessary. Generally, novice hackers only target the values that are displayed on the screen and are known what they are used for (For example player health, ammo capacity etc.). So most of the time only "exposed" values need to be protected.

For example on the screenshot above, every value on the screen is a potential target for hacking.

So the question is how to protect the important values against Value Scanning attack? The answer is Obfuscation.

Obfuscation is the action of making something obscure, unclear, or unintelligible.

In this tutorial I will be showing how to obfuscate int and float variables, which are the most commonly used types for key values.

Now there are many ways to obfuscate a variable, but I will be using a method which I call Randomizer. Basically the random value is generated at the start, then the real value is subtracted from it (subsequently hiding it), then when needed, the hidden value is subtracted from a generated random value, with a difference being the original number. The key is to have a value that is displayed on the screen to have a completely different value from the variable, leading hacker in a completely wrong way when scanning.

  • Create new script, call it 'SC_Obf' and paste the code below inside it:

SC_Obf.cs

using UnityEngine;

public class SC_Obf : MonoBehaviour
{
    static float random = -1;

    public static void Initialize()
    {
        if(random == -1)
        {
            random = Random.Range(10000, 99999);
        }
    }

    public static float Obfuscate(float originalValue)
    {
        return random - originalValue;
    }

    public static float Deobfuscate(float obfuscatedValue)
    {
        return random - obfuscatedValue;
    }
}

The script above will be used to generate a random number and 2 simple methods to obfuscate and deobfuscate the values.

  • Now let's move to a regular example of a script without any obfuscation:
using UnityEngine;

public class SC_Test : MonoBehaviour
{
    public float health = 100;
    public int ammo = 30;

    public void Damage(float points)
    {
        health -= points;
    }

    void OnGUI()
    {
        GUI.Label(new Rect(5, 5, 150, 25), health + " HP");
        GUI.Label(new Rect(5, 30, 150, 25), ammo + " Ammo");
    }
}

The script above contains 2 simple variables: health (float) and ammo (int). Both variables are displayed on the screen:

This way of doing things is simple and convenient in terms of maintenance, but the hacker would easily be able to scan and overwrite them using Cheat Engine.

  • Now here is the same script, but using an obfuscation methods defined in 'SC_Obf':
using UnityEngine;

public class SC_Test : MonoBehaviour
{
    public float health;
    public int ammo;

    void Awake()
    {
        SC_Obf.Initialize();
        health = SC_Obf.Obfuscate(100);
        ammo = (int)SC_Obf.Obfuscate(30);
    }

    public void Damage(float points)
    {
        health = SC_Obf.Obfuscate(SC_Obf.Deobfuscate(health) - points);
    }

    void OnGUI()
    {
        GUI.Label(new Rect(5, 5, 150, 25), SC_Obf.Deobfuscate(health) + " HP");
        GUI.Label(new Rect(5, 30, 150, 25), SC_Obf.Deobfuscate(ammo) + " Ammo");
    }
}

Instead of initializing health and ammo variables directly, we initialize them at the start in void Awake() (But make sure to call SC_Obf.Initialize(); before assigning the values using SC_Obf.Obfuscate(value)).

Then when displaying the values, we deobfuscate them on the fly by calling SC_Obf.Deobfuscate(value) thus displaying the real values.

The hacker would try to search for 100 and 30 but would not be able to find them, because the real values are completely different.

To manipulate the obfuscated values (ex. subtracting health) we first deobfuscate the value then subtract the needed value then obfuscate the final result back.

For more advanced solution feel free to check this Asset Store package.