目录

返回首页

初探macOS移动端lldb动态调试

MacOS之iOS动态调试

  • 下载PlayCover工具

  • 安装脱壳后的ipa包体文件

  • 右键应用图标在访达中显示

  • 打开包名.app文件夹(右键显示包内容)

01

  • 使用命令lldb ./Arc-mobile(具体的可执行文件)

  • 在lldb窗口中输入run即可运行应用进程

MacOS之Android动态调试

  • 首先需要使用apktool或者mt管理器编辑apk包体文件开启调试模式

  • 在AndroidManifest.xml的application标签里加入android:debuggable="true"然后重新打包签名安装

  • 使用brew install android-platform-tools安装安卓平台工具(adb)

  • 打开模拟器并在安装完编辑好的包体后,就需要使用adb命令连接模拟器了

  • 输入adb kill-server->adb devices

  • 如有端口占用问题可以使用lsof -i :5555查看占用进程的PID然后使用kill -9 「PID」杀死占用进程并重启模拟器,最终出现list of devices-emulator

  • 输入adb shell getprop ro.product.cpu.abi返回模拟器架构(一般就是arm64-v8a)选择合适的lldb-server(这里可以安装Android NDK里面有预编译的lldb-server)

  • 拿到对应版本的lldb-server文件复制到内置存储adb shell cp /storage/emulated/0/Pictures/aarch64/lldb-server /data/local/tmp/

  • 赋予lldb-server执行权限adb shell chmod +x /data/local/tmp/lldb-server

  • 端口转发8700使用adb forward tcp:8700 tcp:1234(可以使用adb forward --list/--remove-all管理转发)

02

  • 直接用模拟器打开游戏,终端输入adb jdwp获取PID,然后adb shell进去cd /data/local/tmp后输入./lldb-server gdbserver *:1234 --attach 「PID」然后提示lldb-server-local_build

  • 打开新终端输入lldb在lldb中再输入gdb-remote 8700后会发现原先adb shell终端就显示Connection established.(代表通信建立了)

  • lldb就可以输入c/process interrupt正常调试了


  • LLDB gdbserver模式无法使用image等指令查看动态基地址,这里给出一个解决方案

  • 新终端输入adb shell cat /proc/「PID」/maps | grep libcocos2dcpp.so

  • 注意到710a627000-710bbd8000 r-xp 00000000 08:13 7995439 /data/app/~~HJepwy-qIpszbcPwWC9hUA==/moe.Saya.Arc3-D8XgWMdpPx6MBzZrLfK6BQ==/lib/arm64/libcocos2dcpp.so

  • 那么所显示的0x710a627000就是libcocos2dcpp.so的动态基地址,与lldb中的偏移地址直接做差运算可得出文件偏移地址

03

  • 比如触发闪退的时候有动态偏移地址0x710b49d208,则hex(0x710b49d208 - 0x710a627000)=0xe76208这个地址可以在IDA Pro中直接跳转查看

04


  • 另外附加一个IDA Python实现 LLDB 动态基址的重定位,就可以不需要手动计算各种地址,直接在IDA Pro中使用lldb提供的地址

  • 输入idaapi.get_imagebase()返回0x00即IDA Pro分配的动态基地址

  • 输入adb shell cat /proc/「PID」/maps | grep libcocos2dcpp.so获得LLDB分配的动态基地址

  • idaapi.rebase_program(LLDB动态基地址 - IDA Pro动态基地址, -1)后续lldb更换基地址只需要idaapi.rebase_program(新动态基地址 - 旧动态基地址, -1)


Android 启动即闪退的预挂起动态调试

部分 Android 应用只在特定系统版本上启动即闪退,等应用启动后再附加调试器往往已经来不及。可以先通过 am start -D 让应用在启动阶段等待调试器,再分别附加 Native 层和 Java 层调试器。

1. 预挂起启动应用

adb shell am start -D -n moe.ncp.src/low.moe.AppActivity

其中 moe.ncp.src 是应用包名,low.moe.AppActivity 是入口 Activity。执行后应用会停留在等待调试器的状态。

2. 附加 Native 层调试器

在第一个终端中依次执行:

# 将本机 8700 端口转发到设备的 1234 端口
adb forward tcp:8700 tcp:1234

# 获取处于可调试状态的进程 PID
adb jdwp

# 在设备上启动 lldb-server 并附加目标进程
adb shell /data/local/tmp/lldb-server gdbserver '*:1234' --attach 「PID」

保持该终端运行,然后打开一个新终端连接 lldb-server:

lldb -o "gdb-remote 8700"

连接成功后,可使用 Ctrl-C 中断进程并检查现场,或在 LLDB 中设置断点后输入 continue 继续运行。

3. 附加 Java 层调试器

再打开一个终端,获取 PID、转发 JDWP 端口并使用 jdb 建立连接:

# 确认目标进程 PID
adb jdwp

# 将本机 5005 端口转发到目标进程的 JDWP 端口
adb forward tcp:5005 jdwp:「PID」

# 附加 Java 调试器
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=5005

Java 调试器连接成功后,应用会离开“等待调试器”状态并继续启动;Native 层 LLDB 仍可捕获随后发生的崩溃。通过这种预挂起方式,可以拿到特定 Android 版本启动闪退时的原始报错地址,例如下图中的 signal SIGSEGV 和故障地址 0x8。

05


安卓动调总结

zsh - adb 核心指令

# 端口转发
adb forward tcp:8700 tcp:1234
# 获取模拟器进程 PID
adb jdwp
# 获取进程动态偏移基地址
adb shell cat /proc/「PID」/maps | grep libcocos2dcpp.so
# 启动调试服务器
adb shell /data/local/tmp/lldb-server gdbserver '*:1234' --attach 「PID」

zsh - lldb 核心指令

# 启动 LLDB 调试
lldb -o "gdb-remote 8700"

IDAPython 核心指令

# 获取当前动态基地址
idaapi.get_imagebase()
# 重新加载项目基地址
idaapi.rebase_program(new_base_addr - old_base_addr, -1)