Disassembly 反編譯#
當程式執行後,檔案中的 Binary code 會被移動至記憶體上執行,並且該過程是可以被觀察的。
在計算機概論中,大家都知道程式由Assembly language到Binary code過程稱作Assemble (組譯),反之要從Binary code到Assemble,則稱作「Disassemble (反組譯)」,名詞為「Assembly (組譯)」、「Disassembly (反組譯)」,對應工具稱作「Assembler (組譯器)」、「Disassembler (反組譯器)」。
透過相關的Debugger軟體,可以在程式被執行之前或執行中進行記憶體上的觀察。
程式執行之前,透過查看執行檔的內容,將其反組譯成 Assembly language 並加以分析,該過程稱為「Static Program Analysis (SPA)」,也就是程式的靜態分析(因為程式並未被執行,而是靜態的被查看而已);
反之在程式執行過程中,邊執行邊組譯分析則稱作「Dynamic Program Analysis (DPA),也就是程式的動態分析(程式已經被執行,觀察過程為動態的)。
工欲善其事,必先利其器#
以下會以「
./binary」表示欲使用指令的二進制檔案路徑。
「elfread」#
了解了什麼是「
ELF」後,就來提一個指令 — 「elfread」。
顧名思義,就是可以讀取ELF相關 info 的指令,實際操作範例如下:1readelf ./binary -x .text參數「
-x, --hex-dump」
「file」#
輸入
file <program>指令即可查看該檔案的一些訊息:1$ file ./binary 2hello-world: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=aa3701cef10f8698f43d0972300359a60fcb09e3, for GNU/Linux 3.2.0, strippedP.s. 如果是自己編譯的朋友,所看到的資訊有不同是正常的,這取決於編譯器或 OS 等多項因素。
「objdump」#
可以用來將 binary 反組譯成 assembly 的程式。(當然它還有其他功能,但本系列文章著重使用該功能)
範例使用該應用以 intel 格式反組譯二進制檔案「./binary」:1# 建議搭配 less 指令以方便觀看 2objdump -d -M intel ./binary | less
-d參數為「disassemble」;-M參數指定程式以何種格式讀取及顯示檔案,如intel、att、i386、amd64… 等。
「patchelf」、「ldd」#
由於 pwn 是非常吃環境的,正常來說會希望本地端的環境與遠端的越相近越好。(這部份稍後會談到)
而我們也在「《Pwn - 0x02》What did the "Compilation" do? And what is ELF?」這篇文章中提到,程式的執行會仰賴loader程式,也時常因「lazy binding」的特性,依賴於 libc 的版本。這部份可以透過「
ldd」指令來查看當前程式的loader及libc檔案的路徑。使用方式為「ldd ./binary」。雖然說 libc 在不同版本中或許使用上感覺不出影響,但實際在底層的運作可能會因為版本而有所不同,因此有時候不得以需要手動指定應用的
loader及libc版本。而「patchelf」就可以很方便的做到這點:1# 置換成指定的 loader 檔案 2patchelf --set-interpreter /path/to/loader ./binary 3# 將原有的 libc 至換成指定的 libc 檔案,大多數情況為「libc.so.6」,請使用「ldd」確認後自行調整 4patchelf --replace-needed libc.so.6 /path/to/libc ./binary需要注意的是,該指令會竄改到檔案本身,建議操作前先對檔案進行備份:
1cp ./binary ./binary.bak 2patchelf --set-interpreter /path/to/loader ./binary 3patchelf --replace-needed libc.so.6 /path/to/libc ./binary這種更動檔案以使其更貼近所期望環境的作法稱作「
patch」。
其常見的分析軟體有IDA Pro、OllyDbg,以及常用於 Unix 系統的 Command line 程式GDB (GNU Debugger)等。
本系列文章將以
GDB來實做動態分析。
Install GDB#
Ubuntu#
1apt-get update -y 2apt-get install -y gdbSource code#
可以在官方站點上選擇不同版本的原始碼壓縮檔 http://ftp.gnu.org/gnu/gdb
以下示範安裝版本12.1:1# For example, install version 12.1 2# Get file 3wget "http://ftp.gnu.org/gnu/gdb/gdb-12.1.tar.gz" 4# Extract 5tar -xvzf gdb-12.1.tar.gz 6cd ./gdb-12.1 7# Compile 8./configure 9make 10# Install 11make install
How to use?#
直接在 Terminal 上輸入「
gdb」即可,也可以使用「gdb <program>」來指定要分析的軟體,如「gdb ./a.out」。
不過本系列文章並不使用該方法,而是使用pwntools搭配 gdb,那…什麼是pwntools?
Pwntools#
這是一個 python 的套件,其顧名思義就是為打 pwn 而生的工具。
直接透過 pip 安裝即可:1pip install pwntools
接著創建一個 python 檔案,並引用
pwntools套件:1from pwn import *
其開啟程式的模式有常見的以下幾種:
1# 創建一個本地程序 2r = process('./binary')
1# 創建一個遠端連線 2r = remote('./binary')
1# 使用 gdb 啟動本地程序,參數二可以放 gdb 指令,指令部份之後會介紹到 2r = gdb.debug('./binary', 'b main')
1# 創建一個程序,並用 gdb attach 上該程序進行動態分析 2# 與上者還是有些許差異,不過這部份就是「坑」了,日後踩到再說 3r = process('./binary') 4gdb.attach(r, 'b main')
本系列文章將以「gdb.debug()」進行動態分析;
以「r.process()」進行最後的 payload 測試;
以「r.remote()」進行實際攻擊。
p.s. 上文中「payload」一詞中文譯作「負載」,指的是資料傳遞中的實際資訊。在此情境指的是那些「能夠繞過程式防護觸發到弱點的攻擊語法」,有些人也會以「exploit」稱呼。
References#
- 《再觀電腦! ep.1 黃恩明》https://hackmd.io/@enmingw32/Sk0l2OJHP?print-pdf#/
- 《負載 (電腦) - 維基百科,自由的百科全書》https://zh.wikipedia.org/zh-tw/%E8%B4%9F%E8%BD%BD_(%E8%AE%A1%E7%AE%97%E6%9C%BA)