iOS 逆向11 -- 动态调试

动态调试

  • 将程序运行起来,通过下断点,打印等方式,查看参数,返回值,函数调用流程等。

Xcode调试App的原理

  • Xcode编译器的发展历程:GCC -> LLVM
  • Xcode调试器的发展历程:GDB -> LLDB
  • debugServer刚开始时存放在Mac的Xcode里面,其路径为:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.3/DeveloperDiskImage.dmg/usr/bin/debugServer
  • 当Xcode识别到真机设备时,Xcode会自动将debugServer安装到真机上,安装路径为:/Developer/usr/bin/debugServer
  • Xcode调试的局限性:一般情况下,只能调试 通过Xcode安装的App

动态调试任意App

debugServer的权限问题
  • 默认情况下,真机设备路径下:/Developer/usr/bin/debugServer的debugServer缺少一定的权限,只能调试通过Xcode安装的App,无法调试其他App;
  • 若希望调试其他App,需要对debugServer重新签名,签上两个调试相关的权限,如下所示:
    • get-task-allow
    • task_for_pid_allow
如何给debugServer签上权限
  • 手机必须越狱;
  • 通过IFunBox,定位到/Developer/usr/bin/debugServer文件路径下,将debugServer文件拷贝到Mac桌面;
  • Mac需要安装ldid签名工具,利用ldid指令导出debugServer文件以前的签名权限文件debugServer.entitlements,终端指令为:ldid -e debugServer > debugServer.entitlements
  • 然后在导出的权限文件debugServer.entitlements中,手动添加get-task-allowtask_for_pid_allow这两个权限选项;
  • 然后终端执行ldid SdebugServer.entitlements debugServer,即将权限文件debugServer.entitlements签到debugServer文件中;
  • 由于/Developer/usr/bin/debugServer文件路径是只读的,不能操作此文件路径下的文件,所以将刚重新签名权限的debugServer文件,拷贝到/usr/bin文件路径下;
  • 最后终端输入:chmod +x /usr/bin/debugServer 赋予操作权限;
让debugServer附加到某个App进程
  • 终端在iPhone环境下,执行命令:debugserver *: 端口号 -a 进程名称
  • *: 端口号:使用iPhone的某个端口号启动debugserver服务(只要不是保留端口号就可以)
  • -a 进程名称:输入App的进程名称或者进程ID
在Mac上启动LLDB,远程连接iPhone上的debugserver服务
  • 启动LLDB:在Mac环境下,输入lldb
  • 连接debugserver服务:在Mac环境下,输入process connect connect ://手机的ip地址:debugserver服务端口号
  • 使用LLDB指令让目标程序继续执行:在Mac环境下,输入c
  • 接下来就可以使用LLDB指令调试目标App了。
LLDB指令
  • help:帮助提示,直接输入help,会打印出所有LLDB指令;
  • help LLDB指令:例如help breakpoint,会打印出breakpoint的所有子命令,例如上面的set子命令;
  • expression 命令选项 -- 执行表达式,例如 expression -O -- self.view
    • --命令选项结束符,表示命令选项已经设置完毕,如没有命令选项可以直接省略;
    • expression -- 对象expression 对象e 对象print 对象p 对象call 对象这些指令的效果一样,打印目标对象;
    • expression -O -- 对象po 对象的效果一样;
    • 总结:expression不仅仅是打印,后面还能跟表达式,执行表达式;
    • expression self.view.layer.backgroundColor = [UIColor redColor].CGColor设置控制器的颜色为红色,可以在运行中动态调试;
  • thread backtrace:打印当前函数的调用堆栈,可简写为bt
  • thread return:让当前函数直接返回某个值,不会执行断点后面的代码;
  • frame variable:打印出当前栈桢函数内部的所有变量;
流程控制
  • thread continue:跳过当前断点,继续执行,如果有下一个断点会卡住在下一个断点,可简写为continuec
  • thread step-over:单步执行;如果遇到函数调用,会直接过掉即将函数调用看成单行代码执行,可简写为nextn
  • thread step-in:单步执行,如果遇到函数调用,会进入到函数内部执行,可简写为steps
  • thread step-out:直接执行完当前函数的所有代码,返回到上一个函数,可简写为finish
  • 上面的四个指令与Xcode中的按钮对应关系如下:
Snip20210707_13.png
  • thread step-inst-over:汇编指令级别的单步执行,可简写为nextini
  • thread step-inst:汇编指令级别的单步执行,如果遇到函数调用,会进入到函数内部执行,可简写为stepisi
普通断点操作
  • breakpoint set -r 正则表达式:例如breakpoint set -r test,给函数名包含test字符串的所有函数添加断点;
  • breakpoint set -s 动态库 -n 函数名:给指定动态库的执行函数添加断点;
  • breakpoint set -a 函数内存地址:给对应的内存地址的函数添加断点;
  • breakpoint list:打印出工程中的所有断点;
  • breakpoint disable 断点编号:禁用指定断点;
  • breakpoint enable 断点编号:启用指定断点;
  • breakpoint delete 断点编号:删除指定断点;
  • breakpoint command add 断点编号:给指定的断点添加额外的执行指令;如下所示:
Snip20210707_15.png
  • 当执行到第18行时,断点断住,然后控制台执行下面的指令,
Snip20210707_16.png
  • breakpoint set -n "-[ViewController touchesBegan:withEvent:]"

  • breakpoint command add 2

  • expression self.view.layer.backgroundColor = [UIColor redColor].CGColor

  • 过掉当前断点,点击屏幕,就会执行在touchesBegan函数停住,并执行上面添加的三条指令;

  • breakpoint command list 断点编号:打印指定断点添加的所有执行指令;

  • breakpoint command delete 断点编号:删除指定断点添加的所有执行指令;

内存断点
  • watchpoint set variable self->_age:监听成员变量_age的内存,只要_age发生变化就会断住;
  • watchpoint set expression 对象的内存地址:功能同上;
  • watchpoint list:打印工程中所有的内存断点
  • watchpoint delete 内存断点编号:删除指定内存断点;
  • watchpoint disable 内存断点编号:禁用指定内存断点;
  • watchpoint enable 内存断点编号:启用指定内存断点;
  • watchpoint command add 内存断点编号:给指定的内存断点添加额外的执行指令;
  • watchpoint command list 内存断点编号:打印指定内存断点添加的所有执行指令;
  • watchpoint command delete 内存断点编号:删除指定内存断点添加的所有执行指令;
与模块镜像相关
  • image list:打印工程中引用的所有的模块,也就是动态库文件,也可称之为镜像;
  • image lookup -t 类型:查看某个类型的信息,例如:image lookup -t int
  • image lookup -a 内存地址:根据内存地址查找在模块中的位置,例如崩溃的代码行定位;
  • image lookup -n 符号或函数名:查找某个符号或者函数的位置;

你可能感兴趣的:(iOS 逆向11 -- 动态调试)