
When it comes to software, the term “hacking” is often associated with piracy and copyright infringement. This article is not about that; on the contrary, I strongly disapprove of any actions that directly or indirectly can harm other developers. Nevertheless, this article is still a practical guide to hacking. Using the tools and methods that will be discussed later, you can check the protection of your own Unity game and learn how to protect it from hacking and theft of resources.
Introduction
The basis of
hacking is
knowledge : it is necessary to understand the features of the compilation of the Unity project in order to hack it. After reading the article, you will learn how Unity compiles game resources and how to extract source materials from them: textures, shaders, 3D models and scripts. These skills will be useful not only for analyzing project security, but also for its advanced debugging. Due to the closeness of the source code, Unity often works as a “black box” and sometimes the only way to understand what is happening in it is to study the compiled version of the scripts. Among other things, decompiling someone else's game can be a serious help in finding its secrets and "Easter eggs." For example, this is how the solution to the
final puzzle in the FEZ game was found.
')

Find the resources of the game
Consider for example a game compiled under Windows and downloaded via Steam. To get to the directory in which we find the resources we need, open the game properties window in the Steam library and in the “Local files” tab, click “Browse local files ...”.

When Unity compiles a project under Windows, resources are always packaged in a similar pattern: the executable file (for example,
Game.exe
) will be located in the root of the game directory, and the directory containing all game resources -
Game_Data
will be located next door.
Extract textures and shaders
Most Unity project resources are packaged in proprietary format files with the
.assets
and
.resources
. The most popular tool for viewing such files and extracting resources from them is the
Unity Assets Explorer .

The graphical interface of the program is not very convenient, and it also suffers from several critical bugs. Regardless, the program is quite capable of extracting most of the textures and shaders from the game. The resulting textures will have a DDS format that can be “read” using the
Windows Texture Viewer .
The situation with shaders is more complicated: they are extracted in an already compiled form and, as far as I know, there are no solutions for their automatic translation into a readable format. However, this circumstance does not prevent the import and use of the resulting shaders in another Unity-project. Do not forget, however, that such a “theft” infringes copyrights and is an act of piracy.
We retrieve 3D models
Three-dimensional models in a typical Unity assembly are “scattered” across various resources, and some of them can be generated at all during the game. Instead of digging into files, there is an interesting alternative - to get geometry data straight from the memory of the graphics accelerator. When the game is running, all the information about the textures and models visible on the screen is in the memory of the video card. Using the
3D Ripper DX utility, you can extract all this information and save it in a format understandable to 3D editors (for example, 3D Studio Max). Note that the program is not the easiest to use - you may have to refer to the documentation.

Breaking PlayerPrefs
PlayerPrefs is a class from the standard Unity library that allows you to save data in the long-term memory of the device. It is often used by developers to store various settings, achievements, player progress, and other information about the state of the game. On Windows, this data is stored in the system registry in the following way:
HKEY_CURRENT_USER\Software\[company name]\[game name]
.

Using the standard
regedit utility, you can easily modify any values of PlayerPrefs, thereby changing the configuration and status of the game.
Protecting PlayerPrefs
Preventing the user to edit the values in the registry, we can not. But to check whether these values have changed without our knowledge is quite real. The hash functions will help us in this: by comparing the checksums of the stored data, we will be able to make sure that nobody and nothing except our code has changed this data.
public class SafePlayerPrefs { private string key; private List<string> properties = new List<string>(); public SafePlayerPrefs (string key, params string [] properties) { this.key = key; foreach (string property in properties) this.properties.Add(property); Save(); }
The class above is a simplified implementation example that works with string variables. To initialize it, it is necessary to transfer the secret key and the list of PlayerPrefs-keys, the values of which must be protected:
SafePlayerPrefs spp = new SafePlayerPrefs("MyGame", "PlayerName", "Score");
Then it can be used as follows:
Each time the
Save
method is called, a checksum is calculated and stored based on the values of all parameters whose keys were passed to the class during initialization. Using the
HasBeenEdited
method
HasBeenEdited
we can then check whether the protected parameters have changed without our knowledge.
Breaking the source code
For Windows builds, Unity compiles and saves the source code of all game scripts in the
Managed
directory. We are interested in the following libraries:
Assembly-CSharp.dll
,
Assembly-CSharp-firstpass.dll
and
Assembly-UnityScript.dll
.

For decompiling and viewing managed code of .NET libraries (which are our victims) there are quite handy and yet free utilities:
IlSpy and
dotPeek .

The data approach is especially effective for our purposes: Unity very sparingly optimizes the source code of game scripts, practically without changing its structure, and also does not hide the names of variables. This makes it easy to read and understand decompiled material.
We protect the source code
Once Unity does not care about the safety of our code, we will do it ourselves. Fortunately, there is a utility that is ready to automatically encrypt the fruits of our intellectual work:
Unity 3D Obfuscator .

And although the program copes with its duties perfectly, many classes that are addressed from the outside of the native library still cannot be encrypted without the risk of disruption of connectivity - be careful!
Hack the memory of the game
Cheat Engine is a well-known program for hacking games. It finds the area of RAM that belongs to the process of a running game and allows you to arbitrarily change it.

This program takes advantage of the fact that game developers rarely protect variable values. Consider the following example: in a certain game we have 100 rounds; using the Cheat Engine, you can search for memory areas that store the value "100". Then we make a shot - the stock of cartridges is 99 units. Scan the memory again, but now we are looking for the value "99". After several such iterations, the location of most game variables can be easily detected and arbitrarily changed.
Protecting the memory of the game
Cheat Engine is so effective that the values of variables are stored in their original form, without any protection. Seriously complicate the life of "cheaters" is quite simple: you only need to slightly change the way you work with variables. Create a
SafeFloat
structure that will serve as a safe replacement for the standard
float
:
public struct SafeFloat { private float offset; private float value; public SafeFloat (float value = 0) { offset = Random.Range(-1000, +1000); this.value = value + offset; } public float GetValue () { return value - offset; } public void Dispose () { offset = 0; value = 0; } public override string ToString() { return GetValue().ToString(); } public static SafeFloat operator +(SafeFloat f1, SafeFloat f2) { return new SafeFloat(f1.GetValue() + f2.GetValue()); }
You can use our new structure as follows:
SafeFloat health = new SafeFloat(100); SafeFloat damage = new SafeFloat(5); health -= damage; SafeFloat nextLevel = health + new SafeFloat(10); Debug.Log(health);
If you display the values of variables on the screen, hackers will still be able to intercept and change them, but this will not affect the actual values stored in memory and used in the logic of the game.
Conclusion
Unfortunately, there are not so many ways to protect the game from hacking. Being installed on a user device, it actually reveals all of your textures, models and source code. If someone wants to decompile the game and steal resources - it is only a matter of time.
Despite this, there are effective methods that will seriously complicate the lives of intruders. This does not mean that you need to go into a panic, encrypt all source code and protect each variable, but at least think about what resources of your project are really important and what you can do to protect them.
Additional Information
- Unity3D Attack By Reverse Engineering : An interesting article describing common security bugs in the implementation of scoring systems in Unity games;
- disunity : One of the best utilities to view and extract resources from Unity games. Unfortunately, it is incompatible with the latest version of the engine;
- Unity Studio : A program for visualizing and extracting 3D models. Also does not work with Unity 5.