Scripting backends: Mono and IL2CPP
Unity runs a game’s C# code through one of two backends, and the data folder shows which. Observed
| Game | Backend | Evidence | Confidence |
|---|---|---|---|
| SkateBIRD | Mono | MonoBleedingEdge/EmbedRuntime/mono-2.0-bdwgc.dll, Managed/ with 104 assemblies including Assembly-CSharp.dll (1,245,696 bytes) and Assembly-CSharp-firstpass.dll; no GameAssembly.dll |
Observed · SkateBIRD |
| PEAK | Mono | MonoBleedingEdge/ and PEAK_Data/Managed/ (Assembly-CSharp.dll, Photon, Zorro, Sirenix, Unity packages) |
Observed · PEAK |
| Sledding Game | IL2CPP | GameAssembly.dll and Sledding Game_Data/il2cpp_data/Metadata/global-metadata.dat (version 39, 26,654,580 bytes) |
Observed · Sledding |
| Big Walk | IL2CPP | GameAssembly.dll and Big Walk_Data/il2cpp_data/Metadata/global-metadata.dat (version 39, 20,269,204 bytes) |
Observed · Big Walk |
A Mono game’s code is ordinary .NET assemblies in Managed/, readable with a decompiler. SkateBIRD’s Assembly-CSharp.dll
has 947 type definitions and is not obfuscated; its namespaces include Skatebirb.Gameplay, Skatebirb.Managers and
ReflexCLI. Observed · SkateBIRD The list of assemblies is repeated in ScriptingAssemblies.json.
Observed · PEAK
A MonoBehaviour’s script identity in a scene is a reference to a MonoScript object, which names the assembly, namespace and
class; its field bytes follow the base fields (script fields). Observed
SkateBIRD’s Assembly-CSharp.dll never mentions AssetBundle, StreamingAssets or a mods folder, so the game has no
code path that loads outside content. Observed · SkateBIRD
IL2CPP
Section titled “IL2CPP”An IL2CPP game’s C# was translated to C++ and compiled into GameAssembly.dll. Class, method and field names survive in
global-metadata.dat (header magic 0xFAB11BAF, then the metadata version). Observed · Sledding, Big Walk Both IL2CPP
games here use metadata version 39. Proven · Sledding, Big Walk
Cpp2IL (2022.1.0-pre.21) reads version 39 metadata and writes dummy .NET assemblies with the game’s types and signatures,
and a decompiler on those gives the class and method list. Observed · Big Walk For Big Walk the output was about
14,000 signature lines over 120 dummy assemblies. Inferred · Big Walk The dummy assemblies lack serialized fields that the metadata does not give them,
so a type tree generated from them comes out 4 bytes short on types that serialize such fields: in Big Walk, PeckSwitch,
TrackedPeckState, PropHome and PlayerPose (each has a serialized ticket field the dummies miss). Types from the
Dissonance voice package do not dump. Observed · Big Walk
Cpp2IL’s dummy assemblies carry no custom attributes unless its attribute processors run
(--use-processor attributeanalyzer,attributeinjector), so a private field marked [SerializeField] looks like an
ordinary private field and a type tree generated from them leaves it out; every serialized value after it is then read
from the wrong offset. With the processors the attributes are restored and the same objects decode to plausible values.
Observed · two Unity 2022.3 and 6000.2 IL2CPP players outside these games, metadata version 31 Unity serializes a
non-public field only when it carries [SerializeField], which is why the attribute decides it.
Sourced · Unity Manual, Script serialization That Big Walk’s
missing ticket fields are private [SerializeField] fields dropped this way fits the 4-byte gap but has not been checked by
regenerating its assemblies with the processors. Inferred · Big Walk
The metadata alone is enough to confirm that a class exists: Big Walk’s contains HouseNetworkManager, NetworkMinder,
PeckSwitch, TrackedPeckState, PeckManager, TicketOffice, ITicketed, PlayerGrease, CullingAgent, KcpTransport,
HouseAuthenticator, WorldManager, DevSettings, PropHome and SaveManager. Observed · Big Walk Sledding Game’s
contains SkiLift, PlayerSledController, SnowmanBall and the FishNet generated code
(Sledding scripts). Observed · Sledding
Serialized MonoBehaviour fields under IL2CPP
Section titled “Serialized MonoBehaviour fields under IL2CPP”A stripped IL2CPP player has no type tree for a script’s fields either, so the same raw-bytes rule applies. A layout has to come from the generated assemblies (with the 4-byte caveat above) or from measuring the data. Observed
Whether dummy assemblies generated with the attribute processors account for every serialized field (Big Walk’s ticket
fields included), or whether some fields are still missed for another reason, is not established.