我是倒车世界的菜鸟。我有一个通过 JNI 使用共享库的 Android Java 应用程序,我想在共享库中设置一个断点。共享库被剥离,据我所知,我只能按地址设置断点。我已经通过 IDA 放置了共享对象,并且有几个我想设置断点的位置,但我不确定如何计算这个或者即使这是可能的。我在 Android 上使用 gdbserver 连接到进程并使用 NDK 中的 gdb 从 Mac OSX 连接。我一直试图通过获取 /proc/'pid'/smap 给我的内容并计算我拥有的 IDA 程序集的偏移量来计算内存地址。这是正确的方向吗?这甚至可能吗?
在共享库上设置断点
我最近一直在做同样/类似的事情,虽然你可以让它工作,但并不是那么容易。
如果你有一个有 root 权限的 android 设备,一个运行 gdbserver 的终端模拟器,并且如果可能的话,一个可以打开多个窗口的终端模拟器,它会有所帮助,所以如果 gdbserver 挂了,你可以从第二个窗口杀死 gdbserver。此外,Android 设备上的真正键盘会有所帮助,因为当您拥有真正的光标键时,重复命令会容易得多。
您无需使用 USB 数据线将 Droid 连接到 Mac。我像这样启动了 gdbserver:
gdbserver --attach 0.0.0.0:8765 2338
(其中 2338 是我的目标应用程序的 pid),然后使用
$ arm-none-eabi-gdb
target remote 192.168.178.103:8765
连接。192.168.178.103 是我的安卓设备的 IP 地址。
我不想在我的机器上安装完整的 NDK,所以我从https://launchpad.net/gcc-arm-embedded/+download下载了 ARM GDB ,它们有 windows、linux 和 mac 版本。当然,NDK GDB 也应该可以正常工作。
您可以将函数的“IDA 地址”添加到 Map 地址中。例如,在我的图书馆中:
- 我感兴趣的两个函数具有“IDA 地址”BA584 和 BA99C。
- /proc/maps 中的地址表示 688D0000 作为可执行段的基地址。
- 真正的函数地址是6898A584/6898A99C,两种情况下都是基地址+“IDA地址”。
当您检查是否确实找到了正确的地址时,需要考虑两件事:
您不能使用 gdb disassemble 命令,因为它依赖于函数和符号。使用 x/i 命令进行反汇编。例如,在我的例子中,x/20i 0x6898A584 来查看这个地址的 20 条指令。
手臂有两种不同的模式,拇指模式和手臂模式。如果 gdb 没有符号,反汇编时可能会选择错误的符号,使您的 GDB 反汇编与 IDA 反汇编完全不同。
使用set arm force-mode arm和set arm force-mode thumb尝试两者。例如,这是 IDA 告诉我的有关我的 BA584 函数的内容:
.text:000BA584
.text:000BA584 sub_BA584 ; CODE XREF: sub_BF1C4+3Ap
...
.text:000BA584 PUSH.W {R4-R11,LR}
.text:000BA588 MOV R6, R0
.text:000BA58A SUB SP, SP, #0x1C
.text:000BA58C LDR R0, [R0,#0x18]
.text:000BA58E MOV R4, R1
.text:000BA590 STR R2, [SP,#0x40+var_34]
这是 gdb 首先制作的:
(gdb) x/20i 0x6890F584
0x6890f584: svcmi 0x00f0e92d
0x6890f588: addlt r4, r7, r6, lsl #12
0x6890f58c: strmi r6, [r12], -r0, lsl #19
0x6890f590: stmdacs r0, {r0, r1, r9, r12, pc}
0x6890f594: bichi pc, r10, r0
0x6890f598: mlapl r12, r6, r8, pc ; <UNPREDICTABLE>
0x6890f59c: ; <UNDEFINED> instruction: 0xf0402d00
然后
(gdb) set arm force-mode thumb
(gdb) x/20i 0x6890F584
0x6890f584: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x6890f588: mov r6, r0
0x6890f58a: sub sp, #28
0x6890f58c: ldr r0, [r0, #24]
0x6890f58e: mov r4, r1
0x6890f590: str r2, [sp, #12]
因此,如果反汇编看起来很奇怪,请不要放弃,尝试强制拇指/手臂模式。
我的应用程序在调试时多次崩溃,这使得 gdbserver 与 gdb 失去同步,导致来自 gdb 的大量“忽略数据包错误”消息。在这些情况下,杀死 gdbserver(因此是第二个窗口)、重新启动应用程序并重新连接 gdb 似乎是唯一的补救措施。当您重新启动应用程序时,请确保您重新检查 /proc/..../maps 以获取 .so 基地址,它大部分时间保持不变,但有时会发生变化,尤其是在调用之间有一段时间时。你会注意到我在上面的例子中的地址(0x6890F584)与我之前告诉你的地址不匹配,这是因为在这个例子中,地图基地址已更改为 68855000。