iOS逆向攻防之LLDB调试

也许我们都一样
总是想要活成什么样
但是生活
总是告诉我们
应该怎么活
iOS逆向攻防之LLDB调试_第1张图片
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 

Command Options Usage:
  po 

'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>(
>
)

(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 *)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=, _cmd=, touches=, event=) 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



 po self.view
>


(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



 po self.view
>

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

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

$ls -a 
$vi .lldbinit

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

-END-

你可能感兴趣的:(iOS逆向攻防之LLDB调试)