Frida is a dynamic instrumentation toolkit that lets you inject JavaScript into running processes, hook functions, change return values, extract secrets at runtime, and build custom tooling. This page covers Android-specific usage.
Installation
Install Frida Tools on Host
pip install frida-tools frida
Push Frida Server to Device
Download the matching server binary from the Frida releases page, then:adb root
adb push frida-server-<ver>-android-<arch> /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
Verify the Connection
frida-ps -U # List processes
frida-ps -Uai # List all installed apps
Frida Server vs. Gadget
Push and run a native daemon — lets you attach to any process.frida-ps -Uai
frida -U -n com.example.app
frida -U -f com.example.app -l hook.js --no-pause
Best for rooted devices or emulators. Bundle Frida as a shared library inside the APK so it loads within the target process.# Decompile APK
apktool d app.apk -o app_m
# ... add libfrida-gadget.so to lib/<abi>/ and create gadget config ...
apktool b app_m -o app_gadget.apk
uber-apk-signer -a app_gadget.apk -o out_signed
adb install -r out_signed/app_gadget-aligned-debugSigned.apk
Gadget config (assets/frida-gadget.config):{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
If the APK has android:debuggable="true", inject without root or repackaging using frida-jdwp-loader:git clone https://github.com/frankheat/frida-jdwp-loader.git
cd frida-jdwp-loader
python frida-jdwp-loader.py frida -n com.example.myapplication
# Keep breakpoint suspended for early hooks:
python frida-jdwp-loader.py frida -n com.example.myapplication -s
# Run a local script via Gadget script mode:
python frida-jdwp-loader.py frida -n com.example.myapplication -i script -l script.js
frida-ui (Browser-Based Controller)
# Install
uv tool install frida-ui --with frida==16.7.19
# Run
frida-ui
frida-ui --host 127.0.0.1 --port 8000 --reload
The web UI at http://127.0.0.1:8000 discovers USB/local devices, supports Attach/Spawn/Spawn & Run modes, has a script editor with CodeShare import, and can connect to remote servers (frida-server -l 0.0.0.0:27042 -D).
Quick Examples — Hooking Java Methods
Hook 1: Boolean Bypass
Override a PIN check to always return true:
Java.perform(function () {
var PinUtil = Java.use("infosecadventures.fridademo.utils.PinUtil")
PinUtil.checkPin.implementation = function (pin) {
console.log("[+] PIN check bypassed!")
return true
}
})
Hook 2: Brute-Force a Static Function
Java.perform(function () {
var PinUtil = Java.use("infosecadventures.fridademo.utils.PinUtil")
for (var i = 1000; i < 9999; i++) {
if (PinUtil.checkPin(i + "") == true) {
console.log("[+] Found correct PIN: " + i)
}
}
})
Hook 3: Log Arguments and Return Values
Java.perform(function () {
var EncryptionUtil = Java.use("infosecadventures.fridademo.utils.EncryptionUtil")
EncryptionUtil.encrypt.implementation = function (key, value) {
console.log("Key: " + key)
console.log("Value: " + value)
var result = this.encrypt(key, value)
console.log("Encrypted: " + result)
return result
}
})
Hook with Overloads
When multiple overloads exist, specify argument types explicitly:
var Cls = Java.use("com.example.Class")
Cls.doThing.overload('java.lang.String', 'int').implementation = function(s, i) {
return this.doThing(s, i)
}
Get an Existing Object Instance
Java.choose("com.example.a11x256.frida_test.my_activity", {
onMatch: function (instance) {
console.log("Found instance: " + instance)
console.log("secret(): " + instance.secret())
},
onComplete: function () {}
})
Clearing FLAG_SECURE at Runtime
Apps that set FLAG_SECURE block screenshots and recordings. Hook the Window methods to strip it:
Java.perform(function () {
var LayoutParams = Java.use("android.view.WindowManager$LayoutParams")
var FLAG_SECURE = LayoutParams.FLAG_SECURE.value
var Window = Java.use("android.view.Window")
var Activity = Java.use("android.app.Activity")
function strip(value) {
var masked = value & (~FLAG_SECURE)
if (masked !== value) console.log("[-] Stripped FLAG_SECURE")
return masked
}
Window.setFlags.overload('int', 'int').implementation = function (flags, mask) {
return this.setFlags.call(this, strip(flags), strip(mask))
}
Window.addFlags.implementation = function (flags) {
return this.addFlags.call(this, strip(flags))
}
Activity.onResume.implementation = function () {
this.onResume()
var self = this
Java.scheduleOnMainThread(function () {
try { self.getWindow().clearFlags(FLAG_SECURE) } catch (e) {}
})
}
})
Run with: frida -U -f <package> -l disable-flag-secure.js --no-pause
Dynamic DEX Dumping with clsdumper
clsdumper survives hardened apps by combining anti-Frida bypass with multiple DEX discovery strategies.
pip install clsdumper
# Attach to running app
clsdumper com.example.app
# Spawn first (hooks before early loaders)
clsdumper com.example.app --spawn
# Select specific strategies
clsdumper com.example.app --strategies fart_dump,oat_extract
# Extract smali after dumping
clsdumper com.example.app --extract-classes
Output layout:
dump_com.example.app/
dex/classes_001.dex ...
classes/ # only with --extract-classes
metadata.json # strategy per hit + hashes
Stealthy Injection with Zygisk Gadget
Some apps detect ptrace or frida-server strings. Zygisk injects the Gadget inside Zygote so no process is ptraced:
# Configure target package and startup delay
adb shell "su -c 'echo infosecadventures.fridademo,5000 > /data/local/tmp/re.zyg.fri/target_packages'"
# Launch app, then attach to Gadget process
frida -U -n Gadget -l hook.js
Frida 17+ and Android 14–16 Notes
From Frida 17.1.x+, Java hooking on Android 14–16 is stable again (ART quick entrypoint offsets were fixed). If Java.choose returns nothing on Android 14+, upgrade frida-server, frida-gadget, and the Python packages to >= 17.1.5.
References