1. 程式人生 > >BombLab Phase-1 & Phase-2

BombLab Phase-1 & Phase-2

Phase_1

  1. 觀察原始碼,看一下輸入有哪些

通過觀察,我們知道每個phase前面都有一個輸入,並且為string型別,我們會將這個string傳入phase_1中,所以棧幀中phase_1幀前面應該只有一個引數。

  1. 反彙編phase_1函式。

我們可以看到,在棧頂的頂8個位元組儲存了兩個東西,第一個是將常量 $0x804a15c存入了(esp)+4的位置,第二個是將ebp+8存入了(esp),這第二個就是我們傳入phase_1的引數,可以看出應該就是我們輸入的字串的地址,那麼可以猜測第一個就是被比較的字串的地址了。

  1. 畫出phase_1的棧幀結構圖

  1. 分析strings_not_equeal作用 

從名字上來看,我們猜得到這個函式是對兩個字串比較是否相等,從呼叫時機來看——在呼叫前將字串地址傳入了棧頂,更加印證我們的猜想,當然這些都是猜測,我們還是具體來看下反彙編程式碼來分析一下。

檢視strings_not_equeal函式彙編程式碼

我們可以看到,上面兩個箭頭分別跳到如下兩個箭頭的位置:

當二者長度不一致,eax的值就為1,當二者一致時,eax返回0.所以這個函式就是用來比較兩個字串是否相等的。

我們看到phase_1裡面呼叫了strings_not_equal函式,那麼我們就來畫一下這個函式的棧幀圖:

到這兒,我們就明白,我們輸入的字元最後是要和0x804a15c地址的字串做比較,既然要求相等,那麼我們檢視這個記憶體裡存放的字串:

我們看到這句話,那當我們輸入進去測試的時候:

    Ok,phase_1就搞定了!

Phase_2

  1. 同樣,我們先對Phase_2進行反彙編測試看看結果:

       觀察phase_2,我們觀察到裡面有兩個函式呼叫,分別是read_six_numbers和explode_bomb函式,此外,觀察到phase_2裡面還有一個迴圈:

  1. 我們可以畫出phase_2的棧幀如下所示:

  1. 看完了phase_2,我們再來研究一下read_six_numbers函式

我們觀察到read_six_numbers的功能就是讀取六個數字然後存到對應的記憶體上,然後我們觀察到在這個函式中,edx暫存器儲存的都是phase_2中儲存的六個書數的地址,這樣scanf讀取的六個數就能存在phase_2的六個記憶體位置上。

對於read_six_numbers的棧幀圖如下;

  1. 瞭解了read_six_numbers之後,我們再回到phase_2的迴圈:

我們可以看到再迴圈之前有兩個暫存器初始化,一個是ebx,還有一個是esi,

Ebx很簡單,我們可以看到,ebx是一個用來記錄迴圈位置的變數,而esi會和ebx 比較,所以esi是一個用來判斷截止條件的。我們有看到這個:

這個實現了前兩個數的相加,這兩個數的位置是根據ebx確定的,所以這個迴圈的意義在於不斷地累加前面兩個值,也就是一個斐波那契地序列計算過程。

  1. 最後地分析:

如果前兩個我們輸入地值不是 0和1,那麼炸彈爆炸。所以我們前面輸入的值必須是0 和1,並且還要滿足斐波那契序列,如果你該數不等於前兩個數相加,則爆炸:

遇到的問題及解決方法

  1. 關於cmp指令和test指令區別

我們發現彙編程式碼在進行指令跳轉的前一步,通常會有這兩步,那麼同樣都是比較指令,二者的具體區別又是什麼呢?

       檢視教材和網上部落格,大致異同點可以整理如下:

              :

cmp 是做加減運算,test是做邏輯與運算。

             

cmp和test運算的結果都不會傳回影響目的運算元,而都會去改變標誌位。

              二者用法

Cmp用來比較有符號數和無符號數的大小,而test用法檢測該數某些位是否存在1,如檢查AL中的位6和位2是否有一位為1,可以用如下指令:test AL,01000100b,如果這兩個位全為0.則ZF的值為1,否則清0,那麼根據標誌位設定的跳轉就只能為jz或jnz

  1. lea指令和mov指令的差別

在剛學這兩個指令時,老師說lea指令和mov指令都可以實現資料傳輸,但是沒有說二者的具體使用區別,一直以來都是處於半知半解的狀態,今天就二者做了下總結。

mov的用法:

mov指令又稱資料傳輸指令,它的作用是進行除記憶體與記憶體之間的其他形式的資料傳輸。

lea的用法:

load effective address,又稱載入有效地址指令,直接將得到的數賦值,而不會去定址。

比如:

lea eax,[ebx+8]---  ebx+8 的值給eax.   等價於   mov  eax,ebx+8

mov eax,[ebx+8] --- 載入記憶體中地址為ebx+8 處的資料

lea eax,ebx+8 ------ 載入記憶體中地址為ebx+8 處的資料

  1. 關於字串儲存方式的疑惑

我們看到關於在傳遞字串時,我們傳遞的是字串的地址,而不是具體內容,既然我們是在棧中申明,為什麼不是將字串存在棧中呢?

後來,我們查詢了記憶體的分配機制:

附:

從一個直觀的角度理解,字串型別不是作為C中的基本型別,在C中並沒有規定string型別的具體長度,所以編譯器在編譯時並不能確定該為它分配多大的棧記憶體,而像int,char他們都有規定的記憶體長度,所以當作為區域性變數時可以存放在棧記憶體中。

綜上,我們就可理解為什麼傳遞字串時是傳遞它的地址而不是它的內容了。