Hacktricks-skills android-frida-pentest
Use this skill whenever you need to perform dynamic analysis, hooking, or instrumentation on Android applications using Frida. Trigger this for any Android app security testing, reverse engineering, DEX dumping, anti-debugging bypass, runtime manipulation, or mobile pentesting tasks. Make sure to use this skill when the user mentions Android app analysis, Frida, dynamic instrumentation, hooking Java methods, DEX dumping, FLAG_SECURE bypass, or any mobile security testing.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/mobile-pentesting/android-app-pentesting/frida-tutorial/frida-tutorial/SKILL.MDAndroid 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
inlibfrida-gadget.so
(e.g.,lib/<abi>/
)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:
- Remove FLAG_SECURE to enable screenshotsclear-flag-secure.js
- Template for common hooking patternsbasic-hook-template.js
- Automated frida-server deploymentsetup-frida-server.sh
Best Practices
-
Spawn vs Attach: Use
(--spawn
) to hook before-f
for early initialization hooks. Use attach for running apps.onCreate() -
Multi-strategy DEX dumping: Hardened apps load code from multiple sources. Use clsdumper with default strategies plus
for maximum coverage.--spawn -
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 });