IOS动态调试汇总-傻瓜版教程

参考博客:
https://juejin.cn/post/6872764160640450574#heading-4 (断点后续指令)
https://www.jianshu.com/p/67f08a4d8cf2 (断点相关)
基础环境搭建 在x-code目录中找到对于版本的DeveloperDiskImage.dmg ,路径大致/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/9.2/DeveloperDiskImage.dmg
双击DeveloperDiskImage.dmg 在/Volumes/DeveloperDiskImage/usr/bin/ 下找到debugserver.
debugserver复制出来
创建一个entitlement.xml文件与debugserver保持同一目录

com.apple.springboard.debugapplications get-task-allow task_for_pid-allow run-unsigned-code

用codesign对debugserver签名, 命令如下:
codesign -s - --entitlements entitlement.xml -f debugserver

scp -r debugserver root@192.168.2.17:/usr/bin/#192.168.2.17 是 iPhone 设备的 ip 地址.debugserver 拷贝到iOS中 目录为/usr/bin/

pc终端命令行窗口1、2中,创建端口代理
iproxy 1998 1998 iproxy 2222 22

pc终端命令行窗口3中连接手机的ssh
#这里前提要安装OpenSSH,Cycriptssh root@localhost -p 2222#默认密码是alpine

手机终端中输入
ps -e |grep app#找到对应的app #如/var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo

手机端开启debugserver
debugserver -x backboard 127.0.0.1:1998 /var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo

pc终端命令行
执行
lldbprocess connect connect://127.0.0.1:1998#如果此事界面出现报错或者停止 按C继续执行,可以先下好断点再运行

image list -o -f# 第一行即为获取 获取ASLR偏移地址#[0] 0x00000000007a0000 /private/var/containers/Bundle/Application/4CF47160-4687-41C9-B987-EB40B541A461/pinduoduo.app/pinduoduo(0x00000001007a0000) 00000000007a0000 为ASLR偏移地址

计算ptrace偏移后地址
p/x 0x0000000101319A8C + 0x00000000007a0000# [ptrace偏移后地址] = 方法位置+ ASLR偏移地址 br s -a [ptrace偏移后地址]

设置断点相关 (每一行代表一种写法) 给所有名为xx的函数设置一个断点
(lldb)breakpoint set —name xx (lldb)br s -n xx (lldb)b xx

在文件F指定行L设置断点
(lldb)breakpoint set —file F —line L (lldb)br s -f F -l L (lldb)b F:L

给所有名为xx的C++函数设置一个断点(希望没有同名的C函数)
(lldb)breakpoint set —method xx (lldb)br s -M xx

给一个OC函数[objc msgSend:]设置一个断点
(lldb)breakpoint set —name “[objc msgSend:]” (lldb)b -n “[objc msgSend:]”

给所有名为xx的OC方法设置一个断点(希望没有名为xx的C或者C++函数)
(lldb)breakpoint set —selector xx (lldb)br s -S count

给所有函数名正则匹配成功的函数设置一个断点
(lldb)breakpoint set --func-regex regular-expression (lldb)br s -r regular-expression

给指定函数地址func_addr的位置设置一个断点
(lldb)br set -a func_addr

断点查看
(lldb)breakpoint list (lldb)br l

断点删除
(lldb)breakpoint delete index (lldb)br del index

index指明断点的序号,如果为空则删除所有断点
断点后续移动操作 IOS动态调试汇总-傻瓜版教程
文章图片

源码级别(和你ida汇编看到一样的一步一步)
step-in步入进入函数内部
(lldb) thread step-in (lldb) step (lldb) s

step-over步入不会进入函数内部
(lldb) thread step-over (lldb) next (lldb) n

指令级别
step-in 在汇编界面,跳转下一步,在有bl指令的地方,si单步进入到bl指令所跳转的子函数内部
(lldb) thread step-inst (lldb) si

step-over 在汇编界面,跳转下一步,在有bl指令的地方,ni不会单步进入到bl指令所跳转的子函数内部
(lldb) thread step-inst-over (lldb) ni

step-out 从一个函数跳出
(lldb) thread step-out (lldb) finish (lldb) f

下一个断点
c

lldb常用命令(以下需要断点命中后操作) 1.计算表达式命令(expression、po、p)
expression可简写为expr
计算以及生成一个表达式
(lldb) expr (int)printf ("Print nine: %d.\n", 4 + 5) Print nine: 9. (int) $0 = 15

创建一个变量并分配值
(lldb) expr int $val = 10 (lldb) expr $val (int) $val = 10

exp打印值、修改值
(lldb) expr width (CGFloat) $0 = 10 (lldb) expr width = 2 (CGFloat) $1 = 2 (lldb) po width 2(lldb) p width (CGFloat) $3 = 2

【IOS动态调试汇总-傻瓜版教程】p、po与expr的关系
(lldb) expr -- person (Person *) $0 = 0x000000010053b7f0 (lldb) p person (Person *) $1 = 0x000000010053b7f0 (lldb) expr -o -- person(lldb) po person

总结
p是expr --的简写,它的工作是把接收到参数在当前环境中进行编译,然后打印出来 po是expr -o --的简写,它所做的操作和p相同。如果接收到的参数是一个指针,那么它会调用对象的description方法并打印;如果接收到的参数是一个core foundation对象,那么它会调用CFShow方法并打印。如果这两个方法都调用失败,那么po打印出和p相同的内容。

使用p做进制转换
//默认打印为10进制 (lldb) p 10 (int) $0 = 10 //转16进制 (lldb) p/x 10 (int) $1 = 0x0000000a //转8进制 (lldb) p/o 10 (int) $2 = 012 //转二进制 (lldb) p/t 10 (int) $3 = 0b00000000000000000000000000001010 //字符转10进制数字 (lldb) p/d 'A' (char) $4 = 65 //10进制数字转字符 (lldb) p/c 66 (int) $5 = B\0\0\0

内存读取
(lldb) x person 0x10053a6b0: 5d 22 00 00 01 80 1d 00 00 00 00 00 00 00 00 00]".............. 0x10053a6c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................ (lldb) x/4gx person 0x10053a6b0: 0x001d80010000225d 0x0000000000000000 0x10053a6c0: 0x0000000000000000 0x0000000000000000 (lldb) x/3wx person 0x10053a6b0: 0x0000225d 0x001d8001 0x00000000 (lldb) x &width 0x7ffeefbff4f0: 00 00 00 00 00 00 00 00 b0 a6 53 00 01 00 00 00..........S..... 0x7ffeefbff500: 30 f5 bf ef fe 7f 00 00 01 00 00 00 00 00 00 000............... (lldb) x/4gx &width 0x7ffeefbff4f0: 0x0000000000000000 0x000000010053a6b0 0x7ffeefbff500: 0x00007ffeefbff530 0x0000000000000001 (lldb) x/4go 0x7ffeefbff510: 03777735757772440 0x7ffeefbff518: 03777755321776311 0x7ffeefbff520: 00 0x7ffeefbff528: 01

x是读取内存的命令,x/4gx中第一个x是读取内存命令,后面的g是每次读取8字节,x的意思是16进制显示结果,4表示连续打印4段。
对于g,常用的大小格式为b对应byte 1字节,h对应half word 2字节,w对应word 4字节,g对应giant word 8字节
对于x,我们还可以用o对应8机制,b对应2进制,x对应16进制,f对应浮点,d对应10进制
call方法调用
(lldb) call width (CGFloat) $0 = 0 (lldb) call testFunction() 123456 复制代码 4.变量检查(frame) (lldb) fr v b (Int??) b = nil (lldb) fr v -r b (Int??) b = nil (lldb) fr v -R b (Swift.Optional>) b = some { some = none { some = { _value = https://www.it610.com/article/0 } } } (lldb) fr v -a b (Int??) b = nil

我们常用fr v -R来查看类型的结构

    推荐阅读