Swift教程

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

本文主要是介绍iOS应用安全7 -- LLDB动态调试,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

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

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

基础LLDB用法

p、po、print、expression

首先就来介绍一下这几个常用命令之间的关系吧。 先看看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指令查看。

help

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

po
接下来使用help expression看看expression -O --是什么意思,如下,可以看到-O代表的是对象的description(描述),即打印出变量的描述。
expression -O

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
复制代码

效果如下:

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

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

组合

breakpoint set虽然在拼写时lldb会提示,但感觉还是太长了,怎么办?
直接使用b即可。

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,效果是一样的,入下:
variable

这里是有点取巧了,变量的内存地址也是直接通过符号获取的,并且这里也只是演示了给变量打内存断点,那么如何给方法打内存断点呢?
假设我现在要给click2:方法打个断点,那么就需要这样计算:

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

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

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

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

frame
在此基础上,还能够使用updown命令查看临近的调用栈信息。
updown

c,n,s

这个就简单了,如下图:

cns

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

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

pviews

pvc

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

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

caflush

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

fv 和 fvc

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

fv

taplog

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

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

presponder

打印出responder响应链。

pclass

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

pclass

pactions

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

pactions

methods

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

methods

flicker

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

flicker

vs

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

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

vs

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

总结

这篇文章主要记录了

  1. xcode自带的LLDB的使用方法。
  2. 逆向时如何设置断点。
  3. 使用插件chisel对LLDB进行功能扩展(更利于逆向)。

本文地址

这篇关于iOS应用安全7 -- LLDB动态调试的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!