如今,讀者可以找到許多關(guān)于匯編的書籍,甚至可以找到更多有關(guān)ELF和PE二進(jìn)制格式的說明。關(guān)于信息流跟蹤和符號執(zhí)行也有大量的文章。但是,沒有哪本書可以向讀者展示從理解基本匯編知識到進(jìn)行高級二進(jìn)制分析的全過程。也沒有哪本書可以向讀者展示如何插樁二進(jìn)制程序、如何使用動態(tài)污點分析來跟蹤程序執(zhí)行過程中的數(shù)據(jù)或使用符號執(zhí)行來自動生成漏洞利用程序。換句話說,直到現(xiàn)在,沒有一本書可以教你二進(jìn)制分析所需的技術(shù)、工具和思維方式。
1.本書面向安全工程師,對二進(jìn)制分析和插樁等方向的一些有趣問題進(jìn)行了介紹,幫助讀者提升二進(jìn)制分析技術(shù)。
2.本書各章后面的練習(xí)有助于讀者深入掌握相關(guān)知識,無論是基本的匯編知識,還是復(fù)雜的二進(jìn)制插樁及分析實踐。
3.本書內(nèi)容詳細(xì),從二進(jìn)制分析的基本概念和二進(jìn)制格式開始介紹,主要包括以下內(nèi)容:
解析ELF和PE二進(jìn)制,并基于libbfd構(gòu)建二進(jìn)制加載器;
通過代碼注入和二進(jìn)制編輯來修改ELF文件;
基于Capstone構(gòu)建自定義反匯編工具;
使用二進(jìn)制插樁來繞過常用的反分析技術(shù);
應(yīng)用污點分析來檢測控制流劫持和數(shù)據(jù)泄露;
使用符號執(zhí)行來構(gòu)建自動化利用工具。
丹尼斯·安德里斯,系統(tǒng)與網(wǎng)絡(luò)安全專業(yè)的博士,主要研究二進(jìn)制分析領(lǐng)域。丹尼斯·安德里斯是PathArmor(一個控制流完整性分析系統(tǒng),可抵抗諸如ROP這樣的控制流劫持攻擊)的主要開發(fā)人員,還是參與攻破GameOver Zeus僵尸網(wǎng)絡(luò)的主要攻手之一。
目 錄
第 一部分 二進(jìn)制格式
第 1章 二進(jìn)制簡介 2
1.1 C編譯過程 3
1.1.1 預(yù)處理階段 3
1.1.2 編譯階段 5
1.1.3 匯編階段 6
1.1.4 鏈接階段 7
1.2 符號和剝離的二進(jìn)制文件 9
1.2.1 查看符號信息 9
1.2.2 剝離二進(jìn)制文件 10
1.3 反匯編二進(jìn)制文件 11
1.3.1 查看對象文件 11
1.3.2 檢查完整的二進(jìn)制執(zhí)行體 13
1.4 加載并執(zhí)行二進(jìn)制文件 17
1.5 總結(jié) 19
1.6 練習(xí) 19
第 2章 ELF格式 20
2.1 ELF頭部 22
2.1.1 e_ident數(shù)組 22
2.1.2 e_type、e_machine及e_version字段 24
2.1.3 e_entry字段 24
2.1.4 e_phoff和e_shoff字段 25
2.1.5 e_flags字段 25
2.1.6 e_ehsize字段 25
2.1.7 e_*entsize和e_*num字段 25
2.1.8 e_shstrndx字段 26
2.2 節(jié)頭 26
2.2.1 sh_name字段 27
2.2.2 sh_type字段 28
2.2.3 sh_flags字段 28
2.2.4 sh_addr、sh_offset及sh_size字段 29
2.2.5 sh_link字段 29
2.2.6 sh_info字段 29
2.2.7 sh_addralign字段 29
2.2.8 sh_entsize字段 29
2.3 節(jié) 30
2.3.1 .init和.fini節(jié) 31
2.3.2 .text節(jié) 31
2.3.3 .bss、.data及.rodata節(jié) 33
2.3.4 延遲綁定和.plt、.got及.got.plt節(jié) 33
2.3.5 .rel.*和.rela.*節(jié) 36
2.3.6 .dynamic節(jié) 37
2.3.7 .init_array和.fini_array節(jié) 38
2.3.8 .shstrtab、.symtab、.strtab、.dynsym及.dynstr節(jié) 39
2.4 程序頭 40
2.4.1 p_type字段 41
2.4.2 p_flags字段 42
2.4.3 p_offset、p_vaddr、p_paddr、p_filesz及p_memsz字段 42
2.4.4 p_align字段 42
2.5 總結(jié) 42
2.6 練習(xí) 43
第3章 PE格式簡介 44
3.1 MS-DOS頭和MS-DOS存根 45
3.2 PE簽名、PF文件頭及PE可選頭 46
3.2.1 PE簽名 48
3.2.2 PE文件頭 48
3.2.3 PE可選頭 48
3.3 節(jié)表 49
3.4 節(jié) 49
3.4.1 .edata和.idata節(jié) 50
3.4.2 PE代碼節(jié)的填充 51
3.5 總結(jié) 51
3.6 練習(xí) 51
第4章 使用libbfd創(chuàng)建二進(jìn)制加載器 53
4.1 什么是libbfd 53
4.2 一個簡單的二進(jìn)制加載接口 54
4.2.1 Binary類 56
4.2.2 Section類 57
4.2.3 Symbol類 57
4.3 實現(xiàn)二進(jìn)制加載器 57
4.3.1 初始化libbfd并打開二進(jìn)制文件 58
4.3.2 解析基礎(chǔ)二進(jìn)制屬性 60
4.3.3 加載符號 63
4.3.4 加載節(jié)信息 66
4.4 測試二進(jìn)制加載器 68
4.5 總結(jié) 71
4.6 練習(xí) 71
第二部分 二進(jìn)制分析基礎(chǔ)
第5章 Linux二進(jìn)制分析 74
5.1 使用file解決類型問題 75
5.2 使用ldd探索依賴性 77
5.3 使用xxd查看文件內(nèi)容 79
5.4 使用readelf解析并提取ELF庫文件 81
5.5 使用nm解析符號 83
5.6 使用strings查看Hints 86
5.7 使用strace和ltrace跟蹤系統(tǒng)調(diào)用和庫文件調(diào)用 88
5.8 使用objdump檢查指令集行為 93
5.9 使用GDB轉(zhuǎn)儲動態(tài)字符串緩沖區(qū) 95
5.10 總結(jié) 97
5.11 練習(xí) 97
第6章 反匯編與二進(jìn)制分析基礎(chǔ) 98
6.1 靜態(tài)反匯編 98
6.1.1 線性反匯編 99
6.1.2 遞歸反匯編 101
6.2 動態(tài)反匯編 104
6.2.1 示例:使用GDB跟蹤二進(jìn) 制執(zhí)行 105
6.2.2 代碼覆蓋策略 108
6.3 構(gòu)建反匯編代碼和數(shù)據(jù) 111
6.3.1 構(gòu)建代碼 112
6.3.2 構(gòu)建數(shù)據(jù) 118
6.3.3 反編譯 119
6.3.4 中間語言 121
6.4 基本分析方法 123
6.4.1 二進(jìn)制分析的特性 123
6.4.2 控制流分析 127
6.4.3 數(shù)據(jù)流分析 129
6.5 編譯器設(shè)置對反匯編的影響 132
6.6 總結(jié) 133
6.7 練習(xí) 134
第7章 簡單的ELF代碼注入技術(shù) 135
7.1 使用十六進(jìn)制編輯器修改裸機(jī)二進(jìn)制文件 135
7.1.1 在操作中觀察off-by-one漏洞 136
7.1.2 修復(fù)off-by-one漏洞 139
7.2 使用LD_PRELOAD修改共享庫行為 142
7.2.1 堆溢出漏洞 143
7.2.2 檢測堆溢出 145
7.3 注入代碼節(jié) 148
7.3.1 注入ELF節(jié):高級概述 149
7.3.2 使用elfinject注入ELF節(jié) 151
7.4 調(diào)用注入的代碼 155
7.4.1 入口點修改 155
7.4.2 劫持構(gòu)造函數(shù)和析構(gòu)函數(shù) 158
7.4.3 劫持GOT條目 161
7.4.4 劫持PLT條目 164
7.4.5 重定向直接調(diào)用和間接調(diào)用 165
7.5 總結(jié) 166
7.6 練習(xí) 166
第三部分 高級二進(jìn)制分析
第8章 自定義反匯編 168
8.1 為什么要自定義反匯編過程 168
8.1.1 一個自定義反匯編實例:代碼混淆 169
8.1.2 編寫自定義反匯編器的其他原因 171
8.2 Capstone介紹 172
8.2.1 Capstone安裝 173
8.2.2 Capstone線性反匯編 174
8.2.3 研究Capstone C的API 179
8.2.4 使用Capstone編寫遞歸反匯編器 180
8.3 實現(xiàn)一個ROP小工具掃描器 188
8.3.1 返回導(dǎo)向式編程簡介 189
8.3.2 尋找ROP的gadget 190
8.4 總結(jié) 196
8.5 練習(xí) 197
第9章 二進(jìn)制插樁 198
9.1 什么是二進(jìn)制插樁 198
9.1.1 二進(jìn)制插樁的相關(guān)API 199
9.1.2 靜態(tài)二進(jìn)制插樁和動態(tài)二進(jìn)制插樁的對比 199
9.2 靜態(tài)二進(jìn)制插樁 201
9.2.1 int 3方法 201
9.2.2 跳板方法 203
9.3 動態(tài)二進(jìn)制插樁 207
9.3.1 DBI系統(tǒng)的體系結(jié)構(gòu) 207
9.3.2 Pin介紹 209
9.4 使用Pin進(jìn)行分析 210
9.4.1 Profiler的數(shù)據(jù)結(jié)構(gòu)和創(chuàng)建代碼 210
9.4.2 解析函數(shù)符號 213
9.4.3 插樁基本塊 214
9.4.4 檢測控制流指令 216
9.4.5 指令、控制轉(zhuǎn)移及系統(tǒng)調(diào)用計數(shù) 219
9.4.6 測試Profiler 220
9.5 用Pin自動對二進(jìn)制文件脫殼 224
9.5.1 可執(zhí)行文件加殼器簡介 224
9.5.2 脫殼器的配置代碼及其使用的數(shù)據(jù)結(jié)構(gòu) 225
9.5.3 對內(nèi)存寫入插樁 228
9.5.4 插樁控制流指令 229
9.5.5 跟蹤內(nèi)存寫入 229
9.5.6 檢測原始入口點并轉(zhuǎn)儲脫殼二進(jìn)制文件 230
9.5.7 測試脫殼器 231
9.6 總結(jié) 236
9.7 練習(xí) 236
第 10章 動態(tài)污點分析的原理 237
10.1 什么是DTA 237
10.2 DTA三步:污點源、污點槽及污點傳播 238
10.2.1 定義污點源 238
10.2.2 定義污點槽 239
10.2.3 追蹤污點傳播 239
10.3 使用DTA檢測心臟滴血漏洞 239
10.3.1 心臟滴血漏洞概述 239
10.3.2 通過污點分析檢測心臟滴血漏洞 241
10.4 DTA設(shè)計因素:污點粒度、污點顏色及污點傳播策略 242
10.4.1 污點粒度 243
10.4.2 污點顏色 244
10.4.3 污點傳播策略 244
10.4.4 過污染和欠污染 246
10.4.5 控制依賴 246
10.4.6 影子內(nèi)存 247
10.5 總結(jié) 249
10.6 練習(xí) 249
第 11章 基于libdft的動態(tài)污點分析 250
11.1 libdft簡介 250
11.1.1 libdft的內(nèi)部結(jié)構(gòu) 251
11.1.2 污點傳播策略指令 253
11.2 使用DTA檢測遠(yuǎn)程控制流劫持攻擊 254
11.2.1 檢查污點信息 257
11.2.2 污點源:將收到的字節(jié)標(biāo)記為污點 258
11.2.3 檢查點:檢查execve參數(shù) 260
11.2.4 檢測控制流劫持攻擊 261
11.3 用隱式流繞過DTA 266
11.4 基于DTA的數(shù)據(jù)泄露檢測器 268
11.4.1 污點源:追蹤打開文件的污點 270
11.4.2 檢查點:監(jiān)控泄露數(shù)據(jù)的網(wǎng)絡(luò)發(fā)送 273
11.4.3 檢測數(shù)據(jù)泄露 275
11.5 總結(jié) 277
11.6 練習(xí) 277
第 12章 符號執(zhí)行原理 278
12.1 符號執(zhí)行概述 278
12.1.1 符號執(zhí)行與正常執(zhí)行的對比 279
12.1.2 符號執(zhí)行的變體和局限 282
12.1.3 提高符號執(zhí)行的可擴(kuò)展性 286
12.2 使用Z3進(jìn)行約束求解 288
12.2.1 證明指令的可達(dá)性 288
12.2.2 證明指令的不可達(dá)性 291
12.2.3 證明公式的永真性 292
12.2.4 簡化表達(dá)式 293
12.2.5 使用位向量對機(jī)器碼建立約束模型 294
12.2.6 用位向量求解不透明謂詞 296
12.3 總結(jié) 296
12.4 練習(xí) 297
第 13章 使用Triton實現(xiàn)符號執(zhí)行 298
13.1 Triton的介紹 298
13.2 使用抽象語法樹維護(hù)符號狀態(tài) 299
13.2.1 完整的抽象語法樹 301
13.2.2 使用引用的抽象語法樹 301
13.3 使用Triton進(jìn)行后向切片 302
13.3.1 Triton的頭文件以及相關(guān)配置 304
13.3.2 符號化配置文件 305
13.3.3 模擬指令 306
13.3.4 設(shè)置Triton的體系結(jié)構(gòu) 307
13.3.5 計算后向切片 308
13.4 使用Triton提升代碼覆蓋率 310
13.4.1 創(chuàng)建符號變量 312
13.4.2 尋找新路徑的解 313
13.4.3 測試代碼覆蓋工具 316
13.5 漏洞利用自動化 319
13.5.1 包含脆弱調(diào)用點的程序 320
13.5.2 查找脆弱調(diào)用點的地址 323
13.5.3 構(gòu)建漏洞利用生成器 325
13.5.4 獲取root權(quán)限的Shell 331
13.6 總結(jié) 334
13.7 練習(xí) 334
第四部分 附錄
附錄A x86匯編快速入門 336
A.1 匯編程序的布局 336
A.1.1 匯編指令、偽指令、標(biāo)號及注釋 337
A.1.2 代碼與數(shù)據(jù)分離 338
A.1.3 AT&T和Intel語法 339
A.2 x86指令結(jié)構(gòu) 339
A.2.1 x86指令的匯編層表示 339
A.2.2 x86指令的機(jī)器級結(jié)構(gòu) 339
A.2.3 寄存器操作數(shù) 340
A.2.4 內(nèi)存操作數(shù) 342
A.2.5 立即數(shù) 343
A.3 常見的x86指令 343
A.3.1 比較操作數(shù)和設(shè)置狀態(tài)標(biāo)志位 344
A.3.2 實現(xiàn)系統(tǒng)調(diào)用 345
A.3.3 實現(xiàn)條件跳轉(zhuǎn) 345
A.3.4 加載內(nèi)存地址 345
A.4 匯編的通用代碼構(gòu)造 345
A.4.1 !346
A.4.2 函數(shù)調(diào)用與函數(shù)棧幀 347
A.4.3 條件分支 351
A.4.4 循環(huán) 352
附錄B 使用libelf實現(xiàn)PT_NOTE覆蓋 354
B.1 請求頭 354
B.2 elfinject使用的數(shù)據(jù)結(jié)構(gòu) 355
B.3 初始化libelf 356
B.4 獲取可執(zhí)行頭 360
B.5 查找PT_NOTE段 360
B.6 注入代碼 362
B.7 為注入的節(jié)對齊加載地址 362
B.8 覆蓋.note.ABI-tag節(jié)頭 363
B.9 設(shè)置注入節(jié)的名稱 367
B.10 覆蓋PT_NOTE程序頭 369
B.11 修改入口點 372
附錄C 二進(jìn)制分析工具清單 373
C.1 反匯編工具 373
C.1.1 IDA Pro(Windows、Linux、macOS) 373
C.1.2 Hopper(Linux、macOS) 373
C.1.3 ODA(所有操作系統(tǒng)) 374
C.1.4 Binary Ninja(Windows、Linux、macOS) 374
C.1.5 Relyze(Windows) 374
C.1.6 Medusa(Windows、Linux) 374
C.1.7 radare(Windows、Linux、macOS) 374
C.1.8 objdump(Linux、macOS) 374
C.2 調(diào)試器 374
C.2.1 GDB(Linux) 374
C.2.2 OllyDbg(Windows) 375
C.2.3 Windbg(Windows) 375
C.2.4 Bochs(Windows、Linux、macOS) 375
C.3 反匯編框架 375
C.3.1 Capstone(Windows、Linux、macOS ) 375
C.3.2 distorm3(Windows、Linux、macOS) 375
C.3.3 udis86(Linux、macOS) 375
C.4 二進(jìn)制分析框架 376
C.4.1 angr(Windows、Linux、macOS) 376
C.4.2 Pin(Windows、Linux、macOS) 376
C.4.3 Dyninst(Windows、Linux) 376
C.4.4 Unicorn(Windows、Linux、macOS) 376
C.4.5 libdft(Linux) 376
C.4.6 Triton(Windows、Linux、macOS) 376