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
首先,進行初始化
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
40111f: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
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
因爲rcx只能是0~F的數,所以0x401bc0這個地址裏面存的應該是一個數據大小爲16的數組,用gdb看,得到:
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裏面就完蛋了。
結果: