iOS逆向 玩轉LLDB調試

歡迎閱讀iOS逆向系列(按序閱讀食用效果更加)html

寫在前面

平常開發中常常會用到LLDB調試,可能用的最多的命令就是po,而在逆向領域中根本不可能讓你在代碼中下斷點調試,因而乎LLDB就成了很是重要的手段express

1、LLDB

LLDB(Low Lever Debug)的縮寫,是默認內置於XCode的動態調試工具,它與LLVM編譯器一塊兒,存在於主窗口底部的控制檯中,可以帶給咱們更豐富的流程控制和數據檢測的調試功能sass

標準的LLDB提供了一組普遍的命令,旨在與老版本的GDB命令兼容。除了使用標準配置外,還能夠很容易的自定義LLDB以知足實際須要安全

2、LLDB命令

1. LLDB語法

<command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument[argument...]]
複製代碼
  • <command>(命令)和<subcommand>(子命令):LLDB調試命令的名稱
  • <action>:執行命令的操做
  • <options>:命令選項
  • <arguement>:命令的參數
  • []:表示命令是可選的,能夠有也能夠沒有

好比breakpoint set -n testbash

  • command:breakpoint表示斷點命令
  • action:set表示設置斷點
  • option:-n表示根據方法name設置斷點
  • arguement:test表示方法名爲test

2. LLDB初級使用

LLDB命令都是在進入LLDB狀態(運行狀態下點擊「暫停符號」)才能使用生效的 微信

  • 查看斷點列表
    • where是斷點所在處
    • address是斷點地址
    • option disable斷點被禁用
(lldb) breakpoint list
複製代碼

  • 設置單個斷點
// 設置c函數的斷點
(lldb) breakpoint set -n cMethod
// 設置oc函數的斷點
(lldb) breakpoint set -n "[ViewController ocMethod1]"
複製代碼

  • 設置一組斷點
(lldb) breakpoint set -n "[ViewController ocMethod1]" -n "[ViewController ocMethod2]" -n "[ViewController ocMethod3]"
複製代碼

  • 禁用/啓用某一組斷點
// 禁用
(lldb) breakpoint disable 1
// 啓用
(lldb) breakpoint enable 1
複製代碼

  • 禁用/啓用某一個斷點
// 禁用
(lldb) breakpoint disable 1.1
// 啓用
(lldb) breakpoint enable 1.1
複製代碼

  • 刪除全部斷點
(lldb) breakpoint delete
複製代碼

  • "刪除"某一組斷點(不能刪除單個斷點,只能禁用單個斷點)
(lldb) breakpoint delete 1.1
複製代碼

  • 設置某一個方法的斷點
(lldb) breakpoint set --selector touchesBegan:withEvent:
複製代碼

  • 設置某文件下某一個方法的斷點
(lldb) breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
複製代碼

  • 設置全部匹配方法名的斷點
(lldb) breakpoint set -r ocMethod
複製代碼

  • 退出LLDB模式
(lldb) c
複製代碼

  • 查看幫助
// 查看LLDB指令幫助
(lldb) breakpoint help
// 查看LLDB的breakpoint幫助
(lldb) breakpoint help
複製代碼

3. LLDB初級使用小結

  • 手動打下的斷點也會出如今LLDB的斷點列表中,但LLDB的斷點不會出如今Xcode的斷點列表處
  • 手動打下的斷點能夠經過單擊/長按來禁用/取消斷點,也能夠經過LLDB命令來操做,但LLDB下的斷點只能經過LLDB來操做
  • 刪除的斷點雖然不在列表中,可是新增斷點會從先前的斷點以後排序
命令 意義 簡寫
breakpoint list 查看斷點列表 breakpoint l
breakpoint set -n cMethod 設置單個斷點 b -n cMethod
breakpoint set -n "[ViewController ocMethod1]"
-n "[ViewController ocMethod2]"
設置一組斷點 b -n "[ViewController ocMethod1]"
-n "[ViewController ocMethod2]"
breakpoint set --selector touchesBegan:withEvent: 設置某一個方法的斷點 b -selector touchesBegan:withEvent:
breakpoint set --file ViewController.m --selector touchesBegan:withEvent: 設置某文件下某一個方法的斷點 b -f ViewController.m --selector touchesBegan:withEvent:
breakpoint set -r ocMethod 設置全部匹配方法名的斷點 b -r ocMethod
breakpoint enable 1 啓用某一組斷點 breakpoint en 1
breakpoint disable 1 禁用某一組斷點 breakpoint dis 1
breakpoint enable 1.1 啓用某一個斷點 breakpoint en 1.1
breakpoint disable 1.1 禁用某一個斷點 breakpoint dis 1.1
breakpoint delete 刪除全部斷點 breakpoint d
continue 退出LLDB模式 c
next 單步運行,將子函數當作總體一塊兒執行 n
stpe 單步運行,將子函數當作總體一塊兒執行 s

關於簡寫:dom

  • bbreakpoint set
  • llist
  • -n--name
  • --f--file
  • disdisable
  • enenable

3、LLDB執行代碼

前文中提到關於開發中最經常使用的po指令,在LLDB中並非print -out的意思,實際上是expression --object-函數

  • p:做爲expression的縮寫,意指表達執行的意思
  • o:則是object的縮寫(經過help expression查看指令)
  • po:執行對象——輸出該對象的信息

既然知道了p指令有執行代碼的做用,接下來就來玩一下工具

  • 動態修改背景顏色(筆者在machOS 10.15.5+Xcode11上並不能成功)post

    1. 進入手動斷點(不要點擊暫停符號,否則不能獲取到self)
    2. 控制檯輸入p self.view.backgroundColor = [UIColor redColor];
    3. 過掉斷點就能看到效果了
  • 動態建立對象並賦值

    1. 設置一個全局變量FXPerson *p
    2. 一樣進入手動斷點
    3. 控制檯輸入p self.p = [FXPerson new]; self.p.name = @"Felix";
    4. 查看效果

4、函數調用棧

接下來在如下代碼中進行調試,點擊屏幕依次調用testtest1test2,在test2處打下斷點

- (void)testWithStr:(NSString *)str {
    NSLog(@"test");
    [self test1WithStr:str];
}

- (void)test1WithStr:(NSString *)str {
    NSLog(@"test1");
    [self test2WithStr:str];
}

- (void)test2WithStr:(NSString *)str {
    NSLog(@"test2");
    NSLog(@"%@", str);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self testWithStr:@"test"];
}
複製代碼
  1. bt——查看函數調用棧,可以看到函數調用的順序

  2. up/down——上下挪動函數調用

  3. frame select 數字——跳轉函數調用(0表示當前方法,2表示2個方法前)

  4. frame variable——查看當前函數屬性:內存地址、方法名、參數

  5. thread return——結束當前函數調用,跳轉回上一個調用棧的下一步(當前是跳轉回第30行代碼,準備執行31行代碼)

由此,能夠嘗試在調用中修改參數的值從而完成新值打印

  1. up修改已經調用過的函數參數

    • 使用up指令回到上一步,使用p str = @"F";進行修改
    • 過掉斷點,仍是打印原來的值
  2. 提早修改函數參數

    • 提早在上一處函數調用時打下斷點進行修改
    • 過掉斷點,新值被打印

總結:已經執行過的代碼再怎麼回滾也不能隨意修改值,應當提早打下斷點進行修改

5、內存斷點

內存斷點,顧名思義就是給內存下的斷點

經過 watchpoint set variable self->_p->_name就能夠給對應的屬性內存下斷點

  • addr:內存地址
  • size:所佔內存字節
  • state:當前是否可用

修改內存地址的值就會來到斷點處(此時至關於KVO機制)同時也能看到函數調用棧

  • 內存斷點也能夠經過watchpoint list來查看內存斷電列表
  • 也能夠經過watchpoint delete進行刪除

6、斷點添加命令

相似於給程序添加腳本命令,斷點執行也能夠添加命令

  • 經過breakpoint command add 1就能夠給指定斷點添加命令
  • 經過DONE結束斷點命令添加

斷點到來時就會執行先前的命令了

7、target stop-hook

target stop-hook是一個給全部斷點添加命令的指令——在每次stop的時候去執行一些命令(只對breakpoint、watchpoint有效)

只要target stop-hook add操做一番,任何斷點都會觸發添加的命令

單條命令能夠簡寫成target stop-hook add -o "frame variable"-o表示單條命令)

一樣的,也可使用target stop-hook list查看列表

target stop-hook disable進行禁用

target stop-hook delete/undisplay 1進行禁用

接下來介紹一個高階的操做

LLDB啓動的時候就會去加載一個叫作.lldbinit的文件,在/Users/用戶名目錄下

若是沒有的話能夠經過vi .lldbinit建立,而後在文件中添加命令target stop-hook add -o "frame variable"

從新啓動運行Xcode.lldbinit文件中的命令就會被加載,是個很方便的調試手段!

8、ASLR

ASLR(Address space layout randomization)全稱叫作地址空間配置隨機加載,是一種防範內存損壞漏洞被利用的計算機安全技術,在各大平臺都有應用

ASLR經過隨機放置進程關鍵數據區域的地址空間來防止攻擊者能可靠地跳轉到內存的特定位置來利用函數

說得簡單易懂些就是物理地址 = ASLR + 虛擬地址

接下來經過實例來了解一下這個傢伙吧

- (void)fxTest {
    NSLog(@"%s", __func__);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self fxTest];
}
複製代碼

cmd+B編譯生成MachO文件,使用Hopper打開,找到fxTest方法

此時拿到了「內存地址」就能夠打下內存斷點來進行調試了,其實0x1340只是個虛擬地址——只是相對於MachO文件的偏移地址(前面的1表示空段,對地址沒有任何影響)

剛纔說了物理地址 = ASLR + 虛擬地址,那麼此時的ASLR又是多少呢?

經過image list就能夠打印出來——0x000000010301e000就是這個進程的ASLR(看過dlyd源碼就知道每次運行這個ASLR值都不相同)

實際地址 = 0x000000010ae85000 + 0x1340 = 0x10AE86340

寫在後面

LLDB這些指令如同Xcode的快捷鍵通常,不掌握也無妨,掌握了就是錦上添花,多了一種調試的思路,便能讓你拉開與同行之間的差距

相關文章
相關標籤/搜索