LLDB調試詳解--逆向開發


一、前言

今天講述在蘋果日常開發中一個裝逼神器LLDB,是Xcode內置的動態調試工具. 在iOS系統程序開發中,會經常需要代碼調試的追蹤, 最常用的也是LLDB(low level debugger) .LLDB能更好的輔助開發者通過各種手段如修改變量進行測試,甚至能協助開發同學來定位bug. 

LLDB是新一代高性能的調試器, 也是Mac OSX上Xcode的默認調試器, 支持在桌面和iOS設備模擬器上調試C,OC和C++以及Swift.

 

二、幫助

LLDB命令的格式如下:

<命令名稱> <命令動作> [-可選項 [可選項的值]] [參數1 [參數2...]]

LLDB命令是由各部分空格分割, 如果參數是包含空格, 則需要雙引號括起參數,如果參數本身中包含雙引號或反斜杠, 就需要使用反斜杠來進行轉義.

LLDB命令是非常多的, 完全記錄下來是不可能的, 而且還沒有必要. 可以利用help命令查看相關LLDB命令的用法.如下:

  

三、LLDB常見命令

 3.1 breakpoint指令

示例Demo1 

  func test1(str: String) {
        self.test2(str: str)
    }

    func test2(str: String) {
        self.test3(str: str)
    }

    func test3(str: String) {
        print(str)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.test1(str: "zxy")
    }

通過breakpoint set -n 某函數名,來給某函數設置斷點

通過breakpoint list 打印出斷點列表

 如果想一次性來設置多個斷點,也可以使用命令

 breakpoint set -n 某函數名, -n 某函數名, -n 某函數名……

但是這樣設置就會將這幾個斷點設置為一組,與上面不一樣,一個個設置的.

breakpoint delete來刪除所有上次設置的斷點

breakpoint disable 斷點Id: 將設置過的斷點禁用,再次打印出breakpoint list 發現斷點式disable的

breakpoint set -r “字符串” 會遍歷整個工程,只要含該字符串的方法、函數都會下斷點

 

breakpoint set -f 類名 -l 斷點行數 會給該類名的具體行數加斷點 

breakpoint set -file 類名 --selector 方法名 會給該類名的具體方法加斷點

 breakpoint command add 標號 :斷點之后執行相應命令,以Done結束,類似於Edit breakpoint

總結如下:

3.2 流程控制

在Xcode調試Debugger時,經常有看到界面

 

對應的解釋和意義如下圖:

 對應的命令如下

 3.3 打印命令

p語句動態執行語句,可以查看基本數據的類型值, 如果用p命令查看的是對象的話, 只會返回對象的指針地址, p后面可以接變量、常量還可以接表達式

po語句: 打印對象的desc信息, 打印對象. 

p和po的區別在於po會輸出對應的值, p會返回返回值的類型及命令結果的引用名

expression語句: 和p語句意思是一樣的

 上面有&0,&1這樣的符號,是指對象的一個引用. 在控制台上可以用這個符號來操作對應的對象.

示例2

-(NSMutableArray<Person *> *)models{
    if (!_models) {
        //arrayWithCapacity 節約內存。容量就是真實的內存中占用的大小。
        _models = [NSMutableArray array];
    }
    return _models;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    Person * p1 = [[Person alloc] init];
    p1.name = @"one";
    p1.age = 1;
    Person * p2 = [[Person alloc] init];
    p2.name = @"two";
    p2.age = 2;
    Person * p3 = [[Person alloc] init];
    p3.name = @"three";
    p3.age = 3;
    
    [self.models addObject:p1];
    [self.models addObject:p2];
    [self.models addObject:p3];
}

 3.4 frame、bt、 up、 down

frame select 斷點排序值 

frame variable :查看參數

bt:查看堆棧

 再看示例1,點擊test1,test2,test3 。對test1設置斷點

可以通過up和down命令來查看步驟

up:向上查看

down:向下查看

 3.5 thread、target

thread info: 輸出當前的線程

thread return :不再執行下面的代碼

 

target stop-hook add -o  "frame  variable": 斷點進入之后做的操作,這里是打印參數

3.6 image指令 

 image lookup -address 查找崩潰信息

 

 image lookup -name 查看方法的來源

 

 image lookup -type 查看成員,可以查看某個類class的所有成員變量以及屬性

 總結圖如下:

 

四、ASLR

4.1 概述

ASLR(Address space layout randomization) 是一種針對緩沖區溢出的安全保護技術,通過對棧、堆、共享庫映射等線性區布局的隨機化,通過增加攻擊者預測目的預測目的地址的難度,防止攻擊者直接定位攻擊代碼位置,達到組織溢出攻擊的目的。

ASLR並不是蘋果Mac與iOS特有的,其他主流的操作系統也已經實現了ASLR。

4.2 講解

4.2.1 demo1代碼

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)eatWithObjc:(NSString *)objc {
    NSLog(@"吃到了%@",objc);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self eatWithObjc:@"小蘑菇燉雞"];
}

@end

運行App,然后利用Hopper disassembler v4查看eatWithObjc()函數的文件地址

 

然后打開MachOView查看可執行文件,pagezero為MachO首地址

 通過image list 查看功能模塊的地址,第一個為MachO地址

 

 然后我們講解一下內容,基本概念

 

 4.2.2 demo2代碼

將斷點斷在a = 20,下面找一下全局變量放的位置。打印全局常量a在內存中的地址,以及MachO可執行文件的地址

 

 將兩個地址相減,得到文件的偏移地址。0x0000000106ce8db0 - 0x0000000106ce5000 = 0x3DB0

然后打開MachOView查看

全局常量為10,找到MachOView的offset為0x3DB0,看Data LO為10,完美。

過掉斷點,發現a = 20了,再次查看內容,發現也已經為20

 

 五、Cycript

Cycript 是由Cydia創始人Saurik推出的一款腳本語言,其混合了OC、JavaScript語法的解釋器,也就意味着可以在一個命令中使用OC或者JavaScript,甚至兩者並用,能夠掛鈎正在運行的進程,能夠在運行時修改很多東西。

提到解釋器,我們來普及兩個概念

高級語言分為兩個部分,解釋型語言和編譯型語言

解釋型語言:Python:直接將源代碼放進內存里面

編譯型語言:OC:將源代碼編譯成可執行文件,運行在設備上

 

 總結

 LLDB功能是非常強大的, 上面僅僅是介紹了一些簡單常用的命令, 還可以做進一步的探索. 下一篇我們將繼續講述LLDB的高級用法的操作, 使用LLDB操作指令可是開發裝逼的一種神器, 快使用起來吧. 希望本篇博客對大家理解使用LLDB有所幫助,如果覺得還不錯,給個點贊撒!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM