Tutorial de Frida

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Instalación

Instalar frida tools:

pip install frida-tools
pip install frida

Descargar e instalar en el android el frida server (Download the latest release).
Comando de una línea para reiniciar adb en modo root, conectarse a él, subir frida-server, darle permisos de ejecución y ejecutarlo en segundo plano:

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

Comprobar si está funcionando:

frida-ps -U #List packages and processes
frida-ps -U | grep -i <part_of_the_package_name> #Get all the package name

frida-ui (controlador de Frida basado en navegador)

frida-ui proporciona una interfaz web en http://127.0.0.1:8000 para listar dispositivos/apps y attach o spawn targets con scripts (no se necesita CLI).

  • Instalar (fijar frida a la versión del device server):
uv tool install frida-ui --with frida==16.7.19
# pipx install frida-ui
# pip install frida-ui
  • Ejecutar:
frida-ui
frida-ui --host 127.0.0.1 --port 8000 --reload
  • Características: descubre dispositivos USB/locales, añade servidores remotos (192.168.1.x:27042), y soporta Attach, Spawn, y Spawn & Run (para hookear antes de la lógica temprana de onCreate()).
  • Scripting: editor, arrastrar y soltar .js, importar CodeShare, descargar scripts y logs de sesión.
  • Servidores remotos: ./frida-server -l 0.0.0.0:27042 -D lo expone en la red para que frida-ui pueda conectarse sin ADB.

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

Dos formas comunes de instrumentar aplicaciones Android con Frida:

  • Frida server (rooted devices): Sube y ejecuta un daemon nativo que te permite hacer attach a cualquier proceso.
  • Frida Gadget (no root): Empaqueta Frida como una librería compartida dentro del APK y la carga automáticamente dentro del proceso objetivo.

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. Desempaqueta el APK, añade el .so del gadget y la configuración:
  • Coloca libfrida-gadget.so en lib/<abi>/ (p. ej., lib/arm64-v8a/)
  • Crea assets/frida-gadget.config con la configuración para cargar tus scripts

Ejemplo frida-gadget.config

{
"interaction": { "type": "script", "path": "/sdcard/ssl-bypass.js" },
"runtime": { "logFile": "/sdcard/frida-gadget.log" }
}
  1. Referencia/carga el gadget para que se inicialice temprano:
  • Lo más sencillo: Añade un pequeño stub Java que llame a System.loadLibrary(“frida-gadget”) en Application.onCreate(), o utiliza la carga de librería nativa ya presente.
  1. Reempaqueta y firma el APK, luego instala:
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. Conectarse desde el host al proceso gadget:
frida-ps -Uai
frida -U -n com.example.app

Notas

  • Gadget is detected by some protections; keep names/paths stealthy and load late/conditionally if needed.
  • On hardened apps, prefer rooted testing with server + late attach, or combine with Magisk/Zygisk hiding.

Inyección Frida basada en JDWP sin root/reempaquetado (frida-jdwp-loader)

Si el APK es debuggable (android:debuggable=“true”), puedes attach over JDWP e inyectar una librería nativa en un breakpoint de Java. No root y no reempaquetado del APK.

  • Repo: https://github.com/frankheat/frida-jdwp-loader
  • Requisitos: ADB, Python 3, USB/Wireless debugging. La app debe ser debuggable (emulator with ro.debuggable=1, rooted device with resetprop, or rebuild manifest).

Inicio rápido:

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

  • Modos: spawn (break at Application.onCreate) o attach (break at Activity.onStart). Usa -b para establecer un método Java específico, -g para seleccionar la versión/ruta de Gadget, -p para elegir el puerto JDWP.
  • Listen mode: forward Gadget (default 127.0.0.1:27042) si es necesario: adb forward tcp:27042 tcp:27042; luego frida-ps -H 127.0.0.1:27042.
  • Esto aprovecha la depuración JDWP. El riesgo es distribuir debuggable builds o exponer JDWP.

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

Frida 17 removed the built-in Java/ObjC bridges from GumJS. Si tu agente hooks Java, debes incluir el Java bridge dentro de tu bundle.

  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

Hook mínimo de Java (obliga a que las tiradas de dados sean 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);
};
});

Crear un bundle único para incrustar:

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

Prueba rápida de USB (opcional):

frida -U -f org.secuso.privacyfriendlydicer -l _agent.js
  1. Configurar Gadget para cargar automáticamente tu script El patcher de Objection espera una configuración de Gadget; al usar script mode, especifica la ruta en disco dentro del lib dir del APK:
{
"interaction": {
"type": "script",
"path": "libfrida-gadget.script.so"
}
}
  1. Automatizar el parcheo de 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

Lo que hace patchapk (a alto nivel):

  • Detecta el ABI del dispositivo (por ejemplo, arm64-v8a) y descarga el Gadget correspondiente
  • Opcionalmente añade android.permission.INTERNET cuando es necesario
  • Inyecta un inicializador de clase estático que llama a System.loadLibrary(“frida-gadget”) en la actividad de lanzamiento
  • Coloca lo siguiente bajo lib/<abi>/:
  • libfrida-gadget.so
  • libfrida-gadget.config.so (config serializado)
  • libfrida-gadget.script.so (tu _agent.js)

Ejemplo de smali inyectado (inicializador estático):

.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. Verificar el 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
  • AndroidManifest.xml puede incluir <uses-permission android:name="android.permission.INTERNET"/>
  • Nuevas librerías nativas bajo lib/<abi>/ como arriba
  • El smali de la actividad lanzable contiene un <clinit> estático que llama a System.loadLibrary(“frida-gadget”)
  1. APKs divididos
  • Parchea el APK base (el que declara la actividad MAIN/LAUNCHER)
  • Vuelve a firmar los splits restantes con la misma clave:
objection signapk split1.apk split2.apk ...
  • Instalar los splits juntos:
adb install-multiple split1.apk split2.apk ...
  • Para distribución, puedes combinar los splits en un único APK con APKEditor, luego alinear/firmar

Borrando FLAG_SECURE durante el análisis dinámico

Las apps que llaman a getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE) impiden capturas de pantalla, displays remotos y hasta las instantáneas de tareas recientes de Android. Cuando Freedom Chat forzó esta bandera la única forma de documentar the leaks fue manipular la ventana en tiempo de ejecución. Un patrón fiable es:

  • Hook every Window overload that can re-apply the flag (setFlags, addFlags, setAttributes) and mask out bit 0x00002000 (WindowManager.LayoutParams.FLAG_SECURE).
  • Después de que cada activity se reanude, programa una llamada en el hilo de UI a clearFlags(FLAG_SECURE) para que los Dialogs/Fragments creados después hereden el estado desbloqueado.
  • Las apps construidas con React Native / Flutter suelen crear ventanas anidadas; hook android.app.Dialog/android.view.View helpers o recorrer getWindow().peekDecorView() si aún ves black frames.
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>

Ejecuta el script con `frida -U -f <package> -l disable-flag-secure.js --no-pause`, interactúa con la interfaz de usuario, y las capturas de pantalla/las grabaciones volverán a funcionar. Como todo ocurre en el hilo de la interfaz de usuario no hay parpadeo, y aún puedes combinar el hook con HTTP Toolkit/Burp para capturar el tráfico que reveló el PIN `/channel` leak.

## Dynamic DEX dumping / unpacking with clsdumper (Frida)

`clsdumper` es un **DEX/class dumper** dinámico basado en Frida que sobrevive a aplicaciones hardened combinando una etapa previa anti-Frida con estrategias de descubrimiento nativas y en Java (funciona incluso si `Java.perform()` deja de funcionar). Requisitos: Python 3.10+, dispositivo rooteado con `frida-server` en ejecución, conexión USB o TCP con `--host`.

**Instalación y uso rápido**
```bash
pip install clsdumper
# Attach to a running app
clsdumper com.example.app
# Spawn first (hooks before early loaders)
clsdumper com.example.app --spawn
# Select strategies
clsdumper com.example.app --strategies fart_dump,oat_extract

Opciones CLI (más útiles)

  • target: nombre del paquete o PID.
  • --spawn: spawn en lugar de attach.
  • --host <ip>: conectar con frida-server remoto.
  • --strategies <comma>: limitar/seleccionar extractors; por defecto todos excepto mmap_hook (costoso).
  • --no-scan / --deep-scan: deshabilitar o ralentizar el deep memory scan (añade CDEX scanning).
  • --extract-classes: postprocesar dumps a .smali vía androguard.
  • --no-anti-frida: omitir la etapa de bypass pre-hook.
  • --list / --list-apps: enumerar procesos en ejecución o paquetes instalados.

Bypass anti-instrumentación (fase 0)

  • Intercepta sigaction/signal para bloquear el registro de manejadores de crash/anti-debug.
  • Sirve un /proc/self/maps filtrado vía memfd_create para ocultar regiones de Frida.
  • Monitorea pthread_create para detectar/neutralizar hilos watchdog que buscan Frida.

Descubrimiento DEX (fases 1–2) — múltiples estrategias complementarias con metadata por resultado + deduplicación (lado agente djb2, lado host SHA-256):

  • Nativo (no se necesita puente Java): art_walk (recorre ART Runtime→ClassLinker→DexFile), open_common_hook (hookea DexFile::OpenCommon), memory_scan (DEX magic en mapas legibles), oat_extract (parsea .vdex/.oat mapeados), fart_dump (hookea DefineClass + recorre class_table_), dexfile_constructor (hookea constructores de OatDexFile), mmap_hook (vigila mmap/mmap64, desactivado por defecto por rendimiento).
  • Java (cuando esté disponible): cookie (leer mCookie de ClassLoaders), classloader_hook (monitorear loadClass, DexClassLoader, InMemoryDexClassLoader).

Formato de salida

dump_<target>/
dex/classes_001.dex ...
classes/                 # only when --extract-classes
metadata.json            # strategy per hit + hashes

Tip: las apps protegidas a menudo cargan código desde varias fuentes (in-memory payload, vdex/oat, cargadores personalizados). Ejecutar con el conjunto multi-estrategia por defecto más --spawn maximiza la cobertura; habilita --deep-scan solo cuando sea necesario para evitar impactos en el rendimiento.

Tutoriales

Tutorial 1

De: https://medium.com/infosec-adventures/introduction-to-frida-5a3f51595ca1
APK: https://github.com/t0thkr1s/frida-demo/releases
Código fuente: https://github.com/t0thkr1s/frida-demo

Sigue el enlace para leerlo.

Tutorial 2

De: https://11x256.github.io/Frida-hooking-android-part-2/ (Parts 2, 3 & 4)
APKs y código fuente: https://github.com/11x256/frida-android-examples

Sigue el enlace para leerlo.

Tutorial 3

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

Sigue el enlace para leerlo.

Puedes encontrar más scripts de Frida increíbles aquí: https://codeshare.frida.re/

Ejemplos rápidos

Llamar a Frida desde la línea de comandos

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 básico de 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 de funciones sin parámetros

Hook la función a() de la clase 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() & .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 funciones con parámetros y obtención del valor

Hooking a decryption function. Imprime la entrada, llama a la función original para decrypt the input y, finalmente, imprime los datos en claro:

Hooking a decryption function (Java) — imprimir entradas/salidas ```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 y llamándolas con nuestra entrada

Hook a function que recibe un string y llámala con otro 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
}

Obtener un objeto ya creado de una clase

Si quieres extraer algún atributo de un objeto creado, puedes usar esto.

En este ejemplo verás cómo obtener el objeto de la clase my_activity y cómo llamar a la función .secret() que imprimirá un atributo privado del objeto:

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

Otros tutoriales de Frida

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks