Android Frida Pentesting Skill
A comprehensive guide for dynamic Android application analysis using Frida instrumentation.
Quick Start
Install Frida Tools
pip install frida-tools
pip install frida
Setup Frida Server on Android
Rooted device (one-liner):
adb root; adb connect localhost:6000; sleep 1; adb push frida-server /data/local/tmp/; adb shell "chmod 755 /data/local/tmp/frida-server"; adb shell "/data/local/tmp/frida-server &"
Verify installation:
frida-ps -U # List all processes
frida-ps -U | grep -i <package_name> # Find specific app
Basic Hooking Commands
# Spawn app with hooks (hooks before onCreate)
frida -U --no-pause -l script.js -f com.example.app
# Attach to running app
frida -U -n com.example.app -l script.js
# List installed apps
frida-ps -Uai
Frida Gadget (No-Root Option)
When you don't have root access, bundle Frida Gadget inside the APK:
Manual Gadget Integration
- Unpack APK:
apktool d app.apk -o app_modified
- Add Gadget files:
- Place
libfrida-gadget.soinlib/<abi>/(e.g.,lib/arm64-v8a/) - Create
assets/frida-gadget.config:
{
"interaction": { "type": "script", "path": "/sdcard/hook.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
- Repack and sign:
apktool b app_modified -o app_gadget.apk
uber-apk-signer -a app_gadget.apk -o out_signed
adb install -r out_signed/app_gadget-aligned-debugSigned.apk
Automated with Objection
objection patchapk -s app.apk \
-c gadget-config.json \
-l agent.js \
--use-aapt2
Common Hooking Patterns
Hook Functions Without Parameters
Java.perform(function () {
var targetClass = Java.use("com.example.ClassName");
targetClass.methodName.overload().implementation = function () {
console.log("[+] methodName called");
return false; // Return custom value
};
});
Hook Functions With Parameters
Java.perform(function () {
var targetClass = Java.use("com.example.ClassName");
targetClass.methodName.overload("java.lang.String", "int").implementation = function (arg1, arg2) {
console.log("[+] Input arg1: " + arg1);
console.log("[+] Input arg2: " + arg2);
var result = this.methodName(arg1, arg2);
console.log("[+] Output: " + result);
return result;
};
});
Hook Activity Lifecycle Methods
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
MainActivity.onCreate.overload("android.os.Bundle").implementation = function (bundle) {
console.log("[+] MainActivity.onCreate() called");
return this.onCreate(bundle);
};
MainActivity.onStart.overload().implementation = function () {
console.log("[+] MainActivity.onStart() called");
return this.onStart();
};
});
Intercept Decryption Functions
function bytesToString(data) {
var result = "";
for (var i = 0; i < data.length; i++) {
result += String.fromCharCode(data[i]);
}
return result;
}
Java.perform(function () {
var cryptoClass = Java.use("com.example.Crypto");
cryptoClass.decrypt.overload("[B", "[B").implementation = function (key, encrypted) {
console.log("[+] Key: " + bytesToString(key));
console.log("[+] Encrypted: " + bytesToString(encrypted));
var decrypted = this.decrypt(key, encrypted);
console.log("[+] Decrypted: " + bytesToString(decrypted));
return decrypted;
};
});
Find and Inspect Object Instances
Java.choose("com.example.ClassName", {
onMatch: function (instance) {
console.log("[+] Found instance: " + instance);
console.log("[+] Private field: " + instance.privateMethod());
},
onComplete: function () {
console.log("[+] Search complete");
}
});
Prevent App Exit
Java.perform(function () {
var System = Java.use("java.lang.System");
System.exit.overload("int").implementation = function (code) {
console.log("[!] App tried to exit with code: " + code);
// Don't call original - app stays running
return;
};
});
Anti-Debugging Bypass
Disable Root Detection
Java.perform(function () {
var Build = Java.use("android.os.Build");
var SystemProperties = Java.use("android.os.SystemProperties");
// Fake fingerprint
Build.FINGERPRINT.get = function() { return "generic/generic/generic"; };
Build.HARDWARE.get = function() { return "generic"; };
Build.MODEL.get = function() { return "Android SDK built for x86"; };
Build.MANUFACTURER.get = function() { return "Google"; };
// Block SystemProperties.get
SystemProperties.get.overload("java.lang.String").implementation = function (key) {
if (key.contains("ro.debuggable") || key.contains("ro.secure")) {
return "0";
}
return this.get(key);
};
});
Block SIGSEGV Handlers
Interceptor.attach(Module.findExportByName("libc.so", "sigaction"), {
onEnter: function (args) {
if (args[1] !== null) {
console.log("[+] sigaction called - blocking anti-debug");
args[1] = null;
}
}
});
DEX Dumping with clsdumper
# Install
pip install clsdumper
# Attach to running app
clsdumper com.example.app
# Spawn with hooks before early loaders
clsdumper com.example.app --spawn
# Use specific strategies
clsdumper com.example.app --strategies fart_dump,oat_extract,memory_scan
# Deep scan (slower, more thorough)
clsdumper com.example.app --deep-scan
# Extract classes to smali
clsdumper com.example.app --extract-classes
JDWP Injection (Debuggable Apps, No Root)
For apps with android:debuggable="true":
# Clone and run
python frida-jdwp-loader.py frida -n com.example.app
# Keep breakpoint suspended for early hooks
python frida-jdwp-loader.py frida -n com.example.app -s
# Load script directly
python frida-jdwp-loader.py frida -n com.example.app -i script -l hook.js
Useful Scripts
See the scripts/ directory for ready-to-use Frida scripts:
clear-flag-secure.js- Remove FLAG_SECURE to enable screenshotsbasic-hook-template.js- Template for common hooking patternssetup-frida-server.sh- Automated frida-server deployment
Best Practices
Spawn vs Attach: Use
--spawn(-f) to hook beforeonCreate()for early initialization hooks. Use attach for running apps.Multi-strategy DEX dumping: Hardened apps load code from multiple sources. Use clsdumper with default strategies plus
--spawnfor maximum coverage.Frida 17+ Java Bridge: If your agent hooks Java, include the Java bridge:
npm install frida-java-bridge
npm run build # Creates bundled _agent.js
Stealth: For Gadget on hardened apps, use obfuscated names and conditional loading to avoid detection.
UI Thread Hooks: For window manipulation, schedule on main thread to avoid flicker:
Java.scheduleOnMainThread(function () {
// UI operations here
});