Obfuscate your C# code in Unity3d

In this article I’m writing about how you can obfuscate your C# code in Unity3d. As you probably already know your C# script code is stored in a .dll file and that file can easily be decompiled and read just like an open book. It is pretty much impossible to prevent anyone to reverse engineer your code, anyone who got your application will be able to do it. However you can make it harder for someone to read your code by obfuscate it.

Kristoffer Karlsson

--

If you don’t know what obfuscation is then you can read about it here and source can be downloaded here.

Now to be honest, for most apps out there it will be a waste of time since it is highly unlikely that someone will look at your code and try to hack/steal it. And remember, if someone really wants to do it, they will do it, it is all just a matter of time.

So you still want to obfuscate your code and you may wonder, why is it so difficult? There are so many great programs out there to obfuscate .net code.

Well, it is quite easy as long as you do as much as possible from code and use the Unity GUI as little as possible. Why? There is basically two main problems with obfuscation and Unity.

If we starts to attach scripts to GameObjects by drag and drop in the gui, the script and the GameObject will be strongly typed. Meaning that if we obfuscate a class name of a script bound to a GameObject then Unity will no longer be able to locate the attached script. So we are going to solve this by loading all prefabs the first time the application is starting and attach our scripts.
However, in Unity there must always be at least one script per scene, we will call those scripts controllers, so Scene1Controller, Scene2Controller and so on.
We won’t be able to obfuscate the names of the controller classes but we can still obfuscate their methods and properties.

Problem number two is that the events in our MonoBahavior objects is also not strongly typed, for example :

void Update()
{
//Some code
}

would become something like

void T20()
{
//Some code
}

after obfuscation and therefore the Update event won’t trigger on that object.

So we want to limit the amount of loose typed events in our code and instead use our own strongly typed events.

No lets start by creating the BahaviorEventBinder class.

public class BahaviorEventBinder : MonoBehaviour
{
public event UpdateExecutedDelegate OnUpdateExecuted;
public delegate void UpdateExecutedDelegate();
public event OnEnableDelegate OnEnableExecuted;
public delegate void OnEnableDelegate();
public event OnDisableDelegate OnDisableExecuted;
public delegate void OnDisableDelegate();
void Update()
{
if (OnUpdateExecuted != null)
{
OnUpdateExecuted();
}
}
void OnEnable()
{
if (OnEnableExecuted != null)
{
OnEnableExecuted();
}
}
void OnDisable()
{
if (OnDisableExecuted != null)
{
OnDisableExecuted();
}
}
}

All our MonoObjects will inherit from this class and this class contains loosely typed code. So this class can be obfuscated but make sure that the loosely typed functions (Update, OnEnable and OnDisable) will keep their names.

Now go ahead and create a MonoBahavior that inherits from our BahaviorEventBinder :

public class MyMonoBahavior : BahaviorEventBinder
{
public MyMonoBahavior()
{
OnEnableExecuted += MyMonoBahavior_OnEnableExecuted;
OnUpdateExecuted += MyMonoBahavior_OnUpdateExecuted;
OnDisableExecuted += MyMonoBahavior_OnDisableExecuted;
}
private void MyMonoBahavior_OnEnableExecuted()
{
// On enable code goes here
}
private void MyMonoBahavior_OnUpdateExecuted()
{
// On update code goes here
}
private void MyMonoBahavior_OnDisableExecuted()
{
// On disable code goes here
}
}

Our MonoBahavior is now safe to obfuscate.

Now we need something that will bind the script MyMonoBahavior to correct prefab since after obfuscation MyMonoBahavior will be named something else.

public class MyMonoBahaviorRegistrator
{
public void Registrate()
{
var gm = Resources.Load<GameObject>(“MyPrefab”);
var s = gm.GetComponent<MyMonoBahavior>();
if (s == null)
{
s = gm.AddComponent<MyMonoBahavior>();
}
}
}

So when Registrate is being called we will load the Prefab of my MyMonoBahavior and if not the script already is attached (which it wont be the first time we run the application) we will add the script to the prefab. When we call AddComponent the script will be added permanently to the prefab. So even if we close the application and restart it the script will still be there, so that if sentence is really important.

Now all we need to do is to create a controller class that will call the MyMonoBahaviorRegistrator.Registrate();
This should done in the first scene so we will call this script Scene1Controller.
The name of the Scene1Controller class can not be obfuscated since it must be placed in the scene.

public class Scene1Controller : BahaviorEventBinder
{
public Scene1Controller()
{
OnEnableExecuted += Scene1Controller_OnEnableExecuted;
}
private void Scene1Controller_OnEnableExecuted()
{
new MyMonoBahaviorRegistrator().Registrate();
}
}

That is basically it! Now your code should be safe to be obfuscated, I usually use SharpObfuscator to obfuscate my code.

Remember not to obfuscate the class name of Scene1Controller. In BahaviorEventBinder everything can be obfuscated except loosely typed method names.

In order to obfuscate you first need to build the project. In this case I built it as a windows standalone application. Locate the dll file (/{application name}_Data/Managed/Assembly-CSharp.dll) and obfuscate it.

If you are working with android or iOS then you first need to extract the .dll file (both .apk and .ipa are zip files so you can open them with winRar), obfuscate the .dll file and then put the obfuscated file back.

If you followed these steps correctly then your code should be running without any problem.

To check if your assembly is obfuscated I recommend using iLSpy.

The game ZMBIS (Android) was developed by using this method and is fully obfuscated. Download the game and de compile it and you will see.

Source

Can be downloaded here.

Don’t forget to follow me on twitter.

BTC

1CGu9Ctt1AuyXiWMJ2nEDoH1RRAKtStdjx

ETH

0xd2291b554075da7f61210db2648a7f0a2d006190

--

--

Kristoffer Karlsson

Software developer and indie game developer from Sweden. Been turning coffee into code since 2010.