Frida is a world-class, open-source dynamic instrumentation toolkit that allows testers, reverse engineers, and developers to inject JavaScript (or Python-driven) snippets into running processes on Windows, macOS, GNU/Linux, iOS, Android, watchOS, tvOS, FreeBSD, and QNX. Rather than statically analyzing a compiled binary, Frida lets you observe and alter a program’s behavior while it is running, without needing to recompile or modify the original source code.
Frida operates through a client-server architecture:
- Frida Client – The CLI tools (
frida,frida-ps,frida-trace,frida-discover,frida-ls-devices,frida-kill) and Python/Node.js bindings that run on your host machine (the Kali Linux workstation). - Frida Server – A small executable (
frida-server) that runs on the target device (typically a rooted Android device or emulator) and listens for instrumentation requests from the client. For non-rooted targets, Frida also supports an injected Gadget library that can be embedded directly into a repackaged APK.
In mobile security testing, Frida is used to:
- Hook Java/Kotlin methods on Android (or Objective-C/Swift methods on iOS) to log arguments, modify return values, or trace call flow.
- Bypass client-side security controls such as SSL/TLS certificate pinning and root/jailbreak detection.
- Dump decrypted data, encryption keys, or session tokens directly from memory at runtime.
- Trace native library (
.so) function calls, including unexported functions by offset. - Serve as the underlying engine that higher-level tools such as Objection are built on top of.
How to Install
Install the Frida CLI tools on Kali Linux (client side):
# Install pip if not already present
sudo apt update
sudo apt install python3-pip -y
# Install frida-tools (includes frida, frida-ps, frida-trace, frida-discover,
# frida-ls-devices, frida-kill) plus the Python bindings
pip3 install frida-tools frida --break-system-packages
Verify installation and check the version:
$ frida --version
16.4.1
Install frida-server on a rooted Android device/emulator (server side):
# Determine your target device's CPU architecture
adb shell getprop ro.product.cpu.abi
# Example output: x86_64
# Download the matching frida-server release (version MUST match the client version)
wget https://github.com/frida/frida/releases/download/16.4.1/frida-server-16.4.1-android-x86_64.xz
# Extract
unxz frida-server-16.4.1-android-x86_64.xz
mv frida-server-16.4.1-android-x86_64 frida-server
# Push to the device and set permissions
adb root
adb push frida-server /data/local/tmp/frida-server
adb shell "chmod 755 /data/local/tmp/frida-server"
# Run the server in the background
adb shell "/data/local/tmp/frida-server &"
Confirm client-server connectivity:
$ frida-ps -U
PID Name
----- ------------------
412 Android System
1091 Google Play Services
2214 InsecureBankv2
Syntax
frida [options] target
frida-ps [options]
frida-trace [options] target
frida-discover [options] target
frida-ls-devices
frida-kill [options] target
All Command-Line Options
frida (main REPL/CLI):
| Option | Description |
|---|---|
-U, --usb | Connect to a USB device |
-R, --remote | Connect to a remote frida-server |
-D ID, --device ID | Connect to a device with the given ID |
-H HOST, --host HOST | Connect to remote frida-server on HOST |
-f TARGET, --file TARGET | Spawn the target application |
-n NAME, --attach-name NAME | Attach by process name |
-p PID, --attach-pid PID | Attach by process ID |
-l SCRIPT, --load SCRIPT | Load a JavaScript file into the session |
--debug | Enable the Node.js compatible script debugger |
--runtime {qjs|v8} | Choose the JavaScript engine runtime |
--no-pause | Do not pause spawned program at entry point |
-o OUTPUT, --output OUTPUT | Write output to file instead of console |
--version | Show the Frida version |
frida-ps (list processes):
| Option | Description |
|---|---|
-U, --usb | Connect to a USB device |
-Ua | List running applications on a USB device |
-Uai | List all installed applications (running or not) on a USB device |
-D ID, --device ID | Connect to a device with the given ID |
-R, --remote | Connect to a remote frida-server |
frida-trace (dynamic function call tracer) — Full List of Options:
| Option | Description |
|---|---|
-D ID, --device ID | Connect to device with the given ID |
-U, --usb | Connect to USB device |
-R, --remote | Connect to remote frida-server |
-H HOST, --host HOST | Connect to remote frida-server on HOST |
-f TARGET, --file TARGET | Spawn TARGET |
-F, --attach-frontmost | Attach to the frontmost application |
-n NAME, --attach-name NAME | Attach to NAME |
-N IDENTIFIER, --attach-identifier IDENTIFIER | Attach to IDENTIFIER |
-p PID, --attach-pid PID | Attach to PID |
-W PATTERN, --await PATTERN | Await spawn matching PATTERN |
--runtime {qjs|v8} | Script runtime to use |
--debug | Enable the Node.js compatible script debugger |
-I MODULE, --include-module MODULE | Include an entire MODULE |
-X MODULE, --exclude-module MODULE | Exclude an entire MODULE |
-i FUNCTION, --include FUNCTION | Include [MODULE!]FUNCTION (glob) |
-x FUNCTION, --exclude FUNCTION | Exclude [MODULE!]FUNCTION (glob) |
-a MODULE!OFFSET, --add MODULE!OFFSET | Trace an unexported function by offset |
-T, --include-imports | Include the program’s imports |
-t MODULE, --include-module-imports MODULE | Include MODULE’s imports |
-m OBJC_METHOD, --include-objc-method OBJC_METHOD | Include an Objective-C method |
-M OBJC_METHOD, --exclude-objc-method OBJC_METHOD | Exclude an Objective-C method |
-j JAVA_METHOD, --include-java-method JAVA_METHOD | Include a Java method (e.g. '*!*certificate*/isu') |
-J JAVA_METHOD, --exclude-java-method JAVA_METHOD | Exclude a Java method |
-s DEBUG_SYMBOL, --include-debug-symbol DEBUG_SYMBOL | Include a debug symbol |
-q, --quiet | Do not format output messages |
-d, --decorate | Add module name to generated onEnter log statements |
-S PATH, --init-session PATH | JavaScript file used to initialize the session |
-P PARAMETERS_JSON, --parameters PARAMETERS_JSON | Pass JSON parameters exposed as global parameters |
-o OUTPUT, --output OUTPUT | Dump messages to a file |
-O FILE, --options-file FILE | Read additional CLI options from a text file |
--ui-port UI_PORT | TCP port to serve the frida-trace UI on |
--squelch-crash | Do not dump crash report to console |
--version | Show version and exit |
frida-ls-devices (list connected devices):
$ frida-ls-devices
Id Type Name
------------------------------------ ------ --------------
local local Local System
0216027d1d6d3a03 usb Pixel 6a
frida-kill (terminate a process on a device):
| Option | Description |
|---|---|
-U, --usb | Connect to USB device |
-D ID, --device ID | Connect to device with the given ID |
-R, --remote | Connect to remote frida-server |
target | Process name or PID to kill |
Basic Usage (Expected Output in Bash)
List running processes on a USB-connected device:
$ frida-ps -U
PID Name
----- ------------------
412 Android System
2214 InsecureBankv2
Attach the REPL to a running application:
$ frida -U InsecureBankv2
____
/ _ | Frida 16.4.1 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . Connected to Pixel 6a (id=0216027d1d6d3a03)
[Pixel 6a::InsecureBankv2]->
Practical Examples with Output
Example 1 — List all installed applications on the device (running or not):
$ frida-ps -Uai
PID Name Identifier
----- ---------------- -----------------------------------
2214 InsecureBankv2 com.android.insecurebankv2
- DIVA jakhar.aseem.diva
- Chrome com.android.chrome
Example 2 — Spawn (launch) an app and attach immediately, pausing at entry:
$ frida -U -f com.android.insecurebankv2 --no-pause
Spawned `com.android.insecurebankv2`. Resuming main thread!
[Pixel 6a::com.android.insecurebankv2]->
Example 3 — Load a custom JavaScript hook script on attach:
$ frida -U -f com.android.insecurebankv2 -l ssl_bypass.js --no-pause
Spawned `com.android.insecurebankv2`. Resuming main thread!
[SSL Pinning Bypass] Hook installed on X509TrustManager
[Pixel 6a::com.android.insecurebankv2]->
Example 4 — Trace all Java methods containing “login” (case-insensitive, user classes only):
$ frida-trace -U -f com.android.insecurebankv2 --runtime=v8 -j '*!*login*/iu'
Instrumenting...
LoginActivity.onLoginClick: Auto-generated handler at "/handlers/__handlers__/LoginActivity_onLoginClick.js"
Started tracing 1 function. Press Ctrl+C to stop.
/* TID 0x2a1e */
1204 ms LoginActivity.onLoginClick()
Example 5 — Trace native open* and read* functions in a running process by PID:
$ frida-trace -p 2214 -i "open*" -i "read*" -x "libc.so!*close*"
Instrumenting...
open: Auto-generated handler at "/handlers/libc.so/open.js"
read: Auto-generated handler at "/handlers/libc.so/read.js"
Started tracing 2 functions. Press Ctrl+C to stop.
/* TID 0x2a20 */
3011 ms open(pathname="/data/data/com.android.insecurebankv2/databases/users.db", flags=0x2)
3012 ms read(fd=48, buf=0x7f3a1c2000, count=4096)
Example 6 — Trace with decorated output showing module names:
$ frida-trace -p 2214 --decorate -i "recv*" -i "send*"
Instrumenting...
Started tracing 6 functions. Press Ctrl+C to stop.
8420 ms send() [libc.so]
8421 ms recv() [libc.so]
Example 7 — Auto-discover interesting native functions in a running process:
$ frida-discover -U -p 2214
Discovering functions in InsecureBankv2...
Found 12 interesting functions.
See discover.sqlite for results.
Example 8 — List connected devices (local, USB, and remote):
$ frida-ls-devices
Id Type Name
------------------------------------ ------ --------------
local local Local System
0216027d1d6d3a03 usb Pixel 6a
Example 9 — Kill a running application on the target device:
$ frida-kill -U InsecureBankv2
$ frida-ps -U | grep InsecureBankv2
(No output — the process has been terminated.)
Example 10 — Trace an unexported native function by module offset:
$ frida-trace -p 2214 -a "libnative-lib.so!0x4793c"
Instrumenting...
sub_4793c: Auto-generated handler at "/handlers/libnative-lib.so/sub_4793c.js"
Started tracing 1 function. Press Ctrl+C to stop.
9102 ms sub_4793c()
Example 11 — Use -P to pass runtime JSON parameters into trace handlers:
$ frida-trace -p 2214 -i "AES_encrypt" -P '{"displayPid": true}'
Instrumenting...
Started tracing 1 function. Press Ctrl+C to stop.
4501 ms AES_encrypt() [libcrypto.so]
Process ID: 2214
Example 12 — Attach to the frontmost (currently visible) app on the device:
$ frida -U -F
____
/ _ | Frida 16.4.1 - A world-class dynamic instrumentation toolkit
| (_| |
> _ |
/_/ |_|
. . . . Connected to Pixel 6a (id=0216027d1d6d3a03)
[Pixel 6a::Frontmost]->
Common Use Cases
- SSL/TLS certificate pinning bypass – Hooking
X509TrustManager,OkHttp3CertificatePinner, or native pinning implementations to allow HTTPS interception via Burp Suite or mitmproxy. - Root/jailbreak detection bypass – Hooking common detection checks (file existence checks,
subinary checks,Build.TAGSchecks) to return benign values so the app runs normally on a rooted test device. - Runtime API and argument logging – Using
frida-traceto observe exactly which functions are called, with what arguments, when a specific action is performed in the app (e.g., tapping “Login”). - In-memory secret extraction – Hooking cryptographic functions (
AES_encrypt,MessageDigest.digest, key generation calls) to print plaintext, keys, or IVs before they are encrypted or after they are decrypted. - Building custom exploitation and testing tools – Writing bespoke JavaScript agents loaded via
frida -l script.jsfor application-specific logic manipulation beyond what generic tools like Objection provide out of the box.
Automation with Bash
The following script automates deploying frida-server to a connected device, verifying connectivity, and launching a trace session against a target package.
#!/bin/bash
# frida_setup_and_trace.sh - Deploy frida-server and start tracing a target app
FRIDA_VERSION="16.4.1"
TARGET_PACKAGE="com.android.insecurebankv2"
ARCH=$(adb shell getprop ro.product.cpu.abi | tr -d '\r')
echo "[*] Detected device architecture: $ARCH"
SERVER_FILE="frida-server-${FRIDA_VERSION}-android-${ARCH}"
if [ ! -f "${SERVER_FILE}" ]; then
echo "[*] Downloading frida-server ${FRIDA_VERSION} for ${ARCH}..."
wget -q "https://github.com/frida/frida/releases/download/${FRIDA_VERSION}/${SERVER_FILE}.xz"
unxz "${SERVER_FILE}.xz"
fi
echo "[*] Pushing frida-server to device..."
adb root > /dev/null 2>&1
adb push "${SERVER_FILE}" /data/local/tmp/frida-server
adb shell "chmod 755 /data/local/tmp/frida-server"
echo "[*] Starting frida-server on device..."
adb shell "/data/local/tmp/frida-server &"
sleep 2
echo "[*] Verifying connectivity..."
frida-ps -U > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "[+] frida-server is running and reachable."
else
echo "[-] Could not reach frida-server."
exit 1
fi
echo "[*] Launching trace session on ${TARGET_PACKAGE}..."
frida-trace -U -f "${TARGET_PACKAGE}" --runtime=v8 -j '*!*password*/iu' -j '*!*login*/iu'
Sample run:
$ chmod +x frida_setup_and_trace.sh
$ ./frida_setup_and_trace.sh
[*] Detected device architecture: x86_64
[*] Pushing frida-server to device...
[*] Starting frida-server on device...
[*] Verifying connectivity...
[+] frida-server is running and reachable.
[*] Launching trace session on com.android.insecurebankv2...
Instrumenting...
LoginActivity.checkPassword: Auto-generated handler at "/handlers/__handlers__/LoginActivity_checkPassword.js"
Started tracing 2 functions. Press Ctrl+C to stop.
Tips and Best Practices
- Always match the
frida-serverversion on the device exactly to thefrida-tools/fridaclient version installed on Kali — mismatched versions are the most common cause of connection failures. - Use
--no-pausewhen spawning apps with-fif you want the app to run immediately rather than sitting paused at its entry point waiting for you to resume it manually. - Prefer
-Ufor USB-connected physical devices and emulators exposed overadb; use-R/-Honly when frida-server is explicitly listening on a network port. - When writing custom Java hooks, wrap them in
Java.perform(function () { ... })to ensure the Java VM is ready before hooking. - Use the order-sensitive nature of
-i/-I/-x/-Xinfrida-tracecarefully — includes and excludes are applied procedurally in the order given on the command line, not declaratively. - For heavily used or long scripts, save them as
.jsfiles and load with-lrather than typing ad hoc code into the REPL each session. - Kill stale frida-server processes on the device (
adb shell "pkill -f frida-server") before starting the server again to avoid “Address already in use” errors.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
Failed to spawn: unable to connect to remote frida-server | frida-server not running or version mismatch | Confirm the server is running (`adb shell “ps -A |
Failed to enumerate applications: permission denied | Device not rooted or adb root not applied | Ensure the device is rooted and run adb root before pushing the server |
| App crashes immediately after hook is applied | Hook logic references a class/method that doesn’t exist in this build | Verify class/method names via jadx decompiled source before writing the hook |
frida: command not found | frida-tools not installed or not in PATH | Run pip3 install frida-tools --break-system-packages and confirm ~/.local/bin is on PATH |
Unable to find process with name 'X' | Process name typo or app not running | Use frida-ps -Ua to confirm the exact running process name first |
| Trace output extremely noisy | Overly broad glob pattern (e.g., -i "*") | Narrow the glob pattern and use -x to exclude noisy modules like libc.so |
| Connection works locally but not for a specific app | App uses Frida detection/anti-instrumentation checks | Use Objection or a custom hook to patch Frida detection strings/signatures before attaching |
References
- Frida Official Documentation:
https://frida.re/docs/home/ - Frida CLI Reference:
https://frida.re/docs/frida-cli/ - frida-trace Reference:
https://frida.re/docs/frida-trace/ - frida-ps Reference:
https://frida.re/docs/frida-ps/ - Frida GitHub Repository:
https://github.com/frida/frida - Frida Release Downloads (frida-server binaries):
https://github.com/frida/frida/releases - OWASP MASTG – Dynamic Analysis with Frida:
https://mas.owasp.org/MASTG/Android/0x05c-Reverse-Engineering-and-Static-Analysis/