CSAPP——實驗二 拆炸彈

《Hardware/Software Interface》實驗二 是拆炸彈,也是實驗裏面比較有意思的一個實驗,實驗能幫助我們加深理解函數的調用過程,提升用GDB調試代碼的能力,話不多說,把實驗內容附上。

附實驗環境:
64位Linux操作系統

拆炸彈

實驗總共有六個階段,難度也是在逐步加大,每個階段都要求你輸入一些信息,只有提供恰當合適的正確信息,纔會拆炸彈成功進入下一個階段,那麼如何獲得正確的信息,就需要用GDB調試在彙編代碼中獲得線索。本文主要介紹每個階段的正確輸入的探索過程,對於GDB工具的使用大家可以另找資料來學習。

Phase1

第一關的C代碼如下,只有三行(其實每關也都只有三行),流程就是讀入輸入的數據然後數據處理,若是“正確”的輸入,代碼就會執行到 phase_defused();若不是“正確”的輸入,炸彈就會爆炸,然後程序終止。好的,就讓我們來找到本關的“正確”輸入。

    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!

首先我們要用工具GDB調試可執行程序bomb, 之後在phase_1 函數這裏加入breakpoint,運行bomb程序。

你會要求輸入信息,第一次我們可以隨便輸入,比如:“1111122222”,之後會到斷點phase_1,此時disas 查看該函數的彙編代碼,彙編代碼如下(截圖效果好點):
這裏寫圖片描述

第一行的命令讓rsp棧頂指針減0x8,是給當前frame更多的棧空間來存儲數據,phase_1要解決不用關注這行重點是後面的mov和callq 。

callq調用了方法strings_not_equal 顯然是判斷兩個字符串是否相同,那麼比較的兩個參數是什麼呢?先看一下現在的寄存器情況:
這裏寫圖片描述

X86-64下有16個64位寄存器,其中%rdi、%rsi、%rdx,%rcx、%r8、%r9用作傳遞函數參數,分別對應第1個參數、第2個參數直到第6個參數(摘自網絡)。那麼說現在我們的輸入,應該是作爲調用函數時用到的參數保存在了寄存器%rdi中(如有不對請指出),查看對應的值確實也是如此:
這裏寫圖片描述
另一個比較的值存到了%esi中(存儲值得內存邏輯地址爲0x401af8)

繼續往後分析,string_not_equal 的返回結果會保存到eax寄存中,0表示相等,1表示不想等,彙編代碼:test %eax,%eax 來設置計算eax與自己本身邏輯與之後的值,若爲0則設置0標識位。 因此只有當string_not_equal 返回0 即兩個字符串相等時程序纔會跳過執行函數 explode_bomb, 本關纔會通過。 那麼現在只需要查看 地址0x401af8的存儲內容就可以了。
這裏寫圖片描述

Phase2

這一關的考點是循環。跟其它關一樣,也是要先輸入信息,再判斷是否引爆炸彈,直接進入彙編代碼:
這裏寫圖片描述
其中的read_six_numbers 的彙編代碼如下:
這裏寫圖片描述
其中<+51>,<+54>兩行表明 讀入的number數目必須大於5,否則就會引起炸彈;同時讀入的數據會存到phase_2的frame棧中。

讀取完前六個數字之後 我們回到phase_2的彙編代碼中,該代碼較長,但是我們只需要看其中的幾個重點的指令行。<+32>行將rsp 與 rbp值統一,然後<+35> r13的值爲一個地址,地址爲rsp+0xc. <+65>將rbp的值加0x4,<+69>比較r13與rbp的值,若不相同就會跳回<+46>因此可以判斷出這個循環要執行三遍。

<+49>和<+52>,比較了當前rbp與rbp+0xc 兩個地址對應內容值,若不想等就會引發炸彈,因此得出結論6個number, 第一與第四個相等,第二與第五個相等,第三與第六個相等。

同時還看到r12d寄存器累加了前三個元素的值,若前三個相加爲0 也會引起爆炸,這也要注意。

通過以上分析,我們可以得到本次該輸入的爲 1 2 3 1 2 3(類似即可)

Phase3

本關的考點是switch語句。phase_3的彙編代碼如下:
這裏寫圖片描述
這裏寫圖片描述

此關相對簡單,首先需要輸入兩個數據,少於兩個數據會引爆炸彈,其次是根據switch的number,第二輸入數要和彙編代碼中數相匹配,假設輸入的第一個number爲2,那麼運行時會調到代碼行<+64>處,0xd6 對應的10進制數爲214. 此時就應當輸入 2 214. 當然我們也可以選擇其他的switch 分支。

Phase4

本關的考點是遞歸。phase_4的彙編代碼如下:
這裏寫圖片描述
有了前幾關的鋪墊,這一關也變得非常簡單。
<+24>的判斷表明了這一關只需要輸入一個數;<+29>表明我們輸入的數必須大於0;<+45>調用了函數 func4, <+50>表明了函數fun4的返回值必須和0x37也就是55相等。滿足上述情況即可拆炸彈成功。

那就看一下func4的彙編代碼:
這裏寫圖片描述
我們之前輸入的數保存到了edi寄存器中,func4裏面會判斷edi與1 的大小,若大於1會將edi的值減1和減2後分別再調用func4函數,仔細觀察可推出這就是求斐波那契數的函數:F(x) = F(x-1)+F(x-2),F(0)=0,F(1)=1. F(9)=55.因此我們要輸入的數爲 9.

Phase5

本關的考點是數組和指針。phase_5的彙編代碼如下:

這裏寫圖片描述
這裏寫圖片描述

<+29>的判斷表明了我們輸入的參數數量大於1;<+39~+53>表明我們輸入的一個參數的二進制後四位不能爲1111(15),也可以相稱第一個參數的值要小於15.

<+65~+82>是一個循環,寄存器edx初值定爲0,每次循環加1,根據<+88>行的cmp 0xc, %edx 可以得出,循環必須要走12遍;同時ecx寄存器不斷的累加數,累加的數來源要看<+70>,每次把一個數的值存到eax寄存器中 並且作爲下次取值的索引;<+93>表明我們最終ecx寄存器的累加值要和我們的第二個參數相同,若相同,即可拆除炸彈。

問題的關鍵在於循環,循環必須循環12次,同時循環終止的條件是eax寄存器的值爲15.我們看一下地址0x401ba0存的是什麼數據:
這裏寫圖片描述
一個大小爲15的數組,如下:

數組 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
value 10 2 14 7 8 12 15 11 0 4 1 13 3 9 6

那麼就是說數組index爲6時對應元素爲15,最後一次加了15,那麼上一次就加了6,依此類推加12次的結果爲: 15+6+14+2+1+10+0+8+4+9+13+11 =93. 第一次加的數爲1,其下標爲7.

因此本關的 輸入爲 7 93.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章