LLDB高级调试+Cycript

对了 LLDB 有了一些认识之后,也能够更好的使用 LLDB 了,但是对于常用的一些指令使用起来还是过于麻烦,为了更简单的使用 LLDB 就需要一些插件帮助了,下面就介绍一些 LLDB 插件的安装和使用。

1、Chisel 安装

这个是 FaceBook 提供给开发者的 LLDB 的插件,打开终端使用 brew install chisel 安装。

安装完成后,在家目录下找 .lldbinit 文件,如果没有就 touch .lldbinit 新建一个,然后 vi .lldbinit 添加 fblld.py 的路径(我的路径为 /usr/local/Cellar/chisel/1.8.1/libexec/fblldb.py)。

添加 command script import /usr/local/Cellar/chisel/1.8.1/libexec/fblldb.py ,最后 ESC ,输入 :wq 保存并退出。

安装完成后,如果已经打开了 Xcode ,可以在 XcodeLLDB 上输入 command source ~/.lldbinit 重新加载,也可以重新打开 Xcode

Xcode 新建工程,随意一个断点, 然后 lldb输入 pviews self.view 指令,回车后打印了 self.view 的详细信息,就说明安装成功了。

Xcode 11 注意:
因为 Xcode 11 版本不支持 python 2 ,所以如果控制台出现如下报错:
error: module importing failed: Missing parentheses in call to 'print'. Did you mean print('Whoops! You are missing the <' + arg.argName + '> argument.')? (fblldb.py, line 98)

点此处下载最新的 Chisel,终端执行下方指令(我当前的是 Chisel 1.8.1) ,进入 1.8.1 ,用新下载的文件替换 1.8.1 里面相同名称的文件即可解决。

cd /usr/local/Cellar/chisel
open .

2、Chisel 使用

启动一个项目,随意进入一个页面,然后暂停项目。

1、pviews 指令

pviews :可以查看图层,能清楚的看到图层关系,是以字符串输出的,成树状结构,很清晰。

Xcode 下方 LLDB 输入 pviews 就能查看所有图层关系。

pviews
2、pvc 指令

pvc :可以查看控制器的层级。

pvc
3、pactions 指令

paction:可以打印一个按钮的所在的页面和它的点击事件方法。

当前页面上有一个 设置 按钮 。

设置按钮

打开 ViewDebug ,这个不管在正向和逆向中都可以看到按钮的指针地址,所以获取到 设置 按钮的指针地址为:0x7fce735209e0

设置按钮地址

LLDB 上输入:pactions 0x7fce735209e0 ,就可以打印 设置 按钮的所在的页面和它的点击事件方法。

获取点击方法
4、presponder 指令

presponder :获取按钮的响应链。

LLDB 输入:presponder 0x7fce735209e0 当前响应链比较少,所以就直接打印了自己和系统的响应链了。

响应链
4、pclass 指令

pclass :可以查看一个类的继承关系。

当前类为 RootNavigationController 、地址为 0x7fce7386c600LLDBpclass 0x7fce7386c600 回车,输出了继承树。

pclass指令
5、pmethods 指令

pmethods :查看一个类的所有方法。

pmethods 指令
6、pinternals 指令

pinternals :查看一个类的成员变量以及在当前内存中的值。

pinternals 指令
7、fvc、fv 指令

fvc:使用一个 Controller 类名获取 Controller 类的在内存中的地址(不一定100%能获取到)。

LLDB 输入:fvc RootNavigationController ,显示如下:

fvc 指令

fv:使用一个 View 类名获取 View 类的在内存中的地址(不一定100%能获取到)。

8、taplog 指令

taplog :断点一次可处理响应事件的 View

暂停程序,然后 Xcode 下方 LLDB 输入 :taplog ,发现断点过掉了,随意点一个 UIButton 然后进会进入断点。

taplog 指令
8、flicker 指令

flicker :会让当前地址的视图隐藏并显示(闪烁)一次。

比如上方获取到的 Buttonflicker 0x7ffc03438290 ,这个 Button 就会闪烁一次。

flicker 指令
9、vs 指令

vs :可以查看图层的当前层级,下一个层级,上一个层级。

LLDB 上输入 :vs 0x7ffc03438290 就会发现,界面上按钮变为红色,LLDB控制台打印了一些的指令信息。

vs 指令
  • (q) to quit. :输入 q 退出。
  • (w) move to superview :输入 w 移动到父 View
  • (s) move to first subview:输入 s 移动到我当前子控件的第一个(subviews.firstObject)。
  • (a) move to previous sibling :输入 a 移动到当前视图平级关系的前一个视图。
  • (d) move to next sibling :输入 d 移动到当前视图平级关系的后一个视图。
  • (p) print the hierarchy :输入 p 打印当前控件的层级关系。

3、lldb_commands 的安装

这也是一个功能比较强大的 LLDB 插件。点此处下载

安装方式如下:

  • To Install, copy/clone the lldb_commands folder to a dir of your choosing
  • Open up (or create) ~/.lldbinit
  • Add the following command to your ~/.lldbinit file: command script import /path/to/lldb_commands/dslldb.py

配置方式和 Chisel 一样,不过就是这个需要自己下载,个人建议可以把 lldb_commandsChisel 放在一个路径下 /usr/local/Cellar/ 下。

终端输入 vi ~/.lldbinit ,按 i,再添加一条 command script import /usr/local/Cellar/lldb_commands/dslldb.py ,然后按 ESC ,在输入 :wq 保存退出。

Xcode 输入 command source ~/.lldbinit 导入一下。

4、lldb_commands 的使用

1、search 指令

search :如果上方的 fvcfv 指令查找不到的话,可以使用 search 指令,比如:search UIView

search 指令
2、sbt 指令

sbt:逆向中是没有符号表的,所以给一个内存地址下断点后,使用并 bt 不能显示详细信息。但是 lldb_commands 就可以帮助恢复一些函数名称,但是不一定能恢复全部。

当前给 下一步 按钮添加断点,然后打印调用队栈。

下一步 按钮

当前按钮是在 WCAccountMainLoginViewController 上,ActiononNext ,使用 mehthods 查找 onNext 的指针地址,然后下断点。

  • search WCAccountMainLoginViewController :获取 WCAccountMainLoginViewController 在内存中的地址:0x11307ea00
  • methods 0x11307ea00:获取 WCAccountMainLoginViewController 的所有方法,查找 onNext 的指针地址为 0x108aab4cc
  • b -a 0x108aab4cc :给 onNext 方法下内存断点
(lldb) search WCAccountMainLoginViewController
<WCAccountMainLoginViewController: 0x11307ea00>
(lldb) methods 0x11307ea00
Instance Methods:
        - (void) WCBaseInfoItemBeginEdit:(id)arg1; (0x108aac7bc)
        - (void) WCBaseInfoItemEndEdit:(id)arg1; (0x108aac870)
        - (void) WCBaseInfoItemPressReturnKey:(id)arg1; (0x108aad3f0)
        - (void) WCBaseInfoItemEditChanged:(id)arg1; (0x108aac924)
        - (void) initMoreView; (0x108aa9838)
        - (void) setupWithData:(id)arg1; (0x108aa6e0c)
        - (void) onNext; (0x108aab4cc)
(lldb) b -a 0x108aab4cc
Breakpoint 1: where = WeChat`___lldb_unnamed_symbol273847$$WeChat, address = 0x0000000108aab4cc
(lldb) 

这样方法的内存断点就下好了,点击一下进入了一个断点。

LLDB 输入 bt ,因为没有符号文件表的关系,看不到函数名称。

没有符号文件的调用队栈

然后使用 lldb_commandssbt 指令,能恢复一些函数名称,看到了刚才的点击方法。

恢复部分函数名称的调用队栈

如果发现恢复的不是当前想要的,就只能重新运行,再次尝试恢复。

5、Cycript 的介绍

Cycript 是由 Cydia 创始人 Saurik 推出的一款脚本语言。Cycript 混合了 OCJavaScript 语法的解释器,这意味着我们能够在一个命令中使用 OC 或者 JavaScript ,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改很多东西。

6、Cycript 的安装

首先点此处下载 Cycript,下载完成后,建议放在 ~/opt 目录下面。打开目录,复制粘贴。

cd ~/opt
open .

接下来需要配置一下环境变量,以便于在任何地方使用。

可以配置在 .bash_profile 下(如果你使用的不是 bash ,那么你可以在你所使用的 Shell 下添加一句 source /Users/XXX(前面改成你的用户名,并删掉括号和括号里的更改描述)/.bash_profile)。

然后 vi ~/.bash_profile ,在 export PATH="/opt/local/bin:/opt/local/sbin:$PATH" 前添加 export CYCRIPT=/opt/cycript_0.9.594/(等号前面的命名可以随意,保证不重复就行,等号后面的就是你的 cycript 的路径) ,然后在 export PATH :$PATH前添加 :$CYCRIPT 名称就可以了。

然后 :wq 保存退出,iTerm 输入 :cycript,回车出现了 cy# ,说明安装成功了。control D 退出。

注意,如果安装过程中出现如下报错:

报错信息

解决方案:
iTerm 输入:cd /System/Library/Frameworks/Ruby.framework/Versionsopen .

cycript报错 解决方案

7、MonkeyDev 的安装

因为要使用 Cycript ,在非越狱环境下,不能将 Cycript 注入手机,所以需要借助 MonkeyDev 注入 Framework 库来实现。

MonkeyDev 安装方式如下

环境要求

使用工具前确保如下几点:

sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
  • 安装ldid(如安装theos过程安装了ldid,跳过)
brew install ldid
安装

你可以通过以下命令选择指定的Xcode进行安装:

sudo xcode-select -s /Applications/Xcode-beta.app

默认安装的Xcode为:

xcode-select -p

执行安装命令:

sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"
卸载
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)"

更新

如果没有发布特殊说明,使用如下命令更新即可:

sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"

安装/更新之后重启下Xcode再新建项目。

8、Cycript 的使用

iTerm 输入 :cycript,就开始使用 cycript 了。

1、简单的判断字符串
cy# "STRING" == "string"
false
2、简单的两数相加
cy# a = 100
100
cy# b = a + 10
110
3、Cycript 的准备工作

上面的2个仅仅是为了认识一下 Cycript ,我们使用 Cycript 是因为它的进程附加能力。

在逆向中,LLDB 虽然也非常好用,但是使用 LLDB 必须要把程序断点下来,有时候对程序的执行有一些影响,更改完一些东西需要过掉断点才能看到修改的结果,并不能及时的反馈给我们。

但是,Cycript 是动态调试程序的,不需要把程序断点下来,能及时的反馈修改的结果,这样就非常方便了。

接下来,尝试进程附加。因为上方说过要在非越狱环境下使用 Cycript ,需要借助 MonkeyDev 注入 Framework 库来实现。

所以打开 Xcode 使用 MonkeyDev(在 Xcode 的最下方) 新建工程。

注意:MonkeyDev 工程目录中不能有中文路径,否则有问题,这个问题是 Theos 的问题,Theos 是外国人开发的,没有考虑中文情况。

首先运行一下空工程,然后把砸过壳的 xxx.app 或者 xxx.ipa 放入 TargetApp 目录下。再次运行工程,就能重签名 xxx.app 了。

MonkeyDev

MonkeyDev 帮我们把 Cycript.framework 注入了,查看 XxxDylib 文件夹下文件 XxxDylib.m 中有一行 CYListenServer(6666); 这个就是注入 Cycript 时的端口号。

打开 iPhone -> 设置 -> 无线局域网 -> 点击当前正在使用的WiFi -> 查看IP 地址

获取到的 IP 地址为:192.168.50.49

注意: 电脑使用的 WiFi 和手机使用的 WiFi 必须是同一 WiFi,运行的 App 不要进入后台。

4、Cycript 的使用

接下来继续 iTerm 操作,如果在 cycript 下,先 control D 退出 cycript,然后iTerm 输入:cycript -r 192.168.50.49:6666 回车就进入了 cycript 了。

1、keyWindow 的获取

想要获取当前的 keyWindowUIWindow.keyWindow()就可以获取。

cy# UIWindow.keyWindow()
#"<iConsoleWindow: 0x10e45a9d0; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x280f063a0>; layer = <UIWindowLayer: 0x28003ea80>>"
2、UIApplication 的获取

想要获取当前的 UIApplication[UIApplication sharedApplication] 或者 UIApp 就可以。

cy# [UIApplication sharedApplication]
#"<UIApplication: 0x10e41a1a0>"
cy# UIApp
#"<UIApplication: 0x10e41a1a0>"
3、变量的定义和使用

OC 的语法很像。当前需要定义一个变量 keyWindowvar keyWindow = UIWindow.keyWindow() ,然后就可以使用 keyWindow 变量了。比如:获取 rootViewController 输入:keyWindow.rootViewController

可以使用 tab 进行语法补全,但是没有提示。

cy# var keyWindow = UIWindow.keyWindow()
#"<iConsoleWindow: 0x10e45a9d0; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x280f063a0>; layer = <UIWindowLayer: 0x28003ea80>>"
cy# keyWindow
#"<iConsoleWindow: 0x10e45a9d0; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x280f063a0>; layer = <UIWindowLayer: 0x28003ea80>>"
cy# keyWindow.rootViewController
#"<MMUINavigationController: 0x111921a00>"
4、# 的使用

cycript 上可以使用 # 跟上一个地址,相当于 LLDBp 跟上一个地址的 功能,执行一个对象。比如:#0x111921a00 回车打印如下:

# 的用法
5、* 的使用

* 跟上一个定义的变量,比如上方的 var keyWindow = UIWindow.keyWindow(),然后 *keyWindow 就会打印所有的成员变量。

* 的用法
6、recursiveDescription() 的使用

cycript 上想查看一个页面的 UI 层级,可以使用 keyWindow.recursiveDescription() 循环遍历层级并打印。如果想要格式化 keyWindow.recursiveDescription().toString()

直接打印层级
格式化的层级
7、choose 的使用

LLDB 上可以使用 fvcfvsearch 跟一个类名去查找对象,在 cycript 可以使用 choose 跟一个类名去查找对象,cycript 输入:choose(UIButton) 回车。

choose 的使用
8、一些其他说明

cycript 下 只要我们的 App 不关闭(即所谓的进程不关闭),那刚才申请的 keyWindow 就会一直存在,退出了 App 就需要重新定义变量了。再次启动就不需要 Xcode 了,因为当前安装的 App 已经注入好了 Framework ,直接使用 cycript 即可。

5、使用脚本启动 Cycript

为了能够快速的使用 Cycript ,避免每次都输入繁琐的命令,就可以使用脚本辅助。

比如连接上方已经注入好 Cycript.framework 的其他 App,把连接指令 cycript -r 192.168.50.49:6666 放入脚本 cylogin.sh 里,下次启动如果在IP 地址没有变化的情况下,直接输入 ./cylogin.sh 就可以了。

为了想能够在任何地方都可以使用这些脚本,就需要配置一下环境变量。

既然需要配置环境变量,那不如新建一个文件夹专为此服务,之后还可以给这个文件夹里添加更多脚本。

在家目录下创建一个文件夹 TCShell(你可以在任何目录创建,叫任何名称,只要配置环境变量时,填写好你放的目录和名称即可),cd TCShellvi cylogin.sh 将上方的指令 cycript -r 192.168.50.49:6666 放入,然后保存退出。再 chomd 755 cylogin.shcylogin.sh 添加执行权限。

脚本添加

在配置环境变量前,验证一下 cylogin.sh 脚本是否正确。sh cylogin.sh 或者 ./cylogin.sh 如果进入了 Cycript 显示 cy# 说明我们配置好了。

验证脚本

接下来需要配置环境变量了(和第6条 Cycript 的安装 同理),vi ~/.bash_profile 打开,export 路径后保存退出。重启一下终端,这样就可以在任何地方使用 sh cylogin.sh 进入 Cycript 了。

环境变量配置
cylogin.sh 的使用
6、Cycript 练习

微信登录页面有一个国家和地区选择,点击进入后,阿尔巴尼亚的编号是 +355 ,现在把这个改成 +1008611

猜测+355 是一个 UILabelcy# 输入 choose(UILabel) 回车,commadn F 搜索 +355,复制地址 0x110351910,然后 #0x110351910.text = '+1008611'; 回车就发现更改成功了。

image.png
tancheng@tanchengdeMacBook-Pro /~ : sh cylogin.sh
cy# choose(UILabel)

//...

cy# #0x110351910.text = '+1008611';
"+1008611"
cy#
结果验证

注意:在重新进入这个页面发现又变成 +355 了,但是执行 #0x110351910 时,打印还是 '+1008611' 这是因为这个对象还没有完全销毁,所以如果页面变了,之前的地址就不要再次使用了。

9、Monkey Dev 中 CY 文件命令的使用

使用 Monkey Dev 注入的 Cycript 时候有一些指令还是很好用的。

  • APPID : 获取 Bundle ID
  • pviews() :获取子视图层级
  • pvcs():获取控制器层级

10、封装 CY 文件

如果不是 Monkey Dev 注入的 Cycript 那是没有这些的,这就需要我们自己封装了。

现在借助 Monkey Dev 帮我们重签的 WeChat 的时候,将我们自定义的 CY 文件 Copy 到工程中。

新建 Monkey Dev 工程,运行一下空工程(每次必做的事情),添加 Target App

Xcode 在第一个 target 新建文件, iOS -> Others -> Empty File ,命名为 CurrentCY.cy ,在这个 targetBulid Phases 下方 Copy Files 添加 CurrentCY.cy

添加 CurrentCY.cy

然后我们写点东西,运行工程。

sum=function(a,b) {
    return a+b;
}

CurrentKeyWindow=function(){
    return UIApp.keyWindow;
}
CurrentRootVC=function(){
    return UIApp.keyWindow.rootViewController;
}

打开 iTerm 进入 Cycript ,导入 CurrentCY.cy 这是必须要做的事情,输入 @import CurrentCY ,回车出现 {} 代表导入成功了,试试导入的指令。

//...
tancheng@tanchengdeMacBook-Pro  ~ : sh cylogin.sh
cy# @import CurrentCY
{}
cy# sum(10,20);
30
cy# CurrentKeyWindow ()
#"<iConsoleWindow: 0x135d4a890; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x282626e50>; layer = <UIWindowLayer: 0x28296ab40>>"
cy# CurrentRootVC()
#"<MMUINavigationController: 0x136849c00>"
cy#

这样自己封装的 CY 文件就可以使用了,后续还可以继续往里面添加一些东西。

以上就是 LLDB高级调试+Cycript 的全部内容了。

关于 Chisel 和 lldb_commands 常用指令整理,请点击这里

Cycript 常用指令整理,请点击这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335