iOS应用安全7 -- LLDB动态调试

LLDB全称是Low Level Debugger,并不是low的调试器,而是轻量级的高性能调试器,xcode默认内置了它,因此我们不需要再自己安装。笔者最近也是系统的学习了LLDB的用法,在此之前就用过 p和po ,哈哈:smile:。本篇文章主要为了将最近学习的LLDB记录并总结,加深记忆并方便以后查找。

另外,本篇文章主要有两部分,一个是LLDB的基础用法,另一个就是对基础LLDB使用插件进行扩展。

基础LLDB用法

p、po、print、expression

首先就来介绍一下这几个常用命令之间的关系吧。 先看看 expression 指令。

从这里可以发现, expression

指令主要有以下作用:

  1. 打印变量的信息
  2. 执行语句,如: expression a = 100 ,同样这里你可以试试 expression self.view.backgroundColor = [UIColor redColor] ,也是能修改背景颜色的。
  3. 通过 $ 符号定义和使用lldb变量,如: expression int $b = 99

可能是p太容易让人联想到 print 了,很多人都会认为 p是print的缩写,po是print object的缩写 ,事实上并不是这样。

p 和 print 其实都是 expression -- 的缩写,可以使用 help 指令查看。

po 也并不是 print object(原本也就没这个写法) 的缩写,而是 expression -O -- 的缩写,同样可以使用 help 指令查看。

接下来使用 help expression 看看 expression -O -- 是什么意思,如下,可以看到 -O 代表的是对象的 description(描述)

,即打印出变量的描述。

breakpoint

断点调试在日常开发中都经常用到,并且在xcode中我们也能够很轻易的设置、禁用、删除断点。下面就来看看如何使用LLDB达到并且超越界面化断点。

设置断点

常用设置断点的参数及代表的意义。

缩写 全称 意义
-f --file 文件名称
-l --line 行数
-n --name 方法名
-S --selector SEL
-r --func-regex 方法正则
  1. 在ViewController.m文件的第28行设置断点。
// 举例
breakpoint set -f ViewController.m -l 28
复制代码
  1. 给方法名是 click1: 的方法设置断点。
breakpoint set -n click1:
复制代码
  1. 给SEL是 click2: 的方法设置断点。
breakpoint set -S click2:
复制代码
  1. 给包含 click 的地方设置断点。
breakpoint set -r click
复制代码

效果如下:

可以看到一次性设置了103个地方,显然想要的不是这样。条件拼接,和第一个例子那样。

  1. ViewController.m 文件中包含 click 的地方设置断点。
breakpoint set -f ViewController.m -r click
复制代码

breakpoint set 虽然在拼写时lldb会提示,但感觉还是太长了,怎么办?

直接使用 b 即可。

查看当前全部断点

// 缩写:br list
breakpoint list
复制代码

这里需要注意以下,由于这三个断点是使用一条语句设置的,因此它们三个会被分到同一个断点组里面。

设置断点无效

这一步就相当于界面操作中,让断点颜色变半透明。

代码设置如下:

// 设置断点14.1无效
br disable 14.1
// 同样,将无效断点设置为有效
br enable 14.1
复制代码

删除断点

br delete 14.3
复制代码

可以看到,14.3并没有被删除,而只是被设置为了无效。原因就是14.3属于14这个组,不能只删除一个,要删必须将全部都删掉。

是不是感觉很666?

其实这些东西基本上用不到,哈哈哈。

正向开发中可以使用xcode提供的界面操作设置和删除断点。

而在逆向中,根本就获取不到这些符号(类名,文件名,方法名等)。

不信?看看下图:

因为在逆向中,是无法获取符号的,因为能够得到的文件就只有一个,MachO文件。而在MachO文件中是没有这些符号的,有的只是地址。

内存断点

上面说了,在逆向中,由于无法获取到符号,是无法直接通过符号设置断点的,而我们还需要使用断点怎么办?下内存断点。

这里在24行的断点处,获取了 _name 指针的地址,然后通过

watchpoint set expression 0x000000014b80b880
复制代码

_name 变量设置了一个内存断点,接下来 c--->continue 过掉断点,点击按钮1,在 _name = @"abc"; 语句调用时,因 _name 指向的空间变化了,就会打印出 old valuenew value

除了使用上面那种方法外,还能够使用 variable

,效果是一样的,入下:

这里是有点取巧了,变量的内存地址也是直接通过符号获取的,并且这里也只是演示了给变量打内存断点,那么如何给方法打内存断点呢?

假设我现在要给 click2: 方法打个断点,那么就需要这样计算:

  1. 先找到ASLR的值。
  2. 使用MachOView或者hooper打开App的MachO文件。
  3. 使用ASLR+方法在MachO文件中的地址 = 方法在内存中的地址。
  4. 测试以下是不是真的断住了click2:方法。点击按钮2,发现程序停到了这个方法。断点设置成功。

LLDB的其他常用命令

image list

上面我们查看 MachO 文件的 ASLR 时使用了这个命令。这里的image不是图片的意思,而是镜像。

可以理解为每一个 MachO 都是一个 image ,主程序是一个 image ,主程序链接的每一个动态库也各自是一个 image

image list 就是打印出 App 中全部的 image 信息,每个 image 信息的那个地址就是这个 image 在内存中的首地址,也即这个 imageASLR

bt

bt命令是用来查看函数调用栈的,如下,我在 click1: 中调了 click2: , click2: 中又调用了 click3: ,再在 click3: 中设置一个断点,点击 按钮1 ,输入 bt 命令,如下:

可以看到函数之间的调用关系。并且还可以使用

frame select [调用栈的编号]
复制代码

查看该调用栈的详细信息,包括调用者的内存地址,调用的方法,参数的内存地址等。

在此基础上,还能够使用 updown

命令查看临近的调用栈信息。

c,n,s

这个就简单了,如下图:

LLDB插件扩展

上面记录的都是xcode自带的lldb所具有的功能,接下来要说的是使用插件对lldb进行扩展,使得lldb更简单,更强大。

chisel

对于 chisel 的安装,最方便的还是使用 Homebrew 安装了,使用mac电脑,安装一个 Homebrew 是非常有用的,不过这个玩意因为是国外的服务器,所以安装更新都特别慢,甚至非常容易出错,一旦出错就要重来。对此,我们可以使用国内的源。

这里提供一种使用国内源进行安装的方法,终端执行下面的语句即可。如果使用的不是zsh,那么可以尝试将zsh改成bash。

/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
复制代码

安装完 Homebrew 之后,直接终端下面的命令即可安装chisel。

brew install chisel
复制代码

完成后在 /Users/[username]/.lldbinit 文件里面添加一句(没有就创建一个文件)。

command script import /usr/local/Cellar/chisel/2.0.0/libexec/fblldb.py
复制代码

安装完chisel之后,可以来尝试一下chisel对lldb的扩展。

pviews

递归获取全部的视图类对象,并且按照视图的层级结构打印出来。

pvc

打印当前全部的控制器对象及层级关系。这里代码进行来一点修改,点击屏幕空白时跳转到 NextViewController

因为 ViewControllerNextViewController 盖住了,可以看到控制器对象的 stateViewController 的 state 是 disappeared

caflush

用来刷新UI,在动态调试时,我们可能会修改UI控件的布局,此时直接使用 caflush 即可刷新视图。

fv 和 fvc

f-->find ,这两个命令是用来查找 viewViewController 的。

taplog

这个就比较厉害了,直接输入taplog,然后你会发现程序正常运行了,此时点击任意一个按钮,那么就会打印出点击的这个按钮的信息。

这个对于逆向调试是非常有帮助的,直接定位到点击的那个控件的内存地址。有了内存地址,什么都好办了。

presponder

打印出responder响应链。

pclass

打印对象所属的类的继承关系。

pactions

通过按钮的内存地址,直接找到按钮响应的actions。

methods

打印对象所属类的全部方法以及属性。类似于 class-dump 的功能。

flicker

让内存地址对应的控件在手机上闪烁一下。

vs

让内存地址对应的控件变成半透明的红色,并且进入一个编辑模式,使用

  • w:定位到当前视图的父视图。
  • s:定位到当前视图的第一个子视图。
  • a:定位到当前视图的兄弟视图的前一个。
  • d:定位到当前视图的兄弟视图的后一个。
  • p:打印定位到的视图的信息。
  • q:退出这个编辑模式。

还有其他的一些功能,使用 help 命令可以进行查看。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章