frida-il2cpp-bridge
frida-il2cpp-bridge copied to clipboard
A Frida module to dump, trace or hijack any Il2Cpp application at runtime, without needing the global-metadata.dat file.
frida-il2cpp-bridge
A Frida module to dump, trace or hijack any Il2Cpp application at runtime, without needing the global-metadata.dat file.

Features
- Dump classes, methods, fields and so on
- Trace, intercept and replace method calls
- Mess around with C# runtime
- Il2Cpp structs and global metadata free
- (TODO) Emit C scaffold code to improve static analysis
Compatibility
Unity version
It should work for any Unity version in the range 5.3.0 - 2022.1.x.
Platforms
Android, Linux, Windows, iOS, macOS are supported. However, only Android and Linux are tested: expect breakage if you are using another platform.
Changelog
0.7.13
- Add
Il2Cpp.Thread::scheduleto schedule a delayed callback:
Of course, it can be used to schedule a callback on a specific thread (see versionIl2Cpp.perform(() => { const Class: Il2Cpp.Class = ...; Class.method("MethodName").implementation = function () { // we probably are on the "main" thread now // non blocking Il2Cpp.currentThread?.schedule(() => { // we are on the same thread! }, 1000); return this..method("MethodName").invoke(); }; });0.7.6release notes). Sometimes, you could face an access violation/abort error when trying to invoke a Il2Cpp function within the wrong thread.
Note:Il2Cpp.perform(() => { const Method: Il2Cpp.Method = ...; // access violation :( Method.invoke(); Il2Cpp.attachedThreads[0].schedule(() => { // works :) Method.invoke(); }); });Il2Cpp.Thread::schedulesimilar toIl2Cpp::scheduleOnInitializerThread. However, they use different approaches. Eventually, one of them will be removed.
Note:Il2Cpp.Thread::schedulemay not work with old Unity versions.
0.7.11
- Fix #171.
0.7.10
- Add
Il2Cpp.Reference::toto easily create aIl2Cpp.Reference:
AIl2Cpp.perform(() => { const TryParse = Il2Cpp.Image.corlib.class("System.Boolean").method("TryParse"); const value = Il2Cpp.Reference.to(false); console.log(value); // ->false TryParse.invoke(Il2Cpp.String.from("TrUe"), value); console.log(value); // ->true });Il2Cpp.Typeis required when creating a reference to anumberorNativePointerin order to disambiguate their representation:const value = Il2Cpp.Reference.to(1355, Il2Cpp.Image.corlib.class("System.UInt16").type); - Make
Il2Cpp.Object::unboxdirectly return aIl2Cpp.ValueType:// old const valueType = new Il2Cpp.ValueType(object.unbox(), object.class.type); // new const valueType = object.unbox();
0.7.9
- Minor things.
0.7.8
- Add
Il2Cpp::installExceptionListener. - Fix #132.
0.7.7
- Fix #107.
0.7.6
- Move
I2Cpp.Thread::currenttoIl2Cpp::currentThread. - Move
I2Cpp.Thread::alltoIl2Cpp::attachedThreads. - Add
Il2Cpp::sheduleOnInitializerThreadto run a callback inside the main Il2Cpp thread instead of Frida's one.
0.7.5
- Fix #66 and #95.
0.7.4
Il2Cpp.Method::restoreImplementationwas renamed toIl2Cpp.Method::revert.Il2Cpp.Tracerapi change:Il2Cpp.perform(() => { Il2Cpp.trace() .classes(Il2Cpp.Image.corlib.class("System.String")) .and() .attach("detailed"); });
0.7.3
Il2Cpp.Thread::idwas added.Il2Cpp::performcan now return a value:async function foo() { const result = await Il2Cpp.perform<string>(() => { const SystemBoolean = Il2Cpp.Image.corlib.class("System.Boolean"); return SystemBoolean.field("TrueLiteral").value.toString(); }); console.log(`Result from Il2Cpp: ${result}`); // ... }
0.7.2
Il2Cpp::internalCall,Il2Cpp::applicationDataPath,Il2Cpp::applicationIdentifier,Il2Cpp::applicationVersion,Il2Cpp::unityVersionwere added.unityTS module was removed as it was quite useless now that I don't need to interact with Unity native module anymore.Il2Cpp.Dumperwas removed as it was just boilerplate code -Il2Cpp::dumpgets the exact same job done.Il2Cpp.Dumper::methodsis gone - I'll provide a snippet to extract methods from the classic dump.Il2Cpp.Apiwill not give any hint about the required version when an export isn't found.
0.7.1
- Support Unity version up to 2022.1.x. Note:
Il2Cpp.GC::choosemakes the application crash in applications whose Unity version is above 2021.1. Il2Cpp.Class::toString,Il2Cpp.Field::toStringandIl2Cpp.Method::toStringare now implemented in JavaScript. I know this is a considerable performance loss, but the C code looks much simpler now as less logic is involved, also dumping is actually performed once per application, so it's not a total drama.Il2Cpp.Class::interfaceCount,Il2Cpp.Class::fieldCountandIl2Cpp.Class::methodCountwere removed because unnecessary.- Faster Unity version detection: the memory isn't scanned anymore, the proper function is invoked instead.
0.7.0
-
Il2Cpp.Domain::assemblies,Il2Cpp.Image::classes,Il2Cpp.Class::methodsand so on now return a plain simple array. -
Il2Cpp.Domain::assembly,Il2Cpp.Image::class,Il2Cpp.Class::methodand so on were added to obtain an item with the given name. They are all equivalent to the old accessor way:// old const mscorlib = Il2Cpp.Domain.assemblies.mscorlib.image; const SystemString = mscorlib.classes["System.String"]; // new const mscorlib = Il2Cpp.Domain.assembly("mscorlib").image; const SystemString = mscorlib.class("System.String");The new look is more consistent and easier to manage and has a positive noticeable impact on performance (e.g. there's no need to find all classes first). Lastly, but not least importantly, there's no need to cast an object to its base when trying to invoke a base method or accessing a base class!
However, there are a couple of important changes:
- Nested classes must be accessed within their declaring class via
Il2Cpp.Class::nested:// old const TransitionTime = mscorlib.classes["System.TimeZoneInfo.TransitionTime"]; // new const TransitionTime = mscorlib.class("System.TimeZoneInfo").nested("TransitionTime"); - Generic type parameters must follow IL convention, so
<T1, ... TN>becomes`Nwhen callingIl2Cpp.Image::classorIl2Cpp.Image::tryClass:// old const List = mscorlib.classes["System.Collections.Generic.List<T>"]; // new const List = mscorlib.class("System.Collections.Generic.List`1");
- Nested classes must be accessed within their declaring class via
-
Il2Cpp.Method::overloadwas added to help picking the correct method with the given parameter type names. -
Il2Cpp.Object::basewas removed because it's not necessary anymore. -
Il2Cpp.Method::implementdoes not artificially cast instances to the method declaring class anymore. -
Il2Cpp.Method::invokedoesn't try to catch C# exceptions anymore: the solutions I adopted (= catchabort was callederror) is unreliable and inconsistent. -
Il2Cpp.FieldandIl2Cpp.Methodnow have type parameters:const SystemBoolean = Il2Cpp.Image.corlib.class("System.Boolean"); const TrueLiteral = SystemBoolean.field<Il2Cpp.String>("TrueLiteral"); TrueLiteral.value = 23; // type error! const Parse = SystemBoolean.method<boolean>("Parse"); const result = Parse.invoke(Il2Cpp.String.from("true"));In
Il2Cpp.Methodthe type parameter was moved out frominvoke. Type parameters for method arguments aren't present because they add too much verbosity for little benefit.
Acknowledgements
Thanks to meme and knobse for helping and getting me into this, and to djkaty and nneonneo for providing the Il2Cpp api.
Problems?
Discussions and Wiki are both active. Use them!