iOS逆向工程(八):动态调试

动态调试

一、什么是动态调试
    1. 动态调试就是将程序运行起来,通过打断点、打印等方式,查看参数、返回值、函数调用流程等信息
    1. 之前我们说的静态分析,就是程序不运行的时候,对程序的可执行文件进行分析,分析头文件、伪代码之类的信息
    1. 学会动态调试之后,我们就可以分析某个程序的整体调用流程了,例如:分析微信抢红包的时候,就可以知道微信调用了哪些方法去抢红包,以便我们hook
二、Xcode动态调试的原理
    1. 其实Xcode自带的LLDB工具,就是动态调试的工具,我们平常开发的时候也一直在用,在Xcode打断点,程序就会暂停,输入lldb指令,就会出现结果,那么Xcode动态调试的原理是怎样的呢?
    1. Xcode动态调试的原理是这样的:我们用Xcode启动程序的时候,就会在自动在手机上安装一个debugserver程序,Xcode的LLDB工具会跟debugserver程序进行交互,将lldb指令传输给debugserver程序,debugserver程序又会将lldb指令传输给App,App执行完之后,会将返回值传输给debugserver程序,debugserver程序又发给LLDB,在控制台显示出结果,如下图所示:
      Xcode动态调试的原理.png
    1. debugserver程序一开始是存放在Mac中的Xcode里面的,手机里是没有的,只有当Xcode识别到手机设备时,才会自动把debugserver程序安装到手机上。debugserver的具体路径,如下所示
debugserver在Mac上的路径是:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.2/DeveloperDiskImage.dmg/usr/bin/debugserver

debugserver安装到手机的路径是:
/Developer/usr/bin/debugserver
    1. 需要注意的是,Xcode动态调试,只能调试通过Xcode安装的App,也就是说我们逆向别人App的时候,是无法用Xcode动态调试来调试的,那么如何才能调试任意App呢?
三、动态调试任意App的原理
    1. 想要调试任意App,我们就需要用终端取代Xcode,终端里的LLDB工具与手机的debugserver程序交互,来传输lldb命令,如下所示:
      动态调试任意App原理.png
    1. 我们知道Xcode安装的debugserver只能与Xcode安装的App进行交互,因为沙盒机制的原因,导致debugserver没有权限与其他App产生交互,所以我们还需要给debugserver赋予相应的权限,才能与任意App进行交互
    1. 动态调试任意App只需要三步:将有权限的debugser安装到手机、让debugserver与App建立交互、让debugserver与LLDB产生交互
四、动态调试任意App的第一步:将有权限的debugserver安装到手机

这一步是一劳永逸的,安装完后,以后只需要第二步和第三步,就可以启动动态调试了

    1. 在Mac的中找到与手机系统版本对应的debugserver程序,Mac中的路径如下:
      /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.2/DeveloperDiskImage.dmg/usr/bin/debugserver
    1. 使用ldid签名工具debugserver新增两个权限:get-task-allow、 task_for_pid-allow,这两个都是Bool值,设置为YES,新增权限流程如下:
    • (1). 通过ldid命令,导出debugserver现有的权限,命令是:
      $ ldid -e debugserver > debugserver.entitlements

    • (2). 编辑debugserver.entitlements文件,新增get-task-allow、 task_for_pid-allow,值设置为YES,如下图所示:

      编辑debugserver.entitlements文件.png

    • (3). 通过ldid命令,对debugserver进行重新签名,命令是:
      $ ldid -Sdebugserver.entitlements debugserver,注意S是大写,并且与debugserver紧挨着。

    1. 将已经签好权限的debugserver放到手机的/usr/bin里面,便于手机找到debugserver命令
五、动态调试任意App的第二步:让debugserver与App建立交互
    1. 远程登录到手机后 ,让debugserver附加到某个App进程,命令如下:
打开命令行:sh usb.sh

新建命令行:sh login.sh,登录到手机后

让debugserver附加到某个App进程:$ debugserver 127.0.0.1:端口号 -a 进程名

例如让debugserver附加到微信的进程:$ debugserver 127.0.0.1:10011 -a WeChat
    1. 重点命令就这一句话:$ debugserver 127.0.0.1:端口号 -a 进程名,其中127.0.0.1:端口号代表使用iPhone的某个端口启动debugserver服务,只要不是保留端口号就行
六、动态调试任意App的第三步:让debugserver与LLDB建立交互
    1. 在Mac上启动LLDB服务,并且远程连接到iPhone的debugserver服务,命令如下:
启动LLDB
` $ lldb    `

连接到iPhone的debugserver服务
` (lldb) process connect connect://手机IP地址:debugserver服务的端口号  `

以微信为例,连接到iPhone的debugserver服务:
` (lldb) process connect connect://10.88.211.170:10011  `
    1. 重点命令就这一句话process connect connect://手机IP地址:debugserver服务的端口号,如果输入完这句命令后,出现以下提示,就说明已经动态调试已经就绪,可以执行LLDB指令来调试了(注意此时会处在线程卡死状态,需要执行(lldb) c命令,让程序先运行起来)
(lldb) process connect connect://localhost:10011
Process 1194 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x000000018da64634 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
->  0x18da64634 <+8>: ret

libsystem_kernel.dylib`mach_msg_overwrite_trap:
    0x18da64638 <+0>: mov    x16, #-0x20
    0x18da6463c <+4>: svc    #0x80
    0x18da64640 <+8>: ret
Target 0: (WeChat) stopped.
七、使用USB方式动态调试任意App
    1. 上面说的流程是通过用Wifi的方式传输LLDB命令的,传输速度较慢,所以推荐使用USB的方式建立交互,也就是:将Mac的10011端口iPhone的10011端口建立映射,然后debugserver服务使用iPhone的10011端口,此时Mac的LLDB工具Mac的10011端口传输数据就相当于与iPhone的10011端口传输数据,如下所示:
在Mac上输入命令,让10011端口与10011端口映射、10010与22端口映射
`python /Users/songpeng/Documents/python-client/tcprelay.py -t 22:10010 10011:10011`

在iPhone上执行下面的命令,启动debugserver服务,端口号为10011
`$ debugserver 127.0.0.1:10011 -a WeChat`

在Mac上执行以下命令,让LLDB与本地的10011传输数据,由于映射已经建立,就相当于给iPhone的debugserver服务发送数据
`$ lldb  `
`(lldb) process connect connect://localhost:10011 `
    1. 可以将以前写的usb.sh文件的内容改成python /Users/songpeng/Documents/python-client/tcprelay.py -t 22:10010 10011:10011,这样即可以用USB的方式SSH登录到手机,也可以以USB的方式让LLDB与debugserver建立交互。以后使用起来就很方便了

- 3. 我们总结一下,使用USB方式动态调试任意App的全部流程,如下所示,以后忘记原理没关系,只需要按顺序输入以下命令,就可以顺利开启动态调试

在Mac上打开命令行窗口,让10011端口与10011端口映射、10010与22端口映射
`$ sh usb.sh`

在Mac上新建命令行窗口,然后SSH登陆到手机
`$ sh login.sh`

登录到手机后,启动手机的debugserver服务,让其与App建立交互
`iPhone7ceshiji:~ root# debugserver 127.0.0.1:10011 -a WeChat`

在Mac上新建命令行窗口,进入lldb工具,并且让LLDB与debugserver建立交互
`$ lldb`
`(lldb) process connect connect://localhost:10011`

使用LLDB命令c,先让程序继续运行
`(lldb) c`
    1. 动态调试建立好之后,我们就可以使用LLDB指令,来正式开始调试了
八、LLDB指令
    1. LLDB指令的格式是:
      <command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]],其中,command代表命令,subcommand代表子命令,action代表命令的动作,- options 代表命令的选项,argument代表命令的参数,[]中的可以省略。
    1. help命令,用于查看指令的用法,例如:help breakpoint、help breakpoint set
    1. expression命令,执行一个表达式,例如:expression self.view.backgroundColor = [UIColor redColor],expression与print、p、call的效果一样
    1. thread backtrace命令,打印线程的堆栈信息,与bt命令效果一样
    1. thread return []命令,让函数直接返回某个值,不会执行断点后面的代码了,例如:thread return 3,返回了3
    1. frame variable []命令,打印当前栈帧的变量
    1. thread continue、continue、c命令,让程序继续运行
    1. thread step-over、next、n命令,单步执行,把子函数当做一个整体,不会进入子函数
    1. thread step-in、step、s命令,单步执行,遇到子函数会进入子函数内部
    1. breakpoint set命令,设置断点,参数主要有以下几种:
    • breakpoint set -a 函数地址
    • breakpoint set -n 函数名
    • breakpoint set -r 正则表达式
    • breakpoint set -s 动态库 -n 函数名
    1. breakpoint list命令,列出所有的断点,每个断点都有自己的编号
    1. breakpoint delete 断点编号命令,删除某个断点
    1. breakpoint command add 断点编号命令,给断点预先设置需要执行的命令,到触发断点时,就会按顺序执行
    1. breakpoint command list 断点编号命令,查看某个断点的预设命令
    1. watchpoint内存断点,就是当内存数据改变时,触发此断点,以便确认是谁修改了内存,子命令主要有以下几种:
    • watchpoint set variable 变量,例如:watchpoint set variable self->_age,当age变量改变时,断点就会触发,以便找到修改age内存的代码

    • watchpoint set expression 地址,例如:watchpoint set expression &self->_age

    • watchpoint list,列出所有的内存断点

    • watchpoint delete 断点编号,删除此内存断点

    • watchpoint command add 断点编号,给此内存断点,增加预设命令

    1. image lookup,寻找模块信息,如果你想找某个类型、某个方法、某个地址在模块中的什么位置,就可以用这个命令,主要参数如下:
    • image lookup -t 类型,查找某个类型的信息,例如image lookup -t NSInterger
    • image lookup -a 地址,看看某个内存地址在模块中的位置
    • image lookup -n 符号或者函数名,查找某个符号或者函数的位置
    1. image list,列出所加载的模块信息
    1. 一些小技巧:敲Enter会自动执行上次的命令、绝大部分命令可以使用缩写
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358

推荐阅读更多精彩内容