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:

  1. Attaches to the game process
  2. Calls il2cpp_MetadataCache_GetTypeInfoFromTypeDefinitionIndex — iterates through all TypeDefinitionIndex values to obtain klass pointers
  3. For each class: retrieves namespace, name, parent type, methods, and fields via the corresponding IL2CPP APIs
  4. 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

  1. Open Strings window (Shift+F12), paste the search string, locate the match
  2. Double-click the string, then open cross-references (Ctrl+X)
  3. Navigate upward from the xref to the function prologue
  4. Record the function RVA — this is the offset

example: il2cpp_class_get_name

  1. Search for %s%s%s must be instantiated using the ScriptableObject.CreateInstance method instead of new %s.
  2. Follow the cross-reference to the call site
  3. Trace upward to the containing function
  4. 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

  1. Download and install Unity 2017.4.30f1
  2. Open the installation directory in an editor with global search (VS Code, Rider)
  3. Use Ctrl+Shift+F to search for the export name (e.g. il2cpp_method_get_return_type)
  4. Locate the matching source file — it will contain an error string such as "implementation not found"
  5. Copy the error string
  6. Return to IDA: Strings window (Shift+F12) → paste the string → search
  7. 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


offsets are patch-dependent and must be re-located in IDA after each game update.