No application is hack-proof. With enough time and resources, anybody can break into your app. If not through technical knowledge, then through social engineering. Because of this, you must design our app with security in mind, especially if it implements competitive multiplayer or involves financial transactions.

How to reverse-engineer Unity apps

To protect your app from hackers , you need to think like a hacker. There are already tons of resources available on how to reverse-engineer Unity apps. I won’t go into detail on how to do it, but others have provided detailed guides:

Some commonly used tools are.

  • dnSpy – is a debugger and .NET assembly editor.
  • ILSpy – alternative to dnSpy. It is an open-source .NET assembly browser and decompiler.
  • Il2CppDumper – restores .dll files of a Unity IL2CPP app. Learn more about IL2CPP dumping here.
  • HxD – a Hex Editor used for editing binary files.
  • SharpMonoInjector wh0am1 Mod – a tool for injecting assemblies into Mono embedded applications, commonly Unity Engine based games. 
  • apkpure – a website that provides original APK files of free smartphone apps.

The gist here is that there are already a lot of tools and tutorials available out there. Anyone who has enough time and resources will be able to figure out how to break into your application. What you can do is make it harder but not impossible for someone to hack your app.

Steps to improve Unity app security

1. Use IL2CPP instead of Mono

In the previous example, we used the default Mono scripting backend to build a sample desktop app. We saw how easy it was for someone to decompile the app, scan through the code, and tweak it a bit. A quick and easy way to obscure your code is to use IL2CPP scripting backend instead of Mono. IL2CPP builds do not have IL bytecode, so tools like dnSpy and ILspy won’t be able to show you the code inside classes. However, the names of classes, methods, parameters, etc. are still visible.

Below is a screenshot of what the user will see if he tries to decompile an IL2CPP build of the ThirdPersonCharacter template using IL2CppDumper and dnSpy.

Switching to IL2CPP increases build time, but it also makes it more inconvenient for someone to decompile and understand your source code.

Enabling IL2CPP also enables another setting called Managed Code Stripping where Unity removes unused or unreachable code to decrease the app’s build size. I’ve read from hacking forums that this makes it slightly inconvenient for users to mod an app because of missing UnityEngine code.

2. Obfuscation

Obfuscating your code makes it harder for a malicious user to understand what your app does after decompilation. One way is by naming your methods, parameters, and variables to unintelligible text. However, this also makes it harder for your co-workers to understand your code. To solve this, we can use assets that automatically modify your code during the build process.

Below is an example of what obfuscated code looks like using dnSpy on the FPS Microgame template project. You can see that it is difficult to decipher what the classes and methods do because their names have been replaced by random strings.

Example of obfuscated code

Here are tools from the Asset Store that automatically obfuscate code for you:

Obfuscator by Beebyte.

  • Supports IL2CPP and Assembly Definition Files
  • Removes Namespaces without any conflicts
  • Recognizes Unity related code that must not be changed
  • Renames classes, methods, parameters, fields, properties, events
  • String literal obfuscation
  • Adds fake methods
  • Easy and extensive customization using the Unity inspector window
  • Consistent name translations are possible across multiple builds and developers
  • Semantically secure cryptographic naming convention for renamed members

Obfuscator Pro by GuardingPearSoftware.

  • Member renaming: namespaces, classes, methods, fields, properties, event
  • String obfuscation
  • Adding random code
  • Anti debugging
  • Anti tampering (mono)
  • ControlFlow obfuscation (mono)
  • Full obfuscation workflow customization
  • StackTrace de-obfuscation to allow restoring and debugging of even the most secured assemblies

3. Memory Hack Detection

Tools such as Cheat Engine and GameGuardian allow users to modify values in the game during runtime. Verify integrity of files.

Anti-Cheat Toolkit 2021 by Code Stage

  • Protects variables in memory.
  • Protects and extends Player Prefs and binary files.
  • Generates build code signature for tampering checks.
  • Detects speedhacks.
  • Detects time cheating.
  • Detects 3 common wallhack types.
  • Detects foreign managed assemblies.
  • Has Obscured Prefs / Player Prefs editor.

4. Injection Detection

DLL Injection is a method of injecting third-party code into a running process by loading a third-party dynamic library. The Anti-Cheat Toolkit above also has features to detect and react to foreign managed Mono assemblies both injected at runtime or into the build on PC and Android.

5. Server-side Code Validation

There is an API Application.genuine which returns false if an application is altered in any way after it was built, but a person skilled enough to decompile and modify an app might be skilled enough to disable this check as well. The previous anti-cheat tool can detect code tampering. However, what if the hacker tampers with the anti-cheat tool itself? This is why you also need to consider server-side checks.

You might have seen this in some games that occasionally shows the “Verifying file integrity” progress bar. It makes sure that the files in the user’s device are the same as the files in the server.

User CShark from stackoverflow explaines it well:

” The main problem being that any code you build into the app to detect changes can be patched away. So you’ll need to prevent that. But there is no practical way of preventing that…

If you try to detect changes in your app by using a signature of the original and compare that to the actual signature for example, you can just exclude that check in the recompiled version. You can try to verify the signature against a server, but that can still be circumvented by removing the server check. You can force a server check for multiplayer games, but then we’ll just use a fake signature. If you then want to calculate the signature on your server to prevent tampering, we’ll just give you the original file and run the recompiled one. “

One way to prevent tampering is to run your app in the cloud and stream it.

6. Never trust the client.

Anything in the client can potentially be tampered, meaning we should never trust the data that the client passes to the server. What we can do is move crucial logic from client to server and minimize the amount of authority the client has. On top of this, we implement a reliable user authentication system and validate the data from the client.

Is it safe to embed secrets / passwords / API keys in your app?

The answer to this is No. The general rule is to not embed any secrets into your app as much as you can. Assume that a scenario where a smart hacker will compromise your app and try to use all the information in it to spoof you.

“There are two basic types of attack, firstly by decompiling the APK to see if it (the key) is stored somewhere in the code, and secondly using a Man in the Middle (MITM) attack to see if it’s transmitted insecurely  over the web.” – riis blog

Ultimately, the best way to protect secret keys is to never put them in your client app. However, this is impractical in certain projects where you need to store keys in your app for performance or convenience reasons. One way to hide your keys in your app is to use generic words to name your keys. Avoid the words “secret”, “key”, “API”, “encrypt”, “decrypt”, “password”, etc.

It is difficult to provide a solution that covers all use cases. I provided links below which can help you determine which solution is best for your project.

Further Reading


Send me a message.


Recent posts: