七 LLDB簡(jiǎn)單使用

nx_001.jpeg

上篇文章中,我們講了Hook的原理分析,fishHook的簡(jiǎn)單使用,在使用的過程中,我們也詳細(xì)的了解了一下MachO文件的構(gòu)成,fishHook的執(zhí)行流程、使用方法等。

在我們玩逆向的時(shí)候在大多數(shù)時(shí)候其實(shí)是拿不到源碼的。所以了解一些LLDB來輔助我對(duì)別人APP的學(xué)(破)習(xí)(壞),是非常有必要的。

本篇文章,我們來了解下LLDB相關(guān)的內(nèi)容吧。。

今天的DEMO也比較簡(jiǎn)單,可以在點(diǎn)擊這里下載到:Demo7_LLDB

接下來本文會(huì)從以下幾點(diǎn)進(jìn)行闡述:

  • LLDB簡(jiǎn)介
  • LLDB斷點(diǎn)設(shè)置
  • LLDB執(zhí)行代碼
  • LLDB查看堆棧信息
  • LLDB內(nèi)存斷點(diǎn)
  • LLDB其它指令
  • target-stop-hook
  • 關(guān)于image和其它常用指令

LLDB 簡(jiǎn)介

LLDB(Low Lever Debug) 默認(rèn)內(nèi)置于Xcode中的動(dòng)態(tài)調(diào)試工具。標(biāo)準(zhǔn)的 LLDB 提供了一組廣泛的命令,旨在與老版本的 GDB 命令兼容。 除了使用標(biāo)準(zhǔn)配置外,還可以很容易地自定義 LLDB 以滿足實(shí)際需要。

默認(rèn)內(nèi)置于Xcode中的動(dòng)態(tài)調(diào)試工具。標(biāo)準(zhǔn)的 LLDB 提供了一組廣泛的命令,旨在與老版本的 GDB 命令兼容。 除了使用標(biāo)準(zhǔn)配置外,還可以很容易地自定義 LLDB 以滿足實(shí)際需要。

命令格式如下:

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

<action>:我們想在前面的命令序列的上下文中執(zhí)行的一些操作。
<options>:行為修改器(action modifiers)。通常帶有一些值。

  • []表示命令是可選的,可以有也可以沒有。
  • <command>(命令)<subcommand>(子命令):LLDB調(diào)試命令的名稱。命令和子命令按層級(jí)結(jié)構(gòu)來排列:一個(gè)命令對(duì)象為跟隨其的子命令對(duì)象創(chuàng)建一個(gè)上下文,子命令又為其子命令創(chuàng)建一個(gè)上下文,依此類推。
  • <action>:我們想在前面的命令序列的上下文中執(zhí)行的一些操作。
  • <options>:行為修改器(action modifiers)。通常帶有一些值。
  • <argument>:根據(jù)使用的命令的上下文來表示各種不同的東西。

The full lldb command names are often long, but any unique short form can be used. Instead of "breakpoint set", "br se" is also acceptable.
一般lldb的命令會(huì)很長(zhǎng),但是只要能夠想出足夠斷,并且又能代表唯一性的縮寫,那么縮寫命令也是同一生效的如:breakpoint set == br se

LLDB的所有命令在LLVM官網(wǎng)或者Apple官網(wǎng) 都可以查詢到。筆者會(huì)在這篇文章中列舉一些比較常用的命令。

1. LLDB斷點(diǎn)設(shè)置

首先,我們先看一下官網(wǎng)關(guān)于LLDB的命令,下面我們提供關(guān)于部分添加斷點(diǎn)的命令,也是我們本段主要的內(nèi)容:

1 breakpoint1.png

1.1 LLDB 命令設(shè)置斷點(diǎn)
1 breakpoint2.png
breakpoint set -n test1(函數(shù)名稱)

注意: 我們項(xiàng)目運(yùn)行起來可以點(diǎn)擊下面按鈕進(jìn)入LLDB模式

1 breakpoint_into.png

1.2 LLDB 設(shè)置多個(gè)斷點(diǎn)
1 breakpoint3.png
4.使用LLDB下載多個(gè)斷點(diǎn)
breakpoint set -n "[ViewController save:]" -n "[ViewController pauseGame:]" -n "[ViewController continueGame:]"
1.3 LLDB 設(shè)置斷點(diǎn)失效、啟用
1 breakpoint4.png
1 breakpoint5.png
// 使某個(gè)斷點(diǎn)失效
breakpoint disable 1 
//啟用某個(gè)斷點(diǎn)
breakpoint enable 1

注意:
breakpoint disable 1 使當(dāng)前的這一組斷點(diǎn)全部失效。
breakpoint disable 1.1 使某一個(gè)斷點(diǎn)失效
使某一個(gè)斷點(diǎn)失效:

1 breakpoint6.png

1.4 LLDB 刪除斷點(diǎn)
1 breakpoint8.png
1 breakpoint9.png
// delete 使用
breakpoint delete 1.1 
breakpoint delete 1

注意:
breakpoint delete 1.1 是使某個(gè)斷點(diǎn)失效。
breakpoint delete 1 是刪除第一組的數(shù)據(jù)。刪除只能刪除指定的組。
breakpoint delete 刪除所有的斷點(diǎn)。

1.5 LLDB 給某一個(gè)函數(shù)設(shè)置斷點(diǎn)(批量設(shè)置斷點(diǎn))
1 breakpoint10.png
// 給某一個(gè)函數(shù)設(shè)置斷點(diǎn)(批量設(shè)置斷點(diǎn))
breakpoint set --select touchesBegan:withEvent:
1.6 LLDB 根據(jù)某個(gè)字符串設(shè)置斷點(diǎn)
1 breakpoint11.png
// 遍歷文件/系統(tǒng)中含有Game的函數(shù)設(shè)置斷點(diǎn)
breakpoint set -r Game: 
1.7 LLDB 根據(jù)某個(gè)字符串設(shè)置斷點(diǎn)
// 給某一個(gè)文件中的某一方法設(shè)置斷點(diǎn)
breakpoint set --file ViewController.m -select touchesBegan:withEvent:
1.8 設(shè)置斷點(diǎn)命令總結(jié)
命令名稱 命令參樣例
使用名稱設(shè)置斷點(diǎn) breakpoint set --name test1(函數(shù)名)
使用內(nèi)存地址設(shè)置斷點(diǎn) breakpoint -a 0xXXXXXXXX 刪除斷點(diǎn) breakpoint delete 1
使斷點(diǎn)失效/生效 breakpoint disable/enable 2
查看所有斷點(diǎn) breakpoint list
OC中所有命名中包含為Test4的方法設(shè)置斷點(diǎn) breakpoint set -r Test4
下載多個(gè)斷點(diǎn) breakpoint set -n "[ViewController save:]" -n "[ViewController pauseGame:]" -n "[ViewController continueGame:]"
使某個(gè)斷點(diǎn)啟用/失效 breakpoint enable 1 breakpoint disable 1注意:breakpoint disable 1 會(huì)使當(dāng)前的這一組斷點(diǎn)全部失效,使用breakpoint disable 1.1 使某一個(gè)斷點(diǎn)失效
刪除斷點(diǎn) breakpoint delete 1.1 breakpoint delete 1注意:breakpoint delete 1.1 是使某個(gè)斷點(diǎn)失效,而breakpoint delete 1 是刪除第一組的數(shù)據(jù)。刪除只能刪除指定的組
查看幫助命令 help breakpoint
給所有同名的函數(shù)設(shè)置斷點(diǎn) breakpoint set --select touchesBegan:withEvent:
清空所有斷點(diǎn) breakpoint delete
給某一個(gè)文件中的某一方法設(shè)置斷點(diǎn) breakpoint set --file ViewController.m -select touchesBegan:withEvent:
遍歷文件/系統(tǒng)中含有Game breakpoint set -r Game:

2. LLDB執(zhí)行代碼

上一節(jié)中我們知道了LLDB怎么去設(shè)置斷點(diǎn),那么這一小節(jié)我們來看一下LLDB怎么執(zhí)行代碼吧。
準(zhǔn)備工作:

  • 1.創(chuàng)建Person類,添加name、age屬性
  • 2.在viewDidLoad中將數(shù)據(jù)添加到數(shù)組中。
// 大致代碼如下:
#import "Person.h"

@interface ViewController ()
@property (nonatomic,strong) NSMutableArray <Person*>*models;
@end

@implementation ViewController
- (NSMutableArray<Person *> *)models{
    if (!_models) {
        _models = [NSMutableArray array];
    }
    return _models;
}

void test1(){
    NSLog(@"test1: %d",3);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"p1";
    p1.age = 11;
    
    Person *p2 = [[Person alloc] init];
    p2.name = @"p2";
    p2.age = 12;
    
    Person *p3 = [[Person alloc] init];
    p3.name = @"p3";
    p3.age = 13;
    
    [self.models addObject:p1];
    [self.models addObject:p2];
    [self.models addObject:p3];
}
2.1 使用LLDB命令向models中添加一個(gè)數(shù)據(jù)
// 添加數(shù)據(jù)
p [self.models addObject:[[Person alloc] init]]

// 查看數(shù)據(jù)
po self.models
2 LLDB插入數(shù)據(jù).png
2.2 使用LLDB命令給數(shù)據(jù)設(shè)值
// 獲取數(shù)據(jù)(拿到最后一個(gè)數(shù)據(jù))
p (Person *)self.models.lastObject

// 設(shè)值(上一步會(huì)返回一個(gè)標(biāo)記,我們使用這個(gè)標(biāo)記就好了,類似于動(dòng)態(tài)對(duì)象,如下圖)
2 LLDB動(dòng)態(tài)設(shè)置數(shù)據(jù).png
2.3 使用LLDB命令查看數(shù)據(jù)值
2 LLDB動(dòng)態(tài)讀取數(shù)據(jù).png
1.先獲取數(shù)據(jù)
2.讀取數(shù)據(jù)
2.4 使用LLDB執(zhí)行代碼
2 LLDB執(zhí)行代碼段.png
1.打開LLDB
2.mac 快捷鍵 option+回車,在面板中寫代碼
3.p Person *p4 = [[Person alloc] init];
  p4.name = @"p4";
  p4.age = 14;
  [self.models addObject:p4]
2.1 LLDB動(dòng)態(tài)運(yùn)行代碼總結(jié)
命令名稱 命令例子
插入數(shù)據(jù) 如上 2.1
給數(shù)據(jù)設(shè)值 如上 2.2
查看數(shù)據(jù) 如上 2.3
LLDB執(zhí)行代碼 如上 2.4

3. LLDB查看堆棧信息

命令名稱 命令例子
查看當(dāng)前所有堆棧 bt
返回上一步堆棧 up
執(zhí)行下一步堆棧 down
查看某一條堆棧 frame select 1
查看當(dāng)前堆棧的參數(shù) frame variable
堆棧回滾到上一條 thread return
程序繼續(xù)執(zhí)行 c
單步下一步 n
進(jìn)入下一個(gè)函數(shù)(方法) s
匯編級(jí)別的單步下一步 ni
匯編級(jí)別的進(jìn)入下一個(gè)函數(shù)(方法) si

下面出示例圖:
LLDB_bt堆棧

3 LLDB_bt堆棧.png

LLDB 選擇堆棧,查看參數(shù)

3 LLDB_select_variable.png

LLDB 修改堆棧函數(shù)的參數(shù)

3 LLDB frame修改參數(shù).png

注意:

  1. 當(dāng)我們使用frame查看指定堆棧,修改函數(shù)的參數(shù)的時(shí)候
frame 修改參數(shù)
frame select 1 // 切換堆棧
frame variable // 修改查看參數(shù)
p str = @"123" // 設(shè)置新參數(shù)
frame variable // 查看新設(shè)置的參數(shù)

如果后面有輸出語句,參數(shù)依然是輸出之前的參數(shù),這是因?yàn)槲覀兇a已經(jīng)走到這里了,函數(shù)調(diào)用關(guān)系已經(jīng)確定。

  1. 回滾指令 thread return
1.回滾指令之后函數(shù)不會(huì)再往下執(zhí)行。
2.函數(shù)直接返回,不會(huì)再執(zhí)行斷點(diǎn)之后的代碼
3.up指令不會(huì)改變其執(zhí)行的流程
  1. si、ni 可以使用 control + 鼠標(biāo)點(diǎn)擊指令按鈕查看

4. LLDB內(nèi)存斷點(diǎn)

某個(gè)屬性地址只要有改變,就觸發(fā)斷點(diǎn)。相當(dāng)于對(duì)某個(gè)屬性設(shè)置了KVO。

命令名稱 命令例子
直接觀察一個(gè)變量 watchpoint set variable global_var
直接觀察一個(gè)變量的地址 watchpoint set expression -- 0xxxxxx
刪除斷點(diǎn) watchpoint delete 1
使斷點(diǎn)失效/生效 watchpoint disable/enable 2
查看所有內(nèi)存斷點(diǎn) watchpoint list
// 例子
1.touchesBegan 添加代碼
Person *p1 = self.models.firstObject;
p1.name = @"hello";

2.再將數(shù)據(jù)添加到模型的時(shí)候設(shè)置斷點(diǎn),當(dāng)p1賦值完成后LLDB執(zhí)行以下代碼。
watchpoint set variable p1->_name

3. 斷點(diǎn)執(zhí)行下一步,查看(查看所有內(nèi)存斷點(diǎn) watchpoint list)內(nèi)存斷點(diǎn)
4 內(nèi)存斷點(diǎn).png

5. LLDB command命令

LLDB 添加 command 指令

1.添加2個(gè)斷點(diǎn),當(dāng)程序走到斷點(diǎn)時(shí),我們執(zhí)行一些其它的命令,第一組屏幕點(diǎn)擊,第二組給某個(gè)方法設(shè)置指令
2.breakpoint 執(zhí)行command命令
 breakpoint command add 2(表示第幾組)
 Enter your debugger command(s).  Type 'DONE' to end.
 > po self
 > p self.view.subViews
 > DONE
 
 // 也可以添加、執(zhí)行刪除命令
 breakpoint command delete 2

如下圖:


5 LLDB command命令.png
命令名稱 命令例子
breakpoint 添加指令 breakpoint command add 2(表示第幾組)
breakpoint 刪除指令 breakpoint command delete 2(表示第幾組)

6. target stop-hook 和 .lldbinit的配置

target stop-hook含義:給所有的斷點(diǎn)添加參數(shù),執(zhí)行某些命令。

// 不管你斷住了哪一個(gè)方法,我都會(huì)把這個(gè)方法的參數(shù)打印出來 -o 表示添加一條指令
target stop-hook add -o "frame variable"

// 刪除
target stop-hook delete

// 查看列表
target stop-hook list
6 target stop-hook.png

以下是部分命令

命令名稱 命令例子
增加一個(gè)HOOK target stop-hook add -o "frame variable"
查看所有HOOK target stop-hook list
刪除HOOK target stop-hook disable 1
使HOOK失效/生效 target stop-hook disable/enable 2

由于每次使用的斷點(diǎn)比較多,并且都是執(zhí)行相同的代碼,這時(shí)我們就可以把這部分代碼封裝起來,寫成一個(gè)文本文件夾,每次執(zhí)行默認(rèn)加載

.lldbinit的配置

1. .lldbinit 是在當(dāng)前用戶的家目錄下,為隱藏文件。
2. .lldbinit 是隱藏文件,默認(rèn)看不見,需要使用 command+shift+. 組合鍵顯示文件。
3. 如果之前沒有使用過,則沒有.lldbinit文件,我們需要使用vim .lldbinit 創(chuàng)建文件。
4. 在 文件中 添加以下命令:target stop-hook add -o "frame variable",保存退出。
5. 使用 cat .lldbinit 查看 .lldbinit文件的內(nèi)容。
6. 執(zhí)行Xcode代碼,會(huì)發(fā)現(xiàn)有斷點(diǎn)的地方都執(zhí)行了一下 “target stop-hook add -o "frame variable""這個(gè)命令

7. 關(guān)于image和其它常用指令

命令名稱 命令例子
查看工程中使用的庫(kù)(包括MachO自己) image list
查找可執(zhí)行文件或共享庫(kù)的原始地址 image lookup --address 0x0000000100000de0
輸出NSURL的成員變量及屬性信息。 image lookup --type NSURL
導(dǎo)出可執(zhí)行文件和共享庫(kù)的所有符號(hào)表 image dump symtab

8. 總結(jié)&Demo

本篇文章,我們講了LLDB的一些常用的語法,和一些命令,
這片文章的內(nèi)容其實(shí)非常簡(jiǎn)單,首先介紹了一下LLDB的一下基本用法,有.lldbinit文件可以幫我們自動(dòng)加載腳本,所有就有了一個(gè)簡(jiǎn)單的LLDB腳本案例,

參考代碼:LLDBDemo

參考:

作者:一縷清風(fēng)揚(yáng)萬里
原文地址:http://m.itdecent.cn/p/fd10bb8b89d6
LLDB調(diào)試器使用簡(jiǎn)介

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容