v0.8.1 #296
vfsfitvnm
announced in
Announcements
v0.8.1
#296
Replies: 1 comment
-
Great Job! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
This is another important release!
JS vs C
Internally,
frida-il2cpp-bridge
used aCModule
to implement missing or additional IL2CPP internals (let's refer to these ones as internal fallbacks).This solution allowed the codebase to not be aware whether a specific IL2CPP internal was present or not, and had a positive impact on code consistency.
However, this solution had a practical drawback and mental one.
The former was the impossibility to use any of the internal fallbacks before, well, the creation of the
CModule
itself! This is obvious (you can't enter a room without opening its door, can you?), but the nasty thing was some internal fallbacks had a dependency on another internal fallbacks, but the creation of theCModule
is atomic, so I couldn't use some internal fallbacks before having other internal fallbacks compiled.Long story short: I couldn't implement 20f6923 and 7c766ec.
The latter is, whenever it came to add a new property to a IL2CPP struct (e.g.
Il2Cpp.Domain::object
), I didn't know if it would have made sense to implement it in C (e.g. 43d3659).This resulted in a cognitive load spike!
The only advantage of using C is speed. Like, 20x/50x improvement over JS. I'll admit: having
Il2Cpp::dump
complete in one fifth of the time andIl2Cpp::backtracer
initialize in one twentieth of the time was very tempting.However, after writing a proof of concept, I realized it wasn't worth it.
Eventually, my final decision was to implement the internal fallbacks in JS (exception made for
Il2Cpp::MemorySnapshot
internals): 20645bb.New threading model
Il2Cpp::perform
does four things jobs: wait for IL2CPP to be loaded and initialized, ensure the caller thread to IL2CPP, execute the given block and then detach the caller thread it has been previously attached byfrida-il2cpp-bridge
.In case you were wondering, I don't exactly know what "attaching to IL2CPP" really does, but it is necessary to do some IL2CPP related stuff. Moreover, when a thread is attached, the garbage collector tracks the resources the thread allocates, so that they can be freed when the thread detaches.
However, the implementation of
Il2Cpp::perform
has a major drawback.Let's consider this snippet:
If you are lazy, this is equivalent to the following:
Can you spot the issue?
The snippet is indeed correct, but it possibly makes the process crash.
How so? The problem here is
Il2pp::perform
itself. In fact, the following lineis invoked when the Frida thread isn't attached to IL2CPP anymore. Sure, you could wrap it inside another
Il2Cpp::perform
:But it still doesn't prevent the garbage collector from eagerly freeing
timer
(well, in this specific scenario, it's unlikely to happen).The same applies to the callbacks passed to
setImmediate
,setTimeout
andsetIntveral
: they are always executed off IL2CPP.Another important drawback of this approach is it wasn't quite nice to interact with IL2CPP from the Frida's REPL.
Now,
Il2Cpp::perform
takes a second (optional) parameter, a string that identifies the detach strategy:"always"
immediately detaches the caller thread after executing the given block (this the classic behaviour);"lazy"
detaches the caller thread only when the script is going to be reloaded or destroyed (this is now the default behaviour);"never"
never detaches the caller thread explicitly."never"
causes the nativeIl2Cpp::Thread
struct to be freed only when the underlying native thread is freed as well. For instance, in the context where you are prototyping a Frida script (so that you save and reload the script frequently to apply changes), it meansIl2Cpp.Thread::managedId
doesn't change across script realods.Now, the previous snippet has the following outcome:
Tracing
Some major refactorings were made to
Il2Cpp::Tracer
.Firstly, tracers are now thread-specific - the default intercepted thread is the main one.
Secondly, tracers are now not verbose by default: it means that they won't print the exact same call stack twice!
Thirdly, tracers now have appliers. An applier is just an jerkish OOP concept - you can read the commit 00865d3 to learn more - but the essential impact is the tracer-specific customization happens outside
Il2Cpp::Tracer
, so it is more flexible.For instance:
I strongly suggest you to use TypeScript with a language server, so you can easily inspect what you can or cannot call now.
Relevant changes
Make
Il2Cpp.Class::initialize
returnthis
:Fix
Il2Cpp.Thread::id
on Windows (Il2Cpp.Thread::id doesn't work on Windows #195).Rename
Il2Cpp::Api
toIl2Cpp::api
:It is now an object literal.
Rename
Il2Cpp.Class::valueSize
toIl2Cpp.Class::valueTypeSize
:Drop
Il2Cpp::Runtime
:It had no practical use cases.
Other changes
v0.8.0...v0.8.1
Beta Was this translation helpful? Give feedback.
All reactions