csapp lab2 bomb 二進制炸彈《深入理解計算機系統》

bomb炸彈實驗

首先對bomb這個文件進行反彙編,得到一個1000+的彙編程序,看的頭大。


phase_1:

0000000000400ef0 <phase_1>:
  400ef0:	48 83 ec 08          	sub    $0x8,%rsp
  400ef4:	be 18 1b 40 00       	mov    $0x401b18,%esi
  400ef9:	e8 10 04 00 00       	callq  40130e <strings_not_equal>
  400efe:	85 c0                	test   %eax,%eax
  400f00:	74 05                	je     400f07 <phase_1+0x17>
  400f02:	e8 dc 07 00 00       	callq  4016e3 <explode_bomb>
  400f07:	48 83 c4 08          	add    $0x8,%rsp
  400f0b:	c3                   	retq   


這個是炸彈一的彙編程序。可以看到,在程序裏面,首先注意到了:

 callq  40130e <strings_not_equal>

strings_not_equal這個函數應該就是對字符串是否相等進行了判斷,所以要找到原來系統設定的字符串。

這是看到前面那句:mov    $0x401b18,%esi

感覺有問題,後來去查了一下,發現esi這個寄存器主要進行串操作,嗯,那字符串應該藏在0x401b18裏面了。

用gdb調試,

果然在哪個地址裏面。

phase_2:



 400f0c:	55                   	push   %rbp
  400f0d:	53                   	push   %rbx
  400f0e:	48 83 ec 28          	sub    $0x28,%rsp
  400f12:	48 89 e6             	mov    %rsp,%rsi
  400f15:	e8 eb 07 00 00       	callq  401705 <read_six_numbers>
  400f1a:	83 3c 24 01          	cmpl   $0x1,(%rsp)
  400f1e:	74 25                	je     400f45 <phase_2+0x39>
  400f20:	e8 be 07 00 00       	callq  4016e3 <explode_bomb>
  400f25:	eb 1e                	jmp    400f45 <phase_2+0x39>
  400f27:	83 c3 01             	add    $0x1,%ebx
  400f2a:	89 d8                	mov    %ebx,%eax
  400f2c:	0f af 45 fc          	imul   -0x4(%rbp),%eax
  400f30:	39 45 00             	cmp    %eax,0x0(%rbp)
  400f33:	74 05                	je     400f3a <phase_2+0x2e>
  400f35:	e8 a9 07 00 00       	callq  4016e3 <explode_bomb>
  400f3a:	48 83 c5 04          	add    $0x4,%rbp
  400f3e:	83 fb 06             	cmp    $0x6,%ebx
  400f41:	75 e4                	jne    400f27 <phase_2+0x1b>
  400f43:	eb 0c                	jmp    400f51 <phase_2+0x45>
  400f45:	48 8d 6c 24 04       	lea    0x4(%rsp),%rbp
  400f4a:	bb 01 00 00 00       	mov    $0x1,%ebx
  400f4f:	eb d6                	jmp    400f27 <phase_2+0x1b>
  400f51:	48 83 c4 28          	add    $0x28,%rsp
  400f55:	5b                   	pop    %rbx
  400f56:	5d                   	pop    %rbp
  400f57:	c3                   	retq   


這個首先看到代碼:

callq 401705<read_six_numbers>

應該是要輸入6個數字。

然後接下來按照下面的幾行的步驟一步一步看下去,可以知道ebx這個寄存器是一個計數器,rbp這個寄存器用來指向當前比較的數字的地址,經過分析,每個數字的計算方法是:%ebx*(-4(%rbp)).即當前的數字的編號(1,2,3,4,5,6,第幾個數字就是第幾號)和上一個數字的乘積,第一個數字爲1.

所以最後6個數字就是:1 2 6 24 120 720

phase_3:

 400f58:	48 83 ec 18          	sub    $0x18,%rsp
  400f5c:	4c 8d 44 24 08       	lea    0x8(%rsp),%r8
  400f61:	48 8d 4c 24 07       	lea    0x7(%rsp),%rcx
  400f66:	48 8d 54 24 0c       	lea    0xc(%rsp),%rdx
  400f6b:	be 6e 1b 40 00       	mov    $0x401b6e,%esi
  400f70:	b8 00 00 00 00       	mov    $0x0,%eax
  400f75:	e8 86 fc ff ff       	callq  400c00 <__isoc99_sscanf@plt>
  400f7a:	83 f8 02             	cmp    $0x2,%eax
  400f7d:	7f 05                	jg     400f84 <phase_3+0x2c>
  400f7f:	e8 5f 07 00 00       	callq  4016e3 <explode_bomb>
  400f84:	83 7c 24 0c 07       	cmpl   $0x7,0xc(%rsp)
  400f89:	0f 87 fc 00 00 00    	ja     40108b <phase_3+0x133>
  400f8f:	8b 44 24 0c          	mov    0xc(%rsp),%eax
  400f93:	ff 24 c5 80 1b 40 00 	jmpq   *0x401b80(,%rax,8)
  400f9a:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400f9f:	81 7c 24 08 40 02 00 	cmpl   $0x240,0x8(%rsp)
  400fa6:	00 
  400fa7:	0f 84 e8 00 00 00    	je     401095 <phase_3+0x13d>
  400fad:	e8 31 07 00 00       	callq  4016e3 <explode_bomb>
  400fb2:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400fb7:	e9 d9 00 00 00       	jmpq   401095 <phase_3+0x13d>
  400fbc:	b8 66 00 00 00       	mov    $0x66,%eax
  400fc1:	81 7c 24 08 bc 03 00 	cmpl   $0x3bc,0x8(%rsp)
  400fc8:	00 
  400fc9:	0f 84 c6 00 00 00    	je     401095 <phase_3+0x13d>
  400fcf:	e8 0f 07 00 00       	callq  4016e3 <explode_bomb>
  400fd4:	b8 66 00 00 00       	mov    $0x66,%eax
  400fd9:	e9 b7 00 00 00       	jmpq   401095 <phase_3+0x13d>
  400fde:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400fe3:	81 7c 24 08 2a 02 00 	cmpl   $0x22a,0x8(%rsp)
  400fea:	00 
  400feb:	0f 84 a4 00 00 00    	je     401095 <phase_3+0x13d>
  400ff1:	e8 ed 06 00 00       	callq  4016e3 <explode_bomb>
  400ff6:	b8 6a 00 00 00       	mov    $0x6a,%eax
  400ffb:	e9 95 00 00 00       	jmpq   401095 <phase_3+0x13d>
  401000:	b8 76 00 00 00       	mov    $0x76,%eax
  401005:	81 7c 24 08 c9 00 00 	cmpl   $0xc9,0x8(%rsp)
  40100c:	00 
  40100d:	0f 84 82 00 00 00    	je     401095 <phase_3+0x13d>
  401013:	e8 cb 06 00 00       	callq  4016e3 <explode_bomb>
  401018:	b8 76 00 00 00       	mov    $0x76,%eax
  40101d:	eb 76                	jmp    401095 <phase_3+0x13d>
  40101f:	b8 62 00 00 00       	mov    $0x62,%eax
  401024:	81 7c 24 08 07 01 00 	cmpl   $0x107,0x8(%rsp)
  40102b:	00 
  40102c:	74 67                	je     401095 <phase_3+0x13d>
  40102e:	e8 b0 06 00 00       	callq  4016e3 <explode_bomb>
  401033:	b8 62 00 00 00       	mov    $0x62,%eax
  401038:	eb 5b                	jmp    401095 <phase_3+0x13d>
  40103a:	b8 69 00 00 00       	mov    $0x69,%eax
  40103f:	81 7c 24 08 3b 03 00 	cmpl   $0x33b,0x8(%rsp)
  401046:	00 
  401047:	74 4c                	je     401095 <phase_3+0x13d>
  401049:	e8 95 06 00 00       	callq  4016e3 <explode_bomb>
  40104e:	b8 69 00 00 00       	mov    $0x69,%eax
  401053:	eb 40                	jmp    401095 <phase_3+0x13d>
  401055:	b8 71 00 00 00       	mov    $0x71,%eax
  40105a:	81 7c 24 08 c6 00 00 	cmpl   $0xc6,0x8(%rsp)
  401061:	00 
  401062:	74 31                	je     401095 <phase_3+0x13d>
  401064:	e8 7a 06 00 00       	callq  4016e3 <explode_bomb>
  401069:	b8 71 00 00 00       	mov    $0x71,%eax
  40106e:	eb 25                	jmp    401095 <phase_3+0x13d>
  401070:	b8 77 00 00 00       	mov    $0x77,%eax
  401075:	81 7c 24 08 74 01 00 	cmpl   $0x174,0x8(%rsp)
  40107c:	00 
  40107d:	74 16                	je     401095 <phase_3+0x13d>
  40107f:	e8 5f 06 00 00       	callq  4016e3 <explode_bomb>
  401084:	b8 77 00 00 00       	mov    $0x77,%eax
  401089:	eb 0a                	jmp    401095 <phase_3+0x13d>
  40108b:	e8 53 06 00 00       	callq  4016e3 <explode_bomb>
  401090:	b8 68 00 00 00       	mov    $0x68,%eax
  401095:	3a 44 24 07          	cmp    0x7(%rsp),%al
  401099:	74 05                	je     4010a0 <phase_3+0x148>
  40109b:	e8 43 06 00 00       	callq  4016e3 <explode_bomb>
  4010a0:	48 83 c4 18          	add    $0x18,%rsp
  4010a4:	c3                   	retq   

被第三個炸彈卡了好久……主要原因是彙編不行啊。當年學的彙編是學的8位單片機上的彙編,所有的寄存器都是單獨的不相關的。而這個程序是在64位環境下運行的,所以像eax rax al 這些寄存器都是相關的,都是擴展的寄存器。不知道這個東西,一直以爲幾個寄存器無關,在gdb調試的時候,就隨便輸了幾個數進去,然後看al和rax這兩個寄存器裏面的值,以爲是定值,就一直按照這個定值來分析的,導致後面怎麼弄都不對……其實炸彈三就是利用這些相關的寄存器來實現不同的跳轉的

分析:

首先,看到:mov    $0x401b6e,%esi  先看看那個地址裏面是什麼東西。

結果: “%d,%c,%d”

應該是輸入的格式,輸入三個數據,其中兩個整數,一個char型的。

接着看下去,

400f84:	83 7c 24 0c 07       	cmpl   $0x7,0xc(%rsp)
400f89:	0f 87 fc 00 00 00    	ja     40108b <phase_3+0x133>
其中一個輸入的數字不能大於7,否則就爆炸了……

mov    0xc(%rsp),%eax

接下去eax被賦值爲那個輸入不能大於7的數據。

jmpq   *0x401b80(,%rax,8)

一個間接跳轉,這裏一開始以爲rax是個獨立的寄存器,導致這個程序都理解錯了……rax是eax的64爲擴展,所以這裏rax裏面的值和eax一樣,所以跳轉到(0x401b80+8*rax)地址裏面的值所對應的地址(比較繞,就是間接跳轉)。這裏跳轉的值和前面那個輸入有關,我輸入1,所以跳轉到(0x401b88)裏面那個值對應的地址,查了一下,地址是0x400fbc.直接看哪裏的指令。

  400fbc:	b8 66 00 00 00       	mov    $0x66,%eax
  400fc1:	81 7c 24 08 bc 03 00 	cmpl   $0x3bc,0x8(%rsp)
  400fc8:	00 
  400fc9:	0f 84 c6 00 00 00    	je     401095 <phase_3+0x13d>
  400fcf:	e8 0f 07 00 00       	callq  4016e3 <explode_bomb>

eax被賦值成0x66,並且第二個整數是0X3BC,跳轉到0x401095

 

 401095: 3a 44 24 07          cmp    0x7(%rsp),%al


這裏那個char型的大小要和al一樣(老坑),eax=0x66,al是eax的低8位,也是0x66,查一下ascii,是f

所以輸入就是1 f 956

這裏1 和956的輸入順序偷了個懶,直接試了兩次給試出來的,沒有看程序來推他的順序……



phase_4:

00000000004010bf <phase_4>:
  4010bf:	48 83 ec 18          	sub    $0x18,%rsp
  4010c3:	48 8d 54 24 0c       	lea    0xc(%rsp),%rdx
  4010c8:	be 74 1b 40 00       	mov    $0x401b74,%esi
  4010cd:	b8 00 00 00 00       	mov    $0x0,%eax
  4010d2:	e8 29 fb ff ff       	callq  400c00 <__isoc99_sscanf@plt>
  4010d7:	83 f8 01             	cmp    $0x1,%eax
  4010da:	75 07                	jne    4010e3 <phase_4+0x24>
  4010dc:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)
  4010e1:	7f 05                	jg     4010e8 <phase_4+0x29>
  4010e3:	e8 fb 05 00 00       	callq  4016e3 <explode_bomb>
  4010e8:	8b 7c 24 0c          	mov    0xc(%rsp),%edi
  4010ec:	e8 b4 ff ff ff       	callq  4010a5 <func4>
  4010f1:	3d 00 5f 37 00       	cmp    $0x375f00,%eax
  4010f6:	74 05                	je     4010fd <phase_4+0x3e>
  4010f8:	e8 e6 05 00 00       	callq  4016e3 <explode_bomb>
  4010fd:	48 83 c4 18          	add    $0x18,%rsp
  401101:	c3                   	retq   


第四個炸彈是關於遞歸的。

首先看到

4010c8:	be 74 1b 40 00       	mov    $0x401b74,%esi
看看0x401b74裏面的內容。

得到:"%d"

這次只要一個數就行了。

繼續下去,看到輸入的數被放入edi這個寄存器裏面,然後調用了func4這個函數。下面看看func4函數

00000000004010a5 <func4>:
  4010a5:	53                   	push   %rbx
  4010a6:	89 fb                	mov    %edi,%ebx
  4010a8:	b8 01 00 00 00       	mov    $0x1,%eax
  4010ad:	83 ff 01             	cmp    $0x1,%edi
  4010b0:	7e 0b                	jle    4010bd <func4+0x18>
  4010b2:	8d 7f ff             	lea    -0x1(%rdi),%edi
  4010b5:	e8 eb ff ff ff       	callq  4010a5 <func4>
  4010ba:	0f af c3             	imul   %ebx,%eax
  4010bd:	5b                   	pop    %rbx
  4010be:	c3                   	retq   

fun4分析:

首先,進行初始化

ebx=edi(函數的輸入),eax=1

然後比較edi和1的大小,若edi<=1 退出函數,若edi>1,edi=edi-1;繼續調用func4,再計算eax=eax*ebx;

這裏就比較清楚了,func4整個函數就是一個遞歸調用,他的輸入是edi,eax寄存器相當於一個累乘器,eax=eax*edi,直到edi<=1;

用c++寫,func4就是:

func4(int x)
{
      if(x>=1)
          return 1;
      return x*func4(x-1);
}

fun4調用結束後,

4010f1: 3d 00 5f 37 00 cmp $0x375f00,%eax

把eax和0x375F00比較,也就是求x!=0x375F00

最後求出來X=10;

輸入結果,正確!


phase_5:

0000000000401102 <phase_5>:
  401102:	53                   	push   %rbx
  401103:	48 89 fb             	mov    %rdi,%rbx
  401106:	e8 e6 01 00 00       	callq  4012f1 <string_length>
  40110b:	83 f8 06             	cmp    $0x6,%eax
  40110e:	74 05                	je     401115 <phase_5+0x13>
  401110:	e8 ce 05 00 00       	callq  4016e3 <explode_bomb>
  401115:	b8 00 00 00 00       	mov    $0x0,%eax
  40111a:	ba 00 00 00 00       	mov    $0x0,%edx
  40111f:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx
  401123:	83 e1 0f             	and    $0xf,%ecx
  401126:	03 14 8d c0 1b 40 00 	add    0x401bc0(,%rcx,4),%edx
  40112d:	48 83 c0 01          	add    $0x1,%rax
  401131:	48 83 f8 06          	cmp    $0x6,%rax
  401135:	75 e8                	jne    40111f <phase_5+0x1d>
  401137:	83 fa 3e             	cmp    $0x3e,%edx
  40113a:	74 05                	je     401141 <phase_5+0x3f>
  40113c:	e8 a2 05 00 00       	callq  4016e3 <explode_bomb>
  401141:	5b                   	pop    %rbx
  401142:	c3                   	retq   

第五個炸彈,感覺有點像密碼轉化的意思。

首先看到

  40110b:	83 f8 06             	cmp    $0x6,%eax

輸入6個數據,而且根據上面的指令,數據時字符串形式的,也就是字符串長度爲6.

  40111f:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx

這條指令中,rax已經初始化爲0,但是一開始沒有搞明白rbx的大小,回過頭看上面,有一句

  401103:	48 89 fb             	mov    %rdi,%rbx
表示rbx就是輸入的數據的存儲地址,那前面那句的意思就是一個一個讀取輸入的字符,將其賦值給ecx這個寄存器。

401123:	83 e1 0f             	and    $0xf,%ecx
這句就是取ecx的低4位,其他爲置零。

  401126:	03 14 8d c0 1b 40 00 	add    0x401bc0(,%rcx,4),%edx

這句就是從(0x401bc0+rcx*4)裏面拿數據出來,加到edx上。

因爲rcx只能是0~F的數,所以0x401bc0這個地址裏面存的應該是一個數據大小爲16的數組,用gdb看,得到:



果然是一個數組,然後下面就是把6個輸入一個一個的轉化爲這個數組,得到累加值edx
401137:	83 fa 3e             	cmp    $0x3e,%edx
最後得到的edx要是0x3e,這個就湊,最後湊了一個答案出來LMNOKA

輸入,正確!

這題總結一下,就是輸入6個字符,然後程序會根據6個字符的ascii碼的低4位作爲索引,在這裏,可以看成是一個預先設定好的數組的下標,通過索引,把數組中相應的值拿出來求和,最後要求求得的和爲0x3e就可以了。


最後一個了

phase_6:

00000000004011b2 <phase_6>:
  4011b2:	48 83 ec 08          	sub    $0x8,%rsp
  4011b6:	ba 0a 00 00 00       	mov    $0xa,%edx
  4011bb:	be 00 00 00 00       	mov    $0x0,%esi
  4011c0:	e8 1b fa ff ff       	callq  400be0 <strtol@plt>
  4011c5:	89 05 55 21 20 00    	mov    %eax,0x202155 (%rip)        # 603320 <node0>
  4011cb:	bf 20 33 60 00       	mov    $0x603320,%edi
  4011d0:	e8 6e ff ff ff       	callq  401143 <fun6>
  4011d5:	48 8b 40 08          	mov    0x8(%rax),%rax
  4011d9:	8b 0d 41 21 20 00    	mov    0x202141(%rip),%ecx        # 603320 <node0>
  4011df:	39 08                	cmp    %ecx,(%rax)
  4011e1:	74 05                	je     4011e8 <phase_6+0x36>
  4011e3:	e8 fb 04 00 00       	callq  4016e3 <explode_bomb>
  4011e8:	48 83 c4 08          	add    $0x8,%rsp
  4011ec:	c3                   	retq   

這個,太坑了。一開始在做的時候,看到一個func6,就一頭紮了進去,被裏面的跳轉搞得快瘋了,以前的程序員真是牛逼,寫這種代碼應該還能接受,但是要是去讀這種彙編級別的代碼,邏輯能被搞死啊……

後來實在受不了了,不看func6,直接給了一個輸入,gdb一步一步調試,竟然成功了,我也是醉了。

從調用func6之後看這段程序。

可以看到:

  4011df:	39 08                	cmp    %ecx,(%rax)



這句是關鍵,他其實比較的是ecx和rax兩個寄存器,經過調試,發現ecx就是輸入的那個數,而rax竟然是一個定值……

通過查看rax這個寄存器,取出裏面地址所對應的的值,得到:



發現就是和692比較,最後輸入692,正確。

最後一個太坑,要是跳到func6裏面就完蛋了。


結果:





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