LLDB命令簡單介紹

簡介

LLDB是Low Lever Debugger的簡稱,翻譯成中文應該叫作底層調試器,它是LLVM項目的調試器組件。LLVM是構架編譯器(compiler)的框架系統,以C++編寫而成,用於優化以任意程序語言編寫的程序的編譯時間(compile-time)、連接時間(link-time)、運行時間(run-time)以及空閒時間(idle-time),對開發者保持開放,併兼容已有腳本。若是你瞭解過Swift語言及其做者,那麼必定對Chris Lattner博士不陌生,那這裏爲何要提到他呢?沒錯LLVM開發最初就是由Chris Lattner博士主持開展的。html

LLDB支持調試C、Objective-C和C++編寫的程序。Swift社區維護了一個版本,增長了對該語言的支持。默認內置於Xcode中,LLDB提供了一組普遍的命令,旨在與老版本的GDB命令兼容。除了使用標準配置之外,還能夠很容易的自定義LLDB命令以知足實際須要。能夠在Xcode的控制器進入lldb調試模式後,輸入help能夠查看全部Debugger commands,也能夠在這個網站查詢 image.pngexpress

breakpoint命令

斷點命令,在平時使用Xcode開發的過程當中,咱們設置斷點通常都是經過在界面上點擊代碼所在的行數設置的。其實也可使用lldb的命令來設置斷點。數組

根據名字設置斷點

設置C函數名斷點

image.png 在touchedBegan方法中,咱們從界面設置了一個斷點,進入了lldb調試模式,再輸入如下命令設置函數斷點:
breakpoint set -n "test1",-n是--name的縮寫,而後點擊繼續按鈕,或者輸入lldb命令c繼續執行,能夠看到其實Xcode集成的不少的調試功能就是從lldb這來的。調試下一步就在lldb輸入n或者s,n遇到子函數不會進入,s遇到子函數會進入。安全

設置OC方法名斷點

先搭建個如圖所示的簡單界面 image.png 而後暫停程序,在控制檯輸入以下命令:
breakpoint set -n "-[ViewController save:]" -n "-[ViewController pause:]" -n "-[ViewController continue:]"
這樣就設置了一組斷點,它有三個斷點。可使用如下命令查看當前全部斷點:
breakpoint list image.pngmarkdown

禁用和啓用斷點

禁用斷點,後面的數字是breakpoint list顯示的編號,能夠同時禁用1組,也能夠單獨禁用組裏的某個 breakpoint disable 編號 image.png 啓用斷點breakpoint enalbe 編號 image.png框架

刪除斷點

刪除斷點breakpoint delete 編號,這裏有個小細節,咱們沒法刪除一組斷點裏面的某一個,只能刪除一整組斷點。若是delete後面跟的是某個組裏面的某個斷點,等同於禁用這個斷點。若是不輸入編號,那就至關於刪除全部斷點 image.png函數

根據方法設置斷點

剛剛咱們設置的斷點,是某個類的某些具體方法,咱們也能夠設置與類無關的方法斷點:
breakpoint set --selector touchesBegan:withEvent: image.png 能夠看到設置了98個斷點,但咱們的項目中沒有明顯調用這個方法,實際上是系統庫UIKit中用到了這個方法,lldb斷到系統庫裏面去了,可使用breakpoint list查看全部98個斷點oop

若是不想這樣把斷點斷到系統庫裏面去,能夠指定文件設置方法斷點,咱們在ViewController里加上touchesBegan:方法:
breakpoint set --file ViewController.m --selector touchesBegan:withEvent: image.png優化

正則匹配設置斷點

能夠輸入help breakpoint set看到-r參數的介紹網站

Set the breakpoint by function name, evaluating a regular-expression to find the function name(s).
複製代碼

breakpoint set -r save:這樣就會根據-r後面的參數去尋找全部能匹配到的方法 image.png 咱們明明只有在ViewController裏面有一個save:方法,爲何顯示有11處斷點呢,使用breakpoint list查看 image.png 能夠看到除了第一個是咱們工程裏面的斷點,其餘的斷點都不在咱們的工程裏。都斷到系統庫裏去了。

一樣的,咱們能夠配合指定文件來使用這個命令 breakpoint set -r save: --file ViewController.m

斷點執行命令

breakpoint command add 編號能夠給斷點加一些命令,這樣斷點來到的時候,能夠自動執行這些命令,可否爲咱們節省一些操做 image.png

以上這些全部的lldb命令,均可以縮寫,好比:
breakpoint set -r save: --file ViewController.m能夠縮寫成b -r save: -f ViewController.m
breakpoint list能夠縮寫成break li
breakpoint disable 8.1能夠縮寫成bre dis 8.1
breakpoint enable 8.1能夠縮寫成bre en 8.1
反正你能夠去各類嘗試,多一個少一個字母或許都能行,比較隨意,比起普通的命令錯一個字符都不行仍是蠻牛逼的。

expression命令

咱們平時在lldb控制檯裏面乾的最多的是什麼?po打印某個對象吧,那麼這個po究竟是什麼意思呢?能夠在終端輸入以下命令查看一下: help po image.png 其實咱們平時使用最多的po指令就是expression -O指令的縮寫。也有人喜歡用p打印,那麼p又是什麼呢,輸入help p發現p就是expression指令的縮寫,直接查看help expression能夠查看到-O的意思,就是指定語言的description方法,因此咱們平時使用poOC對象,就是執行OC對象的description方法。

經過help po咱們知道就是在主線程執行表達式,那麼咱們能夠試試在lldb中修改一些常見的屬性,好比self.view.backgroundColor,首先來到touchesBegan:斷點,在lldb輸入以下指令
p self.view.backgroundColor = [UIColor redColor];
image.png 發現確實執行了這句代碼,可是卻報了一個讓人疑惑的錯誤,並且過掉斷點以後並無任何效果,固然了明明執行都報錯了,怎麼可能會有效果呢。。。可是這一行代碼,在程序中運行的話,確定是沒有問題的,咱們查看UIView的頭文件也能夠發現它肯定是有backgroundColor這個屬性的。至於爲何我在網上搜索半天沒有找到任何答案,感受多是lldb的bug?雖然這句代碼無效,可是咱們依然能夠嘗試使用其餘的方式來修改,好比:
p [self.view setValue:[UIColor blueColor] forKey:@"backgroundColor"] image.png KVC仍是牛逼啊,還有一種辦法,咱們知道UIView真正用來顯示的是它的layer,修改layer:
p self.view.layer.backgroundColor = [UIColor yellowColor].CGColor image.png

再來一個案例,我麼建立一個persons數組,存放一組Person模型,而後經過lldb的expression命令動態添加一個Person。 image.png 能夠看到lldb的expression命令後面能夠跟多條代碼,用來動態調試真是太方便了

bt命令

進入lldb輸入help bt能夠看到,bt是查看當前線程調用棧的意思 image.png

新建如下這四個方法,並給demo4方法下個斷點,而後點擊屏幕進入斷點 image.png 輸入bt能夠看到當前方法的調用棧 image.png 輸入up能夠查看調用的上一個方法,連源碼都能看到,固然在逆向中是看不到源碼的,只能看到彙編代碼,輸入down能夠返回到下一個方法 image.png 若是嫌一步一步的up,down太慢了,也能夠直接使用frame select 編號直接到位 image.png 這樣上下切換棧幀是爲何呢,固然是爲了查看當前棧的一些信息,好比當前棧用到的變量,使用frame variable查看,咱們知道OC方法有兩個隱藏的參數self和_cmd,event就是demo1的顯示參數,若是不知道frame variable是什麼意思,也能夠經過lldb的幫助文檔查看help frame variable image.png

thread return 命令

當咱們調試到某一幀的時候,若是不想讓程序以後的代碼,可使用thread return線程返回,須要注意return後面根據實際狀況返回對應的值,例如: image.png 若是沒有使用thread return NO命令,那麼確定是打印正在運行的,當斷點來到isRuning的時候,咱們強制返回了NO,因此在調試過程當中改變了程序的執行流程

以上全部方式在逆向中都無法使用。。。由於逆向的項目咱們都拿不到符號

那麼逆向應該如何玩lldb?內存斷點

watchpoint 內存斷點

內存斷點,不只能夠給方法斷點,還能夠給變量斷點

watchpoint 根據變量名設置內存斷點

watchpoint set variable p1->_name如圖所示,Person類有一個name屬性,可是咱們設置內存斷點的時候,屬性是無法用的,由於屬性的本質是getter和setter加下劃線的成員變量嘛,因此須要使用p1->_name設置成功以後,當程序中有給p1.name賦值的地方,都會來到斷點。下圖立刻給p1.name賦值lldb就提示Watchpoint 1 hit命中了。而後還會顯示old value和new value image.png

watchpoint 根據內存地址設置內存斷點

watchpoint set expression 地址 仍是剛剛的例子,咱們在p1實例化以後,它在內存中的地址就肯定了,那麼它的成員變量的地址也是肯定的,咱們能夠拿到p1.name的內存地址,根據它的內存地址設置斷點。當程序對p1.name進行修改的時候,都會來到斷點,能夠看到下面的斷點來了兩次,一次是在viewDidload中,另外一次在touchesBegan裏面進行的修改 image.png

target stop-hook 命令

這個命令有點相似breakpoint的斷點執行命令,只不過breakpoint的斷點執行命令須要指定某個斷點,而這個命令是全局的,只要是斷點來了,就會執行後面的命令 image.png 經過log能夠看到stop-hook命令同樣能夠add,delte,disable,enable,list,具體每條命令怎麼使用,能夠繼續使用help命令查看,好比add,幫助文檔很詳細 image.png 咱們這裏全局添加一條frame variable指令,而後走到斷點試試 image.png 能夠看到斷點一過來就會自動執行frame variable指令,打印參數變量 image.png 這裏關於刪除stop-hook指令,它還有一個快捷的命令undisplay 編號相比target stop-hook delete 編號要簡短很多

.lldbinit文件

能夠將一些常用的命令配置到.lldbinit文件裏面,這樣就不用每次都去添加一些命令。這個文件通常放在用戶目錄下,點開頭的表明是隱藏文件,若是沒有能夠本身新建一個。如圖咱們在裏面添加這樣一句指令 image.png 再次運行項目,運行到斷點就能夠看到相關打印 image.png

image 指令

這個是查看當前進程加載的鏡像相關信息,什麼是鏡像,一個Mach-O文件就是一個鏡像。咱們的APP也是一個鏡像。咱們先來查看一下咱們APP中的某個類的信息

image look up -t name

image.png

image list

輸入help image list查看命令的介紹 image.png 能夠看到image list意思是列出當前可執行文件和依賴的共享庫鏡像,在逆向中常用這個命令來獲取咱們APP在內存中的位置。

逆向中下內存地址斷點

如圖咱們在touchesBegan:方法中調用了demo4方法 image.png 如今咱們將APP的Mach-O文件用hopper打開,假設對咱們的demo4方法很感興趣,想要下一個斷點。 image.png hopper這裏的地址只是這個方法相對於咱們的APP首地址的偏移加上了虛擬地址,想要獲取到這個方法在咱們手機裏的真實內存地址,還須要加上咱們APP首地址在咱們內存中的地址。經過image list命令查看第一個就是咱們APP的首地址了。 image.png 虛擬地址在咱們Mach-O文件的__PAGEZERO段能夠看到 image.png 那麼這個方法在咱們手機內存中的地址就是:
0x102964000 + 0x100005b8c - 0x100000000 = 0x102969B8C
咱們進入lldb模式,輸入如下內存地址斷點 breakpoint set --address 0x102969B8C image.png 斷點設置成功,而後咱們推出lldb模式,點擊屏幕,會發現斷點果真來了 image.png

這裏提一下ASLR,是一種防範內存損壞漏洞被利用的計算機安全技術,就是咱們的APP每次加載進手機的真實內存的時候,位置不是固定的,因此咱們每次APP運行起來後經過image list看到的咱們APP的首地址是隨機的。

咱們APP的Mach-O文件中的內容,相對於Mach-O文件的首地址來講都是固定不變的,APP加載進內存以後首地址就肯定了,那麼Mach-O文件中的內容,好比方法實現,函數實現,常量等數據在內存中的位置均可以找到了。。。

能夠在ViewController.m文件中定義一個全局變量,而後咱們在Mach-O文件看可否找到它。如圖定義一個全局變量,而後運行起來以後,打印它所在的地址,和當前APP的首地址,它的地址減去APP的首地址就是它相對於咱們APP的Mach-O文件的偏移了。 Snip20210713_167.png 0x102b959f0 - 0x102b8c000 = 0x99F0
在使用MachOView查看咱們APP的Mach-O文件,找到地址0x99F0,看看是否是這個a的值0x123456678 image.png 有些同窗可能會好奇,這個怎麼是這個樣子,其實這是由於機器的存取數據方式決定的,有些是大端模式,而有些機器是小端模式,這裏貼一下百度的大小端模式

從這裏也能夠看出咱們的全局變量是存放在__DATA,__data節的。

相關文章
相關標籤/搜索