In this tutorial you’ll use ILSpy and AssetStudio to extract code and assets from a compiled Unity game.
In the context of software, reverse engineering is the practice of analyzing a system to extract design and implementation information. This is often used to better understand how software functions. One method of reverse engineering is decompiling, which performs the opposite operations of a compiler to convert executable programs back into human-readable code.
You can decompile Unity games using specialized tools to extract the code and most assets. Here are some common use cases where this can be useful:
- Recover the lost code and assets of a game you made.
- Take a look at the source code or 3D models of a game to study and learn from.
- Mod a game by replacing assets with your own.
Note: With great power comes great responsibility. The reverse engineering techniques described in this tutorial are intended for legal use cases like recovering projects you made yourself or for educational use. Stealing code and assets and claiming them as your own is illegal and I am not responsible for any legal consequences.
In this tutorial, you’ll use ILSpy and AssetStudio to decompile a Unity game on Windows. Along the way, you’ll learn how to:
- Use ILSpy to decompile a game’s code
- Save the code to your computer
- Inspect assets using AssetStudio
- Extract audio and 3D models from a game
While I’ll be covering Windows applications in this tutorial, there are alternatives for Linux and macOS out there with the same functionality like AvaloniaILSpy and UnityPy. I’ve also added some more software considerations at the bottom of the tutorial, some of which are cross-platform.
Getting Started
Click the Download Materials button at the top or bottom of this page to download the sample game, Avoiding Responsibility. Extract the zip file to a folder for use later on. If you want, you can play the game on Windows by running Avoiding Responsibility.exe. You can quit the game by pressing Escape or Alt + F4.
Granted, there’s not much going on except for some red “responsibility” crystals falling down from above while a cheery tune plays in the background. It won’t be the game of the year anytime soon, but that’s not the focus of this tutorial. In the following sections, you’ll pick this game apart to access its source code and assets.
Tool requirements
On to the tools! Both ILSpy and AssetStudio need the .NET 6 SDK to work. To check if you already have this SDK installed, open a Command Prompt by opening the Start menu, entering “cmd” and pressing Enter. With the Command Prompt open, enter the following command and press Enter to execute it:
dotnet –list-sdks
If you have .NET 6 SDK installed, there should be a 6.X.X entry in the list:
If there’s no 6.X.X entry, or you get an “dotnet is not recognized” error, you’ll need to install the latest version of the SDK from here: https://dotnet.microsoft.com/en-us/download/dotnet/6.0
Choose the installer version that matches your CPU’s architecture and download it. In most modern systems, this will be x64:
Now install the SDK and re-run the dotnet –list-sdks command in a Command Prompt to verify it’s installed.
Downloading ILSpy and AssetStudio
With the requirements out of the way, head over to the releases page of ILSpy: https://github.com/icsharpcode/ILSpy/releases
Click on the Assets button at the bottom of the changelog of the latest release and click on the ILSpy_selfcontained_x64 zip to download it.
Once the download finishes, extract the zip to a folder for use in the next section.
Next up is AssetStudio, the download process here is similar to IlSpy. To start off, head over to the releases page: https://github.com/Perfare/AssetStudio/releases
Click the Assets button if the assets aren’t visible straight away and click on the .net6 link to download the .NET 6 version of AssetStudio.
Extract the contents of the zip to a folder for later use.
Extracting Source Code
To extract the code from the sample game, you’ll need to use ILSpy, which is a an open-source .NET assembly browser and decompiler. Unity games use C# for their scripts, which get compiled to Intermediate Language, or IL for short. IL is a lower level language than C#, but still higher level than machine code. Here’s what IL code looks like:
.method public hidebysig static void Main() il managed
{
.entrypoint
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr “Hello, World”
IL_0005: call void [mscorlib]System.Console::WriteLine
(class System.String)
} // end of method HelloWorld::Main
By default, Unity compiles all scripts together into a single file named Assembly-CSharp.dll. As a Unity developer, you can choose to group scripts in additional assembly definitions files, which will generate extra assembly files once you compile your game. ILSpy can read the IL code in these files and convert them back to C# classes.
Time to take a look at what IlSpy offers! Open the ILSpy folder and double click on ILSpy.exe to start ILSpy. If your requirements are in order, this is what you’ll see once the application loads:
Exploring ILSpy
The interface is split up into two main sections: a list of loaded assemblies on the left and the decompiled C# code on the right. ILSpy has some commonly used .NET assemblies loaded by default like mscorelib and System.
To load the sample game’s CSharp assembly, click on the folder icon in the menu bar or press CTRL + O on your keyboard to open a folder browser window.
Navigate to the Avoiding Responsibility folder you unzipped earlier, there should be a file named Avoiding Responsibility.exe in there. From there, navigate to the Data folder, named Avoiding Responsibility_Data in this case and open the Managed folder in there. In short: Game folder / Data / Managed.
You should see a list of DLL files in there.
Double-click Assembly-CSharp.dll to load the assembly in ILSpy. If all went well, a new entry was added in the Assemblies list on the left named Assembly-CSharp.
To inspect the assembly, click on the little + button on the left of the entry to expand the assembly. This unveils the following items:
- Metadata: This contains information on the assembly, including its headers and strings.
- References: A list of other assemblies this assembly references. ILSpy will automatically load in these assemblies when you’re inspecting code that references them, so don’t be surprised if the Assemblies list gets filled up with more assemblies.
- A “-” namespace: The sample game doesn’t use namespaces in its code, but other projects can have a list here of the different namespaces used. This is where the source code lives.
Expand the – namespace to get your first glimpse of something familiar — a list of classes! Next, click on the Rotate class and you’ll see the source code being shown on the right.
You may have to click the + buttons in the code to expand the methods, but it’s all right there:
Exporting Code
You can save the code by copy-pasting it into a file, or by right-clicking the class in the Assemblies list and selecting Save Code… in the menu. You can now choose a location to save the C# file to. Don’t worry, you’re free to copy my amazing code and use it for your own. :]
In large assemblies, having to inspect and save the classes separately can get tedious, so I’ll introduce you to a more efficient way of saving the code. Right-click on Assembly-CSharp and choose Save Code… in the menu. This will prompt you to choose a location to save the C# project file to. It might seem like you’re saving a single file here, but ILSpy will actually copy over all classes it can find as C# files, along with a project file.
Generally, ILSpy does a pretty good job of decompiling the code, but you may run into some weird code here and there if the decompiler wasn’t sure what to do. For instance, if you take a look at the BrokenResponsibility class, it has a DestroySelf method which differs from the original code. The decompiled version looks like this:
private void DestroySelf()
{
Object.Destroy(base.gameObject);
}
While the original code was the following:
private void DestroySelf()
{
Destroy(gameObject);
}
Note the Object class and base keyword that were added to the method call. The decompiled code is still valid, but you might want to consider cleaning it up a bit when using it in your own projects.
That concludes the use of ILSpy! It’s a powerful tool to keep in mind when you need to extract the source code from Unity games and other .NET based products. It has saved me a few times already when I lost my projects due to data corruption. Backups are better in every way, but this is a nice backup. Just remember to be nice and use it for good only.
Now you know how to inspect and save source code, it’s time to move on to extracting the assets.
Extracting Assets
AssetStudio is an open-source tool that can inspect and extract the following asset types from Unity 3.4 to 2022.1:
- Textures and sprites
- Audio
- Fonts
- Meshes
- Text
- Shaders
- Video files
- Animations
It does this by reverse engineering the packed formats and converting those back into usable formats. A texture for example can be converted into png, tga, jpeg or bmp.
Open AssetStudio by opening the folder you extracted in the Getting Started section and double-click AssetStudioGUI.exe. After a short while, you’ll be greeted by its user interface:
Tour of AssetStudio
Like ILSpy, AssetStudio has two main sections: a file browser on the left and a preview on the right. Unlike ILSpy however, there’s nothing to see here until you open an assets file or a folder of a compiled game.
Before delving deeper in the application, disable all error messages as at the time of writing AssetStudio has some issues with loading in shaders, resulting in a ton of errors being generated. To ignore these, select Debug in the toolbar and uncheck Show error message.
Now load in the assets by selecting File ▸ Load folder in the toolbar to open a folder browser window.
Navigate to the Avoiding Responsibility folder, you know you’re at the right place if you see the Avoiding Responsibility_Data folder:
Select this folder to load it. AssetStudio will now search all subfolders for any asset files and read their contents. This can take quite a while depending on the amount of assets and their type. As long as the progress bar at the bottom is moving and the text field below the preview reads “Read assets…” you should be good. It took my system about two minutes before the application was finally done loading.
Once the assets are loaded, you should see a list of scenes and prefabs appearing in the Scene Hierarchy tab:
You can expand these to get a rough idea of what sort of GameObjects make up the scene, but apart from that it’s not that useful.
Exporting Assets
Open the Asset List tab, as that’s where the fun begins. In here, you can find all assets supported by AssetStudio that are part of the sample game. Most of these are included by Unity, but some were added by me when creating the game.
The list can be filtered by name if you know what to look for by using the textbox below the tabs. For example, type in “Entertainer” and wait a short while, the list will shrink down to a single AudioClip of the background music.
Preview the file by clicking on its name in the Asset List and pressing the Play button in the Preview window on the right.
Click on the Stop button once you’re done enjoying the tune. You can save this asset by right-clicking its name and selecting Export selected assets in the menu. This will prompt you to choose a folder to save it to.
Note: The music is “The Entertainer” by Kevin MacLeod (incompetech.com). It’s licensed under the Creative Commons: By Attribution 4.0 License.
AssetStudio will create a folder based on the type of asset, AudioClip in this case. Inside you’ll find the audio file in WAV format.
Clear out the filter by selecting the text you’ve added and hitting Backspace or Delete on your keyboard. There’s another way to filter assets: by their type.
Select Filter Type ▸ Mesh in the toolbar to only show 3D models in the list. The models used in the sample game all have the same name: default. You can select them one by one to get a nice preview.
Now select all default meshes, right-click on any of them and select Export selected Assets in the menu. Select a folder to save the models to in the folder browser window like before.
Once the models are exported, they’re all in OBJ format. You can use an application like Blender to import these files, edit them and export to a format of your choosing. You can also use them as-is, as most game engines support OBJ meshes.
Here’s the default.obj file opened up in Blender as an example:
That’s it for AssetStudio, another fine tool to have in your arsenal.
Where to Go From Here?
Congratulations on finishing this tutorial! You now know how to extract the source code and assets out of a compiled Unity game. I sincerely hope these techniques will prove as useful for you as they did for me.
You can download the sample game using the Download Materials button at the top or bottom of this tutorial if you want to play around with it some more.
If you want to try out some other tools to reverse engineer Unity games, here are my recommendations:
- dnSpyEx: Similar to ILSpy, but it allows you to debug and even edit assemblies
- IL2CppDumper: Extracts the source code from games that were built with IL2CPP
- AssetRipper: An alternative to AssetStudio to extract assets
Thanks for reading this tutorial to the end! If you have any questions or comments, feel free to join the discussion below.
Source by www.kodeco.com