iOS逆向攻防之LLDB調(diào)試

也許我們都一樣
總是想要活成什么樣
但是生活
總是告訴我們
應(yīng)該怎么活
A188E6F85A82EB64E64261B7B18ABC75.jpg

接下來上今天的干貨LLDB調(diào)試部分。日常的正向開發(fā),Xcode提供了多種快捷鍵以及快捷方式方便我們開發(fā)者進行LLDB調(diào)試,所以其中的很多操作我們都相當(dāng)熟悉了;但是這里需要說明的是,逆向開發(fā)所有的符號斷點都是無效的,你只能對著MachO文件摸索著調(diào)試,更不存在像正向開發(fā)那樣,把斷點斷到指定類的某一行的界面快捷操作,逆向開發(fā)主要使用的就是內(nèi)存斷點,所以逆向開發(fā)熟練掌握LLDB調(diào)試快捷指令是非常有必要的。下面是干貨部分內(nèi)容:

  • 簡單了解LLDB及LLDB斷點設(shè)置
  • LLDB執(zhí)行代碼
  • 查看函數(shù)調(diào)用棧
  • 內(nèi)存斷點
  • 斷點添加command
  • target stop-hook

一、簡單了解LLDB及LLDB斷點設(shè)置


1、了解LLDB
LLDB(Low Level Debug)是默認內(nèi)置于Xcode中的輕量級動態(tài)調(diào)試工具。標準的LLDB提供了一組廣泛的命令,旨在與老版本的GDB命令兼容。除了使用標準配置外,還可以很容易地自定義LLDB以滿足實際需要。

2、LLDB斷點設(shè)置命令

  • 設(shè)置斷點
    • $breakpoint set -n XXX (set 是子命令, -n是選項,是--name的縮寫)

    • $b -n XXX 是上面的縮寫,breakpoint 可以縮寫成break,部分情況下直接縮寫成b也是可以的

    • $breakpoint set --selector XXX(此處XXX詳細解釋:如果設(shè)置函數(shù)斷點,這里就是函數(shù)或者方法名;如果方法或者函數(shù)有入?yún)ⅲ枰由厦疤?,比?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:
  • 繼續(xù)執(zhí)行

    • $continue 簡寫 c
  • 單步運行,將子函數(shù)當(dāng)做整體一步執(zhí)行

    • $next 簡寫 n
  • 單步運行,遇到子函數(shù)會進去

    • $s
  • stop-hook

    • 讓你在每次stop的時候去執(zhí)行一些命令,針對breakpoint 和 watchpoint
  • 其他命令

    • image list
    • p (expression的簡寫)
    • b -[xxx xxx]
    • x
    • register read
    • po (expression -O的簡寫, 其中 -O代表Object description,就是輸出對象的description方法,相當(dāng)于NSLog)
    • help(help可以查看所有指令意思,也可以help+xxx查看指定LLDB指令的意思)

3、LLDB設(shè)置斷點后的信息解釋

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

詳細解釋就是

  • Breakpoint 1 -> 代表斷點第1組,斷點的組數(shù),一組里面可以有多個斷點

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

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

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

如果我們想要設(shè)置方法斷點,比如斷在ViewDidLoad中,可以設(shè)置如下

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

在一組斷點中一次性設(shè)置多個斷點可以這樣,函數(shù)有入?yún)⒌挠浀眉由厦疤?:'哦

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

下完斷點的結(jié)果解釋:

(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 

比如你只想禁用第一組的第一個,可以這樣設(shè)置,結(jié)果同理

(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執(zhí)行代碼


LLDB的 p 指令是可以執(zhí)行代碼的。在斷點中執(zhí)行修改背景色的代碼,然后 c 指令執(zhí)行

(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

可以看出視圖的背景色就變成了紅色;這樣就可以實時調(diào)試執(zhí)行代碼

比如往數(shù)據(jù)源中添加一個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) 

三、查看函數(shù)調(diào)用棧


先來介紹一些指令

  • bt 查看函數(shù)調(diào)用棧
  • frame select X 查看棧中的指定組,比如frame select 1
  • frame variable 查看變量
  • $thread return 回滾到上面一步操作,然后直接return,不會再執(zhí)行后面的代碼了

實戰(zhàn)演練

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

四、內(nèi)存斷點


以上所有設(shè)置斷點方式只針對正向開發(fā),逆向的時候只有一個MachO文件是沒有任何符號的,所以上面所說的斷點方式在逆向中全部無效。

逆向中使用的是內(nèi)存斷點:

  • $watchpoint
  • $watchpoint set expression XXX(此處XXX是0x開頭的內(nèi)存地址,因為逆向一般是拿不到變量名的)

這個和breakpoint的使用方式類似

比如VC里面有這樣依據(jù)代碼

- (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";
}

使用內(nèi)存斷點能獲取到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命令查看完整的觸發(fā)調(diào)用堆棧信息,可以看出是touchBegin觸發(fā)的。

(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/我愛學(xué)習(xí)/iOS進階作業(yè)/3、安全攻防作業(yè)文件夾/6、Mach-O/20191016-應(yīng)用安全-第六講-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就可以結(jié)束命令

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文件,所以這些全局命令可以直接寫在這個文件里面,如果沒有這個文件,可以自己創(chuàng)建一個同名的,這樣以來,相當(dāng)于只要在這個電腦上都可以使用,一勞永逸哦~

進入隱藏文件夾,然后創(chuàng)建或者編輯這個文件內(nèi)容就可以全局配置了!

$ls -a 
$vi .lldbinit

好了,今天的LLDB就到這里睡了睡了狗命要緊

-END-

溪浣雙鯉的技術(shù)摸爬滾打之路

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

相關(guān)閱讀更多精彩內(nèi)容

  • ??LLDB的Xcode默認的調(diào)試器,它與LLVM編譯器一起,帶給我們更豐富的流程控制和數(shù)據(jù)檢測的調(diào)試功能。平時用...
    Thinkdifferents閱讀 1,951評論 1 4
  • iOS調(diào)試之LLDB Xcode內(nèi)嵌了LLDB控制臺,在Xcode代碼編輯區(qū)的下方。shift + cmd + y...
    comst閱讀 1,662評論 0 3
  • 前言LLDB是我們平時調(diào)試中使用最多的工具之一,p或者po是使用最多的指令。除了p和po之外,還有什么指令可以使用...
    Hanfank閱讀 1,909評論 7 10
  • [轉(zhuǎn)]淺談LLDB調(diào)試器文章來源于:http://www.cocoachina.com/ios/20150126/...
    loveobjc閱讀 2,728評論 2 6
  • [TOC] MachO文件結(jié)構(gòu) 單個架構(gòu)的mach-O文件包含:MachO Header、Load Command...
    _順_1896閱讀 505評論 0 0

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