深入理解計算機系統(CSAPP)課程實驗bomb程式炸彈實驗日誌(phase_3)
在Notepad++編輯器中找到函式phase_3,程式碼如下:
08048ea1 <phase_3>: 8048ea1: 55 push %ebp 8048ea2: 89 e5 mov %esp,%ebp 8048ea4: 83 ec 28 sub $0x28,%esp 8048ea7: 8d 45 f0 lea -0x10(%ebp),%eax 8048eaa: 89 44 24 0c mov %eax,0xc(%esp) 8048eae: 8d 45 f4 lea -0xc(%ebp),%eax 8048eb1: 89 44 24 08 mov %eax,0x8(%esp) 8048eb5: c7 44 24 04 3e a2 04 movl $0x804a23e,0x4(%esp) 8048ebc: 08 8048ebd: 8b 45 08 mov 0x8(%ebp),%eax 8048ec0: 89 04 24 mov %eax,(%esp) 8048ec3: e8 78 f9 ff ff call 8048840 <__isoc99_sscanf@plt> 8048ec8: 83 f8 01 cmp $0x1,%eax 8048ecb: 7f 05 jg 8048ed2 <phase_3+0x31> 8048ecd: e8 ff 01 00 00 call 80490d1 <explode_bomb> 8048ed2: 83 7d f4 07 cmpl $0x7,-0xc(%ebp) 8048ed6: 77 6b ja 8048f43 <phase_3+0xa2> 8048ed8: 8b 45 f4 mov -0xc(%ebp),%eax 8048edb: ff 24 85 a0 a1 04 08 jmp *0x804a1a0(,%eax,4) 8048ee2: b8 00 00 00 00 mov $0x0,%eax 8048ee7: eb 53 jmp 8048f3c <phase_3+0x9b> 8048ee9: b8 00 00 00 00 mov $0x0,%eax 8048eee: 66 90 xchg %ax,%ax 8048ef0: eb 45 jmp 8048f37 <phase_3+0x96> 8048ef2: b8 00 00 00 00 mov $0x0,%eax 8048ef7: eb 39 jmp 8048f32 <phase_3+0x91> 8048ef9: b8 00 00 00 00 mov $0x0,%eax 8048efe: 66 90 xchg %ax,%ax 8048f00: eb 2b jmp 8048f2d <phase_3+0x8c> 8048f02: b8 00 00 00 00 mov $0x0,%eax 8048f07: eb 1f jmp 8048f28 <phase_3+0x87> 8048f09: b8 00 00 00 00 mov $0x0,%eax 8048f0e: 66 90 xchg %ax,%ax 8048f10: eb 11 jmp 8048f23 <phase_3+0x82> 8048f12: b8 14 03 00 00 mov $0x314,%eax 8048f17: eb 05 jmp 8048f1e <phase_3+0x7d> 8048f19: b8 00 00 00 00 mov $0x0,%eax 8048f1e: 2d 5a 03 00 00 sub $0x35a,%eax 8048f23: 05 ef 02 00 00 add $0x2ef,%eax 8048f28: 2d 16 02 00 00 sub $0x216,%eax 8048f2d: 05 16 02 00 00 add $0x216,%eax 8048f32: 2d 16 02 00 00 sub $0x216,%eax 8048f37: 05 16 02 00 00 add $0x216,%eax 8048f3c: 2d 16 02 00 00 sub $0x216,%eax 8048f41: eb 0a jmp 8048f4d <phase_3+0xac> 8048f43: e8 89 01 00 00 call 80490d1 <explode_bomb> 8048f48: b8 00 00 00 00 mov $0x0,%eax 8048f4d: 83 7d f4 05 cmpl $0x5,-0xc(%ebp) 8048f51: 7f 05 jg 8048f58 <phase_3+0xb7> 8048f53: 3b 45 f0 cmp -0x10(%ebp),%eax 8048f56: 74 05 je 8048f5d <phase_3+0xbc> 8048f58: e8 74 01 00 00 call 80490d1 <explode_bomb> 8048f5d: c9 leave 8048f5e: 66 90 xchg %ax,%ax 8048f60: c3 ret
在這一關中,使用gdb偵錯程式對程式進行除錯可以非常清楚地看到整個執行過程,指令的跳轉能夠幫助我們很好地理解程式的功能。
從0x8048ea1到0x8048ec0依然是幀的開闢和運算前的一些準備工作。0x8048ec3開始讀入資料,從0x8048ea7和0x8048eae可以看出,兩個引數分別位於-0x10(%ebp)位置和-0xc(%ebp)位置,分別設為val2和val1(val1的輸入順序在val2之前)。再大概瀏覽一下接下來的程式碼,基本都是進行一些數學運算,所以可以推斷出這一關的要求應該是輸入兩個數,它們之間要符合某種計算關係。
從0x8048ed2位置的cmpl指令分析,-0xc(%ebp)位置的引數val1應該是一個不大於7的數字,否則,程式將跳轉到0x8048f43位置的<explode_bomb>,即引爆炸彈。
所以輸入的第一個引數val1是不大於7的一個整數,第二個引數val2在0x8048f53位置出現,與儲存在eax中的計算結果進行比較,若不相等則跳轉至0x8048f58位置,同樣是引爆的結果,所以,引數1經過中間的一系列計算得到的結果必須和引數2相等,否則將引爆炸彈。
接下來在gdb偵錯程式中進行探索。將第一個引數設定為0,第二個引數設定為一個任意值(因為還不知道將會執行何種操作,並且在gdb除錯的過程中,如果沒有進行到0x8048f58位置則暫時不會引爆炸彈),這裡選擇10。開啟除錯功能,將斷點設定在phase_3函式位置,輸入r開始除錯,首先要將第1、2關的正確答案輸入,否則將會引爆炸彈,接下來輸入兩個引數0和10:
進入phase_3函式後,使用ni指令單步進入進行除錯,檢視程式的執行情況。使用info reg指令檢視暫存器情況。當0x8048ec3位置的指令執行完成(即資料讀入結束)後,檢視暫存器內容:
這時候可以看到,eax的值已經被修改為2,而0x8048ec8位置開始的指令就是將eax中的值和1做比較,所以這一步是一定會發生跳轉的(多次測試後發現,eax的內容在這裡總是被修改為2,和輸入的資料無關,猜測可能是輸入資料的個數)。
按照0x8048ecb位置的jg跳轉指令,函式跳轉到0x8048ed2位置,從這一行開始解讀,將引數1的值和7做比較,大於則引爆炸彈,否則將引數1的值存在暫存器eax中,接著就是一個無條件跳轉指令jmp *0x804a1a0(,%eax,4),為了看清楚這個指令使程式跳轉到了一個什麼位置,我們繼續使用gdb功能。
可以清楚地看到,0x8048edb位置的跳轉指令執行後,程式跳轉到了0x8048f12位置,這個位置的指令是mov $0x314,%eax,說明已經開始運算,檢視暫存器可以發現,我們輸入的第一個引數0也已經成功存入eax暫存器。繼續單步除錯。看看程式下一步會做什麼。
通過彙編程式碼可以看到,0x8048f1e到0x8048f3c位置執行的全部是運算指令,接著是0x8048f41位置的一個無條件跳轉指令,跳轉到0x8048f4d位置,0x8048f4d位置的內容是cmpl $0x5,-0xc(%ebp),還是對引數1進行篩選的一個指令,下一條是jg指令,跳轉至0x8048f58位置,引爆炸彈。這樣可以推斷出輸入的第一個引數必須小於等於5。之前輸入的0也是符合的。而且我們可以看到,運算指令執行完成後,eax中的值變成了147,而0x8048f53位置的cmp -0x10(%ebp),%eax指令正是將運算結果和引數2進行比較,若相等則函式執行結束,否則引爆炸彈,所以可以推斷出當第一個引數為0時,第二個引數的值必定是147,否則將引爆炸彈。
回頭觀察0x8048edb位置的這個jmp跳轉指令,內容是:
8048ed8: 8b 45 f4 mov -0xc(%ebp),%eax
8048edb: ff 24 85 a0 a1 04 08 jmp *0x804a1a0(,%eax,4)
跳轉到哪個地址,取決於eax中的值是多少,所以引數1輸入不同的值,將跳轉到不同的位置,執行不同的運算,得到的結果(也就是引數2)也不相同。實際上這個程式實現的應該是一個switch結構,每個輸入對應唯一的一個輸出。同時,輸入的引數1有0,1,2,3,4,5這些值,所以答案不是唯一的。輸入1-5分別進行除錯,得到幾種正確答案:
0,147
1,-641
2,217
3,-534
4,0
5,-534
以上輸入都是正確的。
驗證一下第一個答案: