Reversing Native Libraries

Reading time: 7 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Für weitere Informationen: https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html

Android-Apps können native Bibliotheken verwenden, typischerweise in C oder C++, für leistungsintensive Aufgaben. Malware-Autoren missbrauchen diese Bibliotheken ebenfalls, weil ELF shared objects immer noch schwerer zu dekompilieren sind als DEX/OAT byte-code. Diese Seite konzentriert sich auf praktische Workflows und aktuelle Verbesserungen der Tools (2023–2025), die das reversing von Android .so-Dateien erleichtern.


Schneller Triage-Workflow für eine frisch gezogene libfoo.so

  1. Extract the library
bash
# 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. Identify architecture & protections
bash
file libfoo.so        # arm64 or arm32 / x86
readelf -h libfoo.so  # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so  # (peda/pwntools)
  1. List exported symbols & JNI bindings
bash
readelf -s libfoo.so | grep ' Java_'     # dynamic-linked JNI
strings libfoo.so   | grep -i "RegisterNatives" -n   # static-registered JNI
  1. Load in a decompiler (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) and run auto-analysis. Neuere Ghidra-Versionen enthalten einen AArch64-Decompiler, der PAC/BTI-Stubs und MTE-Tags erkennt und die Analyse von Bibliotheken, die mit dem Android 14 NDK erstellt wurden, deutlich verbessert.
  2. Decide on static vs dynamic reversing: stripped, obfuscated code often needs instrumentation (Frida, ptrace/gdbserver, LLDB).

Dynamische Instrumentation (Frida ≥ 16)

Die 16er-Serie von Frida brachte mehrere Android-spezifische Verbesserungen, die helfen, wenn das Ziel moderne Clang/LLD-Optimierungen verwendet:

  • thumb-relocator can now hook tiny ARM/Thumb functions generated by LLD’s 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.

Beispiel: enumerating all functions registered through RegisterNatives and dumping their addresses at runtime:

javascript
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.

Process-local JNI telemetry via preloaded .so (SoTap)

Wenn vollumfängliche Instrumentierung übertrieben oder blockiert ist, kannst du trotzdem native Sichtbarkeit gewinnen, indem du einen kleinen Logger im Zielprozess vorgeladen. SoTap ist eine leichte Android native (.so) Bibliothek, die das Laufzeitverhalten anderer JNI (.so) Bibliotheken im selben App-Prozess protokolliert (no root required).

Wichtige Eigenschaften:

  • Initialisiert früh und beobachtet JNI/native Interaktionen innerhalb des Prozesses, der es lädt.
  • Persistiert Logs über mehrere beschreibbare Pfade mit einem sauberen Fallback zu Logcat, wenn der Speicher eingeschränkt ist.
  • Quellcode-anpassbar: bearbeite sotap.c, um zu erweitern/anpassen, was geloggt wird, und baue pro ABI neu.

Setup (repack the 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:
smali
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

Hinweise und Fehlerbehebung:

  • ABI-Ausrichtung ist zwingend. Eine Nichtübereinstimmung löst eine UnsatisfiedLinkError aus und der Logger wird nicht geladen.
  • Speicherbeschränkungen sind auf modernen Android-Geräten üblich; wenn Datei-Schreibvorgänge fehlschlagen, gibt SoTap weiterhin über Logcat aus.
  • Verhalten und Ausgabedetailgrad sind anpassbar; nach Änderungen an sotap.c aus dem Quellcode neu bauen.

Dieser Ansatz ist nützlich für Malware-Triage und JNI-Debugging, wenn das Beobachten nativer Aufrufflüsse vom Prozessstart an kritisch ist, aber Root-/systemweite Hooks nicht verfügbar sind.


Jüngste Schwachstellen, nach denen man in APKs suchen sollte

YearCVEAffected libraryNotes
2023CVE-2023-4863libwebp ≤ 1.3.1Heap-Buffer-Overflow, zugänglich aus nativen Code, der WebP-Bilder decodiert. Mehrere Android-Apps enthalten verwundbare Versionen. Wenn Sie eine libwebp.so in einer APK finden, prüfen Sie deren Version und versuchen Sie Exploitierung oder Patchen.
2024MultipleOpenSSL 3.x seriesMehrere Speicher-Sicherheits- und Padding-Oracle-Probleme. Viele Flutter- & ReactNative-Bundles liefern ihre eigene libcrypto.so mit.

Wenn Sie third-party .so-Dateien in einer APK entdecken, gleichen Sie deren Hash stets mit Upstream-Advisories ab. SCA (Software Composition Analysis) ist auf Mobilgeräten selten, daher sind veraltete, verwundbare Builds weit verbreitet.


  • Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14 aktiviert PAC/BTI in Systembibliotheken auf unterstütztem ARMv8.3+ Silizium. Decompiler zeigen jetzt PAC-bezogene Pseudo-Instruktionen; für dynamische Analyse injiziert Frida Trampoline nachdem PAC entfernt wurde, aber Ihre eigenen Trampoline sollten bei Bedarf pacda/autibsp aufrufen.
  • MTE & Scudo hardened allocator: Memory-Tagging ist optional, aber viele Play-Integrity-bewusste Apps werden mit -fsanitize=memtag gebaut; verwenden Sie setprop arm64.memtag.dump 1 plus adb shell am start ..., um Tag-Faults zu erfassen.
  • LLVM Obfuscator (opaque predicates, control-flow flattening): Kommerzielle Packer (z. B. Bangcle, SecNeo) schützen zunehmend nativen Code, nicht nur Java; erwarten Sie gefälschte Kontrollflüsse und verschlüsselte String-Blobs in .rodata.

Ressourcen

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks