CMU-CSAPP-Lab2拆解二進位制炸彈
一、 實驗目的
1.理解C語言程式的機器級表示。
2.初步掌握GDB偵錯程式的用法。
3.閱讀C編譯器生成的x86-64機器程式碼,理解不同控制結構生成的基本指令模式,過程的實現。
二、實驗工具
- SecureCRT
- Linux
- Objdump命令反彙編
- GDB除錯工具
三、實驗內容
登入bupt1伺服器,在home目錄下可以找到Evil博士專門為你量身定製的一個bomb,當執行時,它會要求你輸入一個字串,如果正確,則進入下一關,繼續要求你輸入下一個字串;否則,炸彈就會爆炸,輸出一行提示資訊並向計分伺服器提交扣分資訊。因此,本實驗要求你必須通過反彙編和逆向工程對bomb執行檔案進行分析,找到正確的字串來解除這個的炸彈。
本實驗通過要求使用課程所學知識拆除一個“binary bombs”來增強對程式的機器級表示、組合語言、偵錯程式和逆向工程等方面原理與技能的掌握。 “binary bombs”是一個Linux可執行程式,包含了5個階段(或關卡)。炸彈執行的每個階段要求你輸入一個特定字串,你的輸入符合程式預期的輸入,該階段的炸彈就被拆除引信;否則炸彈“爆炸”,列印輸出 “BOOM!!!”。炸彈的每個階段考察了機器級程式語言的一個不同方面,難度逐級遞增。
為完成二進位制炸彈拆除任務,需要使用gdb偵錯程式和objdump來反彙編bomb檔案,可以單步跟蹤除錯每一階段的機器程式碼,也可以閱讀反彙編程式碼,從中理解每一組合語言程式碼的行為或作用,進而設法推斷拆除炸彈所需的目標字串。實驗2的具體內容見實驗2說明。
四、實驗步驟及實驗分析
1、反彙編並利用SSH Secure Shell Client工具下載反彙編程式碼
通過ls指令顯示當前目錄下的檔案,找到壓縮包bomb115.tar,即目標炸彈。通過tar xvf bomb115.tar解壓此壓縮包,然後再通過ls顯示解壓出的檔案:bomb、bomb.c和README。
通過objdump –d bomb > bomb.txt將炸彈程式反彙編並重定向到bomb.txt,通過ls顯示反彙編出的程式碼檔案bomb.txt。
開啟SSH Secure Shell Client工具,登入到遠端主機,將遠端主機上的檔案下載到本機上,便於檢視。
2、檢視目標檔案並做好除錯準備
檔案介紹:
bomb.txt:反彙編得到的程式碼檔案,也是主要研究的目標檔案。
bomb.c:主函式,通過呼叫每一關的函式實現,未顯示每關的具體程式碼。
bomb:炸彈程式,當除錯得出每一關的密碼後開啟程式執行來拆炸彈。
通過gdb bomb指令進入gdb除錯環境。
大致瀏覽反彙編程式碼,可以觀察到整個程式一共有六關,分別為phase_1到phase_6,並有一關隱藏關secret_phase,每次輸入錯誤時會呼叫引爆函式explode_bomb,因此為避免除錯時引爆炸彈,需要首先在引爆函式前設定斷點,即b explode_bomb。
3、拆除炸彈
1、 第一個炸彈
程式流程:
- 取記憶體地址0x4024b0處的內容;
- 取使用者輸入的內容(即密碼);
- 比較兩者的值,相等則%eax置為0,進入下一關,不相等則呼叫引爆程式引爆炸彈。
破解思路:
通過x/s 0x4024b0指令取出該地址的字串,得到:Only you can give me that feeling.
則密碼為:Only you can give me that feeling.
通過 !
2、 第二個炸彈
程式流程:
- 讀取使用者輸入內容(為6個數字);
- 判斷輸入的第一個值是否為1,不是則引爆炸彈;
- 做一個6次迴圈,判斷後一個數是否等於前一個數加上之前迴圈變數,不是則引爆炸彈;
- 六個數字判斷相等結束後,進入下一關
破解思路:
設輸入內容為一個數組Key[6],則可知Key[0]=1,Key[i+1]=Key[i]+i。
因此第二關的密碼是:1 2 6 24 120 720
3、 第三個炸彈
程式流程:
- 讀取輸入引數1和引數2,呼叫scanf函式傳入兩個引數;
- 比較引數1與7的大小,小於等於7繼續,大於7引爆;
- 根據引數1的值來搜尋跳轉地址,計算得到最終的%eax;
- 比較引數1與5的大小,小於等於5繼續,大於5引爆;
- 比較引數2與計算得到的%eax是否相等,相等則進入下一關,不相等則引爆。
重點在於引數1的選擇決定了switch的跳轉,該實驗地址為(設引數1為x):
0x402510+x*8
其中存在一個Switch函式表,這個炸彈我選擇引數1為2,則跳轉地址為0x00400f33
Switch跳轉到改地址開始計算eax%,最終結果為0x328-0xf7=0x231=561。
輸入 2 561。
成功 !
4、 第四個炸彈
主程式流程:
- 讀取2個引數,呼叫scanf函式傳入引數;
- 比較輸入引數與2的大小,小於則引爆;比較輸入引數與4的大小,大於則引爆。
- 把輸入引數傳入函式func4,並呼叫函式func4;
- 若函式func4返回值等於%rsp+0x8,則返回,進入下一關,否則引爆炸彈。
func4函式流程:
1. 比較傳入引數是否大於1,大於1則繼續,小於1則返回0,等於1則返回%rax;
2. 迴圈%edi=%edi-1,並遞迴呼叫函式func4,直到引數小於等於1;
3. 迴圈變數%edi=edi-2,並傳入%esp繼續遞迴呼叫函式func4;
4. 函式返回的所得值加到%eax;
設b=%edi,a=%esi,則f(a,b)=f(a,b-1)+f(a,b-2)+a;
第二個引數小於1則返回0,等於1則返回%rax(即a)。
炸彈中預設b=8,我們輸入a=2,經過上述式子計算得f(8)=561.
輸入108 2 或者162 3。
成功 !
5、 第五個炸彈
程式流程:
- 輸入字串
- 呼叫string_length的字串長度函式,測得的長度若不為6則引爆;
- 做一個6次的迴圈,迴圈變數%eax從1到6,;
- 我們要使得 string_not_equal返回值為0 ,也就是%ebp處的值和0x4024fe處的值相等,檢視0x4024fe處的值,發現為bruins
- 迴圈賦giant了, 依次改變以%ebp為開始位置的char的陣列的值 那麼b,r,u,I,n,s就存在於該字串,尋找改變字串值的語句。
- 取得 (0x8[%ebp]+0xc(%ebp)) &0xf的值,作為下標取得0x402550中的值,檢視 0x402550處的記憶體為 maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
- bruins分別對應 13 6 3 4 8 7 所以要取得13 6 3 4 8 7
- 我們輸入的內容寫成 ASCII碼應該是xd x6 x3 x4 x8 x7。x表示任取,隨便取得 3d 36 33 34 38 37,對應ASCII碼為=63487。輸入
- 成功 !