|
5 | 5 |
|
6 | 6 | **For further information check:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html)
|
7 | 7 |
|
8 |
| -Android apps can use native libraries, typically written in C or C++, for performance-critical tasks. Malware creators also use these libraries, as they're harder to reverse engineer than DEX bytecode. The section emphasizes reverse engineering skills tailored to Android, rather than teaching assembly languages. ARM and x86 versions of libraries are provided for compatibility. |
9 |
| - |
10 |
| -### Key Points: |
11 |
| - |
12 |
| -- **Native Libraries in Android Apps:** |
13 |
| - - Used for performance-intensive tasks. |
14 |
| - - Written in C or C++, making reverse engineering challenging. |
15 |
| - - Found in `.so` (shared object) format, similar to Linux binaries. |
16 |
| - - Malware creators prefer native code to make analysis harder. |
17 |
| -- **Java Native Interface (JNI) & Android NDK:** |
18 |
| - - JNI allows Java methods to be implemented in native code. |
19 |
| - - NDK is an Android-specific set of tools to write native code. |
20 |
| - - JNI and NDK bridge Java (or Kotlin) code with native libraries. |
21 |
| -- **Library Loading & Execution:** |
22 |
| - - Libraries are loaded into memory using `System.loadLibrary` or `System.load`. |
23 |
| - - JNI_OnLoad is executed upon library loading. |
24 |
| - - Java-declared native methods link to native functions, enabling execution. |
25 |
| -- **Linking Java Methods to Native Functions:** |
26 |
| - - **Dynamic Linking:** Function names in native libraries match a specific pattern, allowing automatic linking. |
27 |
| - - **Static Linking:** Uses `RegisterNatives` for linking, providing flexibility in function naming and structure. |
28 |
| -- **Reverse Engineering Tools and Techniques:** |
29 |
| - - Tools like Ghidra and IDA Pro help analyze native libraries. |
30 |
| - - `JNIEnv` is crucial for understanding JNI functions and interactions. |
31 |
| - - Exercises are provided to practice loading libraries, linking methods, and identifying native functions. |
32 |
| - |
33 |
| -### Resources: |
34 |
| - |
35 |
| -- **Learning ARM Assembly:** |
36 |
| - - Suggested for a deeper understanding of the underlying architecture. |
37 |
| - - [ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/) from Azeria Labs is recommended. |
38 |
| -- **JNI & NDK Documentation:** |
39 |
| - - [Oracle's JNI Specification](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) |
40 |
| - - [Android's JNI Tips](https://developer.android.com/training/articles/perf-jni) |
41 |
| - - [Getting Started with the NDK](https://developer.android.com/ndk/guides/) |
42 |
| -- **Debugging Native Libraries:** |
43 |
| - - [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3) |
| 8 | +Android apps can use native libraries, typically written in C or C++, for performance-critical tasks. Malware creators also abuse these libraries because ELF shared objects are still harder to decompile than DEX/OAT byte-code. |
| 9 | +This page focuses on *practical* workflows and *recent* tooling improvements (2023-2025) that make reversing Android `.so` files easier. |
44 | 10 |
|
| 11 | +--- |
45 | 12 |
|
46 |
| -{{#include ../../banners/hacktricks-training.md}} |
| 13 | +### Quick triage-workflow for a freshly pulled `libfoo.so` |
| 14 | + |
| 15 | +1. **Extract the library** |
| 16 | + ```bash |
| 17 | + # From an installed application |
| 18 | + adb shell "run-as <pkg> cat lib/arm64-v8a/libfoo.so" > libfoo.so |
| 19 | + # Or from the APK (zip) |
| 20 | + unzip -j target.apk "lib/*/libfoo.so" -d extracted_libs/ |
| 21 | + ``` |
| 22 | +2. **Identify architecture & protections** |
| 23 | + ```bash |
| 24 | + file libfoo.so # arm64 or arm32 / x86 |
| 25 | + readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc. |
| 26 | + checksec --file libfoo.so # (peda/pwntools) |
| 27 | + ``` |
| 28 | +3. **List exported symbols & JNI bindings** |
| 29 | + ```bash |
| 30 | + readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI |
| 31 | + strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI |
| 32 | + ``` |
| 33 | +4. **Load in a decompiler** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) and run auto-analysis. |
| 34 | + Newer Ghidra versions introduced an AArch64 decompiler that recognises PAC/BTI stubs and MTE tags, greatly improving analysis of libraries built with the Android 14 NDK. |
| 35 | +5. **Decide on static vs dynamic reversing:** stripped, obfuscated code often needs *instrumentation* (Frida, ptrace/gdbserver, LLDB). |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +### Dynamic Instrumentation (Frida ≥ 16) |
| 40 | + |
| 41 | +Frida’s 16-series brought several Android-specific improvements that help when the target uses modern Clang/LLD optimisations: |
| 42 | + |
| 43 | +* `thumb-relocator` can now *hook tiny ARM/Thumb functions* generated by LLD’s aggressive alignment (`--icf=all`). |
| 44 | +* Enumerating and rebinding *ELF import slots* works on Android, enabling per-module `dlopen()`/`dlsym()` patching when inline hooks are rejected. |
| 45 | +* Java hooking was fixed for the new **ART quick-entrypoint** used when apps are compiled with `--enable-optimizations` on Android 14. |
| 46 | + |
| 47 | +Example: enumerating all functions registered through `RegisterNatives` and dumping their addresses at runtime: |
| 48 | +```javascript |
| 49 | +Java.perform(function () { |
| 50 | + var Runtime = Java.use('java.lang.Runtime'); |
| 51 | + var register = Module.findExportByName(null, 'RegisterNatives'); |
| 52 | + Interceptor.attach(register, { |
| 53 | + onEnter(args) { |
| 54 | + var envPtr = args[0]; |
| 55 | + var clazz = Java.cast(args[1], Java.use('java.lang.Class')); |
| 56 | + var methods = args[2]; |
| 57 | + var count = args[3].toInt32(); |
| 58 | + console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' methods'); |
| 59 | + // iterate & dump (JNI nativeMethod struct: name, sig, fnPtr) |
| 60 | + } |
| 61 | + }); |
| 62 | +}); |
| 63 | +``` |
| 64 | +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. citeturn5search2turn5search0 |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +### Recent vulnerabilities worth hunting for in APKs |
47 | 69 |
|
| 70 | +| Year | CVE | Affected library | Notes | |
| 71 | +|------|-----|------------------|-------| |
| 72 | +|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.| citeturn2search0| |
| 73 | +|2024|Multiple|OpenSSL 3.x series|Several memory-safety and padding-oracle issues. Many Flutter & ReactNative bundles ship their own `libcrypto.so`.| |
48 | 74 |
|
| 75 | +When you spot *third-party* `.so` files inside an APK, always cross-check their hash against upstream advisories. SCA (Software Composition Analysis) is uncommon on mobile, so outdated vulnerable builds are rampant. |
49 | 76 |
|
| 77 | +--- |
| 78 | + |
| 79 | +### Anti-Reversing & Hardening trends (Android 13-15) |
| 80 | + |
| 81 | +* **Pointer Authentication (PAC) & Branch Target Identification (BTI):** Android 14 enables PAC/BTI in system libraries on supported ARMv8.3+ silicon. Decompilers now display PAC‐related pseudo-instructions; for dynamic analysis Frida injects trampolines *after* stripping PAC, but your custom trampolines should call `pacda`/`autibsp` where necessary. |
| 82 | +* **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. |
| 83 | +* **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`. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +### Resources |
| 88 | + |
| 89 | +- **Learning ARM Assembly:** [Azeria Labs – ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/) |
| 90 | +- **JNI & NDK Documentation:** [Oracle JNI Spec](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Android JNI Tips](https://developer.android.com/training/articles/perf-jni) · [NDK Guides](https://developer.android.com/ndk/guides/) |
| 91 | +- **Debugging Native Libraries:** [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3) |
| 92 | + |
| 93 | +### References |
| 94 | + |
| 95 | +- Frida 16.x change-log (Android hooking, tiny-function relocation) – [frida.re/news](https://frida.re/news/) citeturn5search0 |
| 96 | +- NVD advisory for `libwebp` overflow CVE-2023-4863 – [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) citeturn2search0 |
| 97 | + |
| 98 | +{{#include ../../banners/hacktricks-training.md}} |
0 commit comments