iOS逆向攻防之LLDB调试

也许我们都一样
总是想要活成什么样
但是生活
总是告诉我们
应该怎么活
A188E6F85A82EB64E64261B7B18ABC75.jpg

接下来上今天的干货LLDB调试部分。日常的正向开发,Xcode提供了多种快捷键以及快捷方式方便我们开发者进行LLDB调试,所以其中的很多操作我们都相当熟悉了;但是这里需要说明的是,逆向开发所有的符号断点都是无效的,你只能对着MachO文件摸索着调试,更不存在像正向开发那样,把断点断到指定类的某一行的界面快捷操作,逆向开发主要使用的就是内存断点,所以逆向开发熟练掌握LLDB调试快捷指令是非常有必要的。下面是干货部分内容:

  • 简单了解LLDB及LLDB断点设置
  • LLDB执行代码
  • 查看函数调用栈
  • 内存断点
  • 断点添加command
  • target stop-hook

一、简单了解LLDB及LLDB断点设置


1、了解LLDB
LLDB(Low Level Debug)是默认内置于Xcode中的轻量级动态调试工具。标准的LLDB提供了一组广泛的命令,旨在与老版本的GDB命令兼容。除了使用标准配置外,还可以很容易地自定义LLDB以满足实际需要。

2、LLDB断点设置命令

  • 设置断点
    • $breakpoint set -n XXX (set 是子命令, -n是选项,是--name的缩写)

    • $b -n XXX 是上面的缩写,breakpoint 可以缩写成break,部分情况下直接缩写成b也是可以的

    • $breakpoint set --selector XXX(此处XXX详细解释:如果设置函数断点,这里就是函数或者方法名;如果方法或者函数有入参,需要加上冒号,比如 viewDidLoad)

  • $breakpoint set --file XXX (此处XXX为文件名,比如VC.m, 这几种命令可以组合使用,可以用来指定具体的某个文件中的某个方法,来指定断点的具体位置)

  • $b -f 是上面的缩写

  • 查看断点列表

    • $breakpoint list
    • $break li ,breakpoint li , break list 都是上面的缩写
  • 删除断点

    • $breakpoint delete 组号(这个组号是从断点列表中查询得到的)
  • 启用/禁用断点

    • $breakpoint disable 禁用 (简写 break dis)
    • $breakpoint enable 启用 (简写 break en)
  • 遍历整个项目中满足Test:这个字符的所有方法,-r后面跟的就是需要满足的条件

    • $breakpoint set -r Test:
  • 继续执行

    • $continue 简写 c
  • 单步运行,将子函数当做整体一步执行

    • $next 简写 n
  • 单步运行,遇到子函数会进去

    • $s
  • stop-hook

    • 让你在每次stop的时候去执行一些命令,针对breakpoint 和 watchpoint
  • 其他命令

    • image list
    • p (expression的简写)
    • b -[xxx xxx]
    • x
    • register read
    • po (expression -O的简写, 其中 -O代表Object description,就是输出对象的description方法,相当于NSLog)
    • help(help可以查看所有指令意思,也可以help+xxx查看指定LLDB指令的意思)

3、LLDB设置断点后的信息解释

(lldb) breakpoint set -n test1
Breakpoint 1: where = LogicDemo1`-[ViewController viewDidLoad] + 41 [inlined] test1 at ViewController.m:26, address = 0x00000001051227ee

详细解释就是

  • Breakpoint 1 -> 代表断点第1组,断点的组数,一组里面可以有多个断点

  • where = LogicDemo1`-[ViewController viewDidLoad] + 41 [inlined] ->代表断点断在ViewController的方法viewDidLoad中

  • test1 at ViewController.m:26 ->代表断点断在ViewController.m文件中的第26行

  • address = 0x00000001051227ee ->地址是0x00000001051227ee

如果我们想要设置方法断点,比如断在ViewDidLoad中,可以设置如下

$breakpoint set -n "-[ViewController viewDidLoad]"

在一组断点中一次性设置多个断点可以这样,函数有入参的记得加上冒号':'哦

$breakpoint set -n "-[ViewController viewDidLoad]" -n "-[ViewController viewWillAppear:]" 

下完断点的结果解释:

(lldb) breakpoint set -n "-[ViewController viewDidLoad]" -n "-[ViewController viewWillAppear:]"
Breakpoint 1: 2 locations.

  • Breakpoint 1 -> 代表的是下了1组断点
  • 2 locations -> 代表的是这1组包含2个断点

接下来我们查一下断点列表

(lldb) breakpoint list
Current breakpoints:
1: names = {'-[ViewController viewDidLoad]', '-[ViewController viewWillAppear:]'}, locations = 2, resolved = 2, hit count = 0
  1.1: where = LogicDemo1`-[ViewController viewDidLoad] + 12 at ViewController.m:23:5, address = 0x000000010f075786, resolved, hit count = 0 
  1.2: where = LogicDemo1`-[ViewController viewWillAppear:] + 12 at ViewController.m:32:5, address = 0x000000010f0757df, resolved, hit count = 0 

(lldb) 

这里注意组头部分

1: names = {'-[ViewController viewDidLoad]', '-[ViewController viewWillAppear:]'}, locations = 2, resolved = 2, hit count = 0

在禁用断点后,不管是组还是组中的元素,再被禁用后再查看断点信息,后面会多出来一个Options: disabled,如下

(lldb) breakpoint disable 1
1 breakpoints disabled.
(lldb) breakpoint list
Current breakpoints:
1: names = {'-[ViewController viewDidLoad]', '-[ViewController viewWillAppear:]'}, locations = 2 Options: disabled 
  1.1: where = LogicDemo1`-[ViewController viewDidLoad] + 12 at ViewController.m:23:5, address = 0x000000010f075786, unresolved, hit count = 0 
  1.2: where = LogicDemo1`-[ViewController viewWillAppear:] + 12 at ViewController.m:32:5, address = 0x000000010f0757df, unresolved, hit count = 0 

比如你只想禁用第一组的第一个,可以这样设置,结果同理

(lldb) breakpoint disable 1.1
1 breakpoints disabled.
(lldb) breakpoint list
Current breakpoints:
1: names = {'-[ViewController viewDidLoad]', '-[ViewController viewWillAppear:]'}, locations = 2, resolved = 1, hit count = 0
  1.1: where = LogicDemo1`-[ViewController viewDidLoad] + 12 at ViewController.m:23:5, address = 0x000000010f075786, unresolved, hit count = 0  Options: disabled 
  1.2: where = LogicDemo1`-[ViewController viewWillAppear:] + 12 at ViewController.m:32:5, address = 0x000000010f0757df, resolved, hit count = 0 

使用help查看po指令的意思

(lldb) help po
     Evaluate an expression on the current thread.  Displays any returned value
     with formatting controlled by the type's author.  Expects 'raw' input (see
     'help raw-input'.)

Syntax: po <expr>

Command Options Usage:
  po <expr>

'po' is an abbreviation for 'expression -O  --'

可以很清楚的看出po的意思就是 expression -O 的简写;

二、LLDB执行代码


LLDB的 p 指令是可以执行代码的。在断点中执行修改背景色的代码,然后 c 指令执行

(lldb) p self.view.backgroundColor = UIColor.redColor;
(UICachedDeviceRGBColor *) $0 = 0x0000600000065400
(lldb) c
2019-10-25 23:57:39.174041+0800 LogicDemo1[30217:3304533] HELLO WORLD
Process 30217 resuming

可以看出视图的背景色就变成了红色;这样就可以实时调试执行代码

比如往数据源中添加一个view

(lldb) po UIView * view = [[UIView alloc] init]; [self.dataArray addObject:view];
(lldb) c
2019-10-26 00:11:27.500407+0800 LogicDemo1[30390:3320236] HELLO WORLD
2019-10-26 00:11:27.500528+0800 LogicDemo1[30390:3320448] XPC connection interrupted
Process 30390 resuming
(lldb) po self.dataArray
<__NSArrayM 0x6000012f3090>(
<UIView: 0x7fe41d50bd50; frame = (0 0; 0 0); layer = <CALayer: 0x600001c94d40>>
)

(lldb) 

三、查看函数调用栈


先来介绍一些指令

  • bt 查看函数调用栈
  • frame select X 查看栈中的指定组,比如frame select 1
  • frame variable 查看变量
  • $thread return 回滚到上面一步操作,然后直接return,不会再执行后面的代码了

实战演练

(lldb) frame select 0
frame #0: 0x000000010dddb6f7 LogicDemo1`-[ViewController setup1withStr:](self=0x00007fcd0af031b0, _cmd="setup1withStr:", str=@"1") at ViewController.m:43:5 [opt]
   40       [self setup1withStr:@"1"];
   41   }
   42   - (void)setup1withStr:(NSString *)str{
-> 43       [self setup2withStr:str];
            ^
   44   }
   45   - (void)setup2withStr:(NSString *)str{
   46       [self setup3withStr:str];
(lldb) frame variable
(ViewController *) self = 0x00007fcd0af031b0
(SEL) _cmd = "setup1withStr:"
(__NSCFConstantString *) str = 0x000000010dddd098 @"1"
(lldb) p str = @"666";
(NSTaggedPointerString *) $0 = 0xbcec7f4581cd17f6 @"666"
(lldb) frame variable
(ViewController *) self = 0x00007fcd0af031b0
(SEL) _cmd = "setup1withStr:"
(NSTaggedPointerString *) str = 0xbcec7f4581cd17f6 @"666"
(lldb) 

四、内存断点


以上所有设置断点方式只针对正向开发,逆向的时候只有一个MachO文件是没有任何符号的,所以上面所说的断点方式在逆向中全部无效。

逆向中使用的是内存断点:

  • $watchpoint
  • $watchpoint set expression XXX(此处XXX是0x开头的内存地址,因为逆向一般是拿不到变量名的)

这个和breakpoint的使用方式类似

比如VC里面有这样依据代码

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.person = [[Person alloc] init];
    self.person.name = @"111";
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person.name = @"666";
}

使用内存断点能获取到Person对象的name属性的改变,并且能拿到新值和旧值

(lldb) watchpoint set variable self->_person->_name
Watchpoint created: Watchpoint 1: addr = 0x60000255c638 size = 8 state = enabled type = w
    watchpoint spec = 'self->_person->_name'
    new value: 0x000000010138c0b8

Watchpoint 1 hit:
old value: 0x000000010138c0b8
new value: 0x000000010138c0d8
(lldb) po (NSString *)0x000000010138c0b8
111

(lldb) po (NSString *)0x000000010138c0d8
666

(lldb) 

使用bt命令查看完整的触发调用堆栈信息,可以看出是touchBegin触发的。

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
  * frame #0: 0x00007fff503c6bae libobjc.A.dylib`objc_setProperty_nonatomic_copy + 44
    frame #1: 0x000000010138a4c9 LogicDemo1`-[ViewController touchesBegan:withEvent:](self=<unavailable>, _cmd=<unavailable>, touches=<unavailable>, event=<unavailable>) at ViewController.m:44:17 [opt]
    
    ...
    
    frame #17: 0x00007fff5123bcf5 libdyld.dylib`start + 1
    frame #18: 0x00007fff5123bcf5 libdyld.dylib`start + 1
(lldb) 

五、断点添加command


给断点添加command的命令是:

  • $breakpoint list
  • $breakpoint command add X (X是断点的组号)

例如:

(lldb) breakpoint list
Current breakpoints:
1: file = '/Users/fightmaster/Desktop/我爱学习/iOS进阶作业/3、安全攻防作业文件夹/6、Mach-O/20191016-应用安全-第六讲-MachO/006--MachO文件/备课代码/LogicDemo1/LogicDemo1/ViewController.m', line = 36, exact_match = 0, locations = 1, resolved = 1, hit count = 1

  1.1: where = LogicDemo1`-[ViewController touchesBegan:withEvent:] + 7 at ViewController.m:36:10, address = 0x000000010c98f4b5, resolved, hit count = 1 

(lldb) breakpoint command add 1
Enter your debugger command(s).  Type 'DONE' to end.
> po self
> po self.view
> DONE
2019-10-26 01:14:42.697650+0800 LogicDemo1[31167:3387465] XPC connection interrupted
 po self
<ViewController: 0x7ffec1e08200>


 po self.view
<UIView: 0x7ffec1c081e0; frame = (0 0; 414 896); autoresize = W+H; layer = <CALayer: 0x60000063b700>>


(lldb) 

其中需要注意的是输入DONE就可以结束命令

Enter your debugger command(s).  Type 'DONE' to end.
> po self
> po self.view
> DONE

六、target stop-hook


除了使用command还可以使用

  • target stop-hook

指令,这个和command差不多,并且这个是全局断点!

target stop-hook 命令用法和breakpoint一样,删除命令就是target stop-hook delete等等,查列表target stop-hook list等等~

(lldb) target stop-hook add -o "frame variable"
Stop hook #1 added.
(lldb) c
Process 31167 resuming
 po self
<ViewController: 0x7ffec1e08200>


 po self.view
<UIView: 0x7ffec1c081e0; frame = (0 0; 414 896); autoresize = W+H; layer = <CALayer: 0x60000063b700>>

由于每次Xcode启动,都会加载.lldbinit文件,所以这些全局命令可以直接写在这个文件里面,如果没有这个文件,可以自己创建一个同名的,这样以来,相当于只要在这个电脑上都可以使用,一劳永逸哦~

进入隐藏文件夹,然后创建或者编辑这个文件内容就可以全局配置了!

$ls -a 
$vi .lldbinit

好了,今天的LLDB就到这里睡了睡了狗命要紧

-END-

溪浣双鲤的技术摸爬滚打之路

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  •   LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。平时用...
    Thinkdifferents阅读 1,498评论 1 4
  • iOS调试之LLDB Xcode内嵌了LLDB控制台,在Xcode代码编辑区的下方。shift + cmd + y...
    comst阅读 1,454评论 0 3
  • 前言LLDB是我们平时调试中使用最多的工具之一,p或者po是使用最多的指令。除了p和po之外,还有什么指令可以使用...
    Hanfank阅读 1,736评论 7 10
  • [转]浅谈LLDB调试器文章来源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc阅读 2,480评论 2 6
  • [TOC] MachO文件结构 单个架构的mach-O文件包含:MachO Header、Load Command...
    _顺_1896阅读 428评论 0 0