- 由于 Android 原生程序的软件保护技术日趋成熟,很多软件和病毒都开始用加密和混淆技术强化自己,对此,静态分析已很难奏效,要用到动态调试
- 用 C、C++ 开发的原生程序,其语言的先天特性决定其二进制代码的分析难度比 Java 开发的 DEX 高得多,加上高强度的代码加密和混淆技术,逆向分析更加困难。因此,使用调试器配合脚本自动化技术,实现原生程序的自动化分析、自动化去除混淆与动态脱壳,已成为逆向分析中必须掌握的技能
gdb 调试器
- Android NDK 早期只支持用 gcc 开发原生程序(现在只支持 Clang),那时原生程序的调试器主要是 gdb(The GNU Project Debugger,GNU 工程调试器),即使是现在,用 gdb 调试原生程序也是一种选择
ndk-gdb 脚本
-
在 Android NDK 目录下有个 ndk-gdb 脚本,它是由 Android NDK 提供且经过配置的 gdb 调试器的启动器,内容如下:
-
ndk-gdb 对应 ndk-gdb.py,ndk-gdb.py 主要执行了如下操作:
- 解析 Android NDK 工程的工程信息。读取项目的
AndroidManifest.xml
,解析原生程序的包名和由 APK 启动的 Activity - 解析 Android NDK 工程的 ABI 信息。读取原生程序支持的 ABI,将其与当前连接到计算机中的设备的 ABI 进行比对,找出适合当前设备的 ABI 版本的原生程序
- 设置调试器的
stl_pretty_printer
。当APP_STL
为 stlport 或 gnustl 时,为 gdb 设置不同的stl_pretty_printer
- 获取已安装的原生程序在设备上的数据目录和 gdbserver 的位置
- 以调试模式启动原生程序所在 APK 的主 Activity
- 从设备上拉取(pull)一些调试中要用的系统动态库和原生程序
- 启动 gdbserver
- 启动 gdb,连接待调试的进程,开始调试
- 解析 Android NDK 工程的工程信息。读取项目的
-
从以上步骤可看出,用 ndk-gdb 动态调试原生程序时有如下限制:
- 独立的原生程序无法调试。原生程序必须和 APK “绑定”,且 APK 必须包含主 Activity
- 包含原生程序的 APK 必须是可调试的,且要先安装到设备上
- 无法便携设置 gdb 调试器前端
配置 gdb 调试器
-
为解决 ndk-gdb 动态调试原生程序时的限制,要手动对 gdb 调试器进行配置,以实现在没有调试符号的情况下也能顺利使用 gdb 以反汇编模式调试 Android 原生程序
-
先编译
android_gdb
脚本(其中的 gdb 路径为 NDK 中 gdb 程序的完整路径): -
再配置
stl_pretty_printer
。新建脚本文件android_gdbinit
: