使用MonkeyDev安装运行任意第三app逆向调试,更方便,更强大@AloneMonkey
在iOS的逆向开发中cycript与Reveal是不可缺少的分析第三方app的利器,利用它们可以很快的定位到UI,找到对应的控制器,进而缩小了代码的区域。最近实用lldb进行调试,发现lldb也可以达到类似的效果。
首先需要在非越狱设备调试任意第三方app参考这篇文章
这边还是以微信作为例子:
这边要达到的效果是找到登录按钮所在内存地址,并且找到所属控制器,修改登录按钮的文字。开始吧!
开始之前先简单介绍一下lldb常用命令,p & po — 打印变量或者对象
因为LLDB支持前缀匹配,因此你可以将print简写为p或者pri,而print则代表expression --;po则代表expression -O --,意为print object,打印对象。输入p指令可打印其对象类型、内存地址以及该对象的值等具体信息,而po指令则是打印其调用description方法得到的值。
(注:打印集合类型对象时,p指令会省略具体的值,只提示集合的数量等信息,因此若需查看集合中的值应使用 po指令,如下图所示:)
-
打印NSString:
-
打印NSDictionary:
expression
expression命令的作用是执行一个表达式,并将表达式返回的结果输出。expression的完整语法是这样的:
expression <cmd-options> -- <expr>
<cmd-options>:命令选项,一般情况下使用默认的即可,不需要特别标明。
--: 命令选项结束符,表示所有的命令选项已经设置完毕,如果没有命令选项,--可以省略
<expr>: 要执行的表达式
说expression是LLDB里面最重要的命令都不为过。因为他能实现2个功能。
-
我们在代码运行过程中,可以通过执行某个表达式来动态改变程序运行的轨迹。
-
假如我们在运行过程中,突然想把self.view颜色改成红色,看看效果。我们不必写下代码,重新run,只需暂停程序,用expression改变颜色,再刷新一下界面,就能看到效果
/ /改变颜色
(lldb) expression -- self.view.backgroundColor = [UIColor redColor]
// 刷新界面
(lldb) expression -- (void)[CATransaction flush]
也就是说我们可以通过expression来打印东西。
假如我们想打印self.view:
(lldb) expression -- self.view
(UIView *) $1 = 0x00007fe322c18a10
命令就介绍这个几个有用到的,其他的可以自行百度,下面就来调试吧!
-
先用xcode调试界面:
以上两张截图中其实已经包含了很多的我们想要的信息,包括UI的布局结构,层次,每个UIView对应的内容地址,以及父控件或容器.选中一下登录按钮,你回发现xcode右边的调试界面中如下内容:
包含了很多有用的信息,包括按钮的类名,内存地址以及Action和Target等
这样的话可以通过调用UIButton的nextResponder方法一直找到其所在的控制器,怎么去调用这个方法?,这时候lldb的expression命令就派上用场了,(e 0x105651b50)登录按钮的内存地址,执行以下命令:
e 0x105651b50
会打印出:
(long) $188 = 4385479504
其中$188就代表登录按钮对象,当然你可以直接使用0x105651b50(即登录按钮对象),改变登录按钮的文字试试:
e [$188 setTitle:@"飘金" forState:UIControlStateNormal]
结果报错如下:
这是因为缺少UIKit库
e @import UIKit
引入UIKit库在试试,What??还是错!
这是因为$188只是代表登录按钮所在内存地址,lldb并不知道他是什么类型对象,试着把$188强转换类型:
由图可知是登录按钮FixTitleColorButton类型
//0x105651b50和$188是一样的,e [(FixTitleColorButton *)0x105651b50 setTitle:@"飘金" forState:UIControlStateNormal]是一样的效果,你可以试试!
e [(FixTitleColorButton *)$188 setTitle:@"飘金" forState:UIControlStateNormal]
这回没有报错,也没有提示任何信息,但是UI 界面中也没看到任何变化,试着刷新界面的命令:
expression (void)[CATransaction flush]
命令执行后也没有任何任何输出,单步调试下一步:
c
执行后看看UI界面:
成功了,expression很强大,可以执行OC代码(和cycript一样,你可以通过方法recursiveDescription打印UIView结构,并且查看到每个UIView的相关信息),我们可以这样来定义一个变量
:
//获取到UIApplication对象,其中必须要在变量前加"$",后面引用定义好的对象时要带上"$",如下引用是$app
e UIApplication *$app = [UIApplication sharedApplication]
//获取到keyWindow,引用时是$keyWindow
e UIWindow *$keyWindow = $app.keyWindow
//获取到登录按钮
e FixTitleColorButton *$loginButton = (FixTitleColorButton *)0x15dd11770
//$loginButton只是0x000000015dd11770的别名
e $loginButton
(FixTitleColorButton *) $loginButton = 0x000000015dd11770
找出登录按钮所在控制器,利用nextResponder方法
(lldb) po [$loginButton nextResponder]
<UIView: 0x15dd0e080; frame = (0 582; 375 65); autoresize = W+TM; layer = <CALayer: 0x174039640>>
(lldb) po [(UIView *)0x15dd0e080 nextResponder]
<UIView: 0x15de27410; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x17022f760>>
(lldb) po [(UIView *)0x15de27410 nextResponder]
<WCAccountLoginFirstViewController: 0x15e80dc00>