阅读目录
IOS平台lldb动态调试介绍
发布于:2016-4-26 15:21 | 197015次阅读 作者: 管理员 | 原作者: TP | 来自: 原创
调试ios程序经常使用gdb,但是gdb还未支持arm64,需要使用XCode的lldb调试IOS下64位程序。lldb调试方法跟gdb最大的不同,在于前者是用OSX中的lldb远程连接debugserver,由debugserver作为lldb和iOS的中转,执行命令和返回结果;而后者是gdb直接运行在iOS上。但对于一般的开发、调试来说,区别不大。 1. lldb调试环境搭建 使用lldb调试需要准备服务端程序,即debugserver。在默认情况下,iOS上并没有安装debugserver,只有在设备连接过一次Xcode,并在Window-》Devices菜单中添加此设备后,debugserver才会被Xcode安装到iOS的“/Developer/usr/bin/”目录下。确定有了debugserver后再一次执行以下步骤: 1.1 拷贝debugserver到本地计算机中: scp root@iOSDeviceIP:/Developer/usr/bin/debugserver ~/debugserver 1.2 由于ldid不支持的fat二进制文件,所以要给debugserver瘦身,通过lipo指定要支持的指令类型,以下是各个ios设备对应的cpu类型:
比如,以arm64设备为例: lipo -thin arm64 ~/debugserver -output ~/debugserver 1.3 给debugserver添加task_for_pid权限,保存以下内容为ent.xml文件:
然后执行以下命令添加权限: ldid -Sent.xml debugserver 1.4 给debugserver重新签名,保存以下内容为entitlements.plist文件:
然后运行以下命令给的debugserver签名: codesign -s - --entitlements entitlements.plist -f debugserver 1.5 到此准备工作完成,重新拷贝debugserver回手机中: scp ~/debugserver root@iOSDeviceIP:/usr/bin/debugserver 2. lldb调试常用命令 lldb调试的具体步骤如下: 2.1 获取进程pid 从shell命令行利用ssh登录ios设备,具体的步骤可以参考上一篇文章 《IOS平台gdb动态调试介绍》 ,随后使用ps -ax命令查看当前ios设备中的进程: ...... 在进程列表中找到想要附加的进程,为了和gdb调试作比较,我们选择的程序和要分析的断点位置和 《IOS平台gdb动态调试介绍》 一样,在此就不对程序的逆向过程作介绍。此处可以看到我们的目标进程ID为693 2.2 利用debugserver附加进程 第一次使用debugserver时需要为其添加可执行权限: chmod +x /usr/bin/debugserver 随后使用debugserver来attach一个进程,debugserver命令行格式如下: debugserver [ 其中各个参数选项如下: 比如我们要attach的进程号为693,我们可以输入如下命令: debugserver *:1234 -a 693 执行结果如下: 此时ios设备端的操作已结束。 2.3 随后重新打开一个shell启动lldb,使用lldb命令可以进入lldb命令行模式,随后使用process connect命令连接客户端: process connect connect://iOSDeviceIP:1234 等待一段时间后,执行结果如下图所示: 随后我们便可以对程序进行调试操作。 2.4 遍历模块 首先还是先利用IDA分析程序,找到我们要调试的断点位置,此处我们直接引用 《IOS平台gdb动态调试介绍》 中的分析结果,即0x007BDA00处: 为了定位该段代码在内存中的实际位置,我们得找到该模块的基址,lldb的遍历模块命令为image list,输入命令后结果如下: 从图中我们可以看到,要分析的模块基址为0x72000,那么是不是直接用该 基址加上偏移就得到了内存中的实际位置呢?我们可以验证一下。0x007BDA00加上0x72000得到0x82FA00,利用disassemble --start-address [start_address] --count [byte size]命令可以查看该地址的反汇编代码,结果如下: 对比之后发现和IDA中看到的反汇编代码不一样,显然该位置并不是我们要找的内存实际地址。造成地址错误的原因在于lldb会为模块自动加上头部偏移,在IDA中可以看到头部长度为0x4000,因此内存中的实际地址为lldb显示的模块基址0x72000加上0x82FA00再减去头部长度0x4000,得到实际地址为0x82BA00,再利用同样的命令验证其正确性,结果如下: 这时可以发现反汇编出的代码和IDA中显示的一样。 2.5 断点操作 得到要断点的地址为0x82BA00以后,我们便能利用lldb的br s -a [地址]明了在该处下断点,还能利用breakpoint list命令查看已存在的断点: 得到上图结果后我们可以知道断点已成功设置。随后输入continue命令让程序继续执行,程序执行到该逻辑时会断下,此时命令行结果如图: 2.6 查看、修改寄存器和内存 程序断下后我们便可以查看和修改当前运行环境的寄存器和内存。其中查看寄存器的命令为register read,运行结果如下:
查看内存值有很多方法,lldb同样支持gdb的查看内存操作指令,为了和gdb调试作对比,我们在此使用该方法查看内存。比如上图看到r4寄存器存的值为0x17fe0280,要得到该地址的内存值,我们可以使用memory read命令加上gdb的查看内存的字段,运行结果如下(各自段含义参考《IOS平台gdb动态调试介绍》 中2.3.5 小节): 而修改寄存器的命令也比较简单,即:register write [register number] [value],比如我们要修改r0的值为1,可以输入如下指令,并利用register read命令查看是否修改成功: 从图中结果可以看出r0寄存器已被我们修改为1。 相对应的,要修改内存的值,我们可以使用memory write [address] [value]指令,比如我们要修改0x17fe0280处的值为0,可以输入如下指令,并利用memory read命令查看是否修改成功: 从图中划红线的字段可以看出0x17fe0280处的值已被修改为0。
2.7 dump内存 Lldb dump内存的命令也为memory read,不同的是后面要加上参数outfile,完整的命令为:memory read --outfile /tmp/mem.bin --binary [start_address] [end_address],运行结果如图所示: 此时要dump的内存已在/tmp/mem.bin文件中,可以对其进行进一步的分析。
|
最新评论
发表评论