Skip to content

Understanding Why ILSpy Get Empty Function Bodies From Assembly-CSharp.dll and How to Handle Them

As a security engineer working with Unity projects, you might encounter situations where, upon inspecting the Assembly-CSharp.dll using a tool like ILSpy, the function bodies appear empty. This can be puzzling, especially when you're attempting to analyze or reverse-engineer a Unity application. In this article, we'll delve into why this happens and discuss methods to effectively handle and analyze such scenarios.

Why Are the Function Bodies Empty?

1. Unity's IL2CPP Compilation and WebAssembly

  • IL2CPP Overview: Unity provides an option to compile scripts using IL2CPP (Intermediate Language To C++), which converts C# scripts into C++ code before compiling them into native binaries.
  • WebAssembly Targets: When building Unity projects for WebGL platforms, IL2CPP is used to compile scripts into C++ and then into WebAssembly (.wasm) code. This process enhances performance and security but complicates straightforward decompilation.

2. Lack of Intermediate Language (IL) Code in Assembly-CSharp.dll

  • No IL Code: The Assembly-CSharp.dll generated during an IL2CPP build doesn't contain actual IL code for the methods. Instead, it includes metadata definitions of types and methods.
  • Empty Function Bodies: When you open this DLL in ILSpy or similar .NET decompilers, they rely on IL code to reconstruct the source code. Since the IL code is absent, the decompiler shows empty function bodies.

3. Role of Il2CppDumper

  • Metadata Extraction: Tools like Il2CppDumper are designed to process IL2CPP-compiled binaries. They extract metadata and attempt to reconstruct assemblies.
  • Limitations with WebAssembly: When dealing with WebAssembly files (.wasm), Il2CppDumper can generate dummy Assembly-CSharp.dll files. However, these DLLs lack the actual method implementations, resulting in empty function bodies in decompilers.

How to Handle Empty Function Bodies

While standard .NET decompilers fall short in this scenario, you can still analyze and reverse-engineer the application using specialized tools and techniques.

1. Use WebAssembly Reverse Engineering Tools

Ghidra

  • What Is Ghidra?: Ghidra is an open-source reverse-engineering framework developed by the NSA. It supports a variety of architectures, including WebAssembly.
  • Steps to Use Ghidra:
    • Load the .wasm File: Open Ghidra and import your WebAssembly binary.
    • Analyze the Binary: Let Ghidra perform an auto-analysis to disassemble the code.
    • Interpret the Code: Although the output is in low-level code, Ghidra's decompiler can help you understand the logic.

IDL Pro

  • Alternative Tool: IDA Pro is a powerful, though commercial, reverse-engineering tool that supports WebAssembly with additional plugins.
  • Functionality: Similar to Ghidra, IDA Pro can disassemble and, to some extent, decompile WebAssembly code.

Binaryen and wasm-decompile

  • Binaryen: A compiler and toolchain infrastructure library for WebAssembly.
  • wasm-decompile: A tool within Binaryen that attempts to decompile WebAssembly into a readable form.

2. Combine Il2CppDumper with Reverse Engineering Tools

  • Generate Scripts: Il2CppDumper can produce scripts compatible with Ghidra or IDA Pro.
  • Import Metadata:
    • Run Il2CppDumper: Provide it with the .wasm file and the global-metadata.dat file.
    • Produce Mapping Scripts: It will generate scripts (e.g., ghidra_script.py or ida_script.py) containing symbol information.
  • Enhance Analysis:
    • Load Scripts into Ghidra/IDA Pro: After disassembling the .wasm file, run the generated script.
    • View Function Names: The script will map the symbol names to the disassembled code, making it easier to interpret.

3. Understand Limitations Due to Optimization and Obfuscation

  • Compiler Optimizations:
    • Code Inlining: Functions might be inlined, making them harder to isolate.
    • Dead Code Elimination: Unused code is removed, possibly omitting parts you're interested in.
  • Code Obfuscation:
    • Name Mangling: Variable and function names can be obfuscated.
    • Control Flow Alterations: The flow of the program might be modified to deter reverse engineering.

4. Reference

Summary

When dealing with Unity projects built for WebGL using IL2CPP, encountering empty function bodies in Assembly-CSharp.dll is expected due to the absence of IL code. The actual implementation resides within the WebAssembly binary. By utilizing tools like Ghidra, combined with metadata extracted via Il2CppDumper, you can effectively reverse-engineer and analyze the application.