前言
说起动态调试,大家普遍第一反应是通过Xcode 安装应用到真机,然后通过添加断点,添加打印等方式来动态的调试程序所遇到的bug或者异常,今天和大家分享一下这个过程的底层原理,希望对动态调试有更深入的了解。
首先我们回顾一下真机调试的过程,
1.打开Xcode
2.通过数据线连接真机和mac
3.在需要的地方添加断点
4.点击Xcode中的run将程序运行到真机上
通过以上的操作我们就与手机建立了一个动态调试的环境,如上图,当我们下发lldb 指令传输给手机的debugserver, debugserver通过监听App运行进程下发指令给App,这时候App 执行了某种操作将结果返回给debugserver,debugserver再将结果告诉给lldb,lldb则会输出结果。
例如我们在viewController 中添加 touches 方法,当点击屏幕,就会进入到Xcode中lldb 环境,我们在控制台输入指令
po self
会得到以下结果这样一个过程则是我们上述我们描述的动态的原理中所执行的操作。
上述过程大家可能看图就能很好的理解,可能唯一疑惑的是这个debugserver 是什么东西?
首先我们在以下的路径中找打它:
Xcode/Contents/Deverloper/Platforms/iPhoneOS.platform/DeviceSupport/9.1(任何系统版本都可以)/DeveloperDiskImage.dmg
双击 DeveloperDiskImage.dmg 在 /usr/bin/debugserver
我们可以看到它,它到是什么,我们可以查看一下,利用file 指令
file debugserver
输出结果
debugserver: Mach-O universal binary with 3 architectures: [arm_v7:Mach-O executable arm_v7] [arm64]
debugserver (for architecture armv7): Mach-O executable arm_v7
debugserver (for architecture armv7s): Mach-O executable arm_v7s
debugserver (for architecture arm64): Mach-O 64-bit executable arm64
这下我们应该可以明白了,它是一个Mach-O格式的通用二进制的可执行文件,包含三种指令集架构.
当我们执行真机调试时候,这个文件会被安装到我们手机中,具体目录我们可以通过越狱手机(个人系统9.1)文件系统管理工具iFunBox查看
/Developer/usr/bin/debugserver
这也就能解释我们第一次真机调试运行缓慢,当然还存在其他原因,这里就不展开分析了。
那么至此全文原理性东西已经解释完毕了,接下来我们可以通过逆向的一些知识,我们手动的实现这个过程,我们说主要的过程
步骤一
首先需要架设一个端口,负责lldb 和 debugserver 之间的指令传输,我们可以使用一个开源的python端口转发脚本实现这一过程,
https://cgit.sukimashita.com/usbmuxd.git/snapshot/usbmuxd-1.0.8.tar.gz
可以通过这个地址下载解压
然后执行
cd ~/Documents/usbmuxd-1.0.8/python-client
python tcprelay.py -t 10011:10011
这样我们就相当于通过访问本地10011端口就可以访问远程的10011端口。
步骤二
我们将debugserver文件重签权限后放入到 /usr/bin
目录下,然后给它赋予可执行权限 chmod +x /usr/bin/debugserver
,执行
debugserver *:10011 -a process_name(这里是进程名)
步骤三
在终端在 输入lldb,进入lldb环境
process connect://localhost:10011
这样我们一个类似Xcode的lldb调试环境就搭建好了,我们可以通过lldb 指令去调试我们想要调试的程序。