Guida a Frida

Reading time: 11 minutes

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:

bash
pip install frida-tools
pip install frida

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

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

Verifica se funziona:

bash
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): Copia e avvia un demone nativo che ti permette di collegarti a qualsiasi processo.
  • Frida Gadget (no root): Incorpora Frida come libreria condivisa all'interno dell'APK e la carica automaticamente nel processo target.

Frida server (rooted)

bash
# 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 gadget .so e la configurazione:
  • Inserisci libfrida-gadget.so in lib/<abi>/ (es. lib/arm64-v8a/)
  • Crea assets/frida-gadget.config con le impostazioni di caricamento degli script

Esempio frida-gadget.config

json
{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Riferire/caricare il gadget in modo che venga inizializzato all'avvio:
  • Più semplice: Aggiungi un piccolo stub Java con System.loadLibrary("frida-gadget") in Application.onCreate(), oppure usa il caricamento nativo delle librerie già presente.
  1. Rimpacchetta e firma l'APK, quindi installalo:
bash
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. Attach dal host al processo gadget:
bash
frida-ps -Uai
frida -U -n com.example.app

Note

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

Self-contained agent + Gadget embedding (Frida 17+; automatizzato con Objection)

Frida 17 ha rimosso i built-in Java/ObjC bridges 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
bash
# 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

Minimale Java hook (forza i lanci dei dadi a 1):

ts
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);
};
});

Crea un singolo bundle per l'embedding:

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

Test USB rapido (opzionale):

bash
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 usi script mode, specifica il percorso on-disk all'interno della APK lib dir:
json
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatizzare APK patching con Objection
bash
# 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

What patchapk does (high level):

  • Rileva l'ABI del dispositivo (es., arm64-v8a) e scarica il Gadget corrispondente
  • Aggiunge opzionalmente android.permission.INTERNET quando necessario
  • Inietta un inizializzatore statico di classe che chiama System.loadLibrary("frida-gadget") nell'activity di avvio
  • Posiziona i seguenti sotto lib/<abi>/:
  • libfrida-gadget.so
  • libfrida-gadget.config.so (serialized config)
  • libfrida-gadget.script.so (your _agent.js)

Example injected smali (static initializer):

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

Cambiamenti previsti:

  • AndroidManifest.xml potrebbe includere <uses-permission android:name="android.permission.INTERNET"/>
  • Nuove librerie native sotto lib// come sopra
  • Lo smali dell'activity avviabile contiene un <clinit> statico che chiama System.loadLibrary("frida-gadget")
  1. Split APKs
  • Patch the base APK (quello che dichiara l'activity MAIN/LAUNCHER)
  • Re-sign i split rimanenti con la stessa chiave:
bash
objection signapk split1.apk split2.apk ...
  • Installa gli splits insieme:
bash
adb install-multiple split1.apk split2.apk ...
  • Per la distribuzione, puoi unire gli split in un singolo APK con APKEditor, poi allineare/firmare

Note difensive (cosa cercare quando si effettua il hardening)

  • Implementare signature/repackage checks e runtime integrity/attestation
  • Rilevare chiamate inattese a System.loadLibrary("frida-gadget") o native libs sospette all'avvio
  • Evitare di dichiarare la INTERNET permission non utilizzata; ridurre la gadget detection surface

Tutorial

Tutorial 1

Da: https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1
APK: https://github.com/t0thkr1s/frida-demo/releases
Codice Sorgente: https://github.com/t0thkr1s/frida-demo

Segui il link per leggerlo.

Tutorial 2

Da: https://11x256.github.io/Frida-hooking-android-part-2/ (Parts 2, 3 & 4)
APKs and Source code: https://github.com/11x256/frida-android-examples

Segui il link per leggerlo.

Tutorial 3

Da: https://joshspicer.com/android-frida-1
APK: https://github.com/OWASP/owasp-mstg/blob/master/Crackmes/Android/Level_01/UnCrackable-Level1.apk

Segui il link per leggerlo.

Puoi trovare altri script Frida qui: https://codeshare.frida.re/

Esempi rapidi

Chiamare Frida dalla 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.

Semplice script Python

python
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

javascript
Java.perform(function () {
;  rootcheck1.a.overload().implementation = function() {
rootcheck1.a.overload().implementation = function() {
send("sg.vantagepoint.a.c.a()Z   Root check 1 HIT!  su.exists()");
return false;
};
});

Hook java exit()

javascript
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()

javascript
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)
}

Intercettare android .onCreate()

javascript
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 funzione di decryption. Stampa l'input, chiama la funzione originale per decryptare l'input e, infine, stampa i dati in chiaro:

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
}

Hooking delle funzioni e chiamarle con il nostro input

Effettua l'hooking di una funzione che riceve una string e chiamala con un'altra string (da qui)

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:

javascript
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