导语:由于iOS内核是一个非常复杂的系统,所以必须要使用调试器才能很方便地进行调试,这样,你就可以很轻松地分步执行代码,设置断点,读取和写入内存和寄存器。
来源|嘶吼
作者|luochicun
步骤1:使用说明
1.你要具备一个可以设置启动参数的iOS设备,或下载一个内核修补程序来启用调试。请注意,在本文的说明中,我会以iPhone 4为例进行演示,这样我就可以在使用RedSn0w工具时设置引导参数。
2.一个iOS串行调试电缆,你可以自己购买或在诸如AliExpress等网站上购买。这些电缆用于将iOS设备的串行输出转换为USB协议,另外,你还必须为你正在使用的操作系统安装正确的驱动程序。
3. 带有XCode的GDB将会非常有利于你的调试。
4.确保serialKDPproxy已安装,用于内核调试的协议通常用于不是串行的UDP套接字,所以你需要使用一个工具来代替它。幸运的是,有人对该工具进行了编译。
步骤2:破解设备并设置引导参数
iOS内核不能被直接调试,这是因为苹果公司的工程师不想让攻击者轻易发起攻击。所以为了达到调试的目的,我必须先破解设备,才能够设置正确的启动参数并应用相应的内核补丁。
关于如何使用RedSn0w破解iOS设备,请点此链接,此处略去不表,但我要提醒的是,在使用该工具时一定要添加适当的启动参数。你可以通过Extras -> Even More -> Preferences -> Boot Args进行设置。在文本框中,你应该输入以下字符串“debug = 0x8f -v wdt = 0”。这些参数为了告诉你内核启动的方式:
1.在调试模式中使用特殊标志引导;
2.在详细模式下启动;
3.启动监视器的计时暂停功能,这样可以暂停执行过程,以免被发现。
这样设备将在停止启动,直到你添加一个调试器。
步骤3:使用SerialKDPproxy
现在该设备暂停,直到添加了调试器,为此我需要启动serialKDPproxy。./SerialKDPProxy的用法很简单,举个例子,在我的设备中就是./SerialKDPProxy /dev/tty.usbserial-AH00NR2W。在此之后,我就可以看到从设备输出到控制台的各种调试消息。你也可以在设备启动之前运行这个程序,并且会有大量的输出,这将有助于告诉你设备启动时真正发生了什么。例如,显示的内核滑动(kernel slide),会帮助你确定函数地址。
步骤4:使用GDB 连接到内核
使用serialKDPproxy就可以非常轻松地连接到内核。首先,你需要使用gdb -arch armv7命令启动gdb。这说明gdb将调试iOS设备,而不是具有i386体系结构的OS X应用程序。在gdb提示符之后,你需要执行的所有操作都是输入target remote-kdp,然后附加localhost。这时,你应该能得到一个响应,说你已经连接上了内核。如果你不能确保将正确的引入引导参数,那就将serialKDPproxy附加到正确的设备上。
另一种方法是,如果你有一个符号化的内核缓存,你可以在开始gdb时将它添加到参数中。然后,它将在连接时将这些符号添加到内核进程中,并允许你通过它们的名称而不是仅仅通过地址来引用函数。
步骤5:基本调试功能
现在你基本上拥有了gdb通常拥有的所有功能,这意味着你可以使用命令p *(int *)地址来获取内存地址,也可以使用set {int} = val来设置内容。你也可以使用x / i addr或反汇编功能反汇编代码,你也可以使用命令寄存器查看所有寄存器。断点也可以由命令break *(addr)来设置,以上这些都是标准的gdb命令。
这些gdb命令的功能非常强大。有很多情况下,这可以大大缩短你逆向工程的时间。有时一分钟的调试可能相当于你二进制静态分析的几个小时。
步骤6:设置一个断点
假设你正在分析一个漏洞的OSUnserializeXML函数,如果你想知道它在特定的时间调用堆栈的过程,你就可以使用静态分析来查看像IDA Pro这样的程序中的内核程序集,或者你可以简单地在IDA中找到OSUnserializeXML函数的地址,并将其添加到在启动时打印到串行控制台的内核滑动中,以查找函数的真实地址,然后在那里设置一个断点。然后当它被调用时,执行就会停止,此时你将通过完整的控制来分析正在发生的进程。