反向分析本地库
Reading time: 9 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
更多信息请参见: https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html
Android 应用可以使用本地库,通常用 C 或 C++ 编写,用于性能关键的任务。恶意软件作者也滥用这些库,因为 ELF 共享对象比 DEX/OAT byte-code 更难反编译。
本页侧重于使逆向 Android .so
文件更容易的实用工作流程和近期工具改进(2023–2025)。
新提取 libfoo.so
的快速初筛流程
- 提取库文件
# 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/
- 识别架构与保护
file libfoo.so # arm64 or arm32 / x86
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so # (peda/pwntools)
- 列出导出符号与 JNI 绑定
readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI
strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI
- 在反编译器中加载 (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) 并运行自动分析。 较新的 Ghidra 版本引入了对 AArch64 的反编译器,能够识别 PAC/BTI stubs 和 MTE tags,大幅改善使用 Android 14 NDK 构建的库的分析。
- 决定使用静态还是动态逆向: 被剥离符号或混淆的代码通常需要插桩(Frida, ptrace/gdbserver, LLDB)。
动态插桩 (Frida ≥ 16)
Frida 16 系列带来了一些针对 Android 的改进,当目标使用现代 Clang/LLD 优化时这些改进很有用:
thumb-relocator
现在可以 hook 由 LLD 的激进对齐(--icf=all
)生成的小型 ARM/Thumb 函数。- 在 Android 上,枚举并重新绑定 ELF import slots 已可行,当内联 hooks 被拒绝时,可对每个模块进行
dlopen()
/dlsym()
修补。 - 修复了 Java hooking 针对新的 ART quick-entrypoint 的兼容性,该入口在 Android 14 上使用
--enable-optimizations
编译的应用中被采用。
Example: enumerating all functions registered through RegisterNatives
and dumping their addresses at runtime:
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)
当完整功能的 instrumentation 过于繁重或被阻止时,你仍然可以通过在目标进程内预加载一个小型 logger 来获得本地级别的可见性。SoTap 是一个轻量级的 Android native (.so) 库,记录同一应用进程内其他 JNI (.so) 库的运行时行为(不需要 root)。
Key properties:
- 初始化较早,观察加载它的进程内的 JNI/native 交互。
- 使用多个可写路径持久化日志,当存储受限时优雅回退到 Logcat。
- 源代码可定制:编辑 sotap.c 来扩展/调整要记录的内容,并按 ABI 重新构建。
Setup (repack the APK):
- 将对应 ABI 的构建放入 APK,以便 loader 能解析 libsotap.so:
- lib/arm64-v8a/libsotap.so (for arm64)
- lib/armeabi-v7a/libsotap.so (for arm32)
- 确保 SoTap 在其他 JNI 库之前加载。尽早注入一次调用(例如,在 Application 子类的静态初始化器或 onCreate 中),以便 logger 优先初始化。Smali snippet example:
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
- 重新构建/签名/安装,运行应用,然后收集日志。
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
注意事项与故障排查:
- ABI 对齐是强制的。不匹配会抛出 UnsatisfiedLinkError,且 logger 无法加载。
- 现代 Android 常见存储限制;如果文件写入失败,SoTap 仍会通过 Logcat 输出。
- 行为/详细程度可自定义;在编辑 sotap.c 后需从源码重新构建。
该方法适用于恶意软件初筛和 JNI 调试,在需要从进程启动就观察本地调用流但无法使用 root/系统级 hooks 时尤其有用。
在 APK 中值得寻找的近期漏洞
Year | CVE | Affected library | Notes |
---|---|---|---|
2023 | CVE-2023-4863 | libwebp ≤ 1.3.1 | 堆缓冲区溢出,可由解码 WebP 图像的本地代码触发。若干 Android 应用捆绑了易受影响的版本。当在 APK 中看到 libwebp.so 时,请检查其版本并尝试利用或修补。 |
2024 | Multiple | OpenSSL 3.x series | 多项内存安全和 padding-oracle 问题。许多 Flutter & ReactNative 包会自带它们自己的 libcrypto.so 。 |
当你在 APK 中发现第三方 .so
文件时,务必将其哈希与上游通报进行交叉核对。移动端很少做 SCA (Software Composition Analysis),因此过时且易受攻击的构建非常普遍。
反逆向与加固趋势(Android 13-15)
- Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14 在支持的 ARMv8.3+ 硬件上在系统库启用了 PAC/BTI。反编译器现在会显示与 PAC 相关的伪指令;对于动态分析,Frida 在去除 PAC 后注入 trampolines,但你的自定义 trampolines 在必要时应调用
pacda
/autibsp
。 - MTE & Scudo hardened allocator: 内存标记(memory-tagging)是可选的,但许多关注 Play-Integrity 的应用使用
-fsanitize=memtag
构建;使用setprop arm64.memtag.dump 1
加上adb shell am start ...
来捕获标记错误。 - LLVM Obfuscator (opaque predicates, control-flow flattening): 商业 packers(例如 Bangcle、SecNeo)越来越多地保护 native 代码,而不仅仅是 Java;在
.rodata
中预计会看到伪造的控制流和加密的字符串块。
资源
- 学习 ARM 汇编: Azeria Labs – ARM Assembly Basics
- JNI 与 NDK 文档: Oracle JNI Spec · Android JNI Tips · NDK Guides
- 调试本地库: Debug Android Native Libraries Using JEB Decompiler
参考资料
- Frida 16.x 变更日志 (Android hooking, tiny-function relocation) – frida.re/news
- 关于
libwebp
溢出的 NVD 通报 CVE-2023-4863 – nvd.nist.gov - SoTap:轻量级应用内 JNI (.so) 行为记录器 – github.com/RezaArbabBot/SoTap
- SoTap Releases – github.com/RezaArbabBot/SoTap/releases
- 如何使用 SoTap? – t.me/ForYouTillEnd/13
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。