LLDB命令简单介绍

本文详细介绍了LLDB调试器的各种命令,包括breakpoint设置、禁用/启用/删除断点、expression命令用于修改属性、bt命令查看调用栈、watchpoint内存断点以及target stop-hook和.lldbinit文件的使用。特别强调了在逆向工程中如何使用内存断点,并探讨了ASLR对逆向调试的影响。此外,还展示了如何通过image指令查看进程加载的镜像信息和设置内存地址断点。

简介

LLDB是Low Lever Debugger的简称,翻译成中文应该叫做底层调试器,它是LLVM项目的调试器组件。LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。如果你了解过Swift语言及其作者,那么一定对Chris Lattner博士不陌生,那这里为什么要提到他呢?没错LLVM开发最初就是由Chris Lattner博士主持开展的。

LLDB支持调试C、Objective-C和C++编写的程序。Swift社区维护了一个版本,增加了对该语言的支持。默认内置于Xcode中,LLDB提供了一组广泛的命令,旨在与老版本的GDB命令兼容。除了使用标准配置以外,还可以很容易的自定义LLDB命令以满足实际需要。可以在Xcode的控制器进入lldb调试模式后,输入help可以查看所有Debugger commands,也可以在这个网站查询

breakpoint命令

断点命令,在平时使用Xcode开发的过程中,我们设置断点一般都是通过在界面上点击代码所在的行数设置的。其实也可以使用lldb的命令来设置断点。

根据名字设置断点

设置C函数名断点

<img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1df1a8fc0824a1eb514cbc346414faf~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image) 在touchedBegan方法中,我们从界面设置了一个断点,进入了lldb调试模式,再输入以下命令设置函数断点:breakpoint set -n "test1",-n是--name的缩写,然后点击继续按钮,或者输入lldb命令c继续执行,可以看到其实Xcode集成的很多的调试功能就是从lldb这来的。调试下一步就在lldb输入n或者s,n遇到子函数不会进入,s遇到子函数会进入" style="margin: auto" />

设置OC方法名断点

先搭建个如图所示的简单界面 <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/026b14e3117e49d6b98f474643da37e3~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image) 然后暂停程序,在控制台输入如下命令:breakpoint set -n "-[ViewController save:]" -n "-[ViewController pause:]" -n "-[ViewController continue:]"这样就设置了一组断点,它有三个断点。可以使用以下命令查看当前所有断点:breakpoint list ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9c17f3eaf4df4d32b259e2295a1da0bd~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image" style="margin: auto" />

禁用和启用断点

禁用断点,后面的数字是breakpoint list显示的编号,可以同时禁用1组,也可以单独禁用组里的某个 breakpoint disable 编号

删除断点

删除断点breakpoint delete 编号,这里有个小细节,我们无法删除一组断点里面的某一个,只能删除一整组断点。如果delete后面跟的是某个组里面的某个断点,等同于禁用这个断点。如果不输入编号,那就相当于删除所有断点

根据方法设置断点

刚刚我们设置的断点,是某个类的某些具体方法,我们也可以设置与类无关的方法断点:breakpoint set --selector touchesBegan:withEvent:

如果不想这样把断点断到系统库里面去,可以指定文件设置方法断点,我们在ViewController里加上touchesBegan:方法:breakpoint set --file ViewController.m --selector touchesBegan:withEvent:

正则匹配设置断点

可以输入help breakpoint set看到-r参数的介绍

Set the breakpoint by function name, evaluating a regular-expression to find the function name(s). 

breakpoint set -r save:这样就会根据-r后面的参数去寻找所有能匹配到的方法

同样的,我们可以配合指定文件来使用这个命令 breakpoint set -r save: --file ViewController.m

断点执行命令

breakpoint command add 编号可以给断点加一些命令,这样断点来到的时候,可以自动执行这些命令,能否为我们节省一些操作

以上这些所有的lldb命令,都可以缩写,比如:breakpoint set -r save: --file ViewController.m可以缩写成b -r save: -f ViewController.m``breakpoint list可以缩写成break li``breakpoint disable 8.1可以缩写成bre dis 8.1``breakpoint enable 8.1可以缩写成bre en 8.1反正你可以去各种尝试,多一个少一个字母或许都能行,比较随意,比起普通的命令错一个字符都不行还是蛮牛逼的。

expression命令

我们平时在lldb控制台里面干的最多的是什么?po打印某个对象吧,那么这个po到底是什么意思呢?可以在终端输入如下命令查看一下: help po

通过help po我们知道就是在主线程执行表达式,那么我们可以试试在lldb中修改一些常见的属性,比如self.view.backgroundColor,首先来到touchesBegan:断点,在lldb输入如下指令p self.view.backgroundColor = [UIColor redColor];<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dc5c508108d54a81a3481ba930115338~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image) 发现确实执行了这句代码,但是却报了一个让人疑惑的错误,而且过掉断点之后并没有任何效果,当然了明明执行都报错了,怎么可能会有效果呢。。。但是这一行代码,在程序中运行的话,肯定是没有问题的,我们查看UIView的头文件也可以发现它确定是有backgroundColor这个属性的。至于为什么我在网上搜索半天没有找到任何答案,感觉可能是lldb的bug?虽然这句代码无效,但是我们依然可以尝试使用其他的方式来修改,比如:p [self.view setValue:[UIColor blueColor] forKey:@"backgroundColor"]

KVC还是牛逼啊,还有一种办法,我们知道UIView真正用来显示的是它的layer,修改layer:p self.view.layer.backgroundColor = [UIColor yellowColor].CGColor ![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0487a68486ae4ceba1fe407eca761560~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image" style="margin: auto" />

再来一个案例,我么创建一个persons数组,存放一组Person模型,然后通过lldb的expression命令动态添加一个Person。

bt命令

进入lldb输入help bt可以看到,bt是查看当前线程调用栈的意思

新建以下这四个方法,并给demo4方法下个断点,然后点击屏幕进入断点

thread return 命令

当我们调试到某一帧的时候,如果不想让程序之后的代码,可以使用thread return线程返回,需要注意return后面根据实际情况返回对应的值,例如:

以上所有方式在逆向中都没法使用。。。因为逆向的项目我们都拿不到符号

那么逆向应该如何玩lldb?内存断点

watchpoint 内存断点

内存断点,不仅可以给方法断点,还可以给变量断点

watchpoint 根据变量名设置内存断点

watchpoint set variable p1->_name如图所示,Person类有一个name属性,但是我们设置内存断点的时候,属性是没法用的,因为属性的本质是getter和setter加下划线的成员变量嘛,所以需要使用p1->_name设置成功之后,当程序中有给p1.name赋值的地方,都会来到断点。下图马上给p1.name赋值lldb就提示Watchpoint 1 hit命中了。然后还会显示old value和new value

watchpoint 根据内存地址设置内存断点

watchpoint set expression 地址 还是刚刚的例子,我们在p1实例化之后,它在内存中的地址就确定了,那么它的成员变量的地址也是确定的,我们可以拿到p1.name的内存地址,根据它的内存地址设置断点。当程序对p1.name进行修改的时候,都会来到断点,可以看到下面的断点来了两次,一次是在viewDidload中,另一次在touchesBegan里面进行的修改

target stop-hook 命令

这个命令有点类似breakpoint的断点执行命令,只不过breakpoint的断点执行命令需要指定某个断点,而这个命令是全局的,只要是断点来了,就会执行后面的命令

.lldbinit文件

可以将一些经常使用的命令配置到.lldbinit文件里面,这样就不用每次都去添加一些命令。这个文件一般放在用户目录下,点开头的代表是隐藏文件,如果没有可以自己新建一个。如图我们在里面添加这样一句指令

image 指令

这个是查看当前进程加载的镜像相关信息,什么是镜像,一个Mach-O文件就是一个镜像。我们的APP也是一个镜像。我们先来查看一下我们APP中的某个类的信息image look up -t name

image list

输入help image list查看命令的介绍

逆向中下内存地址断点

如图我们在touchesBegan:方法中调用了demo4方法

这里提一下ASLR,是一种防范内存损坏漏洞被利用的计算机安全技术,就是我们的APP每次加载进手机的真实内存的时候,位置不是固定的,所以我们每次APP运行起来后通过image list看到的我们APP的首地址是随机的。

我们APP的Mach-O文件中的内容,相对于Mach-O文件的首地址来说都是固定不变的,APP加载进内存之后首地址就确定了,那么Mach-O文件中的内容,比如方法实现,函数实现,常量等数据在内存中的位置都可以找到了。。。

可以在ViewController.m文件中定义一个全局变量,然后我们在Mach-O文件看能否找到它。如图定义一个全局变量,然后运行起来之后,打印它所在的地址,和当前APP的首地址,它的地址减去APP的首地址就是它相对于我们APP的Mach-O文件的偏移了。 <img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6691afc10908400598503fe1abae024f~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image) 0x102b959f0 - 0x102b8c000 = 0x99F0在使用MachOView查看我们APP的Mach-O文件,找到地址0x99F0,看看是不是这个a的值0x123456678

有些同学可能会好奇,这个怎么是这个样子,其实这是因为机器的存取数据方式决定的,有些是大端模式,而有些机器是小端模式,这里贴一下百度的[大小端模式](https://link.juejin.cn/?target=https%3A%2F%2Fbaike.baidu.com%2Fitem%2F%25E5%25A4%25A7%25E5%25B0%258F%25E7%25AB%25AF%25E6%25A8%25A1%25E5%25BC%258F%2F6750542%3Ffr%3Daladdin "https://baike.baidu.com/item/%E5%A4%A7%E5%B0%8F%E7%AB%AF%E6%A8%A1%E5%BC%8F/6750542?fr=aladdin"" style="margin: auto" />

从这里也可以看出我们的全局变量是存放在__DATA,__data节的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值