Reprogram running software, from the app down to the kernel.
Frida is a dynamic instrumentation toolkit. It puts your code inside live processes and operating system kernels, where you can hook any function, trace private code, and change behavior while the target keeps running. No source code, no rebuild, no restart.
- User mode
- Windows, macOS, GNU/Linux, iOS, watchOS, tvOS, Android, FreeBSD, QNX, and PlayStation 5.
- Kernel mode
- Windows NT from XP through 11, Windows 9x/ME, XNU, and Linux, in virtual machines or on physical hardware.
- Bare metal
- Microcontrollers and custom kernels, over a debug stub.
Four ways in.
Pick the vantage point the target allows. Everything above it, from the scripting API to frida-trace and Luma, stays the same.
Injected
frida-core
Attach to a running process, or spawn one with your hooks in place before its first instruction. frida-core does the injecting, from inside your own tool on the machine you are on. On a remote device it runs headless as frida-server, and frida-portal fronts a whole fleet the same way. How injection works.
As a library
frida-gadget
No root or jailbreak? Frida injects Gadget into a debuggable iOS or Android app for you. Elsewhere, preload it, load it from your own test runner, or repackage an app with it when you want custom tweaks baked in. It waits for you to connect, or runs scripts on its own. About Gadget.
In the kernel
frida-barebone-agent
Load the Barebone agent into the operating system kernel, as a driver or through a debugger. Instrument the kernel itself and every process above it, from one session, with nothing left for the process to detect. Meet Barebone.
On bare metal
GDB remote stub
A microcontroller, a bootloader, or a kernel with no room for an agent: point Barebone at its GDB remote stub and your script runs on the host instead. Memory reads become stub reads, and Interceptor callbacks become breakpoints. Hand it a NativePointer and it places an inline hook in the target's memory, usually code you built with RustModule.
Get up and running in seconds.
One pip install gives you frida-trace, the REPL, frida-ps and friends. Here frida-trace spawns curl, hooks SSL_write, and a two-line edit to the generated handler shows each request before it is encrypted.
Frida 17.25.2 on Linux x86_64. A few status lines are trimmed; nothing else is edited.
Terminal
~ $ pip install frida-tools ~ $ frida-trace -f /usr/bin/curl -i SSL_write -- --http1.1 -s -o /dev/null https://frida.re Instrumenting... SSL_write: Auto-generated handler at "…/__handlers__/libssl.so.3/SSL_write.js" Started tracing 1 function. Web UI available at http://localhost:38595/ /* TID 0xb43a5 */ 126 ms SSL_write(ssl=0x55d7c85d5220, buf=0x55d7c85de900, num=0x48) Process terminated # Edit SSL_write.js so onEnter logs the plaintext instead: # const n = args[2].toInt32(); # log(JSON.stringify(args[1].readUtf8String(n))); ~ $ frida-trace -f /usr/bin/curl -i SSL_write -- --http1.1 -s -o /dev/null https://frida.re SSL_write: Loaded handler at "…/__handlers__/libssl.so.3/SSL_write.js" Started tracing 1 function. Web UI available at http://localhost:41553/ /* TID 0xb4408 */ 39 ms "GET / HTTP/1.1\r\nHost: frida.re\r\nUser-Agent: curl/8.23.0\r\nAccept: */*\r\n\r\n" Process terminated
Down to the kernel.
Barebone is Frida's bare-metal backend. Its agent is written in Rust around the same GumJS engine that runs inside user processes, so the API you already know now works against a kernel. Where there is no kernel to host it, the same API works over a debug stub alone.
Getting it in
- Through a GDB remote stub
- QEMU, VirtualBox, Parallels, and the Android emulator all expose one. So does a hardware debugger, which puts a physical device's kernel in reach over JTAG or SWD.
- As a driver
- On Linux and Android,
insmod frida-agent.ko. On macOS, load the agent as a kernel extension. Then ask frida-core for thebarebonedevice, from the CLI or the API:add_barebone_device()on the DeviceManager takes options, andFRIDA_BAREBONE_CONFIGpoints the default device at a JSON config. Only tools on another machine need afrida-server --device=barebonein between. - Or with no kernel at all
- Point Barebone at the target's GDB remote stub and your script runs on the host.
readU32()becomes a stub read, Interceptor with JavaScript callbacks becomes a software or hardware breakpoint, and Interceptor with a NativePointer becomes an inline hook in the target's memory, typically code built with RustModule, the Barebone runtime's counterpart to CModule.
What you get
- Kernel and user mode, together
- Enumerate processes, attach, spawn with instrumentation in place, hook functions, query the kernel's BTF types, and watch kernel modules come and go. From the kernel, the agent injects into user processes itself.
- Invisible from inside the process
- The kernel half cloaks the user-mode agent's threads and memory mappings. Runtime application self-protection looking from inside the process finds nothing to see.
- Light on memory
- User-mode agents map the same physical pages the kernel agent already uses. Each instrumented process allocates only its own writable portion.
From the command line
The same tools, pointed at a kernel instead of a process.
# Kernel running under QEMU with its GDB stub on? That is the default: 127.0.0.1:3333. ~ $ frida-ps -D barebone # Loaded frida-agent.ko or the kext instead? Point the default device at it. ~ $ FRIDA_BAREBONE_CONFIG=barebone.json frida-ps -D barebone # Attach to the kernel, or to any process, with frida, frida-trace, or Luma. # Scripts see kernel modules, kallsyms, and BTF types alongside the usual Gum APIs. # Tools on another machine? Run frida-server --device=barebone there and connect as usual.
Agents shipped with every release:
frida-barebone-agent-{linux-arm64, linux-arm, linux-x86_64, linux-x86, xnu-arm64, xnu-kext-arm64e, winnt-x86_64, winnt-x86, winnt-arm64, win9x-x86}.
The kext is the loadable kernel extension for macOS. The Linux kernel
module is built against your exact kernel from the GumJS devkit, so it
is not a prebuilt download.
JavaScript first, not JavaScript only.
Most people start with a few lines of JavaScript because the edit, save, see loop takes seconds. The rest of the stack speaks whatever you do, on the host and inside the target.
Interceptor.attach(Module.getGlobalExportByName('recvfrom'), { onEnter(args) { this.fd = args[0].toInt32(); }, onLeave(retval) { console.log(`recvfrom(fd=${this.fd}) => ${retval.toInt32()}`); } });
The agent side
This runs inside the target, in a process or in a kernel, on QuickJS or V8. Write it in TypeScript if you like, with autocompletion from the bundled type definitions. Hot paths can drop into C with CModule.
import frida device = frida.get_usb_device() session = device.attach("Twitter") script = session.create_script(open("agent.js").read()) script.on("message", lambda msg, data: print(msg["payload"])) script.load()
The host side
Device discovery, spawning, attaching and messaging. The same API that frida-tools is built on, so anything the CLI does, your script can do.
pip install frida
import frida from 'frida'; const device = await frida.getUsbDevice(); const session = await device.attach('Twitter'); const script = await session.createScript(source); script.message.connect(msg => console.log(msg.payload)); await script.load();
Same model, async by default
Typed bindings with Promises and signals, suited to tooling that talks to many devices at once, or to a desktop app built on Electron.
npm install frida
use frida::{Frida, DeviceManager, ScriptOption}; let frida = unsafe { Frida::obtain() }; let manager = DeviceManager::obtain(&frida); let device = manager.get_local_device()?; let session = device.attach(pid)?; let mut script = session.create_script(AGENT, &mut ScriptOption::default())?; script.handle_message(Handler)?; script.load()?;
No JavaScript required
The frida crate wraps frida-core for the host side. Build a static binary that drives devices and sessions without a Python or Node runtime anywhere near it.
use frida_gum::{Gum, Module, interceptor::*}; struct Log; impl InvocationListener for Log { fn on_enter(&mut self, ctx: InvocationContext) { println!("recvfrom(fd={})", ctx.arg(0)); } fn on_leave(&mut self, _ctx: InvocationContext) {} } let gum = Gum::obtain(); let mut interceptor = Interceptor::obtain(&gum); let recvfrom = Module::find_global_export_by_name("recvfrom").unwrap(); interceptor.attach(recvfrom, &mut Log).unwrap();
The hooks themselves, in Rust
The frida-gum crate exposes Interceptor, Stalker and the rest of Gum directly. Compile your instrumentation into a shared library and inject it, link it into your own program, or run it inside Gadget. No script engine in the loop.
Debug the build you already shipped.
Logging has blind spots, and you find them in the field. Instead of redeploying a special build just to see more, build a tool on Frida that attaches to the software your customers are already running.
Look anywhere, after the fact
Hook the function that the logs do not cover, inspect its arguments, and change what it returns, on the process that is misbehaving right now. No new build, no restart, no lost state.
One tool, every version
Resolve symbols, offsets and types at runtime, so a single product-specific tool supports the versions out in the field. That is more elegant than a tracing feature per release, and it ages better.
In-house or in-product
Keep the tool external and leave the product untouched, or ship Gadget inside your own software as a first-party inspector. Build it in Python, Rust, Swift or Node.js, or as a Luma workspace your whole team shares.
Prefer a GUI?
Luma is the official Frida app: a native workspace with persistent sessions, a live REPL, frida-trace with a built-in handler editor, and real-time collaboration.
Free
Frida is and will always be free software (free as in freedom). We want to empower the next generation of developer tools, and help other free software developers achieve interoperability through reverse engineering.
Battle-tested
NowSecure uses Frida to do fast, deep analysis of mobile apps at scale, and a comprehensive test suite runs on every change.
Scales down
Build only what you need. The same core fits embedded systems, with a footprint you control feature by feature.
In the open
Over a decade of releases, with detailed notes for every one, and a community that ships fixes upstream.