1. 程式人生 > >深入理解計算機系統(CSAPP)課程實驗bomb程式炸彈實驗日誌(phase_3)

深入理解計算機系統(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

以上輸入都是正確的。

驗證一下第一個答案: