hacktricks/src/mobile-pentesting/android-app-pentesting/reversing-native-libraries.md

8.5 KiB
Raw Blame History

Reversión de bibliotecas nativas

{{#include ../../banners/hacktricks-training.md}}

Para más información consulta: https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html

Las apps Android pueden usar bibliotecas nativas, típicamente escritas en C o C++, para tareas que requieren rendimiento. Los creadores de malware también abusan de estas bibliotecas porque los ELF shared objects siguen siendo más difíciles de decompilar que el byte-code DEX/OAT. Esta página se centra en flujos de trabajo prácticos y mejoras recientes en tooling (2023-2025) que hacen más fácil revertir archivos .so de Android.


Flujo rápido de triage para un libfoo.so recién extraído

  1. Extraer la biblioteca
# From an installed application
adb shell "run-as <pkg> cat lib/arm64-v8a/libfoo.so" > libfoo.so
# Or from the APK (zip)
unzip -j target.apk "lib/*/libfoo.so" -d extracted_libs/
  1. Identificar arquitectura y protecciones
file libfoo.so        # arm64 or arm32 / x86
readelf -h libfoo.so  # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so  # (peda/pwntools)
  1. Listar símbolos exportados y bindings JNI
readelf -s libfoo.so | grep ' Java_'     # dynamic-linked JNI
strings libfoo.so   | grep -i "RegisterNatives" -n   # static-registered JNI
  1. Cargar en un descompilador (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) y ejecutar el auto-análisis. Las versiones más recientes de Ghidra introdujeron un descompilador AArch64 que reconoce PAC/BTI stubs y MTE tags, mejorando enormemente el análisis de bibliotecas compiladas con el Android 14 NDK.
  2. Decidir entre reversing estático vs dinámico: el código stripped u ofuscado a menudo necesita instrumentation (Frida, ptrace/gdbserver, LLDB).

Instrumentación dinámica (Frida ≥ 16)

La serie 16 de Frida trajo varias mejoras específicas para Android que ayudan cuando el objetivo usa optimizaciones modernas de Clang/LLD:

  • thumb-relocator can now hook tiny ARM/Thumb functions generated by LLDs aggressive alignment (--icf=all).
  • Enumerating and rebinding ELF import slots works on Android, enabling per-module dlopen()/dlsym() patching when inline hooks are rejected.
  • Java hooking was fixed for the new ART quick-entrypoint used when apps are compiled with --enable-optimizations on Android 14.

Ejemplo: enumerar todas las funciones registradas mediante RegisterNatives y volcar sus direcciones en tiempo de ejecución:

Java.perform(function () {
var Runtime = Java.use('java.lang.Runtime');
var register = Module.findExportByName(null, 'RegisterNatives');
Interceptor.attach(register, {
onEnter(args) {
var envPtr  = args[0];
var clazz   = Java.cast(args[1], Java.use('java.lang.Class'));
var methods = args[2];
var count   = args[3].toInt32();
console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' methods');
// iterate & dump (JNI nativeMethod struct: name, sig, fnPtr)
}
});
});

Frida will work out of the box on PAC/BTI-enabled devices (Pixel 8/Android 14+) as long as you use frida-server 16.2 or later earlier versions failed to locate padding for inline hooks.

Telemetría JNI a nivel de proceso mediante .so precargado (SoTap)

Cuando la instrumentación completa es exagerada o está bloqueada, aún puedes obtener visibilidad a nivel nativo precargando un pequeño logger dentro del proceso objetivo. SoTap es una librería nativa ligera de Android (.so) que registra el comportamiento en tiempo de ejecución de otras librerías JNI (.so) dentro del mismo proceso de la app (no se requiere root).

Propiedades clave:

  • Se inicializa temprano y observa las interacciones JNI/nativas dentro del proceso que la carga.
  • Persiste registros usando múltiples rutas escribibles con retroceso a Logcat cuando el almacenamiento está restringido.
  • Personalizable en origen: edita sotap.c para ampliar/ajustar lo que se registra y recompila por ABI.

Configuración (reempacar el APK):

  1. Drop the proper ABI build into the APK so the loader can resolve libsotap.so:
  • lib/arm64-v8a/libsotap.so (for arm64)
  • lib/armeabi-v7a/libsotap.so (for arm32)
  1. Ensure SoTap loads before other JNI libs. Inject a call early (e.g., Application subclass static initializer or onCreate) so the logger is initialized first. Smali snippet example:
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
  1. Rebuild/sign/install, run the app, then collect logs.

Log paths (checked in order):

/data/user/0/%s/files/sotap.log
/data/data/%s/files/sotap.log
/sdcard/Android/data/%s/files/sotap.log
/sdcard/Download/sotap-%s.log
# If all fail: fallback to Logcat only

Notas y solución de problemas:

  • ABI alignment is mandatory. A mismatch will raise UnsatisfiedLinkError and the logger wont load.
  • Storage constraints are common on modern Android; if file writes fail, SoTap will still emit via Logcat.
  • Behavior/verbosity is intended to be customized; rebuild from source after editing sotap.c.

This approach is useful for malware triage and JNI debugging where observing native call flows from process start is critical but root/system-wide hooks arent available.


Véase también: inmemory native code execution via JNI

A common attack pattern is to download a raw shellcode blob at runtime and execute it directly from memory through a JNI bridge (no ondisk ELF). Details and readytouse JNI snippet here:

{{#ref}} in-memory-jni-shellcode-execution.md {{#endref}}


Vulnerabilidades recientes que vale la pena buscar en APKs

Año CVE Biblioteca afectada Notas
2023 CVE-2023-4863 libwebp ≤ 1.3.1 Heap buffer overflow reachable from native code that decodes WebP images. Several Android apps bundle vulnerable versions. When you see a libwebp.so inside an APK, check its version and attempt exploitation or patching.
2024 Multiple OpenSSL 3.x series Several memory-safety and padding-oracle issues. Many Flutter & ReactNative bundles ship their own libcrypto.so.

Cuando encuentres archivos .so de third-party dentro de un APK, siempre verifica su hash contra las advisories upstream. SCA (Software Composition Analysis) es poco común en mobile, por lo que las builds vulnerables y desactualizadas son rampantes.


Tendencias de Anti-Reversing & Hardening (Android 13-15)

  • Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14 enables PAC/BTI in system libraries on supported ARMv8.3+ silicon. Decompilers now display PACrelated pseudo-instructions; for dynamic analysis Frida injects trampolines after stripping PAC, but your custom trampolines should call pacda/autibsp where necessary.
  • MTE & Scudo hardened allocator: memory-tagging is opt-in but many Play-Integrity aware apps build with -fsanitize=memtag; use setprop arm64.memtag.dump 1 plus adb shell am start ... to capture tag faults.
  • LLVM Obfuscator (opaque predicates, control-flow flattening): commercial packers (e.g., Bangcle, SecNeo) increasingly protect native code, not only Java; expect bogus control-flow and encrypted string blobs in .rodata.

Recursos

Referencias

{{#include ../../banners/hacktricks-training.md}}