You switched your Unity build to IL2CPP, and at some point you learned that a file called global-metadata.dat ships inside the APK. Tools read it to reconstruct your class names, method names, and string literals. You have seen that some studios encrypt it, and now you need to decide whether yours should.
Most of what is written about this file falls into two camps. One explains how to dump it. The other tells you to protect it and sells you something that does. Neither gives you what the decision actually needs: what the protection changes, what it leaves untouched, and what it costs to keep working.
Encrypting global-metadata.dat raises the capability level an attacker needs. It does not remove your program's structure from the build, because the runtime still has to read that structure to run your game.
Before any of that is worth discussing, there is a more upstream assumption to correct. It is the reason many teams never examine this question closely, and it comes from what developers believe IL2CPP already did for them.
IL2CPP Is a Compiler, Not a Security Feature
Unity's current documentation introduces IL2CPP as its custom ahead-of-time scripting back end, originally developed for platforms such as iOS that do not support Mono and just-in-time compilation. It converts intermediate language to C++, compiles that to platform-specific native code, and packages the result in the target platform's normal format. The benefits Unity names are performance and shorter startup times. The cost Unity names is that including machine code in the build generally increases both build time and final application size.
That is the whole of it. Unity describes a compilation strategy with a stated trade-off. There is no claim anywhere in that documentation that IL2CPP protects your code, obscures your logic, or raises the difficulty of reverse engineering. Nor has Unity added one since: developers were still asking for metadata encryption as a built-in engine option in February 2026.
The gap between that and what developers believe is documented in the tooling itself. The IDA plugin unity_metadata_loader opens its README by noting that IL2CPP compilation strips symbols such as class and function names from the binary, which makes static analysis of these games significantly harder and, in its words, is usually considered un-hackable — and then describes recovering all class names, method names, and string constants and mapping them back into IDA. The tool exists because the belief exists.
Both things are true at once. Compiling to native code does raise the effort required to read your program, and that is a real effect worth having. It is a by-product of how IL2CPP works rather than a protection Unity designed or supports, which is why the amount of protection it provides is not something Unity maintains, documents, or commits to across versions.
What Is Actually in the File
Native code carries no notion of a class name or a method signature. The IL2CPP runtime still needs those things — to resolve types, dispatch virtual calls, read and write fields at known offsets, and hand back string literals. Unity puts that information in global-metadata.dat and ships it alongside the native binary.
For anyone analyzing your build, that file is the difference between a stripped binary and an annotated one. Static tools read it to rebuild a symbol table and map those symbols onto addresses in libil2cpp.so, turning what would otherwise be thousands of unnamed subroutines into a browsable class hierarchy with your original names attached. What matters for the decision is narrower than how that works: the file is a discrete artifact on disk, read through a specific code path at startup, and that code path is where every static protection scheme intervenes.
What Encryption Changes
The static analysis path has three steps. A tool reads the metadata file, parses its structures, and reconstructs symbols from them. Encrypting the file breaks the first step, and everything downstream of it fails.
The effect is visible in the issue trackers of the tools themselves. In March 2024, a user reported that Il2CppDumper 6.7.40 could no longer process Standoff 2, a Unity 2022.3.19f1 build: the dumper threw an end-of-stream exception while reading metadata class arrays and never reached IL2CPP initialization at all. A commenter suggested loading the metadata structure in IDA, applying it to the global metadata header, and comparing output across two tool versions — and added that he did not think the fix could be automated.
That case was not an encryption case. The reporter explicitly said the developers had broken the metadata rather than encrypted it: the file's layout no longer matched what the parser expected. Encryption is a different intervention that produces a similar outcome, and both act on the same step of the same path. The case demonstrates that interfering with static metadata parsing can take an off-the-shelf tool from working to not working, and force whoever wants the symbols into manual structure analysis. It does not demonstrate that encryption specifically has been validated in the field, and it is one game against one tool version, not a measured effect.
The same caution runs in a second direction. A large share of dumper failures have nothing to do with protection at all: Il2CppDumper 6.7.46 rejects a Unity 6000.3.0f1 build outright with a message that metadata version 39 is not supported, because the tool has not caught up to a newer engine release. A failing dumper is not evidence that a protection worked. Teams evaluating this trade need to separate the two, because a build that resists today's tool version because of a Unity upgrade will stop resisting when the tool is updated, and no engineering effort of yours was involved either way.
What Encryption Does Not Change
Whatever you do to the file on disk, the IL2CPP runtime has to end up with usable metadata in memory. Encrypt it and the game must decrypt it during startup, because the runtime cannot resolve a single type without it. This follows from what IL2CPP needs in order to function rather than from any statement by Unity, and it is a property of the design rather than a flaw in any particular implementation.
That has a direct consequence for the attack surface. Once the process is running, the structures are present in memory in the form the runtime expects, and an attacker who can attach to the process does not need your file. The Frida module frida-il2cpp-bridge describes itself as a way to dump, trace, or hijack any IL2CPP application at runtime without needing the global-metadata.dat file. Its README states it should work across Unity versions from 5.3.0 through 6000.3.x, on Android, Linux, Windows, iOS, and macOS, with only Android and Linux tested.
The existence of a tool tells you what is possible, not how common it is, and nothing here says anything about how many Unity games are actually attacked this way. What it does establish is that the runtime path exists, is maintained, and covers the engine versions your game is likely built on.
What an in-process check can still observe from that position, and how much a developer should rely on it, is a separate question worth working through.
What encryption buys, stated honestly, is a shift in required capability. Someone with a downloaded dumper and no particular skill could previously extract your symbol table; that person is now stopped, and the people who are not stopped are the ones who can run instrumentation on a rooted or emulated device and work at runtime. You have not closed the door — you have moved it, and made the remaining path require tooling, environment setup, and knowledge that a meaningful share of casual attackers do not have.
What It Costs
The first-time implementation cost has fallen recently. In June 2026 the open-source .NET and Mono obfuscator BitMono shipped metadata support in version 0.42.1: a global-metadata.dat parser and inspector, an in-place metadata writer, and a metadata encryptor with a matching native C++ decryptor reference, with the encrypt-decrypt round trip verified byte-perfect on a real Unity 6 build. Work that used to mean patching Unity's own metadata loading path yourself now has a published implementation to start from.
What did not fall is everything that comes after. The same release notes make a useful inventory of it, because they record the failures a maintained implementation actually runs into rather than the ones a vendor page warns you about.
| Cost | What it looks like | When you pay it |
|---|---|---|
| Implementation | Intervening in the metadata loading path and pairing it with a build-side encryptor | Once — and there is now a published implementation to work from |
| Build pipeline coupling | Tooling that rewrites build output can break the build. One release note records build-time assemblies being shipped into the IL2CPP player build, hanging the build at "Extracting script serialization layouts" | Whenever the pipeline or the tool changes |
| Reflection and serialization | Renaming silently breaks [SerializeField] members, Unity-serialized fields, and methods invoked by name through Invoke or SendMessage, so each has to be excluded |
Continuously, as the codebase grows |
| Platform divergence | A developer who added decryption to Unity's metadata loading path reported it working on Android while the iOS build behaved as though the code never ran | Once per platform, then again on toolchain changes |
| Engine upgrades | Metadata format versions change across Unity releases — the same fact that leaves dumpers behind leaves your protection needing revalidation | Every engine upgrade |
The pattern in those middle rows is coupling. Anything that rewrites your build output binds itself to your build pipeline and to the engine's reflection and serialization behavior, and when that binding breaks it breaks at build time or at runtime in ways that do not point back at their cause. The real cost of metadata protection is not building it. It is keeping it working.
When It Is Worth Doing
Whether this trade pays off depends on who you expect to show up and what they can do when they arrive. Sorting attackers by capability rather than by intent makes the answer easier to see.
| Attacker profile | Capability | Effect of static metadata protection |
|---|---|---|
| Casual modder | Downloads a dumper, follows a guide | Largely effective — the off-the-shelf path stops working |
| Persistent modder | Reads structures manually, adapts tools, has time | Slows the work down, does not prevent it |
| Runtime-capable attacker | Rooted or emulated device, dynamic instrumentation | Little effect — the runtime path does not read the file |
Set against that, the case for doing it is strongest when your exposure is concentrated in the first row. A game whose risk is modded APKs circulating on third-party download sites, ad removal, or unlocked paid content is largely facing people working from tutorials. Raising the floor above tutorial level removes most of that volume, and volume is the whole problem when the same modified build is redistributed to thousands of players.
The case is weakest in two situations that look different but fail for the same reason. If a determined attacker with runtime tooling is your actual threat — because your game is competitive, or because a single compromised client is enough to cause harm — static metadata protection is aimed at the wrong step and will not reach them. Which step a control acts on, and which security layer it belongs to, matters more than how much of it you apply. And if what an attacker would gain by reading your client is state the server ultimately controls anyway, then symbol names were never the thing standing between them and the payoff.
That second case is the more common misjudgment. Teams reach for client-side protection because the client is the part they can change, when the state worth defending is decided somewhere else entirely.
If you do only one thing, do the one that costs least and survives longest: make sure your names carry no meaning before they ever reach the metadata file. Names are assigned at the C# stage, and the metadata file records what the compiler was given — so a build whose classes and methods are already meaningless produces metadata that reconstructs into meaningless symbols. Nothing about that approach touches the loading path, which is why the metadata format can change from one Unity release to the next without anything of yours needing to be revalidated.
Encrypting the file on top of that is a reasonable addition for teams with the budget to maintain it. It is a poor substitute for deciding what a compromised client is actually able to do — which is the question underneath this one, and the one worth answering first.
References
- Unity Manual: Introduction to IL2CPP
- Unity Discussions: IL2CPP & Data Encryption — February 16, 2026
- Unity Discussions: Encrypt il2cpp's global-metadata.dat, but not work on iOS — June 2020
- Il2CppDumper Issue #781: Il2cppdumper stopped working on Standoff 2 — March 2024
- Il2CppDumper Issue #892: unsupported metadata version 39 — December 11, 2025
- frida-il2cpp-bridge
- unity_metadata_loader
- BitMono release 0.42.1 — June 2026