With 4.4 out the door, we can now offer you a brand new RPC API
that makes it super-easy to communicate with your scripts and have them expose
services to your application. We also got some amazing contributions from
Adam Brady, who just ported frida-node to
Nan, making it easy to build it for multiple
versions of Node.js.
So to summarize this release:
core: add new RPC API
python: add support for calling RPC exports
node: add support for calling RPC exports
node: allow posted message value to be anything serializable to JSON
Time for another packed release. This time we’re bringing a brand new spawn
gating API that lets you catch processes spawned by the system, and tons of
Android improvements and improvements all over the place.
So without further ado, the list of changes:
4.5.0:
core: add Process.pageSize constant
core: let Memory.alloc() allocate raw pages when size >= page size
core: fix NativeFunction’s handling of small return types
core: fix PC alignment when rewriting BLX instructions
core: add spawn gating API
core: implement get_frontmost_application() on Android
core: implement enumerate_applications() on Android
core: add support for spawning Android apps
core: add support for injecting into arm64 processes on Android
core: add support for Android M
core: patch the kernel’s live SELinux policy
core: integrate with SuperSU to work around restrictions on Samsung kernels
core: work around broken sigsetjmp on Android, and many other Android fixes
core: fix crash when enumerating modules on Linux
core: optimize exports enumeration for remote processes on Darwin
dalvik: port to ART and deprecate Dalvik name, now known as Java
java: add Java.openClassFile() to allow loading classes at runtime
java: fixes for array conversions and field setters
python: add support for the new spawn gating API
python: allow script source and name to be unicode on Python 2.x also
Wow, another major release! We decided to change the Device API to give you
persistent IDs so you can easily tell different devices apart as they’re
hotplugged.
But that’s just the beginning of it, we’re also bringing a ton of other
improvements this time:
5.0.0:
core: change Device.id to represent individual devices across reconnects
core: add new Droidy backend for interfacing with connected Android devices
core: adjust confusing iPhone 5+ device name on Darwin
core: normalize the fallback iOS device name for consistency with Android
core: upgrade V8 to 4.5.103.30
objc: include both class and instance methods in $methods and $ownMethods
python: add -D switch for specifying the device id to connect to
python: add frida-ls-devices CLI tool for listing devices
python: update to the new Device.id API
python: add get_local_device() and improve API consistency with frida-node
node: update to the new Device.id API
node: improve the top-level facade API
qml: update to the new Device.id API
clr: update to the new Device.id API
frida-ps: improve the output formatting
5.0.1:
core: add support for source maps
node: add frida.load() for turning a CommonJS module into a script
node: upgrade Nan
5.0.2:
core: add console.warn() and console.error()
core: add Module.enumerateImports() and implement on Darwin, Linux,
and Windows
core: allow null module name when calling Module.findExportByName()
core: move Darwin.Module and Darwin.Mapper from frida-core to frida-gum,
allowing easy Mach-O parsing and out-of-process dynamic linking
core: better handling of temporary files
frida-trace: add support for conveniently tracing imported functions
frida-trace: blacklist dyld_stub_binder from being traced
python: avoid logging getting overwritten by the status message changing
5.0.3:
core: improve arm64 hooking, including support for hooking short functions
5.0.4:
core: improve arm64 hooking, also taking care to avoid relocating instructions
that other instructions depend on, including the next instruction after
a BL/BLR/SVC instruction
core: port Arm64Writer and Arm64Relocator to Capstone
5.0.5:
core: fix crash on teardown by using new API provided by our GLib patch
core: fix module name resolving on Linux
core: improve ELF handling to also consider ET_EXEC images as valid modules
core: improve arm64 hooking
core: port {Arm,Thumb}Writer and {Arm,Thumb}Relocator to Capstone
python: fix tests on OS X 10.11
node: fix tests on OS X 10.11
5.0.6:
core: turn NativeFunction invocation crash into a JS exception when possible
core: add Process.setExceptionHandler() for handling native exceptions from
JS
core: install a default exception handler that emits error messages
core: prevent apps from overriding our exception handler if we install ours
early in the process life-time
core: gracefully handle it if we cannot replace native functions
core: allow RPC exports to return ArrayBuffer values
python: add support for rpc methods returning ArrayBuffer objects
node: add support for rpc methods returning ArrayBuffer objects
5.0.7:
core: don’t install a default exception handler for now
5.0.8:
Re-release of 5.0.7 due to build machine issues.
5.0.9:
python: update setup.py to match new build server configuration
5.0.10:
core: fix instrumentation of arm64 functions with early usage of IP registers
Epic release this time, with brand new iOS 9 support and improvements all over
the place. For some more background, check out my blog posts here
and here.
There’s a lot of ground to cover here, but the summary is basically:
6.0.0:
core: add support for OS X El Capitan
core: add support for iOS 9
core: fix launchd plist permissions in Cydia package
core: disable our dynamic linker on iOS for now
core: add new JavaScript runtime based on JavaScriptCore, as we cannot
use V8 on iOS 9 with the current jailbreak
core: add brand new system session when attaching to pid=0
core: improve arm hooking, including support for early TBZ/TBNZ/IT/B.cond,
and avoid relocating instructions that a later instruction loops back to
core: fix relocation of LDR.W instructions on arm64
core: abort when we’re stuck in an exception loop
core: fix AutoIgnorer-related deadlocks
core: drop our . prefix so temporary files are easier to discover
python: add support for running without ES6 support
python: tweak setup.py to allow offline installation
python: lock the prompt-toolkit version to 0.38 for now
frida-repl: fix display of raw buffers as returned by Memory.readByteArray()
frida-repl: fix crash in completion on error
node: add support for DeviceManager’s added and removed signals
node: add example showing how to watch available devices
node: use prebuild instead of node-pre-gyp
node: Babelify the source code read by frida.load()
node: remove frida.load() as it’s now in the frida-load module
6.0.1:
python: stop providing 3.4 binaries and move to 3.5 instead
node: fix Linux linking issue where we fail to pick up our libffi
node: also produce prebuild for Node.js LTS
6.0.2:
core: provide FridaGadget.dylib for instrumenting iOS apps without jailbreak
core: add support for the iOS Simulator
core: improve MemoryAccessMonitor to allow monitoring any combination of
R, W or X operations on a page
python: fix UTF-8 fields being accidentally exposed as str on Python 2.x
6.0.3:
core: fix spawn() on OS X
6.0.4:
core: add partial support for using the gadget standalone
CLI tools: fix crash when the stdout encoding cannot represent all characters
frida-trace: always treat handler scripts as UTF-8
6.0.5:
core: add logical shift right and left operations to NativePointer
core: improve Interceptor to support attaching to a replaced function
core: add support for hooking tiny functions on 32-bit ARM
core: emulate {Get/Set}LastErrror and TLS key access on Windows, allowing
us to hook more low-level APIs
6.0.6:
core: fix launchd / Jetsam issue on iOS 9
core: fix iOS 9 code signing issue
core: update security attributes on named pipe to allow us to inject into
more Windows apps
6.0.7:
core: add support for injecting into processes on linux-arm
core: fix crashes related to the DebugSymbol API on Mac and iOS
frida-trace: improve manpage parser
6.0.8:
core: fix Linux compatibility issue caused by failing to link libstdc++
statically
6.0.9:
core: add support for running frida-gadget standalone
core: add a temporary workaround for Windows compatibility regression
core: port the Fruity backend to Linux, allowing direct access to connected
iOS devices
core: expose the InvocationContext context read-write in the JavaScriptCore
runtime also
core: fix issue with InvocationContext’s CpuContext getting GCed prematurely
6.0.10:
Re-release of 6.0.9 with a Windows build regression fix.
6.0.11:
core: prevent stale HostSession objects in case of network errors
CLI tools: assume UTF-8 when the stdout encoding is unknown
node: fix double free caused by using the wrong Nan API
6.0.12:
core: update security attributes on named pipe on Windows
core: add CreateProcessW flags to prevent IFEO loop on Windows
core: fix hooking of recursive functions on arm and arm64
Some time ago @s1341 ported Frida to QNX, and just a
few weeks back he was running into memory footprint issues when using Frida on
embedded ARM devices. This was right after he contributed pull-requests porting
Frida to linux-arm. We started realizing that it might be time for a new
JavaScript runtime, and agreed that Duktape seemed like a
great fit for our needs.
This runtime has now landed, all tests are passing, and it even beats our V8
runtime on the measured overhead for a call to a hooked function with an empty
onEnter/onLeave callback. To give you an idea:
…/interceptor_on_enter_performance: V8 min=2max=31avg=2 OK
…/interceptor_on_enter_performance: DUK min=1max=2avg=1 OK
(Numbers are in microseconds, measured on a 4 GHz i7 running OS X 10.11.2.)
Anyway, even if that comparison isn’t entirely fair, as we do some clever
recycling and copy-on-write tricks that we don’t yet do in our V8 runtime, this
new runtime is already quite impressive. It also allows us to run on really tiny
devices, and the performance difference between a roaring JIT-powered monster
like V8 and a pure interpreter might not really matter for most users of Frida.
So starting with this release we are also including this brand new runtime
in all of our prebuilt binaries so you can try it out and tell us how it works
for you. It only adds a few hundred kilobytes of footprint, which is nothing
compared to the 6 MB that V8 adds per architecture slice. Please try it out
by passing --disable-jit to the CLI tools, or calling session.disable_jit()
before the first call to session.create_script().
Considering that this new runtime also solves some issues that would require a
lot of work to fix in our JavaScriptCore runtime, like ignoring calls from
background threads and avoid poisoning the app’s heap, we decided to get rid
of that runtime and switch to this new Duktape-based runtime on OSes where V8
cannot currently run, like on iOS 9. We feature-detect this at runtime, so you
still get to use V8 on iOS 8 like before – unless you explicitly --disable-jit
as just mentioned.
So in closing, here’s a summary of the changes:
6.1.0:
core: replace the JavaScriptCore runtime with its successor built on Duktape
core: add disable_jit() to allow users to try out the new Duktape engine
core: fix crash on Linux when injecting into processes where pthread_create
has never been called/bound yet
core: add support for linux-armhf (e.g. Raspberry Pi)
python: add disable_jit() to Session
node: add disableJit() to Session
CLI tools: add –disable-jit switch
frida-repl: upgrade to latest prompt-toolkit
frida-trace: fix crash when attempting to trace partially resolved imports
frida-trace: stick to ES5 in the generated handlers for Duktape compatibility
6.1.1:
core: fix synchronization logic and error-handling bugs in the Duktape runtime
6.1.2:
core: fix Android regression resulting in crash on inject
core: fix Python 3.x build regression
clr: add DisableJit() to Session
6.1.3:
core: give the iOS frida-helper all the entitlements that the Preferences app
has, so system session scripts can read and write system configuration
core: changes to support AppContainer ACL on temporary directory/files within
node: fix pid check so it allows attaching to the system session
6.1.4:
core: implement spawn() for console binaries on iOS
core: improve support for hooking low-level OS APIs
core: fix mapper issues preventing us from injecting into Mac processes
where libraries frida-agent depends are not yet loaded
core: make InvocationContext available to replaced functions also
6.1.5:
core: add support for generator functions in scripts generated by frida-load
Slides
for our talk—titled Testing interoperability with closed-source software through scriptable
diplomacy—are available on our presentations page. No videos of the talk yet.
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:
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
It’s been a while since our last major release bump. This time we’re addressing
the long-standing issue where 64-bit integers were represented as JavaScript
Number values. This meant that values beyond 53 bits were problematic due to
the fact that the underlying representation is a double.
The 64-bit types in the Memory, NativeFunction, and NativeCallback APIs
are now properly represented by the newly introduced Int64
and UInt64 types, and their APIs are almost
identical to NativePointer.
core: fix Int64/UInt64 field capacity on 32-bit architectures
7.0.2:
core: allow Int64 and UInt64 to be passed as-is to all relevant APIs
core: fix handling of $protocols on ObjC instances
7.0.3:
core: fix race-condition where listener gets destroyed mid-call
core: fix handling of nested native exception scopes
core: improve QNX support
frida-repl: tweak the startup message
7.0.4:
core: massively improve the function hooking success-rate on 32-bit ARM
core: improve the function hooking success-rate on 64-bit ARM
core: fix the sp value exposed by Interceptor on 32-bit ARM
7.0.5:
core: spin the main CFRunLoop while waiting for Device#resume() when
spawning iOS apps, allowing thread-sensitive early instrumentation to be
applied from the main thread
7.0.6:
core: fix hooking of half-word aligned functions on 32-bit ARM
core: fix thread enumeration on Linux
core: add simple hexdump() API to the Script runtimes
core: make the Duktape runtime’s CpuContext serializable to JSON
7.0.7:
core: allow passing a NativePointer to hexdump()
7.0.8:
core: fix handling of wrapper objects in retval.replace()
core: fix behavior of Memory.readUtf8String() when a size is specified
core: add support for the new task_for_pid(0) method on the iOS 9.1 JB
core: don’t use cbnz which is not available in ARM mode on some processors
core: implement enumerate_threads() and modify_thread() for QNX
7.0.9:
core: fix early crash in FridaGadget.dylib on iOS when running with
ios-deploy and other environments where we are loaded before
CoreFoundation
core: run a CFRunLoop in the main thread of frida-helper on Darwin,
allowing system session scripts to make use of even more Apple APIs
core: add stream APIs for working with GIO streams, for now only exposed
through UnixInputStream and UnixOutputStream (UNIX), and
Win32InputStream and Win32OutputStream (Windows)
7.0.10:
core: fix deadlock on script unload when I/O operations are pending
7.0.11:
core: spin the main CFRunLoop while FridaGadget.dylib is blocking waiting for
Device#resume(), allowing thread-sensitive early instrumentation to be
applied from the main thread
If you’ve ever used Frida to spawn programs making use of stdio you might have
been frustrated by how the spawned process’ stdio state was rather undefined and
left you with very little control. Starting with this release we have started
addressing this, and programs are now always spawned with stdin, stdout and
stderr redirected, and you can even input your own data to stdin and get
the data being written to stdout and stderr. Frida’s CLI tools get this
for free as this is wired up
in the ConsoleApplication base-class. If you’re not using ConsoleApplication
or you’re using a different language-binding, simply connect to the output
signal of the Device object and your handler will get three arguments each
time this signal is emitted: pid, fd, and data, in that order. Hit the
input() method on the same class to write to stdin. That’s all there is to
it.
Now that we have normalized the stdio behavior across platforms, we will
later be able to add API to disable stdio redirection.
Beside this and lots of bug-fixes we have also massively improved the support
for spawning plain programs on Darwin, on both Mac and iOS, where spawn() is
now lightning fast on both and no longer messes up the code-signing status on
iOS.
For those of you doing advanced instrumentation of Mac and iOS apps there’s now
also brand new API for dynamically creating your own Objective-C protocols at
runtime. We already supported creating new classes and proxy objects, and with
this new API you can do even more.
So in closing, here’s a summary of the changes:
7.1.0:
core: add Device.input() API for writing to stdin of spawned processes
core: add Device.output signal for propagating output from spawned processes
core: implement the new spawn() stdio behavior in the Windows, Darwin, and
Linux backends
core: downgrade to Capstone 3.x for now due to non-trivial regressions in 4.x
node: add support for the new stdio API
node: add missing return to error-path
python: add support for the new stdio API
7.1.1:
core: fix intermittent crash in spawn()
7.1.2:
core: rework the spawn() implementation on Darwin, now much faster and
reliable
core: add support for enumerating and looking up dynamic symbols on Darwin
core: fix page size computation in the Darwin Mach-O parser
7.1.3:
core: revert temporary hack
7.1.4:
python: fix ConsoleApplication crash on EOF
frida-trace: flush queued events before exiting
7.1.5:
frida-repl: improve REPL autocompletion
objc: add ObjC.registerProtocol() for dynamic protocol creation
objc: fix handling of class name conflicts
objc: allow proxies to be named
7.1.6:
python: fix setup.py download fallback
7.1.7:
python: improve the setup.py download fallback
7.1.8:
python: fix the setup.py local fallback and look in home directory instead
7.1.9:
core: fix handling of overlapping requests to attach to the same pid
core: (Darwin) fix spawn() without attach()
core: (Darwin) fix crash when shutdown requests overlap
frida-server: always recycle the same temporary directory
7.1.10:
core: (Windows) upgrade from VS2013 to VS2015
node: add prebuild for Node.js 6.x
python: fix handling of unicode command-line arguments on Python 2.x
qml: use libc++ instead of libstdc++ on Mac
7.1.11:
core: provide a proper error message when the remote Frida is incompatible
core: ignore attempts to detach from the system session
core: guard against create_script() and detach() overlapping
core: fix setTimeout() so the delay is optional and defaults to 0
Some of you may be aware that Frida has two JavaScript runtimes, one based
on V8, and another one based on Duktape.
We also used to have a runtime based on JavaScriptCore,
but it got retired when our Duktape runtime proved better in all of the
situations where V8 wasn’t a good fit, e.g. on tiny embedded systems and
systems where RWX pages are forbidden.
Anyway, what is pretty neat is that Duktape has an API for compiling to
bytecode, allowing you to cache the compiled code and save precious startup time
when it’s time to instrument a new process. Starting with this release we now
have brand new API for compiling your JavaScript to bytecode, and of course
instantiating a script from it. This API is not yet supported in our V8 runtime,
but we should be able to implement it there after our next V8 upgrade, by using
the WebAssembly infrastructure that started appearing in the latest releases.
So without further ado, let’s take this new API for a spin with the Duktape
runtime by forcing Frida to favor Duktape through Session.disable_jit().
Note that the same caveats as specified in the Duktape documentation
apply here, so make sure the code you’re trying to load is well-formed and
generated by the same version of Duktape. It may get upgraded when you upgrade
to a future version of Frida, but will at least be architecture-neutral; i.e.
you can compile to bytecode on a 64-bit x86 desktop and load it just fine in
a 32-bit iOS app on ARM.
So that’s bytecode compilation through the API, but you probably want to use the frida-compile
CLI tool for this instead:
While developing you can also use it in watch mode by adding -w, which makes
it watch the inputs and perform fast incremental builds whenever one of them
changes.
Whether you’re using bytecode (-b) or not, frida-compile is highly recommended
as it also comes with a number of other benefits, letting you:
Split your script into multiple .js files by using require().
It’s finally release o’clock, and this time around the focus has been on
improving quality. As it’s been a while since the last time we upgraded our
third-party dependencies, and I found myself tracking down a memory-leak in GLib
that had already been fixed upstream, I figured it was time to upgrade our
dependencies. So with this release I’m happy to announce that we’re now packing
the latest V8, GLib, Vala compiler, etc. Great care was also taken to eliminate
resource leaks, so you can attach to long-running processes without worrying
about memory allocations or OS handles piling up.
So in closing, let’s summarize the changes:
7.3.0:
core: upgrade to the latest V8, GLib, Vala, Android NDK, etc.
core: plug resource leaks
core: fix thread enumeration on Linux/x86-32
core: (arm64) improve function hooking by adding support for relocating LDRPC
with an FP/SIMD destination register
7.3.1:
core: build Android binaries with PIE like we used to
First off is the long-standing issue where multiple Frida clients attached to
the same process were forced to coordinate so none of them would call detach()
while one of the others was still using the session.
This was probably not a big deal for most users of Frida. However, we also had
the same issue if one running frida-server was shared by multiple clients.
You might have frida-trace running in one terminal while using the REPL in
another, both attached to the same process, and you wouldn’t then expect one of
them calling detach() to result in the other one getting kicked out.
Some of you may have tried this and observed that it works as expected, but this
was due to some crazy logic in frida-server that would keep track of how many
clients were interested in the same process, so it could ignore a detach()
call if other clients were still subscribed to the same session. It also had
some logic to clean up a certain client’s resources, e.g. scripts, if it
suddenly disconnected.
Starting with 8.0 we have moved the session awareness into the agent, and kept
the client-facing API the same, but with one little detail changed. Each call to
attach() will now get its own Session, and the injected agent is aware of it.
This means you can call detach() at any time, and only the scripts created in
your session will be destroyed. Also, if your session is the last one alive,
Frida will unload its agent from the target process.
That was the big change of this release, but we didn’t stop there.
One important feature of Frida’s scripts is that you can exchange messages with
them. A script may call send(message[, data]) to send a JSON-serializable
message, and optionally a binary blob of data next to it. The latter is so
you don’t have to spend CPU-cycles turning your binary data into text that you
include in the message.
It is also possible to communicate in the other direction, where the script
would call recv(callback) to get a callback when you post_message() to
it from your application. This allowed you to post a JSON-serializable message
to your script, but there was no support for sending a binary blob of data
next to it.
To address this shortcoming we renamed post_message() to post(), and gave it
an optional second argument allowing you to send a binary blob of data next to
it.
We also improved the C API by migrating from plain C arrays to GBytes,
which means we are able to minimize how many times we copy the data as it flows
through our APIs.
So in closing, let’s summarize the changes:
8.0.0:
core: add support for multiple parallel sessions
core: rename Script’s post_message() to post() and add support for passing
out-of-band binary data to the script
core: replace C arrays with GBytes to improve performance
core: fix heap corruption caused by use-after-free in libgee
core: fix multiple crashes
core: fix exports enumeration crash on macOS Sierra
core: add basic support for running on Valgrind
core: bump the macOS requirement to 10.9 so we can rely on libc++
node: update to the new 8.x API
python: update to the new 8.x API
swift: update to the new 8.x API
swift: upgrade to Swift 3
qml: update to the new 8.x API
clr: update to the new 8.x API
clr: plug leaks
8.0.1:
node: fix Script#post()
8.0.2:
core: fix deadlock when calling recv().wait() from our JS thread
8.0.3:
core: reduce Interceptor base overhead by up to 65%
core: minimize Interceptor GC churn in our V8 runtime, using the same
recycling and copy-on-write tricks as our Duktape runtime
core: speed up gum_process_get_current_thread_id() on macOS and iOS
It’s time for a release, and this time we have some big new things for those of
you building Frida-based tools, plus a few additional goodies. Let’s start with
the first part.
There’s no doubt that Frida’s JavaScript API is fairly low-level and only
meant to provide low-level building blocks that don’t pertain to just one
specific use-case. If your use-case involves grabbing screenshots on iOS, for
example, this is not functionality one would expect to find in Frida itself.
You may then wonder how different tools with common features are supposed to
share agent code with each other, and luckily the answer is not “copy paste”.
We have a growing ecosystem of Frida-specific libraries, like
frida-screenshot, frida-uikit, frida-trace, etc.
Perhaps some of you would be interested in APIs for instrumenting backend
software written in Java, .NET, Python, Ruby, or Perl, or perhaps you would want
to trace crypto APIs across different OSes and libraries, or some other cool
idea. I would then highly recommend that you publish your module to npm, perhaps
naming your module frida-$name to make it easy to discover.
Now you might be asking “but Frida does not support require(), how can I even
split my agent code into multiple files in the first place?”. I’m glad you
asked! This is where a handy little CLI tool called frida-compile enters
the picture.
You give it a .js file as input and it will take care of bundling up any other
files it depends on into just one file. But unlike a homegrown concatenation
solution using cat, the final result also gets an embedded source map, which
means filenames and line numbers in stack traces are meaningful. Modules are
also separated into separate closures so variables are contained and never
collide. You can also use the latest JavaScript syntax, like
arrow functions, destructuring, and generator functions, as it
compiles the code down to ES5 syntax for you. This means that your code also
runs on our Duktape-based runtime, which you are forced to use if you use Frida
on a jailed iOS device, or on a jailbroken iOS device running iOS >= 9.
In order to give you a short feedback loop while developing, frida-compile also
provides a watch mode through -w, so you get instant incremental builds as you
develop your agent.
Anyway, enough theory. Let’s look at how we can use an off-the-shelf web
application framework from npm, and inject that into any process.
First, make sure you have the latest version of Node.js installed. Next, create
an empty directory and paste this into a file named “package.json”:
{"name":"hello-frida","version":"1.0.0","scripts":{"prepublish":"npm run build","build":"frida-compile agent -o _agent.js","watch":"frida-compile agent -o _agent.js -w"},"devDependencies":{"express":"^4.14.0","frida-compile":"^2.0.6"}}
Then in agent.js, paste the following code:
'use strict';constexpress=require('express');constapp=express();app.get('/ranges',(req,res)=>{res.json(Process.enumerateRangesSync({protection:'---',coalesce:true}));}).get('/modules',(req,res)=>{res.json(Process.enumerateModulesSync());}).get('/modules/:name',(req,res)=>{try{res.json(Process.getModuleByName(req.params.name));}catch(e){res.status(404).send(e.message);}}).get('/modules/:name/exports',(req,res)=>{res.json(Module.enumerateExportsSync(req.params.name));}).get('/modules/:name/imports',(req,res)=>{res.json(Module.enumerateImportsSync(req.params.name));}).get('/objc/classes',(req,res)=>{if(ObjC.available){res.json(Object.keys(ObjC.classes));}else{res.status(404).send('Objective-C runtime not available in this process');}}).get('/threads',(req,res)=>{res.json(Process.enumerateThreadsSync());});app.listen(1337);
Install frida-compile and build your agent in one step:
$ npm install
Then load the generated _agent.js into a running process:
Sweet. We just built a process inspection REST API with 7 different endpoints in
fewer than 50 lines of code. What’s pretty cool about this is that we used an
off-the-shelf web application framework written for Node.js. You can actually
use any existing modules that rely on Node.js’ built-in net and http
modules. Like an FTP server, IRC client, or NSQ client.
So up until this release you could use Frida-specific modules like those
mentioned earlier. You could also use thousands of other modules from npm, as
most of them don’t do any I/O. Now with this release you also get access to
all net and http based modules, which opens up Frida for even more cool
use-cases.
In case you are curious how this was implemented, I added Socket.listen()
and Socket.connect() to Frida. These are minimal wrappers on top of GIO’s
SocketListener and SocketClient, which are already part of Frida’s
technology stack and used by Frida for its own needs. So that means our
footprint stays the same with no dependencies added. Because frida-compile
uses browserify behind the scenes, all we had to do was plug in our own
builtins for net and http. I simply ported the original net and http
modules from Node.js itself.
This release also brings some other goodies. One long-standing limitation with
NativeFunction is that calling a system API that requires you to read errno
(UNIX) or call GetLastError() (Windows) would be tricky to deal with. The
challenge is that Frida’s own code might clobber the current thread’s error
state between your NativeFunction call and when you try to read out the
error state.
Enter SystemFunction. It is exactly like NativeFunction, except that the
call returns an object wrapping the returned value and the error state right
afterwards. Here’s an example:
constopen=newSystemFunction(Module.findExportByName(null,'open'),'int',['pointer','int']);constO_RDONLY=0;constpath=Memory.allocUtf8String('/inexistent');constresult=open(path,O_RDONLY);console.log(JSON.stringify(result,null,2));/* * Which on Darwin typically results in the following output: * * { * "value": -1, * "errno": 2 * } * * Where 2 is ENOENT. */
This release also lets you read and modify this system error value from your
NativeCallback passed to Interceptor.replace(), which might come handy if
you are replacing system APIs. Note that you could already do this with
Interceptor.attach(), but that’s not an option in cases where you don’t want
the original function to get called.
Another big change worth mentioning is that our V8 runtime has been heavily
refactored. The code is now easier to understand and it is way less work to add
new features. Not just that, but our argument parsing is also handled by a
single code-path. This means that all of our APIs are much more resilient to bad
or missing arguments, so you get a JavaScript exception instead of having some
APIs do fewer checks and happily crash the target process in case you forgot an
argument.
Anyway, those are the highlights. Here’s a full summary of the changes:
8.1.0:
core: add Socket.listen() and Socket.connect()
core: add setImmediate() and clearImmediate()
core: improve set{Timeout,Interval}() to support passing arguments
core: fix performance-related bug in Interceptor’s dirty state logic
8.1.1:
core: add Script.nextTick()
8.1.2:
core: teach Socket.listen() and Socket.connect() about UNIX sockets
core: fix handling of this.errno / this.lastError replacement functions
core: add SystemFunction API to get errno / lastError on return
core: fix crash on close() during I/O with the Stream APIs
core: fix and consolidate argument handling in the V8 runtime
8.1.3:
core: temporarily disable Mapper on macOS in order to confirm whether this was
the root cause of reported stability issues
core: add .call() and .apply() to NativeFunction
objc: fix parsing of opaque struct types
8.1.4:
core: fix crash in the V8 runtime caused by invalid use of v8::Eternal
frida-repl: add batch mode support through -e and -q
8.1.5:
node: generate prebuilds for 6.0 (LTS) and 7.0 only
8.1.6:
node: generate prebuilds for 4.0 and 5.0 in addition to 6.0 and 7.0
8.1.7:
objc: fix infinite recursion when proxying some proxies
objc: add support for proxying non-NSObject instances
python: fix removal of signal callbacks that are member functions
Some big changes this time. We now use our Duktape-based JavaScript runtime
by default on all platforms, iOS app launching no longer piggybacks on Cydia
Substrate, and we are bringing some massive performance improvements. That, and
some bugfixes.
Let’s talk about Duktape first. Frida’s first JS runtime was based on V8,
and I’m really happy about that choice. It is however quite obvious that there
are use-cases where it is a bad fit.
Some systems, e.g. iOS, don’t allow RWX memory1,
and V8 won’t run without that. Another example is resource-constrained embedded
systems where there just isn’t enough memory. And, as reported by users from
time to time, some processes decide to configure their threads to have tiny
stacks. V8 is however quite stack-hungry, so if you hook a function called by
any of those threads, it won’t necessarily be able to enter V8, and your hooks
appear to be ignored2.
Another aspect is that V8 is way more expensive than Duktape for the native ⇔
JS transitions, so if your Frida agent is all about API hooks, and your hooks
are really small, you might actually be better off with Duktape. Garbage
collection is also more predictable with Duktape, which is good for hooking
time-sensitive code.
That said, if your agent is heavy on JavaScript, V8 will be way faster. It also
comes with native ES6 support, although this isn’t too big a deal since
non-trivial agents should be using frida-compile, which compiles your code
to ES5.
So the V8 runtime is not going away, and it will remain a first-class citizen.
The only thing that’s changing is that we pick Duktape by default, so that you
are guaranteed to get the same runtime on all platforms, with a high probability
that it’s going to work.
However, if your use-case is JS-heavy, all you have to do is callSession#enable_jit() before the first script is created, and V8 will be used.
For our CLI tools you may pass –enable-jit to get the same effect.
That was Duktape. What’s the story about app launching and Substrate, then?
Well, up until now our iOS app launching was piggybacking on Substrate. This was
a pragmatic solution in order to avoid going into interoperability scenarios
where Frida and Substrate would both hook posix_spawn() in launchd and
xpcproxy, and step on each other.
It was however on my long-term TODO to fix this, as it added a lot of complexity
in other areas. E.g. an out-of-band callback mechanism so our Substrate plugin
could talk back to us at load time, having to manage temporary files, etc.
In addition to that, it meant we were depending on a closed source third-party
component, even though it was a soft-dependency only needed for iOS app
launching. But still, it was the only part of Frida that indirectly required
permanent modifications to the running system, and we really want to avoid
that.
Let’s have a look at how the new app launching works. Imagine that you ran
this on your host machine that’s got a jailbroken iOS device connected to it
over USB:
$ frida-trace -U -f com.atebits.Tweetie2 -i open
We’re telling it to launch Twitter’s iOS app and trace functions named open.
As a side-note, if you’re curious about the details, frida-trace is written in
Python and is less than 900 lines of code, so it might be a good way to
learn more about building your own tools on top of Frida. Or perhaps you’d
like to improve frida-trace? Even better!
The first part that it does is that it gets hold of the first USB device and
launches the Twitter app there. This boils down to:
Our launchd.js agent then intercept launchd’s __posix_spawn() and addsPOSIX_SPAWN_START_SUSPENDED, and signals back the identifier and PID.
This is the /usr/libexec/xpcproxy helper that will perform an exec()-style
transition to become the app.
We then inject our xpcproxy.js agent into this so it can hook__posix_spawn() and add POSIX_SPAWN_START_SUSPENDED just like our launchd
agent did. This one will however also have POSIX_SPAWN_SETEXEC, so that
means it will replace itself with the app to be launched.
We resume() the xpcproxy process and wait for the exec to happen and the
process to be suspended.
At this point we let the device.spawn() return with the PID of the app that
was just launched. The app’s process has been created, and the main thread is
suspended at dyld’s entrypoint. frida-trace will then want to attach to it
so it can load its agent that hooks open. So it goes ahead and does something
similar to this:
session=device.attach(pid)script=session.create_script("""Interceptor.attach(Module.findExportByName(null, 'open'), { onEnter: function () { console.log('open()'); }});""")script.load()
Now that it has applied the instrumentation, it will ask Frida to resume
the process so the main thread can call main() and have some fun:
device.resume(pid)
Note that I did skip over a few details here, as the attach() operation is
actually a bit more complicated due to how uninitialized the process is, but
you can read more about that here.
Finally, let’s talk about footprint and performance. First, let’s examine how
much disk space is required when Frida is installed on an iOS device and is
in a fully operational state:
That’s the 64-bit version, which is only 1.87 MB xz-compressed. The 32-bit
version is obviously even smaller. Quite a few optimizations at play here:
We used to write the frida-helper binary out to a temporary file and spawn it.
The meat of the frida-helper program is now statically linked into
frida-server, and its entitlements have been boosted along with it. This
binary is only necessary when Frida is used as a plugin in an unknown process,
i.e. where we cannot make any guarantees about entitlements and code-signing.
In the frida-server case, however, it is able to guarantee that all such
constraints are met.
The library that we inject into processes to be instrumented,frida-agent.dylib, is no longer written out to a temporary file. We use
our own out-of-process dynamic linker to map it from frida-server’s memory
and directly into the address space of the target process. These mappings
are made copy-on-write, so that means it is as memory-efficient as the old
dlopen() approach was.
V8 was disabled for the iOS binaries as it’s only really usable on old
jailbreaks where the kernel is patched to allow RWX pages.
(If V8 is important to your use-case, you can build it like this:
make server-ios FRIDA_DIET=no)
The iOS package has been split into two, “Frida” for 64-bit devices, and
“Frida for 32-bit devices” for old devices.
Getting rid of the Substrate dependency for iOS app launching also meant
we got rid of FridaLoader.dylib. This is however a very minor improvement.
Alright, so that’s disk footprint. How about memory usage?
Nice. How about performance? Let’s have a look:
Note that these measurements include the time spent communicating from the
macOS host to the iOS device over USB.
Enjoy!
1 Except if the process has an entitlement, although that’s
limited to just one region. ↩
2: It is technically possible to work around this by
having a per-thread side-stack that we switch to before calling into V8. We
did actually have this partially implemented in the past. Might be something
we should revive in the longer term. ↩
This time we’re kicking it up a notch. We’re bringing you stability
improvements and state of the art JavaScript support.
Let’s talk about the stability improvements first. We fixed a heap
corruption affecting all Linux users. This one was particularly hard to
track down, but rr saved the day. The other issue was a crash on
unload in the Duktape runtime, affecting all OSes.
Dependencies were also upgraded, so as of Frida 10.0.0 you can now enjoy
V8 6.0.124, released just days ago. We also upgraded Duktape to the
latest 2.1.x. The Duktape upgrade resulted in slight changes to the
bytecode semantics, which meant we had to break our API slightly.
Instead of specifying a script’s name at load time, it is now specified
when compiling it to bytecode, as this metadata is now included in the
bytecode. This makes a lot more sense, so it was a welcome change.
Beside V8 and Duktape we’re also using the latest GLib, Vala compiler,
etc. These upgrades also included JSON-GLib, which recently ditched
autotools in favor of Meson. This is excellent news, as we’re also
planning on moving to Meson down the road, so we’ve now done the
necessary groundwork for making this happen.
So that’s about it. This upgrade should not require any changes to
existing code – unless of course you are among the few using the
bytecode API.
Frida provides quite a few building blocks that make it easy to do portable
instrumentation across many OSes and architectures. One area that’s been lacking
has been in non-portable use-cases. While we did provide some primitives like
Memory.alloc(Process.pageSize) and Memory.patchCode(), making it possible to
allocate and modify in-memory code, there wasn’t anything to help you actually
generate code. Or copy code from one memory location to another.
Considering that Frida needs to generate and transform quite a bit of machine
code for its own needs, e.g. to implement Interceptor and Stalker, it should
come as no surprise that we already have C APIs to do these things across six
different instruction set flavors. Initially these APIs were so barebones that I
didn’t see much value in exposing them to JavaScript, but after many years of
interesting internal use-cases they’ve evolved to the point where the essential
bits are now covered pretty well.
So with 10.4 we are finally exposing all of these APIs to JavaScript. It’s also
worth mentioning that these new bindings are auto-generated, so future additions
will be effortless.
Let’s take a look at an example on x86:
vargetLivesLeft=Module.findExportByName('game-engine.so','get_lives_left');varmaxPatchSize=64;// Do not write out of bounds, may be// a temporary buffer!Memory.patchCode(getLivesLeft,maxPatchSize,function(code){varcw=newX86Writer(code,{pc:getLivesLeft});cw.putMovRegU32('eax',9999);cw.putRet();cw.flush();});
Which means we replaced the beginning of our target function with simply:
moveax,9999ret
I.e. assuming the return type is int, we just replaced the function body withreturn 9999;.
As a side-note you could also use Memory.protect() to change the page
protection and then go ahead and write code all over the place, butMemory.patchCode() is very handy because it also
ensures CPU caches are flushed;
takes care of code-signing corner-cases on iOS.
So that was a simple example. Let’s try something a bit crazier:
Though that’s quite a few hoops just to multiply 42 by 7, the idea is to
illustrate how calling functions, even back into JavaScript, and jumping to
labels, is actually quite easy.
Finally, let’s look at how to copy instructions from one memory location to
another. Doing this correctly is typically a lot more complicated than a
straight memcpy(), as some instructions are position-dependent and need to
be adjusted based on their new locations in memory. Let’s look at how we can
solve this with Frida’s new relocator APIs:
We just made our own replica of puts() in just a few lines of code. Neat!
Note that you can also insert your own instructions, and use skipOne() to
selectively skip instructions in case you want to do custom instrumentation.
(This is how Stalker works.)
Anyway, that’s the gist of it. You can find the brand new API references at:
Also note that Process.arch is convenient for determining which
writer/relocator to use. On that note you may wonder why there’s just a single
implementation for 32- and 64-bit x86. The reason is that these instruction sets
are so close that it made sense to have a unified implementation. This also
makes it easier to write somewhat portable code, as some meta register-names are
available. E.g. xax resolves to eax vs rax depending on the kind of
process you are in.
The midnight oil has been burning and countless cups of coffee have been
consumed here at NowSecure, and boy do we have news for you this time.
Continuing in the spirit of last release’ low-level bag of goodies, we’ll be
moving one level up the stack this time. We are going to introduce a brand new
way to use new CodeWriter APIs, enabling you to weave in your own instructions
into the machine code executed by any thread of your choosing. We’re talking
lazy dynamic recompilation on a per-thread basis, with precise control of the
compilation process.
But first a little background. Most people using Frida are probably using theInterceptor API to perform inline hooking, and/or doing method swizzling or
replacement through the ObjC and Java APIs. The idea is typically to
modify some interesting API that you expect to be called, and be able to divert
execution to your own code in order to observe, augment, or fully replace
application behavior.
One drawback to such approaches is that code or data is modified, and such
changes can be trivially detected. This is fine though, as being invisible to
the hosting process’ own code is always going to be a cat and mouse game when
doing in-process instrumentation.
These techniques are however quite limited when trying to answer the question
of “behind this private API, which other APIs actually get called for a given
input?”. Or, when doing reversing and fuzzing, you might want to know where
execution diverges between two known inputs to a given function. Another example
is measuring code coverage. You could use Interceptor’s support for
instruction-level probes, first using a static analysis tool to find all the
basic blocks and then using Frida to put single-shot probes all over the place.
Enter Stalker. It’s not a new API, but it’s been fairly limited in what it
allowed you to do. Think of it as a per-thread code-tracer, where the thread’s
original machine code is dynamically recompiled to new memory locations in
order to weave in instrumentation between the original instructions.
It does this recompilation lazily, one basic-block at a time. Considering that
a lot of self-modifying code exists, it is careful about caching compiled blocks
in case the original code changes after the fact.
Stalker also goes to great lengths to recompile the code such that
side-effects are identical. E.g. if the original instruction is a CALL it will
make sure that the address of the original next instruction is what’s pushed on
the stack, and not the address of the next recompiled instruction.
Anyway, Stalker has historically been like a pet project inside of a pet
project. A lot of fun, but other parts of Frida received most of my attention
over the years. There have been some awesome exceptions though. Me and@karltk did some fun pair-programming sessions many years ago when we
sat down and decided to get Stalker working well on hostile code. At some
later point I put together CryptoShark in order get people excited about its
potential. Some time went by and suddenly Stalker received a critical bug-fix
contributed by Eloi Vanderbeken. Early this year, Antonio Ken Iannillo
jumped on board and ported it to arm64. Then, very recently, Erik Smit
showed up and fixed a critical bug where we would produce invalid code for
REP-prefixed JCC instructions. Yay!
Stalker’s API has so far been really limited. You can tell it to follow a
thread, including the thread you’re in, which is useful in combination with
inline hooking, i.e. Interceptor. The only two things you could do was:
Tell it which events you’re interested in, e.g. call: true, which will
produce one event per CALL instruction. This means Stalker will add some
logging code before each such instruction, and that would log where the
CALL happened, its target, and its stack depth. The other event types are
very similar.
Add your own call probes for specific targets, giving you a synchronous
callback into JavaScript when a CALL is made to a specific target.
I’m super-excited to announce that we’ve just introduced a third thing you
can do with this API, and this one is a game changer. You can now customize
the recompilation process, and it’s really easy:
The transform callback gets called synchronously whenever a new basic block
is about to be compiled. It gives you an iterator that you then use to drive
the recompilation-process forward, one instruction at a time. The returnedInstruction tells you what you need to know about the instruction that’s
about to be recompiled. You then call keep() to allow Stalker to recompile
it as it normally would. This means you can omit this call if you want to skip
some instructions, e.g. because you’ve replaced them with your own code. The
iterator also allows you to insert your own instructions, as it exposes the full
CodeWriter API of the current architecture, e.g. X86Writer.
The example above determines where the application’s own code is in memory, and
adds a few extra instructions before every RET instruction in any code belonging
to the application itself. This code checks if eax contains a value between 60
and 90, and if it does, calls out to JavaScript to let it implement arbitrarily
complex logic. This callback can read and modify registers as it pleases.
What’s nice about this approach is that you can insert code into hot code-paths
and selectively call into JavaScript, making it easy to do really fast checks in
machine code but offload more complex tasks to a higher level language. You can
also Memory.alloc() and have the generated code write directly there, without
entering into JavaScript at all.
So that’s the big new thing in 10.5. Special thanks to @asabil who helped
shape this new API.
In closing, the only other big change is that the Instruction API now exposes
a lot more details of the underlying Capstone instruction. Stalker also
uses a lot less memory on both x86 and arm64, and is also more reliable. Lastly,Process.setExceptionHandler() is now a documented API, along with ourSQLite API.
This component is really useful when dealing with jailed iOS and Android
devices, but is now also able to cover a lot of other scenarios.
Its environment variables are now gone, and have been replaced by an optional
configuration file. Because some apps may look for loaded libraries with “Frida”
in their name as part of their “anti-debug” defenses, we now allow you to rename
Gadget’s binary however you like. Along with this it now also supports three
different interaction types.
It can listen on a TCP port, like before, and it can also load scripts from the
filesystem and run fully autonomously. The latter part used to be really limited
but is now really flexible, as you can even tell it to load scripts from a
directory, where each script may have filters. This is pretty useful for
system-wide tampering, and should allow for even more interesting use-cases.
So without further ado, I would urge you all to check out the brand new docs
available here.
iOS users rejoice: Frida is now compatible with the latest Electra
jailbreak on iOS 11! At the time of this writing that means 1.0.4, but
now that Electra seems to have stabilized it should be safe to assume
that we’ll also be compatible with future updates. Just make sure you’re
not running anything older than 1.0.4.
In other news, our Android support has improved significantly over the
last releases, so if you’re even slightly behind: go grab the latest
10.7.x right away.
Some of you may be aware that Frida has two JavaScript runtimes, one based
on V8, and another one based on Duktape.
We also used to have a runtime based on JavaScriptCore,
but it got retired when our Duktape runtime proved better in all of the
situations where V8 wasn’t a good fit, e.g. on tiny embedded systems and
systems where RWX pages are forbidden.
Anyway, what is pretty neat is that Duktape has an API for compiling to
bytecode, allowing you to cache the compiled code and save precious startup time
when it’s time to instrument a new process. Starting with this release we now
have brand new API for compiling your JavaScript to bytecode, and of course
instantiating a script from it. This API is not yet supported in our V8 runtime,
but we should be able to implement it there after our next V8 upgrade, by using
the WebAssembly infrastructure that started appearing in the latest releases.
So without further ado, let’s take this new API for a spin with the Duktape
runtime by forcing Frida to favor Duktape through Session.disable_jit().
Note that the same caveats as specified in the Duktape documentation
apply here, so make sure the code you’re trying to load is well-formed and
generated by the same version of Duktape. It may get upgraded when you upgrade
to a future version of Frida, but will at least be architecture-neutral; i.e.
you can compile to bytecode on a 64-bit x86 desktop and load it just fine in
a 32-bit iOS app on ARM.
So that’s bytecode compilation through the API, but you probably want to use the frida-compile
CLI tool for this instead:
While developing you can also use it in watch mode by adding -w, which makes
it watch the inputs and perform fast incremental builds whenever one of them
changes.
Whether you’re using bytecode (-b) or not, frida-compile is highly recommended
as it also comes with a number of other benefits, letting you:
Split your script into multiple .js files by using require().
Use ES6 syntax and have your code compiled to ES5 so it’s compatible with
the Duktape runtime.
So in closing, let’s summarize the changes:
7.2.0:
core: add support for compiling and loading to/from bytecode
core: include error name and stack trace in RPC error replies
node: add support for the new bytecode APIs
node: augment RPC errors with name and stack when available
node: port examples to ES6
python: add support for the new bytecode APIs
python: update to the revised RPC protocol
7.2.1:
objc: add support for resolving methods on minimal Objective-C proxies
7.2.2:
objc: fix handling of methods returning structs and floating point values
7.2.3:
objc: expose the raw handle of Objective-C methods
7.2.4:
core: fix deadlock that was easily reproducible on iOS 9
java: improve Java.perform() robustness and handling of non-app processes
7.2.5:
objc: fix handling of methods returning a struct in registers on x86-64
7.2.6:
core: port Gum to MIPS
core: avoid swallowing exception when a Proxy object misbehaves
objc: add support for accessing Objective-C instance variables
7.2.7:
core: port .so injector to MIPS
core: enhance MIPS fuzzy backtracer with more branch-and-link instructions
core: fix UnixInputStream and UnixOutputStream pollable behavior on TTYs,
fixing hang on script unload
core: remove “0x” prefix from hexdump() offsets
7.2.8:
objc: fix parsing of type hints
objc: add support for including type hints
objc: make ObjC.Block’s types field public
objc: add support for properly declaring void *
core: (MIPS) fix stack offset when getting/setting stack arguments
7.2.9:
core: fix bug preventing registers from being written in the V8 runtime
7.2.10:
core: add support for attaching to iOS Simulator processes
core: fix Android class-resolving regression introduced in 7.2.4
7.2.11:
core: always kill iOS apps through SpringBoard
7.2.12:
objc: unregister Objective-C classes on unload and GC
7.2.13:
core: fix application kill logic on iOS 9
7.2.14:
core: make the Duktape runtime preemptible like the V8 runtime
core: fix a few locking bugs in the V8 runtime
7.2.15:
core: implement the Kernel API in the Duktape runtime also
core: remove the dangerous Kernel.enumerateThreads() API
7.2.16:
core: improve robustness when quickly reattaching to the same process
core: fix deadlock when pending calls exist at detach time
core: fix hooking regression on 32-bit ARM
core: fix dlsym() deadlock in frida-gadget on Linux
core: fix Windows build regression
core: fix iOS 7 regression
7.2.17:
core: fix session teardown regression
7.2.18:
core: fix long-standing stability issue on iOS 9, where the injected bootstrap
code was not pseudo-signed and caused processes to eventually lose their
CS_VALID status
core: speed up app launching on iOS by eliminating unnecessary disk I/O
core: fix temporary directory clean-up on iOS
7.2.19:
core: fix preemption-related lifetime-issue in the Duktape runtime
7.2.20:
core: rework the V8 runtime to support fully asynchronous unloading
core: rework the Duktape runtime to support fully asynchronous unloading
core: make the Duktape runtime fully reentrant
core: add Script.pin() and Script.unpin() for extending a script’s
lifetime in critical moments, e.g. for callbacks expected from external
APIs out of one’s control
core: fix a timer-related leak in both the V8 and the Duktape runtime
objc: keep script alive until callback scheduled by ObjC.schedule() has
been executed
objc: add a dealloc event to the ObjC proxy API
7.2.21:
core: fix hang on detach()
7.2.22:
core: fix hang on script unload
core: fix hang on abrupt connection loss during detach()
7.2.23:
core: fix two low-probability crashes during script unload
7.2.24:
core: fix use-after-free in the Duktape runtime
core: fix use-after-free bugs in ModuleApiResolver
core: improve unload-behavior when an exception handler is set
7.2.25:
core: fix app launching on iOS 9.3.3
frida-server: fix “hang” on detach when another client is attached to the
same process