Frida Anleitung

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

Installation

Installiere frida tools:

pip install frida-tools
pip install frida

Download und installiere auf dem Android-Gerät den frida server (Download the latest release).
Ein Einzeiler, um adb im Root-Modus neu zu starten, eine Verbindung herzustellen, 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 server vs. Gadget (root vs. no-root)

Zwei gängige Möglichkeiten, Android-Apps mit Frida zu instrumentieren:

  • Frida server (rooted devices): Ein natives Daemon auf das Gerät kopieren und ausführen, das es ermöglicht, sich an jeden Prozess anzuhängen.
  • Frida Gadget (no root): Frida als shared library in die 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)

  1. Entpacke das APK, füge die libfrida-gadget.so und die Konfigurationsdatei hinzu:
  • Platziere libfrida-gadget.so in lib/<abi>/ (z. B. lib/arm64-v8a/)
  • Erstelle assets/frida-gadget.config mit den Einstellungen zum Laden deines Skripts

Beispiel frida-gadget.config

{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Gadget referenzieren/laden, sodass es früh initialisiert wird:
  • Am einfachsten: Füge einen kleinen Java-Stub hinzu, der System.loadLibrary(“frida-gadget”) in Application.onCreate() aufruft, oder verwende bereits vorhandenes natives Lib-Loading.
  1. Repacke und signiere die APK, dann installiere sie:
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
  1. Vom Host an den gadget process anhängen:
frida-ps -Uai
frida -U -n com.example.app

Hinweise

  • Gadget wird von einigen Schutzmechanismen erkannt; halte Namen/Pfade stealthy und lade sie spät/bedingt, falls nötig.
  • Bei gehärteten Apps bevorzugt rooted Testing mit Server + late attach, oder kombiniere das mit Magisk/Zygisk hiding.

JDWP-basierte Frida injection ohne root/repackaging (frida-jdwp-loader)

Wenn die APK debuggable ist (android:debuggable=“true”), kannst du über JDWP attachen und an einem Java breakpoint eine native library injecten. Kein root und kein APK repackaging.

  • Repo: https://github.com/frankheat/frida-jdwp-loader
  • Voraussetzungen: ADB, Python 3, USB/Wireless debugging. Die App muss debuggable sein (emulator with ro.debuggable=1, rooted device with resetprop, oder das 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

Notes

  • Modi: spawn (Halt bei Application.onCreate) oder attach (Halt bei Activity.onStart). Verwende -b, um eine spezifische Java-Methode zu setzen, -g, um Gadget-Version/Pfad 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; dann frida-ps -H 127.0.0.1:27042.
  • Dies nutzt JDWP-Debugging. Risiko ist das Ausliefern debuggabler Builds oder das Offenlegen von JDWP.

Self-contained agent + Gadget embedding (Frida 17+; automated with 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.

  1. Create a Frida agent (TypeScript) and include the Java bridge
# 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 Würfelwürfe auf 1):

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 zur Einbettung:

npm run build    # produces _agent.js via frida-compile

Kurzer USB-Test (optional):

frida -U -f org.secuso.privacyfriendlydicer -l _agent.js
  1. Gadget so konfigurieren, dass dein script automatisch geladen wird Objection’s patcher erwartet eine Gadget config; wenn du den script mode verwendest, gib den Pfad auf der Festplatte innerhalb des APK lib dir an:
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatisiere das APK-Patching 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 macht (auf hoher Ebene):

  • Erkennt das Geräte-ABI (z. B. arm64-v8a) und lädt das passende Gadget
  • Fügt optional android.permission.INTERNET hinzu, wenn erforderlich
  • Injiziert einen statischen Klasseninitialisierer, der System.loadLibrary(“frida-gadget”) in der Launch-Activity aufruft
  • Legt die folgenden Dateien unter lib/<abi>/ ab:
  • libfrida-gadget.so
  • libfrida-gadget.config.so (serialisierte Konfiguration)
  • libfrida-gadget.script.so (dein _agent.js)

Beispiel injizierter smali (static initializer):

.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
  1. 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 Launchable activity smali enthält eine statische <clinit>, die System.loadLibrary(“frida-gadget”) aufruft
  1. Split APKs
  • Die base APK patchen (diejenige, 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 ...
  • Zur Verteilung kannst du Splits mit APKEditor zu einer einzigen APK zusammenführen und anschließend alignen/signieren

FLAG_SECURE während der dynamischen Analyse entfernen

Apps, die getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) aufrufen, verhindern Screenshots, Remote-Displays und sogar Androids recent-task snapshots. Als Freedom Chat dieses Flag durchsetzte, war die einzige Möglichkeit, die leaks zu dokumentieren, das Window zur Laufzeit zu manipulieren. Ein zuverlässiges Muster ist:

  • Hook jede Window-Überladung, die das Flag wieder setzen kann (setFlags, addFlags, setAttributes) und maskiere das Bit 0x00002000 (WindowManager.LayoutParams.FLAG_SECURE).
  • Nachdem jede Activity wieder aufgenommen wurde, plane einen Aufruf im UI-Thread zu clearFlags(FLAG_SECURE), damit später erstellte Dialogs/Fragments den entsperrten Zustand übernehmen.
  • Apps, die mit React Native / Flutter gebaut wurden, erzeugen oft verschachtelte Windows; hooke android.app.Dialog/android.view.View-Hilfen oder durchlaufe getWindow().peekDecorView(), falls du noch 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 Skript mit `frida -U -f <package> -l disable-flag-secure.js --no-pause` aus, interagiere mit der UI, und Screenshots/Recordings 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 offenlegte.


## Tutorials

### [Tutorial 1](frida-tutorial-1.md)

**Quelle**: [https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1](https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1)\
**APK**: [https://github.com/t0thkr1s/frida-demo/releases](https://github.com/t0thkr1s/frida-demo/releases)\
**Quellcode**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)

**Folge dem [Link, um es zu lesen](frida-tutorial-1.md).**

### [Tutorial 2](frida-tutorial-2.md)

**Quelle**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Teile 2, 3 & 4)\
**APKs und Quellcode**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)

**Folge dem [Link, um es zu lesen.](frida-tutorial-2.md)**

### [Tutorial 3](owaspuncrackable-1.md)

**Quelle**: [https://joshspicer.com/android-frida-1](https://joshspicer.com/android-frida-1)\
**APK**: [https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk](https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk)

**Folge dem [Link, um es zu lesen](owaspuncrackable-1.md).**

**Weitere Awesome Frida-Skripte findest du hier:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)

## Schnellbeispiele

### Frida von der Kommandozeile aufrufen
```bash
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.

Einfaches 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() {
send("sg.vantagepoint.a.c.a()Z   Root check 1 HIT!  su.exists()")
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 von 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 Rückgabewerts

Hooking einer Entschlüsselungsfunktion. Drucke die Eingabe, rufe die Originalfunktion auf, entschlüssele die Eingabe und gib schließlich die Klartextdaten aus:

Hooking einer Entschlüsselungsfunktion (Java) — Eingaben/Ausgaben ausgeben ```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>

### Funktionen hooken und mit unserer Eingabe aufrufen

Hook eine Funktion, die einen string empfängt, und rufe sie mit einem anderen string auf (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
}

Zugriff auf ein bereits erstelltes Objekt einer Klasse

Wenn du ein Attribut eines bereits erstellten Objekts extrahieren möchtest, kannst du das Folgende 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

Referenzen

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