iOS逆向 玩转LLDB调试

2021-10-19  本文已影响0人  文博同学

写在前面

日常开发中经常会用到LLDB调试,可能用的最多的命令就是po,而在逆向领域中根本不可能让你在代码中下断点调试,于是乎LLDB就成了非常重要的手段

一、LLDB

LLDB(Low Lever Debug)的缩写,是默认内置于XCode的动态调试工具,它与LLVM编译器一起,存在于主窗口底部的控制台中,能够带给我们更丰富的流程控制和数据检测的调试功能

标准的LLDB提供了一组广泛的命令,旨在与老版本的GDB命令兼容。除了使用标准配置外,还可以很容易的自定义LLDB以满足实际需要

二、LLDB命令

1. LLDB语法

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument[argument...]]

比如breakpoint set -n test

如果你正在面试,或者正准备跳槽,不妨看看我精心总结的面试资料:https://gitee.com/Mcci7/i-oser 来获取一份详细的大厂面试资料 为你的跳槽加薪多一份保障

2. LLDB初级使用

LLDB命令都是在进入LLDB状态(运行状态下点击“暂停符号”)才能使用生效的 [图片上传失败...(image-6ff20f-1634645644917)]

(lldb) breakpoint list
// 设置c函数的断点
(lldb) breakpoint set -n cMethod
// 设置oc函数的断点
(lldb) breakpoint set -n "[ViewController ocMethod1]"
复制代码
(lldb) breakpoint set -n "[ViewController ocMethod1]" -n "[ViewController ocMethod2]" -n "[ViewController ocMethod3]"
// 禁用
(lldb) breakpoint disable 1
// 启用
(lldb) breakpoint enable 1

// 禁用
(lldb) breakpoint disable 1.1
// 启用
(lldb) breakpoint enable 1.1
复制代码
(lldb) breakpoint delete
复制代码
(lldb) breakpoint delete 1.1
复制代码
(lldb) breakpoint set --selector touchesBegan:withEvent:
复制代码
(lldb) breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
复制代码
(lldb) breakpoint set -r ocMethod
复制代码
(lldb) c
复制代码
// 查看LLDB指令帮助
(lldb) breakpoint help
// 查看LLDB的breakpoint帮助
(lldb) breakpoint help
复制代码

3. LLDB初级使用小结

命令 意义 简写
breakpoint list 查看断点列表 breakpoint l
breakpoint set -n cMethod 设置单个断点 b -n cMethod
breakpoint set -n "[ViewController ocMethod1]"
-n "[ViewController ocMethod2]" 设置一组断点 b -n "[ViewController ocMethod1]"
-n "[ViewController ocMethod2]"
breakpoint set --selector touchesBegan:withEvent: 设置某一个方法的断点 b -selector touchesBegan:withEvent:
breakpoint set --file ViewController.m --selector touchesBegan:withEvent: 设置某文件下某一个方法的断点 b -f ViewController.m --selector touchesBegan:withEvent:
breakpoint set -r ocMethod 设置所有匹配方法名的断点 b -r ocMethod
breakpoint enable 1 启用某一组断点 breakpoint en 1
breakpoint disable 1 禁用某一组断点 breakpoint dis 1
breakpoint enable 1.1 启用某一个断点 breakpoint en 1.1
breakpoint disable 1.1 禁用某一个断点 breakpoint dis 1.1
breakpoint delete 删除所有断点 breakpoint d
continue 退出LLDB模式 c
next 单步运行,将子函数当做整体一起执行 n
stpe 单步运行,将子函数当做整体一起执行 s

关于简写:

三、LLDB执行代码

前文中提到关于开发中最常用的po指令,在LLDB中并不是print -out的意思,其实是expression --object-

既然知道了p指令有执行代码的作用,接下来就来玩一下

四、函数调用栈

接下来在以下代码中进行调试,点击屏幕依次调用testtest1test2,在test2处打下断点

- (void)testWithStr:(NSString *)str {
    NSLog(@"test");
    [self test1WithStr:str];
}

- (void)test1WithStr:(NSString *)str {
    NSLog(@"test1");
    [self test2WithStr:str];
}

- (void)test2WithStr:(NSString *)str {
    NSLog(@"test2");
    NSLog(@"%@", str);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self testWithStr:@"test"];
}
复制代码
  1. bt——查看函数调用栈,能够看到函数调用的顺序
  1. up/down——上下挪动函数调用
  1. frame select 数字——跳转函数调用(0表示当前方法,2表示2个方法前)
  1. frame variable——查看当前函数属性:内存地址、方法名、参数
  1. thread return——结束当前函数调用,跳转回上一个调用栈的下一步(当前是跳转回第30行代码,准备执行31行代码)

由此,可以尝试在调用中修改参数的值从而完成新值打印

  1. up修改已经调用过的函数参数
    • 使用up指令回到上一步,使用p str = @"F";进行修改
  1. 提前修改函数参数
    • 提前在上一处函数调用时打下断点进行修改

总结:已经执行过的代码再怎么回滚也不能随意修改值,应当提前打下断点进行修改

五、内存断点

内存断点,顾名思义就是给内存下的断点

通过watchpoint set variable self->_p->_name就可以给对应的属性内存下断点

修改内存地址的值就会来到断点处(此时相当于KVO机制)同时也能看到函数调用栈

六、断点添加命令

类似于给程序添加脚本命令,断点执行也可以添加命令

断点到来时就会执行先前的命令了

七、target stop-hook

target stop-hook是一个给所有断点添加命令的指令——在每次stop的时候去执行一些命令(只对breakpoint、watchpoint有效)

image.png

只要target stop-hook add操作一番,任何断点都会触发添加的命令

单条命令可以简写成target stop-hook add -o "frame variable"-o表示单条命令)

同样的,也可以使用target stop-hook list查看列表

target stop-hook disable进行禁用

target stop-hook delete/undisplay 1进行禁用

接下来介绍一个高阶的操作
复制代码

LLDB启动的时候就会去加载一个叫做.lldbinit的文件,在/Users/用户名目录下

如果没有的话可以通过vi .lldbinit创建,然后在文件中添加命令target stop-hook add -o "frame variable"

重新启动运行Xcode.lldbinit文件中的命令就会被加载,是个很方便的调试手段!

八、ASLR

ASLR(Address space layout randomization)全称叫做地址空间配置随机加载,是一种防范内存损坏漏洞被利用的计算机安全技术,在各大平台都有应用

ASLR通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数

说得简单易懂些就是物理地址 = ASLR + 虚拟地址

接下来通过实例来了解一下这个家伙吧

- (void)fxTest {
    NSLog(@"%s", __func__);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self fxTest];
}
复制代码

cmd+B编译生成MachO文件,使用Hopper打开,找到fxTest方法

此时拿到了“内存地址”就可以打下内存断点来进行调试了,其实0x1340只是个虚拟地址——只是相对于MachO文件的偏移地址(前面的1表示空段,对地址没有任何影响)

刚才说了物理地址 = ASLR + 虚拟地址,那么此时的ASLR又是多少呢?

通过image list就可以打印出来——0x000000010301e000就是这个进程的ASLR(看过dlyd源码就知道每次运行这个ASLR值都不相同)

实际地址 = 0x000000010ae85000 + 0x1340 = 0x10AE86340

写在后面

LLDB这些指令如同Xcode的快捷键一般,不掌握也无妨,掌握了就是锦上添花,多了一种调试的思路,便能让你拉开与同行之间的差距

作者:我是好宝宝
链接:https://juejin.cn/post/6847902223926722573

上一篇 下一篇

猜你喜欢

热点阅读