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, stripped
P.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 gdb
Source 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)