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

Installer frida tools:

pip install frida-tools
pip install frida

Télécharger et installer sur l’appareil Android le frida server (Download the latest release).
Commande en une ligne pour redémarrer adb en root mode, s’y connecter, téléverser frida-server, lui donner les permissions d’exécution et l’exécuter 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-ui (contrôleur Frida basé sur navigateur)

frida-ui fournit une interface web sur http://127.0.0.1:8000 pour lister devices/apps et attach or spawn targets avec des scripts (no CLI needed).

  • Installer (pin frida to the device server version):
uv tool install frida-ui --with frida==16.7.19
# pipx install frida-ui
# pip install frida-ui
  • Exécuter:
frida-ui
frida-ui --host 127.0.0.1 --port 8000 --reload
  • Fonctionnalités : découvre les appareils USB/locaux, ajoute des serveurs distants (192.168.1.x:27042), et prend en charge Attach, Spawn, et Spawn & Run (pour hooker avant l’exécution précoce de onCreate()).
  • Scripting : éditeur, glisser-déposer .js, importer CodeShare, télécharger des scripts et des logs de session.
  • Serveurs distants : ./frida-server -l 0.0.0.0:27042 -D l’expose sur le réseau afin que frida-ui puisse se connecter sans ADB.

Frida server vs. Gadget (root vs. no-root)

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

  • Frida server (rooted devices) : Déployer et exécuter un démon natif qui vous permet d’effectuer un Attach sur 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 le .so du gadget et la config :
  • Placez libfrida-gadget.so dans lib/<abi>/ (par ex., lib/arm64-v8a/)
  • Créez assets/frida-gadget.config avec vos paramètres de chargement de script

Exemple frida-gadget.config

{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Référencer/charger 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 natif de la bibliothèque déjà présent.
  1. Repackez et signez l’APK, puis installez-le :
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. Attacher 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 des apps hardenées, privilégiez des tests sur appareil rooté avec 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
  • Prérequis : ADB, Python 3, USB/Wireless debugging. L’app doit être debuggable (émulateur avec ro.debuggable=1, appareil rooté avec resetprop, ou recompiler le 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

Remarques

  • Modes : spawn (interrompre à Application.onCreate) ou attach (interrompre à Activity.onStart). Utilisez -b pour définir une méthode Java spécifique, -g pour sélectionner la version/chemin de Gadget, -p pour choisir le port JDWP.
  • Mode d’écoute : redirigez le 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 exploite le débogage JDWP. Le risque est de publier des builds débogables ou d’exposer JDWP.

Agent autonome + intégration du Gadget (Frida 17+; automatisé avec Objection)

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

  1. Créez un Frida agent (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

Minimal Java hook (force les lancers 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 bundle unique 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. Configure Gadget pour charger automatiquement votre script Le patcher d’Objection attend une Gadget config ; lorsque vous utilisez le script mode, spécifiez le chemin on-disk à l’intérieur de l’APK lib dir :
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatiser le patching d’APK 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 (p.ex., arm64-v8a) et récupère le Gadget correspondant
  • Ajoute éventuellement android.permission.INTERNET si nécessaire
  • Injecte un initialiseur de classe statique 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 (votre _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 peut inclure <uses-permission android:name="android.permission.INTERNET"/>
  • Nouvelles bibliothèques natives sous lib/<abi>/ comme ci-dessus
  • Le smali de l’activité pouvant être lancée contient un <clinit> static qui appelle System.loadLibrary(“frida-gadget”)
  1. Split APKs
  • Patchez 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 apps qui appellent getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) empêchent les captures d’écran, les affichages à distance et même les snapshots des tâches récentes d’Android. Lorsque Freedom Chat appliquait ce flag, la seule façon de documenter les leaks était de manipuler la fenêtre à l’exécution. Un schéma fiable est :

  • Hook every Window overload that can re-apply the flag (setFlags, addFlags, setAttributes) and mask out 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 ; hook android.app.Dialog/android.view.View helpers 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. Étant donné que tout se passe sur le thread de l'UI, il n'y a aucun scintillement, et vous pouvez toujours combiner le hook avec HTTP Toolkit/Burp pour capturer le trafic qui a révélé le `/channel` PIN leak.


## Tutorials

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

**Source**: [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 [link to read it](frida-tutorial-1.md).**

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

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

**Suivez le [link to read it.](frida-tutorial-2.md)**

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

**Source**: [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 [link to read it](owaspuncrackable-1.md).**

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

## Quick Examples

### Calling Frida from command line
```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 de 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 des fonctions sans paramètres

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

Hooking d’une fonction de décryptage. Affichez l’entrée, appelez la fonction originale pour décrypter l’entrée et, enfin, affichez les données en clair :

Hooking d'une fonction de décryptage (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 functions et les appeler avec notre input

Hook a function qui reçoit une string et appelez-la avec une autre string (from [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
}

Récupérer 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 allez voir 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 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