你能夠用gdb,和反編譯破解做者設置的密碼。固然,做者提供了不帶實現的c源碼和(估計使用0g優化級別)。下降難度。node
code:數組
0000000000400ee0 <phase_1>: 400ee0: 48 83 ec 08 sub $0x8,%rsp 400ee4: be 00 24 40 00 mov $0x402400,%esi # 關鍵代碼 400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal> 400eee: 85 c0 test %eax,%eax 400ef0: 74 05 je 400ef7 <phase_1+0x17> 400ef2: e8 43 05 00 00 callq 40143a <explode_bomb> 400ef7: 48 83 c4 08 add $0x8,%rsp 400efb: c3 retq
作了挺多無用功,好比靠函數名就能才猜到的功能不必去反推c源碼。也瞭解了elf文件,知道如何定義程序入口。最後使用gdb查看地址找到密碼:數據結構
0x402400: "Border relations with Canada have never been better."
函數
000000000040145c <read_six_numbers>: # (%rsp) in %rsi offse comp to 400efe 40145c: 48 83 ec 18 sub $0x18,%rsp # 400efe-64 401460: 48 89 f2 mov %rsi,%rdx # rdx=rsp-40 save arg2 401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx 401467: 48 8d 46 14 lea 0x14(%rsi),%rax 40146b: 48 89 44 24 08 mov %rax,0x8(%rsp) 401470: 48 8d 46 10 lea 0x10(%rsi),%rax 401474: 48 89 04 24 mov %rax,(%rsp) # 401478: 4c 8d 4e 0c lea 0xc(%rsi),%r9 # 40147c: 4c 8d 46 08 lea 0x8(%rsi),%r8 # 401480: be c3 25 40 00 mov $0x4025c3,%esi 401485: b8 00 00 00 00 mov $0x0,%eax 40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt> 40148f: 83 f8 05 cmp $0x5,%eax 401492: 7f 05 jg 401499 <read_six_numbers+0x3d> 401494: e8 a1 ff ff ff callq 40143a <explode_bomb> 401499: 48 83 c4 18 add $0x18,%rsp 40149d: c3 retq
read_six_number,根據傳入的是棧指針,以及彙編一直在基於棧作賦值之類的運算,能夠推測出arg2是數組。再用內存查看對0x4025c3,能夠看到是"%d %d ..." 六個d。結合sscanf函數的意義,能夠理解爲把input,即參數0,以指定格式給到六個參數中,這六個參數應該是數組。oop
這裏能夠gdb而後畫個圖方便理解。優化
再看phase2就比較簡單了。this
0000000000400efc <phase_2>: 400efc: 55 push %rbp 400efd: 53 push %rbx 400efe: 48 83 ec 28 sub $0x28,%rsp # -40 400f02: 48 89 e6 mov %rsp,%rsi 400f05: e8 52 05 00 00 callq 40145c <read_six_numbers> 400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) 400f0e: 74 20 je 400f30 <phase_2+0x34> 400f10: e8 25 05 00 00 callq 40143a <explode_bomb> 400f15: eb 19 jmp 400f30 <phase_2+0x34> 400f17: 8b 43 fc mov -0x4(%rbx),%eax 400f1a: 01 c0 add %eax,%eax 400f1c: 39 03 cmp %eax,(%rbx) 400f1e: 74 05 je 400f25 <phase_2+0x29> 400f20: e8 15 05 00 00 callq 40143a <explode_bomb> 400f25: 48 83 c3 04 add $0x4,%rbx 400f29: 48 39 eb cmp %rbp,%rbx 400f2c: 75 e9 jne 400f17 <phase_2+0x1b> # jump to loop 400f2e: eb 0c jmp 400f3c <phase_2+0x40> # jump to exit 400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx 400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp 400f3a: eb db jmp 400f17 <phase_2+0x1b> 400f3c: 48 83 c4 28 add $0x28,%rsp 400f40: 5b pop %rbx 400f41: 5d pop %rbp 400f42: c3 retq
就是數組開頭必須是1,而後依次*2.咱們也能夠根據-4,+4,+0x18猜到這是一個int 數組。debug
結果:1 2 4 8 16 323d
That's number 2. Keep going!
指針
應該是lab裏面最簡單的一個了。方法本地分配兩個變量,假設0x8(%rsp)=a,0xc(%rsp)=b,那麼只須要知足公式:8a+0x400f7c=b便可,那麼設置a=0,指令會跳轉到0x400f7c處,能夠看到直接賦值%rax 0xcf,那麼咱們只須要另b=207就好了。400fbe地址處
400f43: 48 83 ec 18 sub $0x18,%rsp 400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx 400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx 400f51: be cf 25 40 00 mov $0x4025cf,%esi 400f56: b8 00 00 00 00 mov $0x0,%eax 400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt> 400f60: 83 f8 01 cmp $0x1,%eax 400f63: 7f 05 jg 400f6a <phase_3+0x27> 400f65: e8 d0 04 00 00 callq 40143a <explode_bomb> 400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp) # arg1<=7 400f6f: 77 3c ja 400fad <phase_3+0x6a> 400f71: 8b 44 24 08 mov 0x8(%rsp),%eax 400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8) 400f7c: b8 cf 00 00 00 mov $0xcf,%eax 400f81: eb 3b jmp 400fbe <phase_3+0x7b> 400f83: b8 c3 02 00 00 mov $0x2c3,%eax 400f88: eb 34 jmp 400fbe <phase_3+0x7b> 400f8a: b8 00 01 00 00 mov $0x100,%eax 400f8f: eb 2d jmp 400fbe <phase_3+0x7b> 400f91: b8 85 01 00 00 mov $0x185,%eax 400f96: eb 26 jmp 400fbe <phase_3+0x7b> 400f98: b8 ce 00 00 00 mov $0xce,%eax 400f9d: eb 1f jmp 400fbe <phase_3+0x7b> 400f9f: b8 aa 02 00 00 mov $0x2aa,%eax 400fa4: eb 18 jmp 400fbe <phase_3+0x7b> 400fa6: b8 47 01 00 00 mov $0x147,%eax 400fab: eb 11 jmp 400fbe <phase_3+0x7b> 400fad: e8 88 04 00 00 callq 40143a <explode_bomb> 400fb2: b8 00 00 00 00 mov $0x0,%eax 400fb7: eb 05 jmp 400fbe <phase_3+0x7b> 400fb9: b8 37 01 00 00 mov $0x137,%eax 400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax 400fc2: 74 05 je 400fc9 <phase_3+0x86> 400fc4: e8 71 04 00 00 callq 40143a <explode_bomb> 400fc9: 48 83 c4 18 add $0x18,%rsp 400fcd: c3 retq
答案:0 207
Halfway there!
000000000040100c <phase_4>: 40100c: 48 83 ec 18 sub $0x18,%rsp # arg1=0 arg0<=e 401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx # 參數1 401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx # 參數0 40101a: be cf 25 40 00 mov $0x4025cf,%esi 40101f: b8 00 00 00 00 mov $0x0,%eax 401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt> 401029: 83 f8 02 cmp $0x2,%eax 40102c: 75 07 jne 401035 <phase_4+0x29> 40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp) 401033: 76 05 jbe 40103a <phase_4+0x2e> 401035: e8 00 04 00 00 callq 40143a <explode_bomb> 40103a: ba 0e 00 00 00 mov $0xe,%edx 40103f: be 00 00 00 00 mov $0x0,%esi 401044: 8b 7c 24 08 mov 0x8(%rsp),%edi 401048: e8 81 ff ff ff callq c <func4> # arg0, 0, e 40104d: 85 c0 test %eax,%eax 40104f: 75 07 jne 401058 <phase_4+0x4c> 401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) 401056: 74 05 je 40105d <phase_4+0x51> 401058: e8 dd 03 00 00 callq 40143a <explode_bomb> 40105d: 48 83 c4 18 add $0x18,%rsp 401061: c3 retq
func4
0000000000400fce <func4>: # x in %rdi , y in %rsi z in %rdx 400fce: 48 83 ec 08 sub $0x8,%rsp 400fd2: 89 d0 mov %edx,%eax 400fd4: 29 f0 sub %esi,%eax 400fd6: 89 c1 mov %eax,%ecx 400fd8: c1 e9 1f shr $0x1f,%ecx 400fdb: 01 c8 add %ecx,%eax 400fdd: d1 f8 sar %eax 400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx 400fe2: 39 f9 cmp %edi,%ecx 400fe4: 7e 0c jle 400ff2 <func4+0x24> 400fe6: 8d 51 ff lea -0x1(%rcx),%edx 400fe9: e8 e0 ff ff ff callq 400fce <func4> 400fee: 01 c0 add %eax,%eax 400ff0: eb 15 jmp 401007 <func4+0x39> 400ff2: b8 00 00 00 00 mov $0x0,%eax 400ff7: 39 f9 cmp %edi,%ecx 400ff9: 7d 0c jge 401007 <func4+0x39> 400ffb: 8d 71 01 lea 0x1(%rcx),%esi 400ffe: e8 cb ff ff ff callq 400fce <func4> 401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax 401007: 48 83 c4 08 add $0x8,%rsp 40100b: c3 retq
這一題要結合phase4 和fun4來看。
首先看sscanf的參數,%rsi
在0x4025c
f處,gdb查看是要求兩個整數,根據40102c
行也能得出此結論。40102e
行說明參數須要0小於等於14,而後0,和e被看成參數1,2傳遞給fun4.再根據fun4的彙編反彙編一下,通過幾版優化,基本能夠得出它的功能如上,一直用z模2,直到z==x
,不然返回2*fun(x,y,--z)
,其實else不用管它,由於若是你x傳遞0,那麼0*任何數都會返回0。並且結合401051
行。發現第二個輸入的數,也要是0,那麼就更不會走第二個狀況了。
感受這題須要的debug會比較多一點。
答案:0 0
鄙人可能錯誤的反彙編
int fun4(int x, int y, int z) //arg0,0,e ,should return 0 { z %=2;//offset%2 if(z == x){ return 0; } else{ return 2*fun(x,y,--z); } }
So you got that one. Try this one.
成功的喜悅~
0000000000401062 <phase_5>: 401062: 53 push %rbx 401063: 48 83 ec 20 sub $0x20,%rsp 401067: 48 89 fb mov %rdi,%rbx 40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax #40 401071: 00 00 401073: 48 89 44 24 18 mov %rax,0x18(%rsp) # 24 金絲雀值 401078: 31 c0 xor %eax,%eax # eax=0; 40107a: e8 9c 02 00 00 callq 40131b <string_length> 40107f: 83 f8 06 cmp $0x6,%eax 401082: 74 4e je 4010d2 <phase_5+0x70> 401084: e8 b1 03 00 00 callq 40143a <explode_bomb> 401089: eb 47 jmp 4010d2 <phase_5+0x70> ~ 40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx ~ 40108f: 88 0c 24 mov %cl,(%rsp) ~ 401092: 48 8b 14 24 mov (%rsp),%rdx ~ 401096: 83 e2 0f and $0xf,%edx ~ 401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx ~ 4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1) ~ 4010a4: 48 83 c0 01 add $0x1,%rax ~ 4010a8: 48 83 f8 06 cmp $0x6,%rax ~ 4010ac: 75 dd jne 40108b <phase_5+0x29> ~ 4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp) ~ 4010b3: be 5e 24 40 00 mov $0x40245e,%esi ~ 4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi ~ 4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal> 4010c2: 85 c0 test %eax,%eax 4010c4: 74 13 je 4010d9 <phase_5+0x77> 4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb> 4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 4010d0: eb 07 jmp 4010d9 <phase_5+0x77> 4010d2: b8 00 00 00 00 mov $0x0,%eax 4010d7: eb b2 jmp 40108b <phase_5+0x29> 4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax 4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax 4010e5: 00 00 4010e7: 74 05 je 4010ee <phase_5+0x8c> 4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt> 4010ee: 48 83 c4 20 add $0x20,%rsp 4010f2: 5b pop %rbx 4010f3: c3 retq
比較核心的代碼就是我用‘~’號標記出來的。大體的意思是取你輸入字符的最後一個字節,保留低4位,在加上基地址0x4024b0
取到一個字符,湊6個成字符串,再和0x40245e
處的字符比較,同樣退出,不然引爆。
比較難懂的是40106a
行mov %fs:0x28,%rax
。搜索得知這是利用段寄存器得到隨機值。還有4010a4: add $0x1,%rax
的目的。弄明白這兩個基本沒有問題。
這題沒有固定答案,只要你輸入的字符串每一個字節低四位依次等於9fe567
的二進制表示就行。個人答案:9/.567
Good work! On to the next...
這是六個語句中最長的一句。總共有三個部分。
4010f4: 41 56 push %r14 4010f6: 41 55 push %r13 4010f8: 41 54 push %r12 4010fa: 55 push %rbp 4010fb: 53 push %rbx 4010fc: 48 83 ec 50 sub $0x50,%rsp 401100: 49 89 e5 mov %rsp,%r13 401103: 48 89 e6 mov %rsp,%rsi 401106: e8 51 03 00 00 callq 40145c <read_six_numbers> 40110b: 49 89 e6 mov %rsp,%r14 40110e: 41 bc 00 00 00 00 mov $0x0,%r12d 401114: 4c 89 ed mov %r13,%rbp # -------------- 401117: 41 8b 45 00 mov 0x0(%r13),%eax 40111b: 83 e8 01 sub $0x1,%eax 40111e: 83 f8 05 cmp $0x5,%eax 401121: 76 05 jbe 401128 <phase_6+0x34> # 401123: e8 12 03 00 00 callq 40143a <explode_bomb> 401128: 41 83 c4 01 add $0x1,%r12d 40112c: 41 83 fc 06 cmp $0x6,%r12d 401130: 74 21 je 401153 <phase_6+0x5f> 401132: 44 89 e3 mov %r12d,%ebx 401135: 48 63 c3 movslq %ebx,%rax 401138: 8b 04 84 mov (%rsp,%rax,4),%eax 40113b: 39 45 00 cmp %eax,0x0(%rbp) 40113e: 75 05 jne 401145 <phase_6+0x51> # 2 401140: e8 f5 02 00 00 callq 40143a <explode_bomb> 401145: 83 c3 01 add $0x1,%ebx 401148: 83 fb 05 cmp $0x5,%ebx 40114b: 7e e8 jle 401135 <phase_6+0x41> 40114d: 49 83 c5 04 add $0x4,%r13 401151: eb c1 jmp 401114 <phase_6+0x20> # (%r13+4)-1<=5 401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi # [5] 401158: 4c 89 f0 mov %r14,%rax # [0] 40115b: b9 07 00 00 00 mov $0x7,%ecx 401160: 89 ca mov %ecx,%edx 401162: 2b 10 sub (%rax),%edx # [i]= 7- [i] i start with 0 401164: 89 10 mov %edx,(%rax) 401166: 48 83 c0 04 add $0x4,%rax # i++ 40116a: 48 39 f0 cmp %rsi,%rax # while (i!=5) loop. 40116d: 75 f1 jne 401160 <phase_6+0x6c>
檢測你輸入的數是否大於7,或者是否有重複的。這裏有for循環嵌套比較難看懂。接着把每一個數-=7。
40116f: be 00 00 00 00 mov $0x0,%esi # rsi = i 401174: eb 21 jmp 401197 <phase_6+0xa3> # -------------------------------- 401176: 48 8b 52 08 mov 0x8(%rdx),%rdx # amazing code! 40117a: 83 c0 01 add $0x1,%eax 40117d: 39 c8 cmp %ecx,%eax 40117f: 75 f5 jne 401176 <phase_6+0x82> # -------------------------------- 401181: eb 05 jmp 401188 <phase_6+0x94> # ----------------------------------------------- 401183: ba d0 32 60 00 mov $0x6032d0,%edx # ------------------------------------內循環 i 找到a[i]>1的,同時對i++ 401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2) 40118d: 48 83 c6 04 add $0x4,%rsi 401191: 48 83 fe 18 cmp $0x18,%rsi # i < 6 401195: 74 14 je 4011ab <phase_6+0xb7> # jump out from loop 401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx 40119a: 83 f9 01 cmp $0x1,%ecx 40119d: 7e e4 jle 401183 <phase_6+0x8f> # ----------------------------------------------- # ------------------------------------else 40119f: b8 01 00 00 00 mov $0x1,%eax 4011a4: ba d0 32 60 00 mov $0x6032d0,%edx 4011a9: eb cb jmp 401176 <phase_6+0x82>
將棧上分配6個變量存放鏈表指針。這裏功能最少確是最複雜的。由於引入了複雜數據結構(即便是最簡單的),因此讓反彙編起來難以理解,特別是雙重循環的關係。到底誰是外循環,誰又是內循環,哪一個寄存器控制着跳出條件?而後就是慢慢完善c語言,最後讓c和彙編的邏輯一一對應。
從gdb看得出來是鏈表
(gdb) x/6xg 0x7fffffffde40 0x7fffffffde40: 0x00000000006032d0 0x0000000000603320 0x7fffffffde50: 0x0000000000603310 0x0000000000603300 0x7fffffffde60: 0x00000000006032f0 0x00000000006032e0 x/12xg 0x6032d0 0x6032d0 <node1>: 0x000000010000014c 0x00000000006032e0 0x6032e0 <node2>: 0x00000002000000a8 0x00000000006032f0 0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300 0x603300 <node4>: 0x00000004000002b3 0x0000000000603310 0x603310 <node5>: 0x00000005000001dd 0x0000000000603320 0x603320 <node6>: 0x00000006000001bb 0x0000000000000000
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx # b=node1 4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax # 4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi # 4011ba: 48 89 d9 mov %rbx,%rcx 4011bd: 48 8b 10 mov (%rax),%rdx # 4011c0: 48 89 51 08 mov %rdx,0x8(%rcx) # 4011c4: 48 83 c0 08 add $0x8,%rax # 4011c8: 48 39 f0 cmp %rsi,%rax # not 4011cb: 74 05 je 4011d2 <phase_6+0xde> 4011cd: 48 89 d1 mov %rdx,%rcx # rcx 4011d0: eb eb jmp 4011bd <phase_6+0xc9> # 0x6032d0 332 4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx) # *(d->next)=0 4011d9: 00 4011da: bd 05 00 00 00 mov $0x5,%ebp 4011df: 48 8b 43 08 mov 0x8(%rbx),%rax 4011e3: 8b 00 mov (%rax),%eax 4011e5: 39 03 cmp %eax,(%rbx) 4011e7: 7d 05 jge 4011ee <phase_6+0xfa> 4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb> 4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx 4011f2: 83 ed 01 sub $0x1,%ebp 4011f5: 75 e8 jne 4011df <phase_6+0xeb> 4011f7: 48 83 c4 50 add $0x50,%rsp 4011fb: 5b pop %rbx 4011fc: 5d pop %rbp 4011fd: 41 5c pop %r12 4011ff: 41 5d pop %r13 401201: 41 5e pop %r14 401203: c3 retq
其實這一部分仍是能夠根據4011d9: 00
分紅2部分。第一部分把0x6032d0
處的鏈表鏈接起來。具體是node6->node1;其他從小到大依次鏈接。
mov 0x8(%rbx),%rax mov (%rax),%eax cmp %eax,(%rbx) jge 4011ee <phase_6+0xfa> callq 40143a <explode_bomb>
第二部分(上面代碼)就是要求前面後四位的要大於後面的。要求node1~node6 數據後4位從大到小排列。即對
(gdb) x/12xg 0x6032d0 0x6032d0 <node1>: 0x000000010000014c 0x0000000000603320 0x6032e0 <node2>: 0x00000002000000a8 0x00000000006032f0 0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300 0x603300 <node4>: 0x00000004000002b3 0x0000000000603310 0x603310 <node5>: 0x00000005000001dd 0x0000000000603320 0x603320 <node6>: 0x00000006000001bb 0x0000000000603310
排列。而這個數據是在第二部放置的。
應該的順序:3 4 5 6 1 2。然而在部分1會對全部輸入-=7。
因此答案:4 3 2 1 6 5Congratulations! You've defused the bomb!
至此,bomblab主線完成,聽說還有一個secret phase .棄。
Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day! Phase 1 defused. How about the next one? That's number 2. Keep going! Halfway there! So you got that one. Try this one. Good work! On to the next... Congratulations! You've defused the bomb!