Frida 6.2 Released ∞

release

It’s release o’clock, and this time we’re bringing you massive performance improvements on all platforms, a brand new API for looking up functions, and major stability improvements on iOS 9.

Let’s talk about the latter subject first. Some of you may have noticed weird bugs and deadlocks when using Frida on iOS 9. The root cause was simply that our inline hooking was causing the process to lose the CS_VALID bit of its code-signing status. This was not a problem on iOS 8 and older as jailbreaks were always able to patch the kernel to loosen up on its code-signing requirements. Starting with this release we have implemented some tricks to be able to do inline hooking without breaking the code-signing status. For the technically curious this means that we dynamically generate a .dylib as a temporary file, write out the new versions of the memory pages that we’d like to modify, e.g. the libc memory page containing open(), then pseudo-sign this binary, ask the kernel to F_ADDFILESIGS to it, and finally mmap() from this file on top of the original memory pages.

This brings us to the next topic: performance. The tricks that I just talked about do actually add quite a bit of extra overhead just to hook one single function. It is also a very different approach from what we can do on systems with support for read-write-execute memory-pages and relaxed code-signing requirements, so this obviously meant that major architectural changes were needed. I had also been thinking for a while about being able to apply a whole batch of hooks in one go, allowing us to be more efficient and have more control on exactly when hooks are activated.

Starting with this release, our Interceptor API now supports transactions. Simply call begin_transaction(), hook all the functions, and make them all active in one go by calling end_transaction(). This results in a massive performance boost, and you get all of this for free without any changes to your existing code. This is because we implicitly begin a transaction whenever we’re entering the JavaScript runtime, and end it when we’re leaving it (and just before we send() a message or return from an RPC method). So unless you’re attaching your hooks from timers or asynchronous APIs like Memory.scan(), they will all be batched into a single transaction and get a performance boost.

Here’s how we stack up to CydiaSubstrate in terms of performance:

400: Invalid request

Note that if you’re using our instrumentation engine from C or C++ you will have to call begin_transaction() and end_transaction() yourself to get this boost, but your code will still work even if you don’t, because every operation will implicitly contain a transaction, and the API allows nesting those calls.

That was function hooking performance, but we didn’t stop there. If you’ve ever used frida-trace to trace Objective-C APIs, or glob for functions across all loaded libraries, you may have noticed that it could take quite a while to resolve all the functions. If you combined this with early instrumentation it could even take so long that we exceeded the system’s launch timeout. All of this has now been optimized, and to give you an idea of the speed-up, a typical Objective-C case that used to take seconds is now completing in a few milliseconds.

Now to the final part of the news. Considering that dynamically discovering functions to hook is such a common use-case, and not just something that frida-trace does, we now have a brand new API for just that:

So in closing, here’s a summary of the changes:

6.2.0:

core: improve Interceptor to avoid breaking dynamic code-signing on iOS 9

core: move to a transaction-based Interceptor API for improved performance

core: fix crash when scheduled callbacks are freed late (V8 and Duktape)

frida-trace: improve performance by removing setTimeout() logic, allowing many hooks to be applied in the same transaction

frida-trace: batch log events in 50 ms chunks to improve performance

6.2.1:

core: add ApiResolver API

frida-trace: improve performance by using the new ApiResolver API

6.2.2:

core: fix oops that prevented injection into Windows Store/Universal apps

core: fix crash on teardown on 32-bit ARM

core: add frida-inject, a tool to inject an agent into a running process with similar semantics to frida-gadget

core: (Linux) prevent libdl from unloading to work around TLS destructor bug

core: (Linux) fix race-condition on rapid uninject

6.2.3:

core: fix source-map handling for eval code, which manifested itself as unhandled exceptions getting swallowed, e.g. when running frida-trace

core: fix Python 3.x build system regression

frida-trace: fix path escaping issue

frida-trace: improve error-handling for bad handlers

6.2.4:

frida-trace: monitor handlers instead of polling them

6.2.5:

core: add support for hooking arbitrary instructions by calling Interceptor.attach() with a function instead of a callbacks object

core: add support for detaching individual listeners added by Interceptor.attach(), even synchronously from their callbacks

core: add Memory.scanSync()

core: fix clobber by improving Interceptor to preserve r12 aka IP on ARM

core: expose r8 through r12 to the JavaScript runtimes

core: fix crash on architectures where unaligned word access is not supported

frida-repl: simplify logic by using the RPC feature

node: upgrade to prebuild 3.x

6.2.6:

core: fix regression on non-jailbroken iOS systems

core: fix Interceptor regression in the Duktape runtime

core: fix module name of resolved imports

core: add API for specifying which host to connect to

core: improve QNX support and fix build regressions

core: fix the frida-inject build system on Mac

core: (Windows) fix crash when USB device location retrieval fails

frida-server: allow overriding the default listen address

frida-node: add addRemoteDevice() and removeRemoteDevice() to DeviceManager

frida-python: add -H switch for specifying the host to connect to

frida-python: add add_remote_device() and remove_remote_device() to DeviceManager

frida-python: fix compatibility issues with the Duktape runtime

frida-python: canonicalize the requested RPC method name

Enjoy!