Reversing Native Libraries

Reading time: 7 minutes

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

Pour plus d'informations, consultez : https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html

Les applications Android peuvent utiliser des bibliothèques natives, typiquement écrites en C ou C++, pour des tâches critiques en performance. Les créateurs de malware abusent aussi de ces bibliothèques parce que les ELF shared objects restent plus difficiles à décompiler que le byte-code DEX/OAT. Cette page se concentre sur des workflows pratiques et des améliorations récentes des outils (2023-2025) qui rendent le reversing des fichiers .so Android plus simple.


Quick triage-workflow for a freshly pulled libfoo.so

  1. Extraire la bibliothèque
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. Identifier l'architecture et les 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. Lister les symboles exportés et les bindings JNI
bash
readelf -s libfoo.so | grep ' Java_'     # dynamic-linked JNI
strings libfoo.so   | grep -i "RegisterNatives" -n   # static-registered JNI
  1. Charger dans un décompilateur (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) et lancer l'auto-analyse. Les versions récentes de Ghidra ont introduit un décompilateur AArch64 qui reconnaît les stubs PAC/BTI et les tags MTE, améliorant grandement l'analyse des bibliothèques construites avec l'Android 14 NDK.
  2. Décider entre static vs dynamic reversing : le code strippé/obfusqué nécessite souvent de l'instrumentation (Frida, ptrace/gdbserver, LLDB).

Instrumentation dynamique (Frida ≥ 16)

La série 16 de Frida a apporté plusieurs améliorations spécifiques à Android qui aident lorsque la cible utilise des optimisations modernes de Clang/LLD :

  • thumb-relocator peut maintenant hooker de petites fonctions ARM/Thumb générées par l'alignement agressif de LLD (--icf=all).
  • L'énumération et le rebinding des ELF import slots fonctionne sur Android, permettant des patchs par-module via dlopen()/dlsym() quand les hooks inline sont rejetés.
  • Le Java hooking a été corrigé pour le nouvel ART quick-entrypoint utilisé lorsque les apps sont compilées avec --enable-optimizations sur Android 14.

Example: 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 fonctionnera immédiatement sur les appareils activés PAC/BTI (Pixel 8/Android 14+) tant que vous utilisez frida-server 16.2 ou plus récent – les versions antérieures échouaient à localiser le padding pour les inline hooks.

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

Quand une instrumentation complète est excessif ou bloquée, vous pouvez toujours obtenir une visibilité au niveau natif en préchargeant un petit logger dans le process cible. SoTap est une bibliothèque native Android légère (.so) qui journalise le comportement d'exécution d'autres bibliothèques JNI (.so) dans le même processus d'app (aucun root requis).

Propriétés clés:

  • S'initialise tôt et observe les interactions JNI/native à l'intérieur du processus qui le charge.
  • Persiste les logs en utilisant plusieurs chemins inscriptibles avec un repli gracieux vers Logcat lorsque le stockage est restreint.
  • Personnalisable depuis la source : éditez sotap.c pour étendre/ajuster ce qui est loggé et reconstruisez par ABI.

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

Notes et dépannage:

  • L'alignement ABI est obligatoire. Un mismatch soulèvera UnsatisfiedLinkError et le logger ne se chargera pas.
  • Les contraintes de stockage sont courantes sur les Android modernes ; si les écritures de fichiers échouent, SoTap émettra quand même via Logcat.
  • Le comportement/la verbosité sont destinés à être personnalisés ; recompilez depuis la source après avoir édité sotap.c.

Cette approche est utile pour le triage de malware et le debugging JNI lorsque l'observation des flux d'appels natifs depuis le démarrage du process est critique mais que des hooks root/à l'échelle du système ne sont pas disponibles.


Recent vulnerabilities worth hunting for in APKs

YearCVEAffected libraryNotes
2023CVE-2023-4863libwebp ≤ 1.3.1Heap 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.
2024MultipleOpenSSL 3.x seriesSeveral memory-safety and padding-oracle issues. Many Flutter & ReactNative bundles ship their own libcrypto.so.

Lorsque vous repérez des fichiers .so third-party à l'intérieur d'un APK, vérifiez toujours leur hash par rapport aux avis en amont. La SCA (Software Composition Analysis) est rare sur mobile, donc des builds anciens et vulnérables sont fréquents.


  • Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14 active PAC/BTI dans les libraries système sur les siliciums ARMv8.3+ supportés. Les décompilateurs affichent désormais des pseudo-instructions liées à PAC ; pour l'analyse dynamique Frida injecte des trampolines after stripping PAC, mais vos trampolines personnalisés doivent appeler pacda/autibsp si nécessaire.
  • MTE & Scudo hardened allocator: le memory-tagging est optionnel mais beaucoup d'apps compatibles Play-Integrity sont compilées avec -fsanitize=memtag ; utilisez setprop arm64.memtag.dump 1 plus adb shell am start ... pour capturer les tag faults.
  • LLVM Obfuscator (opaque predicates, control-flow flattening): les packers commerciaux (par ex. Bangcle, SecNeo) protègent de plus en plus le code native, pas seulement Java ; attendez-vous à du bogus control-flow et des blobs de chaînes chiffrées dans .rodata.

Resources

References

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