Frida 16.2.0 Released ∞
release
Lots of exciting new things this time around. Let’s dive right in.
Thread Names
The Process.enumerateThreads() API now also exposes thread names when available:
Kudos to @Hexploitable for the awesome pull-request that got this ball rolling 🙌
Memory Protection Queries
Sometimes it’s essential to quickly determine the current protection of a page in memory. Thanks to @mrmacete, now you can:
QuickJS 2024-01-13
This release also contains the latest QuickJS, released last month. This means there’s almost complete ES2023 support, and even some features from the upcoming ES2024 specification. Plus, quite a few bug-fixes as well. It’s also worth mentioning that top-level await is now supported, making it easier to write portable scripts that work on both of our JavaScript runtimes.
Cloaking
Frida keeps track of its own memory ranges, threads, etc., to keep you from seeing yourself during process introspection. Introspection APIs such as Process.enumerateThreads() ensure that Frida’s own resources are hidden, and things appear as if you were not inside the process being instrumented.
For those of you using Stalker, or other things that expose you to raw memory locations, you might see code not belonging to any loaded module, and wonder where it came from. For example, if you use Stalker.follow() to follow execution into or out of a hooked function, it’s going to execute some trampoline code generated by Interceptor.
Agents using Gum’s C APIs could already query whether a given memory address, thread, etc., is owned by Frida, but this hadn’t yet been exposed to our JavaScript bindings. But now, thanks to another awesome contribution by @mrmacete, this is now supported. For example:
Fast Interceptor
One little known and fairly recent feature, now also available from JavaScript, is Interceptor.replaceFast(). What’s different about it is that the target is modified to vector directly to your replacement, which means there is less overhead compared to Interceptor.replace(). This also means that you need to use the returned pointer if you want to call the original implementation. It is also not possible to combine it with Interceptor.attach() for the same target. However, if you’re dealing with a hot target it’s definitely something you want to have in your toolbox, especially when combined with CModule.
ELF Exports Regression
We discovered way late that Frida 16.1.0 broke Module#enumerateExports() on some ELF binaries, and this is now finally fixed. It turned out to be a bug in the bounds-checking that I added when making Gum.ElfModule a cross-platform API, when it got support for offline use-cases like that of our Barebone backend. (Where we use it to dynamically inject Rust code into OS kernels and bare-metal targets.)
ELF Import Slots
Those of you using Frida on Apple platforms may have noticed that Module#enumerateImports() provides you with import objects that always have a slot property. One way you can use this is to write a new pointer to that address, letting you rebind imports on a per-module basis. Super-handy if Interceptor is unable to hook a function, or for scenarios where you want to avoid inline hooks.
As of this release, we now provide the slot property on ELF-based platforms too, so you can also use this feature on Linux, Android, FreeBSD, and QNX. Yay!
Android Stability
Avid users on recent versions of Android may have experienced “soft-loops”, where Frida randomly crashes Zygote and causes a big chunk of user-space to restart. This turned out to be caused by the runtime preparing itself to fork() by polling /proc/self/stat while waiting for the thread count to drop to one, i.e. waiting for the process to become single-threaded.
This has now been solved by subtracting the threads owned by Frida, which we determine by internally using the Cloak API, touched upon earlier in this post. We also make use of the new ELF Import Slots feature, so we can hook read() only for callers in libart.so. Inserting an inline hook in libc.so’s read() is not a great idea in this case, as the process we’re in might use it for a blocking read that blocks indefinitely. This becomes a challenge when wanting to unload, and getting stuck waiting for the chance to roll back our inline hook.
Anyway, quite an interesting bug. Shout-out to @enovella_ for reporting and helping track this one down 🙌
While on the topic of Android, this release also improves Java hooking on Android 14, where a new ART quick entrypoint is being used in case of –enable-optimizations. Kudos to @cr4zyserb for this neat contribution.
Better iOS 16 support
If you ever got hit by Service cannot load in requested session
when trying
to install Frida on iOS, this is now finally fixed. Kudos to @as0ler for the
assist on fixing this.
Jailbroken tvOS
Another exciting development is that we now support jailbroken tvOS, and you can grab a .deb straight from our repo at https://build.frida.re/. Special thanks to @tmm1 for the pull-requests that made this happen.
Misc
This release also has a lot more to offer. The remaining changes are:
- symbolutil-libdwarf: Fix handling of DW_AT_ranges in DWARF 5. This means the DebugSymbol API works properly on binaries built by newer toolchains.
- elf-module: Fix relocation address when online.
- interceptor: Check module prefix when claiming grafts on arm64, for compatibility with Xcode’s new libLogRedirect.dylib interposing on iOS 17. Thanks @mrmacete!
- interceptor: Cloak thunks on arm64. Thanks @mrmacete!
- windows: Ensure that the MSVC source-charset is set to UTF-8, so embedded JavaScript can be parsed correctly at runtime. Thanks @Qfrost911!
- freebsd: Improve allocate-near strategy.
- gumjs: Plug leak during QJS load() w/ ESM.
- objc: Ensure block structure is writable in implementation setter. Thanks @mrmacete!
- compiler: Bump @types/frida-gum to 18.6.0.
Enjoy!