context
Starting from version 4.8, GameAssembly.dll and user_assembly.dll are no longer distributed as standalone files. The IL2CPP runtime is now embedded directly into GenshinImpact.exe. The traditional method — extracting global-metadata.dat and GameAssembly.dll, then processing them through Il2CppDumper — is no longer viable. A runtime dump approach is required.
This guide is based on the open-source dumper lRumper and the methodology described in Rumi’s article. The goal is to understand the internals and, ideally, develop a custom dumper.
how lRumper works
git clone https://github.com/lRefund/lRumper
The dumper operates as an injected DLL:
- Attaches to the game process
- Calls
il2cpp_MetadataCache_GetTypeInfoFromTypeDefinitionIndex— iterates through all TypeDefinitionIndex values to obtainklasspointers - For each class: retrieves namespace, name, parent type, methods, and fields via the corresponding IL2CPP APIs
- Writes the output to
dump.cs
Critical offsets (as defined in the lRumper source):
kOff_GetTypeInfo // il2cpp_MetadataCache_GetTypeInfoFromTypeDefinitionIndex
kOff_get_methods // il2cpp_class_get_methods
kOff_get_name // il2cpp_class_get_name
kOff_method_get_name // il2cpp_method_get_name
Additional optional APIs: get_namespace, get_parent, get_fields, field_get_name, field_get_flags, is_enum, class_from_type, field_get_type, method_get_return_type, method_get_param_count, method_get_param, method_get_param_name.
finding offsets via error strings
Load GenshinImpact.exe into IDA Pro and wait for auto-analysis to complete. All IL2CPP API functions are obfuscated — their names are not exported. The recommended approach is to locate them through error strings embedded in the binary.
Open the Strings window (View → Open subviews → Strings, Shift+F12). Each IL2CPP function logs a characteristic error string when it encounters an invalid state. By locating the string, following its cross-reference, and tracing upward to the function entry point, the RVA offset can be extracted.
offset reference table
| Offset | Search string in IDA |
|---|---|
GetTypeInfoFromTypeDefinitionIndex |
because generic types cannot have explicit layout. |
il2cpp_class_get_name |
%s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s. |
il2cpp_class_get_namespace |
%s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s. |
il2cpp_class_get_methods |
ConstructorInfo (locate via Class::GetMethods xref) |
il2cpp_method_get_name |
Script error (%s): %s.\n |
il2cpp_class_get_fields |
Class::GetFields (locate via cross-reference) |
il2cpp_field_get_name |
value__ (use Immediate Value + xref; the function is inlined) |
procedure
- Open Strings window (Shift+F12), paste the search string, locate the match
- Double-click the string, then open cross-references (Ctrl+X)
- Navigate upward from the xref to the function prologue
- Record the function RVA — this is the offset
example: il2cpp_class_get_name
- Search for
%s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s. - Follow the cross-reference to the call site
- Trace upward to the containing function
- This function is
il2cpp_class_get_name. Record its RVA.
note on hardcoded offsets
Offsets such as 0x00588610, 0x00A1A7E0, 0x00A1A7F0 from the original article are specific to a particular build. API addresses and obfuscation patterns change between game updates. Offsets must be re-located after every patch.
undocumented offsets
For APIs not covered by the reference table above, the error strings can be extracted from the Unity IL2CPP source.
method
- Download and install Unity 2017.4.30f1
- Open the installation directory in an editor with global search (VS Code, Rider)
- Use
Ctrl+Shift+Fto search for the export name (e.g.il2cpp_method_get_return_type) - Locate the matching source file — it will contain an error string such as
"implementation not found" - Copy the error string
- Return to IDA: Strings window (Shift+F12) → paste the string → search
- Follow the xref → navigate to function start → F5 for pseudocode → record the RVA
undocumented API list
| API | Source of error string |
|---|---|
il2cpp_method_get_return_type |
Unity IL2CPP source → error string → IDA |
il2cpp_method_get_param_count |
Unity IL2CPP source → error string → IDA |
il2cpp_method_get_param |
Unity IL2CPP source → error string → IDA |
il2cpp_method_get_param_name |
Unity IL2CPP source → error string → IDA |
il2cpp_field_get_flags |
Unity IL2CPP source → error string → IDA |
il2cpp_field_static_get_value |
Unity IL2CPP source → error string → IDA |
il2cpp_field_get_type |
Unity IL2CPP source → error string → IDA |
il2cpp_class_from_type |
Unity IL2CPP source → error string → IDA |
il2cpp_class_is_enum |
Unity IL2CPP source → error string → IDA |
tip
When the pseudocode is difficult to parse manually, pass the decompiled function (F5 output) to an LLM. It will assist in identifying the logic and confirming the API match.
building and injecting
git clone https://github.com/lRefund/lRumper
# update offsets in Main.cpp, build Release x64
lRenjector.exe GenshinImpact.exe lRumper.dll
Output is written to %TEMP%\Dump\dump.cs.
developing a custom dumper
lRumper serves as a functional reference, but several improvements can be made in a custom implementation:
- Proper field type resolution (currently all fields are emitted as
System.Int32) - Method signature parsing via
il2cpp_method_get_return_type,il2cpp_method_get_param_count,il2cpp_method_get_param - Structured output format (JSON for automated processing)
- Multithreaded dumping (already implemented in lRumper)
The architecture remains the same: inject → iterate TypeDefinitionIndex → dump.
references
- lRumper — C++ runtime dumper
- lRenjector — injector
- Rumi’s guide — offset search methodology
offsets are patch-dependent and must be re-located in IDA after each game update.