Modes of Operation
Table of contents
Most of the time, however, you want to spawn an existing program, attach to a running program, or hijack one as it’s being spawned, and then run your instrumentation logic inside of it. As this is such a common way to use Frida, it is what most of our documentation focuses on. This functionality is provided by frida-core, which acts as a logistics layer that packages up GumJS into a shared library that it injects into existing software, and provides a two-way communication channel for talking to your scripts, if needed, and later unload them. Beside this core functionality, frida-core also lets you enumerate installed apps, running processes, and connected devices. The connected devices are typically iOS and Android devices where frida-server is running. That component is essentially just a daemon that exposes frida-core over TCP, on localhost:27042.
It is sometimes not possible to use Frida in Injected mode, for example on jailed iOS and Android systems. For such cases we provide you with frida-gadget, a shared library that you’re supposed to embed inside the app that you want to instrument. This library starts running as soon as the dynamic linker executes its constructor function, and exposes the same interface as frida-server does, listening on localhost:27042. The only difference is that the lists of running processes and installed apps only contain a single entry, which is for the app itself. The process name is always just Gadget, and the installed app’s identifier is always re.frida.Gadget. In order to achieve early instrumentation we let the aforementioned constructor function block until you either attach() to the process, or call resume() after going through the usual spawn() -> attach() -> …apply instrumentation… steps. This means that existing CLI tools like frida-trace work the same ways you’re already using them.
Perhaps you’re familiar with LD_PRELOAD, or DYLD_INSERT_LIBRARIES? Wouldn’t
it be cool if there was JS_PRELOAD? This is where frida-gadget, the shared
library discussed in the Embedded section, also provides a second
mode of operation which doesn’t involve any TCP or outside communication. All
you need to do is to set the
FRIDA_GADGET_SCRIPT environment variable to the
For example on Linux, just create the file
hook.js with the contents:
The latest frida-gadget for your OS can be found on GitHub.
Now just set two environment variables and launch your target process:
Use DYLD_INSERT_LIBRARIES on macOS and iOS. Note that /bin/cat won’t work on El Capitan and above, as it ignores such attempts for system binaries.
You may also add
FRIDA_GADGET_ENV=development while developing your
instrumentation logic, which will make frida-gadget watch your file for
changes and automatically reload the script whenever it changes on disk. This
will even work if your script hooks functions, like in this example above, as
all hooks are reverted automatically when the old version of the script is
The reason we expose an
init() method using Frida’s RPC feature
is because frida-gadget will call it and wait for it to return until it lets
the program continue executing its entrypoint. This means you can return a
Promise if you need to do something asynchronous, e.g. Memory.scan() to
locate a function you want to instrument, and guarantees that you won’t miss any
early calls. You may also expose a
dispose() method if you need to perform
some explicit cleanup when the process exits or your script get unloaded before
the new version is loaded from disk (which happens with
For debugging you can use console.log(), console.warn(), and console.error(), which will print to stdout/stderr.