在進入逆向正式實戰以前 , 動態調試和靜態分析都是咱們必不可少的能力 .面試
LLDB
是無論在正向開發仍是逆向開發中 , 都是幫助咱們調試必不可少的手段 . 而在逆向開發中不能像正向開發同樣頁面斷點 , 可視化數據展現 , 源代碼調試等方式的狀況下 , LLDB
的做用就會尤爲重要 .express
考慮到並非全部同窗都會親自建一個工程來實戰演練一下 LLDB
, 本篇文章我會結合實戰來介紹 LLDB
經常使用指令的實際效果 , 以此來更好地理解和記憶 LLDB
( 畢竟面試仍是常常會問到的 ) , 熟悉的同窗能夠自行跳過 .vim
另外筆者寫指令時會盡可能寫全 , 全稱指令有助於理解 , 而且之後再換爲簡寫也很簡單 , 反過來就不行了 . 所以大佬勿噴 . bash
默認內置於
Xcode
中的動態調試工具。標準的LLDB
提供了一組普遍的命令,旨在與老版本的GDB
命令兼容。 除了使用標準配置外,還能夠很容易地自定義LLDB
以知足實際須要。函數
help
help
能夠查看某一條指令的說明 : breakpoint help
.
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"touch screen");
testFunc();
}
void testFunc(){
printf("testFunc");
}
- (IBAction)btnAction1:(id)sender {
}
- (IBAction)btnAction2:(id)sender {
}
- (IBAction)btnAction3:(id)sender {
}
@end
複製代碼
continue
, 簡寫爲 c
.step
, 簡寫爲 s
, 遇到嵌套子函數會進去.next
, 簡寫爲 n
, 遇到嵌套子函數會當作總體一步執行 .指令 : breakpoint list
, 簡寫爲 b l
工具
( 咱們在 Xcode
可視化加的斷點也能夠被查看到 , 由於自己都在寄存器中 ) .ui
指令 : breakpoint set --name testFunc
atom
結果 : spa
說明 :線程
該指令直接經過方法名稱下斷點 . --name
可簡寫爲 -n
查看斷點 :
結果驗證 : continue 過掉斷點 , 點擊屏幕 , 來到咱們下的斷點 .
指令 :
breakpoint set --name "-[ViewController btnAction1:]" --name "-[ViewController btnAction2:]" --name "-[ViewController btnAction3:]"
複製代碼
結果 :
說明 :
該指令直接經過一次添加多個方法名稱下斷點 . --name
可簡寫爲 -n
, 添加結果是一組斷點 , 可是爲多個位置 .
查看斷點 :
指令 : breakpoint disable 5
/ breakpoint enable 5
結果 :
說明 :
經過 breakpoint list
先查看斷點 ID
, 而後禁用或者啓用某一個或者某一組斷點.
查看斷點 :
指令 : breakpoint set --selector touchesBegan:withEvent:
結果 :
說明 :
經過 selector
添加斷點 , 不侷限於某個類 , 當再添加 --file
指令時 , 會具體到該類中尋找這個 sel
下斷點 .
例: breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
查看斷點 :
指令 : breakpoint set --func-regex btnActi
結果 :
說明 :
selector
添加斷點 , 可是並不是是模糊搜索的模式 , 用的正則來處理的 , 所以輸入的名稱不能錯 , 只能是未寫完 .--file
指令來針對某個類處理 查看斷點 :
指令 : breakpoint delete 10
結果 :
說明 :
不傳斷點 ID
則爲刪除全部斷點 , 會提示確認操做.
查看斷點 :
LLDB
指令對斷點作的操做與Xcode
可視化頁面中對斷點所作的添加 / 刪除 / 禁用 / 啓用 操做都是同步的.當刪除斷點時 , 不能刪除某一組中的一個 , 刪除會變成
disable
, 只能刪除組
breakpoint set
可直接簡寫爲b
breakpoint list
可簡寫爲break l
,breakpoint disable
可簡寫爲break dis
等等以此類推 , 能夠簡寫到只要系統能夠區分你到底敲的是哪一條命令均可以
指令 : expression self.view.subviews
, 簡寫 p
結果 :
說明 :
p
爲 expression
的簡寫 , 並不是不少同窗理解的 print
哦 , po
是 expression -O
( --object-description
NSObject
的 description
方法 ) 的簡寫.
使用舉例 :
p self.view.backgroundColor = [UIColor orangeColor];
c
一樣的 , p
能夠寫多句代碼 , 使用 ;
便可 . 該方法經常使用與逆向中 Cycript
檢查是不是咱們要找的 view
.
thread backtrace
, 簡寫 bt
,bt 3
up / down
方法能夠跳轉到 前一個
/ 後一個
方法中 frame select 5
也能夠直接經過編號跳轉對應方法frame variable
能夠查看方法參數
thread return
能夠線程回滾 , 並且能夠修改參數 , 可是執行完該函數會直接 return
.還有一些其餘的指令這裏就不一一列舉了 , 經過 help
指令能夠查看自行練習.
image list
image lookup -t LBPerson
剛剛咱們看了不少斷點調試指令 , 那麼逆向過程當中呢 ? 咱們並無源碼 , 結果就是 : 不少經過方法名稱下斷點等方式都不能用 😶 .
爲何 ?
release
模式的狀況下 , 符號是會被編譯器自動去掉的 .怎麼辦 ?
#import "ViewController.h"
@interface LBPerson : NSObject
@property(nonatomic , assign) int age;
@property(nonatomic , copy) NSString * name;
@end
@implementation LBPerson
@end
@interface ViewController ()
@property(nonatomic, strong) LBPerson * person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[LBPerson alloc] init];
self.person.age = 20;
self.person.name = @"lb";
NSLog(@"haha");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.person.name = @"test";
}
複製代碼
在 NSLog
處加個斷點 , 運行 .
來到斷點後輸入指令 : watchpoint set variable self->_person->_name
過掉斷點 . 點擊屏幕 , 修改了 person
的 name
, 監控到內存斷點 , 並打印以下 :
Watchpoint 1 hit:
old value: 0x0000000107f72078
new value: 0x0000000107f720b8
複製代碼
查看內容 .
經過函數調用棧能夠看到實際上是在屬性的set
方法時調用的 .
逆向中咱們每每只有內存地址 , 甚至不必定拿獲得變量或者屬性 . 那麼就須要經過內存地址下斷點 .
一樣剛剛的代碼 , 從新運行來到 NSLog
斷點.
p
查看 name
內存地址 , p &self->_person->_name
watchpoint set expression 0x0000600000db2f70
同上述 breakpoint
, 很少贅述.
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"touch screen");
[self test];
}
- (void)test{
NSLog(@"Add Command test");
}
複製代碼
testFunc
添加斷點指令 : b testFunc
指令 : breakpoint command add 1
輸入 :
>po self
>p self.view.backgroundColor = [UIColor orangeColor];
>DONE
複製代碼
過掉斷點 , 點擊屏幕.
再過掉斷點 , 查看頁面 .
這種方法適用場景較多 , 例如某個斷點一斷住就查看形參 等等 , 自由發揮 .
breakpoint command list 1
breakpoint command list 1
指令 : target stop-hook add --one "frame variable"
說明 :
--one
表明添加一條指令 , 可簡寫爲-o
- 可視化頁面中
Pause paogram execution
以及Debug view
不屬於stop
範疇.
結果: 在 TouchBegan
添加一個斷點 , 點擊屏幕 , 打印以下 :
相較於上一個 特定斷點添加指令 , 顯然是更通用 .
那麼一樣 , 查看斷點指令列表 : target stop-hook list
target stop-hook delete
, 使用
undisplay 1
, 也是同樣的 .
禁用
/
啓用
同理 .
以上咱們說的這些 , 創建在工程運行起來以後 , 進入 lldb
模式 , 添加指令等操做的前提下 . 那麼咱們思考一個問題 , 每次運行工程都要從新添加 , 能否自動處理呢 ?
答案是確定的 .
打開 終端
/ iTerm2
. 來到家目錄下 , ls -a
查看文件.
.lldbinit
文件 , 直接 vim
添加 target stop-hook add -o "frame variable"
.target stop-hook add -o "frame variable"
.來到工程中 , 從新 run
一下 , 點擊屏幕方法添加一個斷點 , 點擊屏幕 :
其緣由是
lldb
在啓動時會加載這個文件 , 對每一個工程都有效 .
最後簡單說一下逆向過程當中如何下一個內存斷點
MachOView
/ Hopper
, 找到方法地址 , 減去 PageZero
的虛擬內存 (也就是最前面的那個 1
, / 64 位下是 4 個 G, ) 獲得方法基於 Mach-O
首地址的真實偏移地址.lldb
查看 Mach-O
地址 .這個是因爲 ASLR 的緣由 . 說白了就是地址空間配置隨機加載 , 所以咱們須要在加載完後再獲取 Mach-O
的地址便可.
物理地址 = ALSR + 虛擬地址