Frida Tutorial

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Installazione

Installa frida tools:

pip install frida-tools
pip install frida

Scarica e installa sul dispositivo Android il frida server (Download the latest release).
Comando one-liner per riavviare adb in modalità root, connettersi ad esso, caricare frida-server, assegnare i permessi di esecuzione ed eseguirlo in background:

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 &"

Controlla se funziona:

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)

Due modi comuni per strumentare le app Android con Frida:

  • Frida server (rooted devices): Installa e avvia un demone nativo che permette di collegarsi a qualsiasi processo.
  • Frida Gadget (no root): Includere Frida come libreria condivisa nell’APK e caricarla automaticamente nel processo di destinazione.

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. Estrai l’APK, aggiungi il file .so del gadget e la configurazione:
  • Posiziona libfrida-gadget.so in lib/<abi>/ (es., lib/arm64-v8a/)
  • Crea assets/frida-gadget.config con le impostazioni di caricamento degli script

Esempio di frida-gadget.config

{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Referenzia/carica il gadget in modo che venga inizializzato precocemente:
  • Il più semplice: aggiungi un piccolo stub Java che esegua System.loadLibrary(“frida-gadget”) in Application.onCreate(), oppure utilizza il caricamento delle lib native già presente.
  1. Ripacchetta e firma l’APK, poi installalo:
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. Collegarsi dal host al processo gadget:
frida-ps -Uai
frida -U -n com.example.app

Note

  • Gadget viene rilevato da alcune protezioni; mantieni nomi/percorsi stealth e caricalo tardi/condizionalmente se necessario.
  • Su app hardened, preferisci rooted testing con server + late attach, oppure combina con Magisk/Zygisk hiding.

Iniezione Frida basata su JDWP senza root/repackaging (frida-jdwp-loader)

Se l’APK è debuggable (android:debuggable=“true”), puoi attach via JDWP e iniettare una libreria nativa a un breakpoint Java. No root e no APK repackaging.

  • Repo: https://github.com/frankheat/frida-jdwp-loader
  • Requisiti: ADB, Python 3, USB/Wireless debugging. L’app deve essere debuggable (emulator con ro.debuggable=1, device rooted con resetprop, o ricostruire il manifest).

Quick start

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

Note

  • Modalità: spawn (ferma l’esecuzione in Application.onCreate) o attach (ferma l’esecuzione in Activity.onStart). Usa -b per impostare un metodo Java specifico, -g per selezionare Gadget versione/percorso, -p per scegliere la porta JDWP.
  • Modalità di ascolto: inoltra Gadget (predefinito 127.0.0.1:27042) se necessario: adb forward tcp:27042 tcp:27042; poi frida-ps -H 127.0.0.1:27042.
  • Questo sfrutta il debugging JDWP. Il rischio è distribuire build debuggable o esporre JDWP.

Agente autonomo + embedding di Gadget (Frida 17+; automatizzato con Objection)

Frida 17 ha rimosso i bridge Java/ObjC integrati da GumJS. Se il tuo agent effettua hook su Java, devi includere il Java bridge all’interno del tuo bundle.

  1. Crea un Frida agent (TypeScript) e includi il 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

Hook Java minimale (forza i lanci dei dadi a 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);
};
});

Creare un unico bundle per l’inclusione:

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

Test USB rapido (opzionale):

frida -U -f org.secuso.privacyfriendlydicer -l _agent.js
  1. Configura Gadget per caricare automaticamente il tuo script Il patcher di Objection si aspetta una Gadget config; quando si usa la script mode, specifica il percorso sul disco all’interno della APK lib dir:
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatizza il patching degli APK con 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

Cosa fa patchapk (a grandi linee):

  • Rileva l’ABI del dispositivo (es., arm64-v8a) e scarica il Gadget corrispondente
  • Opzionalmente aggiunge android.permission.INTERNET quando necessario
  • Inietta un inizializzatore statico di classe che chiama System.loadLibrary(“frida-gadget”) nell’activity di avvio
  • Colloca quanto segue sotto lib/<abi>/:
  • libfrida-gadget.so
  • libfrida-gadget.config.so (config serializzata)
  • libfrida-gadget.script.so (il tuo _agent.js)

Esempio di smali iniettato (inizializzatore statico):

.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. Verifica il repack
apktool d org.secuso.privacyfriendlydicer.apk
apktool d org.secuso.privacyfriendlydicer.objection.apk
# Inspect differences
diff -r org.secuso.privacyfriendlydicer org.secuso.privacyfriendlydicer.objection

Modifiche previste:

  • AndroidManifest.xml potrebbe includere <uses-permission android:name="android.permission.INTERNET"/>
  • Nuove librerie native sotto lib/<abi>/ come sopra
  • Il file smali dell’activity avviabile contiene un static <clinit> che chiama System.loadLibrary(“frida-gadget”)
  1. Split APKs
  • Applica la patch all’APK base (quello che dichiara l’activity MAIN/LAUNCHER)
  • Rifirma gli split rimanenti con la stessa chiave:
objection signapk split1.apk split2.apk ...
  • Installa gli splits insieme:
adb install-multiple split1.apk split2.apk ...
  • Per la distribuzione, puoi unire gli split in un unico APK con APKEditor, poi align/sign

Rimozione di FLAG_SECURE durante l’analisi dinamica

Le app che chiamano getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) impediscono screenshot, display remoti e persino gli snapshot delle recent-task di Android. Quando Freedom Chat imponeva questo flag l’unico modo per documentare i leaks era manomettere la finestra a runtime. Una strategia affidabile è:

  • Hook ogni overload di Window che può riapplicare il flag (setFlags, addFlags, setAttributes) e maschera il bit 0x00002000 (WindowManager.LayoutParams.FLAG_SECURE).
  • Dopo il resume di ogni activity, programma una chiamata sul thread UI a clearFlags(FLAG_SECURE) in modo che i Dialogs/Fragments creati successivamente ereditino lo stato sbloccato.
  • Le app sviluppate con React Native / Flutter spesso creano finestre nidificate; hook gli helper android.app.Dialog/android.view.View o percorri getWindow().peekDecorView() se vedi ancora frame neri.
Frida hook per rimuovere 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>

Esegui lo script con `frida -U -f <package> -l disable-flag-secure.js --no-pause`, interagisci con l'UI, e gli screenshots/recordings funzioneranno di nuovo. Poiché tutto avviene nel thread UI non c'è sfarfallio, e puoi comunque combinare l'hook con HTTP Toolkit/Burp per catturare il traffico che ha rivelato il `/channel` PIN leak.


## Tutorial

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

**Da**: [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)\
**Codice sorgente**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)

**Segui il [link per leggerlo](frida-tutorial-1.md).**

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

**Da**: [https://11x256.github.io/Frida-hooking-android-part-2/](https://11x256.github.io/Frida-hooking-android-part-2/) (Parts 2, 3 & 4)\
**APK e codice sorgente**: [https://github.com/11x256/frida-android-examples](https://github.com/11x256/frida-android-examples)

**Segui il [link per leggerlo.](frida-tutorial-2.md)**

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

**Da**: [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)

**Segui il [link per leggerlo](owaspuncrackable-1.md).**

**Puoi trovare altri script Frida qui:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)

## Esempi rapidi

### Chiamare Frida da riga di comando
```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.

Script Python di base

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 di funzioni senza parametri

Hook la funzione a() della classe 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 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 di funzioni con parametri e recupero del valore

Hooking di una decryption function. Stampa l’input, chiama la funzione originale per decrypt the input e infine stampa i dati in chiaro:

Hooking a decryption function (Java) — stampa input/output ```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 e chiamarle con il nostro input

Esegui un hook su una function che riceve una string e chiamala con un'altra string (da [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
}

Ottenere un oggetto già creato di una classe

Se vuoi estrarre qualche attributo di un oggetto già creato puoi usare questo.

In questo esempio vedrai come ottenere l’oggetto della classe my_activity e come chiamare la funzione .secret() che stamperà un attributo privato dell’oggetto:

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 () {},
})

Altri tutorial su Frida

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks