Frida-Tutorial
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Installation
Installiere die frida tools:
pip install frida-tools
pip install frida
Herunterladen und installieren des frida server auf dem Android-Gerät (Download the latest release).
Einzeiler, um adb im Root-Modus neu zu starten, sich damit zu verbinden, frida-server hochzuladen, Ausführungsrechte zu vergeben und ihn im Hintergrund auszuführen:
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 &"
Überprüfe, ob es funktioniert:
frida-ps -U #List packages and processes
frida-ps -U | grep -i <part_of_the_package_name> #Get all the package name
frida-ui (browserbasierter Frida-Controller)
frida-ui stellt eine Web-Oberfläche unter http://127.0.0.1:8000 bereit, um devices/apps aufzulisten und targets mit Skripten zu attachen oder zu spawnen (keine CLI nötig).
- Installieren (pin
fridaauf die device server version):
uv tool install frida-ui --with frida==16.7.19
# pipx install frida-ui
# pip install frida-ui
- Ausführen:
frida-ui
frida-ui --host 127.0.0.1 --port 8000 --reload
- Features: entdeckt USB-/lokale Geräte, fügt Remote-Server hinzu (
192.168.1.x:27042) und unterstützt Attach, Spawn, und Spawn & Run (um Hooks vor der frühenonCreate()-Logik zu setzen). - Scripting: Editor, Drag & Drop von
.js-Dateien, CodeShare importieren, Scripts und Session-Logs herunterladen. - Remote servers:
./frida-server -l 0.0.0.0:27042 -Dmacht diesen Dienst im Netzwerk verfügbar, sodass frida-ui ohne ADB verbinden kann.
Frida server vs. Gadget (root vs. no-root)
Two common ways to instrument Android apps with Frida:
- Frida server (rooted devices): Auf das Gerät kopieren und einen nativen Daemon starten, der es dir ermöglicht, dich an jeden Prozess anzuhängen.
- Frida Gadget (no root): Frida als Shared Library in das APK einbinden und automatisch im Zielprozess laden.
Frida server (rooted)
# Download the matching frida-server binary for your device's arch
# https://github.com/frida/frida/releases
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 & # run at boot via init/magisk if desired
# From host, list processes and attach
frida-ps -Uai
frida -U -n com.example.app
Frida Gadget (no-root)
- APK entpacken, das Gadget .so und die Konfig hinzufügen:
- Lege libfrida-gadget.so in
lib/<abi>/ab (z. B. lib/arm64-v8a/) - Erstelle assets/frida-gadget.config mit Einstellungen zum Laden deiner Skripte
Beispiel frida-gadget.config
{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
- Das Gadget referenzieren/laden, damit es früh initialisiert wird:
- Am einfachsten: Fügen Sie einen kleinen Java-Stub mit System.loadLibrary(“frida-gadget”) in Application.onCreate() hinzu, oder verwenden Sie bereits vorhandenes native lib loading.
- Repacken und signieren Sie die APK, dann installieren:
apktool d app.apk -o app_m
# ... add gadget .so and 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
- Vom Host an den Gadget-Prozess anhängen:
frida-ps -Uai
frida -U -n com.example.app
Hinweise
- Gadget wird von einigen Schutzmechanismen erkannt; Namen/Pfade stealthy halten und bei Bedarf spät/konditional laden.
- Bei gehärteten Apps vorzugsweise rooted testing mit Server + late attach verwenden, oder mit Magisk/Zygisk hiding kombinieren.
JDWP-based Frida injection ohne root/repackaging (frida-jdwp-loader)
Wenn die APK debuggable ist (android:debuggable=“true”), kannst du über JDWP anhängen und eine native Library an einem Java-Breakpoint injecten. Kein root und kein APK repackaging.
- Repo: https://github.com/frankheat/frida-jdwp-loader
- Anforderungen: ADB, Python 3, USB/Wireless debugging. Die App muss debuggable sein (Emulator mit
ro.debuggable=1, gerootetes Gerät mitresetprop, oder Manifest neu bauen).
Schnellstart:
git clone https://github.com/frankheat/frida-jdwp-loader.git
cd frida-jdwp-loader
# Inject frida-gadget.so into a debuggable target
python frida-jdwp-loader.py frida -n com.example.myapplication
# Keep the breakpoint thread suspended for early hooks
python frida-jdwp-loader.py frida -n com.example.myapplication -s
# Networkless: run a local agent script via Gadget "script" mode
python frida-jdwp-loader.py frida -n com.example.myapplication -i script -l script.js
Hinweise
- Modi: spawn (break at Application.onCreate) oder attach (break at Activity.onStart). Verwende
-b, um eine spezifische Java-Methode zu setzen,-g, um Gadget version/path auszuwählen,-p, um den JDWP-Port zu wählen. - Listen-Modus: Gadget weiterleiten (Standard 127.0.0.1:27042) falls nötig:
adb forward tcp:27042 tcp:27042; dannfrida-ps -H 127.0.0.1:27042. - Dies nutzt JDWP debugging. Risiko: Versand von debuggable builds oder das Offenlegen von JDWP.
Eigenständiger Agent + Gadget-Einbettung (Frida 17+; automatisiert mit Objection)
Frida 17 hat die eingebauten Java/ObjC bridges aus GumJS entfernt. Wenn dein Agent Java hookt, musst du die Java bridge in dein Bundle einbinden.
- Erstelle einen Frida agent (TypeScript) und binde die Java bridge ein
# Scaffolding
frida-create -t agent -o mod
cd mod && npm install
# Install the Java bridge for Frida 17+
npm install frida-java-bridge
# Dev loop (optional live-reload via REPL)
npm run watch
Minimaler Java hook (erzwingt, dass Würfelwürfe 1 sind):
import Java from "frida-java-bridge";
Java.perform(function () {
var dicer = Java.use("org.secuso.privacyfriendlydicer.dicer.Dicer");
dicer.rollDice.implementation = function (numDice: number, numFaces: number) {
return Array(numDice).fill(1);
};
});
Erstelle ein einzelnes Bundle zum Einbetten:
npm run build # produces _agent.js via frida-compile
Kurzer USB-Test (optional):
frida -U -f org.secuso.privacyfriendlydicer -l _agent.js
- Gadget so konfigurieren, dass es dein script automatisch lädt Objection’s patcher erwartet eine Gadget config; wenn du script mode verwendest, gib den on-disk path innerhalb des APK lib dir an:
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
- Automatisiere das Patchen von APKs mit Objection
# Embed Gadget, config, and your compiled agent into the APK; rebuild and sign
objection patchapk -s org.secuso.privacyfriendlydicer.apk \
-c gadget-config.json \
-l mod/_agent.js \
--use-aapt2
Was patchapk tut (auf hoher Ebene):
- Ermittelt die ABI des Geräts (z. B. arm64-v8a) und lädt das passende Gadget
- Fügt optional android.permission.INTERNET hinzu, falls erforderlich
- Injiziert einen statischen Klasseninitialisierer, der System.loadLibrary(“frida-gadget”) in die Launch-Activity aufruft
- Platziert Folgendes unter
lib/<abi>/: - libfrida-gadget.so
- libfrida-gadget.config.so (serialisierte Konfiguration)
- libfrida-gadget.script.so (dein _agent.js)
Beispiel injizierter smali (statischer Initialisierer):
.method static constructor <clinit>()V
.locals 1
const-string v0, "frida-gadget"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
- Repack verifizieren
apktool d org.secuso.privacyfriendlydicer.apk
apktool d org.secuso.privacyfriendlydicer.objection.apk
# Inspect differences
diff -r org.secuso.privacyfriendlydicer org.secuso.privacyfriendlydicer.objection
Erwartete Änderungen:
- AndroidManifest.xml kann
<uses-permission android:name="android.permission.INTERNET"/>enthalten - Neue native libs unter
lib/<abi>/wie oben - Die smali der startbaren Activity enthält ein statisches
<clinit>, das System.loadLibrary(“frida-gadget”) aufruft
- Split APKs
- Die base APK patchen (diejenige, die die MAIN/LAUNCHER Activity deklariert)
- Die verbleibenden Splits mit demselben Schlüssel neu signieren:
objection signapk split1.apk split2.apk ...
- Installiere splits zusammen:
adb install-multiple split1.apk split2.apk ...
- Für die Verteilung kannst du Split-APKs mit APKEditor zu einer einzigen APK zusammenführen, dann align/sign
Clearing FLAG_SECURE during dynamic analysis
Apps, die getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) aufrufen, verhindern Screenshots, Remote-Displays und sogar Android’s recent-task snapshots. Als Freedom Chat dieses Flag durchsetzte, war die einzige Möglichkeit, die leaks zu dokumentieren, zur Laufzeit am Window zu manipulieren. Ein zuverlässiges Muster ist:
- Hook jede Überladung von
Window, die das Flag erneut setzen kann (setFlags,addFlags,setAttributes), und maskiere das Bit0x00002000(WindowManager.LayoutParams.FLAG_SECURE). - Nach jedem Activity-Resume plane einen UI-Thread-Aufruf zu
clearFlags(FLAG_SECURE), damit Dialogs/Fragments, die später erstellt werden, den entsperrten Zustand erben. - Apps, die mit React Native / Flutter gebaut sind, erzeugen oft verschachtelte Windows; hook die
android.app.Dialog/android.view.View-Hilfen oder durchlaufegetWindow().peekDecorView(), wenn du weiterhin schwarze Frames siehst.
Frida hook clearing Window.FLAG_SECURE
```javascript 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 from 0x” + value.toString(16)); } 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)); };
Window.setAttributes.implementation = function (attrs) { attrs.flags.value = strip(attrs.flags.value); return this.setAttributes.call(this, attrs); };
Activity.onResume.implementation = function () { this.onResume(); var self = this; Java.scheduleOnMainThread(function () { try { self.getWindow().clearFlags(FLAG_SECURE); console.log(“[+] Cleared FLAG_SECURE on “ + self.getClass().getName()); } catch (err) { console.log(”[!] clearFlags failed: “ + err); } }); }; });
</details>
Führe das Script mit `frida -U -f <package> -l disable-flag-secure.js --no-pause` aus, interagiere mit der UI, und Screenshots/Aufnahmen funktionieren wieder. Da alles im UI-Thread passiert, gibt es kein Flackern, und du kannst den hook weiterhin mit HTTP Toolkit/Burp kombinieren, um den Traffic zu erfassen, der das `/channel` PIN leak offenbarte.
## Dynamisches DEX dumping / unpacking mit clsdumper (Frida)
`clsdumper` ist ein Frida-basiertes dynamisches **DEX/class dumper**, das gehärtete Apps überlebt, indem es eine anti-Frida-Vorstufe mit native- und Java-Discovery-Strategien kombiniert (funktioniert sogar, wenn `Java.perform()` ausfällt). Voraussetzungen: Python 3.10+, gerootetes Gerät mit laufendem `frida-server`, USB- oder `--host` TCP-Verbindung.
**Installation & schnelle Nutzung**
```bash
pip install clsdumper
# Attach to a running app
clsdumper com.example.app
# Spawn first (hooks before early loaders)
clsdumper com.example.app --spawn
# Select strategies
clsdumper com.example.app --strategies fart_dump,oat_extract
CLI-Optionen (am nützlichsten)
target: Paketname oder PID.--spawn: spawn statt attach.--host <ip>: mit remote frida-server verbinden.--strategies <comma>: Extraktoren einschränken/auswählen; Standard ist alle außermmap_hook(ressourcenintensiv).--no-scan/--deep-scan: deaktiviert bzw. verlangsamt den Deep-Memory-Scan (fügt CDEX-Scanning hinzu).--extract-classes: Dumps nachverarbeiten in.smalivia androguard.--no-anti-frida: überspringt die Pre-Hook-Bypass-Phase.--list/--list-apps: laufende Prozesse oder installierte Pakete auflisten.
Anti-instrumentation bypass (phase 0)
- Hookt
sigaction/signal, um die Registrierung von Crash-/Anti-Debug-Handlern zu blockieren. - Stellt ein gefiltertes
/proc/self/mapsviamemfd_createbereit, um Frida-Regionen zu verbergen. - Überwacht
pthread_create, um Watchdog-Threads, die Frida suchen, abzufangen/neutralisieren.
DEX discovery (phases 1–2) — mehrere komplementäre Strategien mit pro-Treffer-Metadaten + Deduplizierung (agentseitig djb2, hostseitig SHA-256):
- Native (kein Java-Bridge nötig):
art_walk(durchläuft ART Runtime→ClassLinker→DexFile),open_common_hook(hooktDexFile::OpenCommon),memory_scan(DEX-Magic in lesbaren Maps),oat_extract(parst gemappte .vdex/.oat),fart_dump(hooktDefineClass+ durchläuftclass_table_),dexfile_constructor(hooktOatDexFile-Konstruktoren),mmap_hook(beobachtetmmap/mmap64, standardmäßig aus Performancegründen deaktiviert). - Java (wenn verfügbar):
cookie(liestmCookieaus ClassLoaders),classloader_hook(überwachtloadClass,DexClassLoader,InMemoryDexClassLoader).
Ausgabe-Layout
dump_<target>/
dex/classes_001.dex ...
classes/ # only when --extract-classes
metadata.json # strategy per hit + hashes
Tipp: geschützte Apps laden häufig Code aus mehreren Quellen (in-memory payload, vdex/oat, custom loaders). Das Ausführen mit dem Standard-Multi-Strategy-Set plus --spawn maximiert die Abdeckung; aktivieren Sie --deep-scan nur bei Bedarf, um Leistungseinbußen zu vermeiden.
Tutorials
Tutorial 1
Quelle: https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1
APK: https://github.com/t0thkr1s/frida-demo/releases
Quellcode: https://github.com/t0thkr1s/frida-demo
Folgen Sie dem Link, um es zu lesen.
Tutorial 2
Quelle: https://11x256.github.io/Frida-hooking-android-part-2/ (Teile 2, 3 & 4)
APKs und Quellcode: https://github.com/11x256/frida-android-examples
Folgen Sie dem Link, um es zu lesen.
Tutorial 3
Quelle: https://joshspicer.com/android-frida-1
APK: https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk
Folgen Sie dem Link, um es zu lesen.
Weitere Awesome Frida-Skripte finden Sie hier: https://codeshare.frida.re/
Schnelle Beispiele
Frida von der Kommandozeile aufrufen
frida-ps -U
#Basic frida hooking
frida -l disableRoot.js -f owasp.mstg.uncrackable1
#Hooking before starting the app
frida -U --no-pause -l disableRoot.js -f owasp.mstg.uncrackable1
#The --no-pause and -f options allow the app to be spawned automatically,
#frozen so that the instrumentation can occur, and the automatically
#continue execution with our modified code.
Grundlegendes Python-Skript
import frida, sys
jscode = open(sys.argv[0]).read()
process = frida.get_usb_device().attach('infosecadventures.fridademo')
script = process.create_script(jscode)
print('[ * ] Running Frida Demo application')
script.load()
sys.stdin.read()
Hooking von Funktionen ohne Parameter
Hook die Funktion a() der Klasse sg.vantagepoint.a.c
Java.perform(function () {
rootcheck1.a.overload().implementation = function () {
return false;
};
});
Hook java exit()
var sysexit = Java.use("java.lang.System")
sysexit.exit.overload("int").implementation = function (var_0) {
send("java.lang.System.exit(I)V // We avoid exiting the application :)")
}
Hook MainActivity .onStart() & .onCreate()
var mainactivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity")
mainactivity.onStart.overload().implementation = function () {
send("MainActivity.onStart() HIT!!!")
var ret = this.onStart.overload().call(this)
}
mainactivity.onCreate.overload("android.os.Bundle").implementation = function (
var_0
) {
send("MainActivity.onCreate() HIT!!!")
var ret = this.onCreate.overload("android.os.Bundle").call(this, var_0)
}
Hook Android .onCreate()
var activity = Java.use("android.app.Activity")
activity.onCreate.overload("android.os.Bundle").implementation = function (
var_0
) {
send("Activity HIT!!!")
var ret = this.onCreate.overload("android.os.Bundle").call(this, var_0)
}
Hooking von Funktionen mit Parametern und Abrufen des Werts
Hooking einer decryption function. Gib die Eingabe aus, rufe die Originalfunktion auf, lass die Eingabe decrypten und gib schließlich die Klartextdaten aus:
Hooking a decryption function (Java) — Eingaben/Ausgaben anzeigen
```javascript function getString(data) { var ret = "" for (var i = 0; i < data.length; i++) { ret += data[i].toString() } return ret } var aes_decrypt = Java.use("sg.vantagepoint.a.a") aes_decrypt.a.overload("[B", "[B").implementation = function (var_0, var_1) { send("sg.vantagepoint.a.a.a([B[B)[B doFinal(enc) // AES/ECB/PKCS7Padding") send("Key : " + getString(var_0)) send("Encrypted : " + getString(var_1)) var ret = this.a.overload("[B", "[B").call(this, var_0, var_1) send("Decrypted : " + ret)var flag = “” for (var i = 0; i < ret.length; i++) { flag += String.fromCharCode(ret[i]) } send(“Decrypted flag: “ + flag) return ret //[B }
</details>
### Hooking functions and calling them with our input
Eine Funktion hooken, die einen string empfängt, und sie mit einem anderen string aufrufen (von [here](https://11x256.github.io/Frida-hooking-android-part-2/))
```javascript
var string_class = Java.use("java.lang.String") // get a JS wrapper for java's String class
my_class.fun.overload("java.lang.String").implementation = function (x) {
//hooking the new function
var my_string = string_class.$new("My TeSt String#####") //creating a new String by using `new` operator
console.log("Original arg: " + x)
var ret = this.fun(my_string) // calling the original function with the new String, and putting its return value in ret variable
console.log("Return value: " + ret)
return ret
}
Ein bereits erstelltes Objekt einer Klasse erhalten
Wenn du ein Attribut eines erstellten Objekts extrahieren möchtest, kannst du dies verwenden.
In diesem Beispiel siehst du, wie du das Objekt der Klasse my_activity erhältst und wie du die Funktion .secret() aufrufst, die ein privates Attribut des Objekts ausgibt:
Java.choose("com.example.a11x256.frida_test.my_activity", {
onMatch: function (instance) {
//This function will be called for every instance found by frida
console.log("Found instance: " + instance)
console.log("Result of secret func: " + instance.secret())
},
onComplete: function () {},
})
Weitere Frida-Tutorials
- https://github.com/DERE-ad2001/Frida-Labs
- Part 1 of Advanced Frida Usage blog series: IOS Encryption Libraries
Referenzen
- Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa
- Frida Gadget documentation
- Frida releases (server binaries)
- Objection (SensePost)
- Modding And Distributing Mobile Apps with Frida
- frida-jdwp-loader
- Library injection for debuggable Android apps (blog)
- jdwp-lib-injector (original idea/tool)
- jdwp-shellifier
- “Super secure” MAGA-themed messaging app leaks everyone’s phone number
- Android Frida Hooking: Disabling FLAG_SECURE
- frida-ui
- clsdumper — Android Dynamic Class Dumper
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


