Tutoriel Frida

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Installation

Installez frida tools:

pip install frida-tools
pip install frida

Télécharger et installer sur l’Android le frida server (Download the latest release).
Commande en une ligne pour redémarrer adb en mode root, s’y connecter, uploader frida-server, lui donner les permissions d’exécution et le lancer en arrière-plan :

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

Vérifiez si cela fonctionne :

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)

Deux façons courantes d’instrumenter des applications Android avec Frida :

  • Frida server (rooted devices): Transférer et exécuter un daemon natif qui vous permet de vous attacher à n’importe quel processus.
  • Frida Gadget (no root): Intégrer Frida en tant que bibliothèque partagée dans l’APK et la charger automatiquement dans le processus cible.

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. Décompressez l’APK, ajoutez la .so du gadget et la configuration :
  • Placez libfrida-gadget.so dans lib/<abi>/ (par ex., lib/arm64-v8a/)
  • Créez assets/frida-gadget.config avec les paramètres de chargement de vos scripts

Exemple frida-gadget.config

{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Référencez/chargez le gadget pour qu’il soit initialisé tôt :
  • Le plus simple : ajoutez un petit stub Java appelant System.loadLibrary(“frida-gadget”) dans Application.onCreate(), ou utilisez le chargement des bibliothèques natives déjà présent.
  1. Repack et signez l’APK, puis installez :
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. Se connecter depuis l’hôte au processus gadget :
frida-ps -Uai
frida -U -n com.example.app

Remarques

  • Gadget is detected by some protections; keep names/paths stealthy and load late/conditionally if needed.
  • Sur les apps durcies, privilégiez des tests sur appareil rooted with server + late attach, ou combinez avec Magisk/Zygisk hiding.

Injection Frida basée sur JDWP sans root/repackaging (frida-jdwp-loader)

Si l’APK est debuggable (android:debuggable=“true”), vous pouvez vous attacher via JDWP et injecter une bibliothèque native à un breakpoint Java. Pas de root et pas de repackage de l’APK.

  • Repo: https://github.com/frankheat/frida-jdwp-loader
  • Requirements: ADB, Python 3, USB/Wireless debugging. App must be debuggable (emulator with ro.debuggable=1, rooted device with resetprop, or rebuild manifest).

Démarrage rapide

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

  • Modes : spawn (arrêt à Application.onCreate) ou attach (arrêt à Activity.onStart). Utilisez -b pour définir une méthode Java spécifique, -g pour sélectionner la version/chemin du Gadget, -p pour choisir le port JDWP.
  • Mode écoute : redirigez le port du Gadget (par défaut 127.0.0.1:27042) si nécessaire : adb forward tcp:27042 tcp:27042; puis frida-ps -H 127.0.0.1:27042.
  • Cela utilise JDWP pour le débogage. Le risque est de livrer des builds déboguables ou d’exposer JDWP.

Self-contained agent + Gadget embedding (Frida 17+; automated with Objection)

Frida 17 a retiré les Java/ObjC bridges intégrés de GumJS. Si votre agent hooks Java, vous devez inclure le Java bridge dans votre bundle.

  1. Créez un agent Frida (TypeScript) et incluez le 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 minimal (force les jets de dés à 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);
};
});

Créer un seul bundle pour l’intégration :

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

Test USB rapide (optionnel) :

frida -U -f org.secuso.privacyfriendlydicer -l _agent.js
  1. Configurer Gadget pour charger automatiquement votre script Le patcher d’Objection attend une Gadget config ; lorsqu’on utilise script mode, spécifiez le on-disk path à l’intérieur du APK lib dir :
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatiser APK patching avec 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

Ce que fait patchapk (haut niveau) :

  • Détecte l’ABI de l’appareil (par ex., arm64-v8a) et récupère le Gadget correspondant
  • Ajoute optionnellement android.permission.INTERNET si nécessaire
  • Injecte un initialiseur statique de classe appelant System.loadLibrary(“frida-gadget”) dans l’activité de lancement
  • Place les éléments suivants sous lib/<abi>/ :
  • libfrida-gadget.so
  • libfrida-gadget.config.so (config sérialisée)
  • libfrida-gadget.script.so (your _agent.js)

Exemple de smali injecté (initialiseur statique) :

.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. Vérifier le 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

Modifications attendues :

  • AndroidManifest.xml may include <uses-permission android:name="android.permission.INTERNET"/>
  • Nouvelles bibliothèques natives sous lib/<abi>/ comme ci-dessus
  • Le smali de l’activité lançable contient un <clinit> statique qui appelle System.loadLibrary(“frida-gadget”)
  1. Split APKs
  • Appliquez un patch à l’APK de base (celui qui déclare l’activité MAIN/LAUNCHER)
  • Ré-signez les splits restants avec la même clé :
objection signapk split1.apk split2.apk ...
  • Installer les splits ensemble :
adb install-multiple split1.apk split2.apk ...
  • Pour la distribution, vous pouvez fusionner les splits en un seul APK avec APKEditor, puis align/sign

Effacer FLAG_SECURE pendant l’analyse dynamique

Les applications qui appellent getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) empêchent les captures d’écran, les affichages à distance et même les instantanés des tâches récentes d’Android. Lorsque Freedom Chat imposait ce flag, la seule façon de documenter les leaks était de manipuler la fenêtre à l’exécution. Un schéma fiable est :

  • Appliquez un hook à chaque surcharge de Window qui peut ré-appliquer le flag (setFlags, addFlags, setAttributes) et masquez le bit 0x00002000 (WindowManager.LayoutParams.FLAG_SECURE).
  • Après chaque reprise d’une activity, planifiez un appel sur le thread UI à clearFlags(FLAG_SECURE) afin que les Dialogs/Fragments créés ensuite héritent de l’état déverrouillé.
  • Les apps construites avec React Native / Flutter créent souvent des fenêtres imbriquées ; hookez les helpers android.app.Dialog/android.view.View ou parcourez getWindow().peekDecorView() si vous voyez encore des cadres noirs.
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>

Exécutez le script avec `frida -U -f <package> -l disable-flag-secure.js --no-pause`, interagissez avec l'UI, et les captures d'écran/enregistrements fonctionneront à nouveau. Parce que tout se passe sur le UI thread, il n'y a pas de clignotement, et vous pouvez toujours combiner le hook avec HTTP Toolkit/Burp pour capturer le trafic qui a révélé le leak PIN `/channel`.


## Tutoriels

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

**Origine**: [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)\
**Code source**: [https://github.com/t0thkr1s/frida-demo](https://github.com/t0thkr1s/frida-demo)

**Suivez le [lien pour le lire](frida-tutorial-1.md).**

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

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

**Suivez le [lien pour le lire.](frida-tutorial-2.md)**

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

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

**Suivez le [lien pour le lire](owaspuncrackable-1.md).**

**Vous pouvez trouver plus de scripts Frida Awesome ici:** [**https://codeshare.frida.re/**](https://codeshare.frida.re)

## Exemples rapides

### Appeler Frida depuis la ligne de commande
```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 basique

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 des fonctions sans paramètres

Hook la fonction a() de la 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() et .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 de fonctions avec paramètres et récupération de la valeur

Hooking d’une fonction de déchiffrement. Afficher l’entrée, appeler la fonction originale pour déchiffrer l’entrée et enfin, afficher les données en clair :

Hooking d'une fonction de déchiffrement (Java) — afficher entrées/sorties ```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 des fonctions et les appeler avec notre entrée

Hook une fonction qui reçoit une chaîne et l'appeler avec une autre chaîne (depuis [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
}

Obtenir un objet déjà créé d’une classe

Si vous voulez extraire un attribut d’un objet déjà créé, vous pouvez utiliser ceci.

Dans cet exemple vous verrez comment obtenir l’objet de la classe my_activity et comment appeler la fonction .secret() qui affichera un attribut privé de l’objet :

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

Autres tutoriels sur Frida

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks