游戏安全实验室 首页 技术入门 查看内容

 阅读目录

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类型

设备

Cpu类型

iPhone 4

armv7

iPhone 4s

armv7

iPhone 5

armv7s

iPhone 5c

armv7s

iPhone 5s

armv64

iPhone 6

armv64

iPhone 6 Plus

armv64

iPad 2

armv7

iPad mini

armv7

iPad with Retina display

armv7s

iPad Air

armv64

iPad Air 2

armv64

iPad mini with Retina display

armv64

iPad mini 2

armv64

iPad mini 3

armv64

iPad touch 5

armvv7

    比如,以arm64设备为例:

        lipo -thin arm64 ~/debugserver -output ~/debugserver

    1.3 给debugserver添加task_for_pid权限,保存以下内容为ent.xml文件:

com.apple.springboard.debugapplications

get-task-allow

task_for_pid-allow

run-unsigned-code

    然后执行以下命令添加权限

ldid -Sent.xml debugserver

    1.4 给debugserver重新签名,保存以下内容为entitlements.plist文件:

com.apple.springboard.debugapplications

run-unsigned-code

get-task-allow

task_for_pid-allow

    然后运行以下命令给的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 [] host: [   ...]

    其中各个参数选项如下:

比如我们要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文件中,可以对其进行进一步的分析。

 

 *转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩0 赞0

收藏

上一篇:IOS平台GDB动态调试介绍

下一篇:【开发篇】——引言

最新评论
B Color Image Link Quote Code Smilies

发表评论