這是 2016 版的 bomb
下載得到 bomb.tar 文件,解壓后只有 bomb 二進(jìn)制文件,以及一個(gè) bomb.c 文件,bomb.c 沒(méi)有對(duì)應(yīng)的頭文件。所有思路只有是反匯編 bomb, 分析匯編代碼。
這里用到兩個(gè)非常強(qiáng)大的工具 objdump,gdb
- objdump 用來(lái)反匯編的,-d 參數(shù)得到 x86 匯編,-M 參數(shù)還可以選擇不同的匯編形式,比如 -M 8086 得到 8086 匯編,詳細(xì)內(nèi)容可以 man objdump.
- gdb 是強(qiáng)大的 GNU DEBUGGER 用法如下
(gdb) b(breakpoint): 用法:b 函數(shù)名 :對(duì)此函數(shù)進(jìn)行中斷 ;b 文件名:行號(hào);
(gdb) run:?jiǎn)?dòng)程序,運(yùn)行至程序的斷點(diǎn)或者結(jié)束;
(gdb) l(list): 用法:l funcname,制定函數(shù)的源碼
(gdb) s(step): 進(jìn)入函數(shù),逐語(yǔ)句運(yùn)行;
(gdb) n(next): 不進(jìn)入函數(shù),逐過(guò)程運(yùn)行;
(gdb) c(continue):繼續(xù)運(yùn)行,跳至下一個(gè)斷點(diǎn);
(gdb) p(print):打印顯示變量值;
(gdb) set variable=value, 為變量賦值;
(gdb) kill:終止調(diào)試的程序;
(gdb) h(help):列出 gdb 詳細(xì)命令幫助列表;
(gdb) clear filename.c:30:清除 30 行處的斷點(diǎn);
(gdb) info break:顯示斷點(diǎn)信息;
(gdb) delete 斷點(diǎn)編號(hào):斷點(diǎn)編號(hào)是 info break 后顯示出來(lái)的;
(gdb) bt(backtrace):回溯到段出錯(cuò)的位置;
(gdb) frame 幀號(hào):幀號(hào)是 bt 命令產(chǎn)生的堆棧針;
(gdb) q:退出;
(gdb) x(examine):查看內(nèi)存中的值等 // 詳細(xì)內(nèi)容在 gdb 中輸入 help x 查看
下面開(kāi)始拆 :bomb: 之旅
general
觀察匯編代碼,可以看到有 main, phase1--6, 等,重點(diǎn)看這幾個(gè)函數(shù),從 main 開(kāi)始,結(jié)合 bomb.c, 可以明白程序的控制流,每個(gè)階段用 phase 函數(shù)判斷輸入是否正確,不正確就 boon, 結(jié)束程序
phase1
來(lái)到 phase1,
第一行準(zhǔn)備棧幀,第二行就是將地址存入 $esi, 這是一個(gè)字符串的地址,可以猜測(cè)下面 string_not_equal 就是比較這個(gè)字符串與輸入字符串是否相等的函數(shù).(最開(kāi)始我還去分析了這個(gè)函數(shù)的匯編代碼,確實(shí)是那樣,先比較長(zhǎng)度,然后逐一比較。所以找到這個(gè)地址0x402400
存儲(chǔ)的字符串就行了,在 asm 文件中搜索,沒(méi)有,所以要在程序運(yùn)行時(shí)才可以到達(dá)這個(gè)虛擬地址,未來(lái) address space 的堆中。這時(shí)就要用到強(qiáng)大的 gdb 了,
切換到 bomb 文件夾,依次輸入
gdb
(gdb) file bomb
(gdb) x /s 0x402400 # x(examine) s 參數(shù)是 string 的意思
即得Border relations with Canada have never been better.
phase2
所以答案是 1 2 4 8 16 32
phase3
0000000000400f43 <phase_3>:
400f43: sub $0x18,%rsp
400f47: lea 0xc(%rsp),%rcx
400f4c: lea 0x8(%rsp),%rdx
400f51: mov $0x4025cf,%esi # 又是一個(gè)字符串,可以用 gdb 查看,得到`"%d %d", 格式化字符串,說(shuō)明輸入兩個(gè)數(shù)字
400f56: mov $0x0,%eax
400f5b: callq 400bf0 <__isoc99_sscanf@plt> # 輸入
400f60: cmp $0x1,%eax # 判斷輸入成功
400f63: jg 400f6a <phase_3+0x27>
400f65: callq 40143a <explode_bomb>
400f6a: cmpl $0x7,0x8(%rsp) # 第一個(gè)參數(shù)是否小于等于 7, 大于則 boom
400f6f: ja 400fad <phase_3+0x6a>
400f71: mov 0x8(%rsp),%eax
400f75: jmpq *0x402470(,%rax,8) # 以下是 switch, 根據(jù) rax, 即第一個(gè)輸入的參數(shù)跳轉(zhuǎn)
400f7c: mov $0xcf,%eax # 由此容易得到答案,比如這里是 rax=0 時(shí),則 另一個(gè)參數(shù)為 0xcf = 207
400f81: jmp 400fbe <phase_3+0x7b>
400f83: mov $0x2c3,%eax
400f88: jmp 400fbe <phase_3+0x7b>
400f8a: mov $0x100,%eax
400f8f: jmp 400fbe <phase_3+0x7b>
400f91: mov $0x185,%eax
400f96: jmp 400fbe <phase_3+0x7b>
400f98: mov $0xce,%eax
400f9d: jmp 400fbe <phase_3+0x7b>
400f9f: mov $0x2aa,%eax
400fa4: jmp 400fbe <phase_3+0x7b>
400fa6: mov $0x147,%eax
400fab: jmp 400fbe <phase_3+0x7b>
400fad: callq 40143a <explode_bomb>
400fb2: mov $0x0,%eax
400fb7: jmp 400fbe <phase_3+0x7b>
400fb9: mov $0x137,%eax
400fbe: cmp 0xc(%rsp),%eax
400fc2: je 400fc9 <phase_3+0x86>
400fc4: callq 40143a <explode_bomb>
400fc9: add $0x18,%rsp
400fcd: retq
swith 跳轉(zhuǎn)表
%rax 跳轉(zhuǎn)地址 0xc(%rsp)
0 0x0000000000400f7c 0xcf 207
1 0x0000000000400fb9 0x137 311
2 0x0000000000400f83 0x2c3 707
3 0x0000000000400f8a 0x100 256
4 0x0000000000400f91 0x185 389
5 0x0000000000400f98 0xce 206
6 0x0000000000400f9f 0x2aa 682
7 0x0000000000400fa6 0x147 327
所以結(jié)果為0 207
...
phase4
000000000040100c <phase_4>:
40100c: sub $0x18,%rsp
401010: lea 0xc(%rsp),%rcx
401015: lea 0x8(%rsp),%rdx
40101a: mov $0x4025cf,%esi #同樣,gdb 中 x /s 知道輸入兩個(gè)數(shù)字
40101f: mov $0x0,%eax
401024: callq 400bf0 <__isoc99_sscanf@plt>
401029: cmp $0x2,%eax # 判斷是否輸入兩個(gè)數(shù)
40102c: jne 401035 <phase_4+0x29>
40102e: cmpl $0xe,0x8(%rsp) # 判斷每個(gè)數(shù)是否≤14 , 大于則 boom
401033: jbe 40103a <phase_4+0x2e> # 跳轉(zhuǎn)
401035: callq 40143a <explode_bomb>
40103a: mov $0xe,%edx # 構(gòu)造 func4 的參數(shù) (phase4 調(diào)用的)
40103f: mov $0x0,%esi # 構(gòu)造 func4 的參數(shù)
401044: mov 0x8(%rsp),%edi # 構(gòu)造 func4 的參數(shù)
401048: callq 400fce <func4>
40104d: test %eax,%eax # 測(cè)試,func4 返回 0, 若不,則 boom
40104f: jne 401058 <phase_4+0x4c>
401051: cmpl $0x0,0xc(%rsp)
401056: je 40105d <phase_4+0x51>
401058: callq 40143a <explode_bomb>
40105d: add $0x18,%rsp
401061: retq
將 func4 轉(zhuǎn)換為 c 語(yǔ)言,并用 0--14 測(cè)試,這點(diǎn)很難,需要翻譯匯編語(yǔ)言,花很多時(shí)間,得熟悉匯編代碼才行
int func4(int a, int b, int c)
{
int result;
result = c;
result = result - b;
int tmp = result;
tmp = (unsigned)tmp >> 31;
result = result + tmp;
result = result / 2;
tmp = result + b;
if(tmp > a)
{
c = tmp - 1;
result = func4(a, b, c);
return (2 * result);
}
result = 0;
if(tmp < a)
{
b = tmp + 1;
result = func4(a, b, c);
return (1 + 2 * result);
}
return result;
}
// 測(cè)試從 0~14 范圍內(nèi)滿足條件的值
int main()
{
for(int input = 0; input < 15; ++input)
{
int result = func4(input, 0, 14);
if(result == 0)
{
printf("input = %d, func4 = %d\n", input, result);
}
}
return 0;
}
得到可行解
因此 phase4 可能結(jié)果為:
0 0
1 0
3 0
7 0
phase5
嗯,加油,還有兩關(guān)了。(●ˇ?ˇ●)
0000000000401062 <phase_5>:
401062: push %rbx
401063: sub $0x20,%rsp
401067: mov %rdi,%rbx
40106a: mov %fs:0x28,%rax
401071:
401073: mov %rax,0x18(%rsp)
401078: xor %eax,%eax
40107a: callq 40131b <string_length>
40107f: cmp $0x6,%eax # 說(shuō)明輸入是六個(gè)字符
401082: je 4010d2 <phase_5+0x70>
401084: callq 40143a <explode_bomb>
401089: jmp 4010d2 <phase_5+0x70>
40108b: movzbl (%rbx,%rax,1),%ecx # 從棧幀中取出各個(gè)字符,記為 x
40108f: mov %cl,(%rsp)
401092: mov (%rsp),%rdx
401096: and $0xf,%edx # y=0xf & x, 即將一個(gè) byte 的高 4 位置 0
401099: movzbl 0x4024b0(%rdx),%edx # 用 gdb 查看 x /s 0x4024b0 得到字符串"maduiersnfotvbyl", 所以這一行是以 y 作為偏移量,取字符數(shù)組的第幾個(gè)字符
4010a0: mov %dl,0x10(%rsp,%rax,1) # 將取得的存于棧幀中 // 后面用 string_not_equl 比較
4010a4: add $0x1,%rax
4010a8: cmp $0x6,%rax # 循環(huán) 6 次
4010ac: jne 40108b <phase_5+0x29>
4010ae: movb $0x0,0x16(%rsp)
4010b3: mov $0x40245e,%esi # 這是要比較的字符串,同樣用 gdb 查看得到 "flyers"
4010b8: lea 0x10(%rsp),%rdi
4010bd: callq 401338 <strings_not_equal>
4010c2: test %eax,%eax
4010c4: je 4010d9 <phase_5+0x77>
4010c6: callq 40143a <explode_bomb>
4010cb: nopl 0x0(%rax,%rax,1)
4010d0: jmp 4010d9 <phase_5+0x77>
4010d2: mov $0x0,%eax
4010d7: jmp 40108b <phase_5+0x29>
4010d9: mov 0x18(%rsp),%rax
4010de: xor %fs:0x28,%rax
4010e5:
4010e7: je 4010ee <phase_5+0x8c>
4010e9: callq 400b30 <__stack_chk_fail@plt>
4010ee: add $0x20,%rsp
4010f2: pop %rbx
4010f3: retq
解釋在上面,反向得到需要的輸入的思路是:對(duì) flyers 的每個(gè)字符,得到在字符數(shù)組中的 index, 也就是輸入的字符的后 4 位 bit, 而鍵盤輸入一般是字母,所以很可能有兩種可能,字符 byte 的高四位為0100
或0110
, 而且可以發(fā)現(xiàn)剛好這是大寫字母 / 小寫字母開(kāi)始的前一個(gè) ascii, 所以用 python 算一下即得"ionefg"或是"IONEFG"
phase6
phase6 很難了,這真的要熟練匯編語(yǔ)言,我翻譯到前面,知道輸入的是六個(gè)不相同的數(shù)字,而且≤6 ,所以可以試全排列了, 后面的實(shí)在看不下去了,在網(wǎng)上找到這份解析
這是鏈接
(gdb) disas phase_6
Dump of assembler code for function phase_6:
0x00000000004010f4 <+0>: push %r14 將被調(diào)用者保存寄存器壓入棧
0x00000000004010f6 <+2>: push %r13
0x00000000004010f8 <+4>: push %r12
0x00000000004010fa <+6>: push %rbp
0x00000000004010fb <+7>: push %rbx %rsp = 0x7fffffffe2c0
0x00000000004010fc <+8>: sub $0x50,%rsp 分配棧空間 %rsp = 0x7fffffffe270
0x0000000000401100 <+12>: mov %rsp,%r13
0x0000000000401103 <+15>: mov %rsp,%rsi
0x0000000000401106 <+18>: callq 0x40145c <read_six_numbers> 讀入 6 個(gè)值,保存至從 %rsi 開(kāi)始的地址
0x000000000040110b <+23>: mov %rsp,%r14
0x000000000040110e <+26>: mov $0x0,%r12d %r12 置 0, 并且 %r13 %r14 %rbp 均和 %rsp 指向相同地址 0x7fffffffe270
0x0000000000401114 <+32>: mov %r13,%rbp
0x0000000000401117 <+35>: mov 0x0(%r13),%eax 將第 %r13 指向的輸入數(shù)復(fù)制到 %eax
0x000000000040111b <+39>: sub $0x1,%eax 將輸入數(shù)減 1
0x000000000040111e <+42>: cmp $0x5,%eax 判斷輸入數(shù)是否小于等于 6, 因?yàn)樯弦徊街袦p 1 操作
0x0000000000401121 <+45>: jbe 0x401128 <phase_6+52> 若大于 6, 則調(diào)用 explode_bomb
0x0000000000401123 <+47>: callq 0x40143a <explode_bomb>
=========================================================================================================================================================
0x0000000000401128 <+52>: add $0x1,%r12d 將 %r12 加 1
0x000000000040112c <+56>: cmp $0x6,%r12d 判斷 %r12 是否等于 6
0x0000000000401130 <+60>: je 0x401153 <phase_6+95> 若等于 6, 跳轉(zhuǎn),否則繼續(xù)執(zhí)行
0x0000000000401132 <+62>: mov %r12d,%ebx 將 %r12 復(fù)制到 %ebx
0x0000000000401135 <+65>: movslq %ebx,%rax 將 %ebx 符號(hào)位擴(kuò)展復(fù)制到 %rax
0x0000000000401138 <+68>: mov (%rsp,%rax,4),%eax 將第 %ebx 輸入數(shù)復(fù)制到 %eax
0x000000000040113b <+71>: cmp %eax,0x0(%rbp) 比較 %r13 指向的輸入數(shù)和 第 %ebx 輸入數(shù) 是否相等
0x000000000040113e <+74>: jne 0x401145 <phase_6+81> 如果相等,則調(diào)用 explode_bomb
0x0000000000401140 <+76>: callq 0x40143a <explode_bomb>
0x0000000000401145 <+81>: add $0x1,%ebx 將 %ebx 加 1
0x0000000000401148 <+84>: cmp $0x5,%ebx 判斷 %ebx 是否小于等于 5
0x000000000040114b <+87>: jle 0x401135 <phase_6+65> 若小于等于,跳轉(zhuǎn),否則繼續(xù)執(zhí)行;該循環(huán)判斷 %r13 指向的數(shù)據(jù)和其后輸入數(shù)不相等
0x000000000040114d <+89>: add $0x4,%r13 將 %r13 指向下一個(gè)輸入數(shù),該循環(huán)判斷所有的輸入數(shù)全部不相等
0x0000000000401151 <+93>: jmp 0x401114 <phase_6+32>
=========================================================================================================================================================
0x0000000000401153 <+95>: lea 0x18(%rsp),%rsi 將 %rsi 指向棧中跳過(guò)讀入數(shù)據(jù)位置作為結(jié)束標(biāo)記,并且 %r14 仍和 %rsp 指向同一個(gè)位置
0x0000000000401158 <+100>: mov %r14,%rax 將 %r14 復(fù)制到 %rax
0x000000000040115b <+103>: mov $0x7,%ecx
0x0000000000401160 <+108>: mov %ecx,%edx 將立即數(shù) 0x7 復(fù)制到 %edx
0x0000000000401162 <+110>: sub (%rax),%edx 立即數(shù) 7 減去 %r14 指向的數(shù)據(jù)
0x0000000000401164 <+112>: mov %edx,(%rax) 將 7 減的結(jié)果存回 %r14 執(zhí)行的內(nèi)存單元
0x0000000000401166 <+114>: add $0x4,%rax %rax 指向下一個(gè)輸入數(shù)
0x000000000040116a <+118>: cmp %rsi,%rax 比較是否達(dá)到輸入數(shù)組的末尾,
0x000000000040116d <+121>: jne 0x401160 <phase_6+108> 該循環(huán)使用立即數(shù) 7 減去每個(gè)輸入數(shù)據(jù)
==========================================================================================================================================================
0x000000000040116f <+123>: mov $0x0,%esi 將 %rsi 置 0
0x0000000000401174 <+128>: jmp 0x401197 <phase_6+163>
0x0000000000401176 <+130>: mov 0x8(%rdx),%rdx 將 0x8(%rdx) 指向內(nèi)存單元的內(nèi)容復(fù)制到 %rdx, 指向鏈表下一個(gè)元素
0x000000000040117a <+134>: add $0x1,%eax 將 %eax 加 1
0x000000000040117d <+137>: cmp %ecx,%eax 比較 %ecx 和 %eax 是否相等
0x000000000040117f <+139>: jne 0x401176 <phase_6+130> 不相等,繼續(xù)遍歷鏈表,最終 %rdx 指向鏈表的第 %ecx 個(gè)節(jié)點(diǎn)
0x0000000000401181 <+141>: jmp 0x401188 <phase_6+148>
0x0000000000401183 <+143>: mov $0x6032d0,%edx 重置鏈表首地址
0x0000000000401188 <+148>: mov %rdx,0x20(%rsp,%rsi,2)
0x000000000040118d <+153>: add $0x4,%rsi
0x0000000000401191 <+157>: cmp $0x18,%rsi
0x0000000000401195 <+161>: je 0x4011ab <phase_6+183>
0x0000000000401197 <+163>: mov (%rsp,%rsi,1),%ecx 將 (%rsp + %rsi) 指向的數(shù)據(jù)復(fù)制到 %ecx
0x000000000040119a <+166>: cmp $0x1,%ecx 比較 %ecx 是否小于等于 1
0x000000000040119d <+169>: jle 0x401183 <phase_6+143> 若小于等于,跳轉(zhuǎn),否則繼續(xù)執(zhí)行,等于 1, %edx 直接指向鏈表首地址
0x000000000040119f <+171>: mov $0x1,%eax 將 %eax 置 1
0x00000000004011a4 <+176>: mov $0x6032d0,%edx 將 %rdx 指向內(nèi)存單元 0x6032d0
0x00000000004011a9 <+181>: jmp 0x401176 <phase_6+130> 跳轉(zhuǎn);該循環(huán)根據(jù)輸入數(shù)將鏈表中對(duì)應(yīng)的第輸入數(shù)個(gè)節(jié)點(diǎn)的地址復(fù)制到 0x20(%rsp) 開(kāi)始的棧中
==========================================================================================================================================================
0x00000000004011ab <+183>: mov 0x20(%rsp),%rbx 將 0x20(%rsp) 的鏈表節(jié)點(diǎn)地址復(fù)制到 %rbx
0x00000000004011b0 <+188>: lea 0x28(%rsp),%rax 將 %rax 指向棧中下一個(gè)鏈表節(jié)點(diǎn)的地址
0x00000000004011b5 <+193>: lea 0x50(%rsp),%rsi 將 %rsi 指向保存的鏈表節(jié)點(diǎn)地址的末尾
0x00000000004011ba <+198>: mov %rbx,%rcx
0x00000000004011bd <+201>: mov (%rax),%rdx
0x00000000004011c0 <+204>: mov %rdx,0x8(%rcx) 將棧中指向的后一個(gè)節(jié)點(diǎn)的地址復(fù)制到前一個(gè)節(jié)點(diǎn)的地址位置
0x00000000004011c4 <+208>: add $0x8,%rax 移動(dòng)到下一個(gè)節(jié)點(diǎn)
0x00000000004011c8 <+212>: cmp %rsi,%rax 判斷 6 個(gè)節(jié)點(diǎn)是否遍歷完畢
0x00000000004011cb <+215>: je 0x4011d2 <phase_6+222>
0x00000000004011cd <+217>: mov %rdx,%rcx
0x00000000004011d0 <+220>: jmp 0x4011bd <phase_6+201>
0x00000000004011d2 <+222>: movq $0x0,0x8(%rdx) 該循環(huán)按照 7 減去輸入數(shù)據(jù)的索引重新調(diào)整鏈表
==========================================================================================================================================================
0x00000000004011da <+230>: mov $0x5,%ebp
0x00000000004011df <+235>: mov 0x8(%rbx),%rax 將 %rax 指向 %rbx 下一個(gè)鏈表節(jié)點(diǎn)
0x00000000004011e3 <+239>: mov (%rax),%eax
0x00000000004011e5 <+241>: cmp %eax,(%rbx) 比較鏈表節(jié)點(diǎn)中第一個(gè)字段值的大小,如果前一個(gè)節(jié)點(diǎn)值大于后一個(gè)節(jié)點(diǎn)值,跳轉(zhuǎn)
0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250>
0x00000000004011e9 <+245>: callq 0x40143a <explode_bomb>
0x00000000004011ee <+250>: mov 0x8(%rbx),%rbx 將 %rbx 向后移動(dòng),指向棧中下一個(gè)鏈表節(jié)點(diǎn)的地址
0x00000000004011f2 <+254>: sub $0x1,%ebp 判斷循環(huán)是否結(jié)束,該循環(huán)判斷棧中重新調(diào)整后的鏈表節(jié)點(diǎn)是否按照降序排列
0x00000000004011f5 <+257>: jne 0x4011df <phase_6+235>
0x00000000004011f7 <+259>: add $0x50,%rsp
0x00000000004011fb <+263>: pop %rbx
0x00000000004011fc <+264>: pop %rbp
0x00000000004011fd <+265>: pop %r12
0x00000000004011ff <+267>: pop %r13
0x0000000000401201 <+269>: pop %r14
0x0000000000401203 <+271>: retq
End of assembler dump.
(gdb) disas read_six_numbers
%rsi 存儲(chǔ)調(diào)用者 phase_2 棧幀的局部變量開(kāi)始地址
%rdx = %rsi + 0
%rcx = %rsi + 4
%r8 = %rsi + 8
%r9 = %rsi + 12
(%rsp) = %rsi + 16
8(%rsp) = %rsi + 20
Dump of assembler code for function read_six_numbers:
0x000000000040145c <+0>: sub $0x18,%rsp
0x0000000000401460 <+4>: mov %rsi,%rdx
0x0000000000401463 <+7>: lea 0x4(%rsi),%rcx
0x0000000000401467 <+11>: lea 0x14(%rsi),%rax
0x000000000040146b <+15>: mov %rax,0x8(%rsp)
0x0000000000401470 <+20>: lea 0x10(%rsi),%rax
0x0000000000401474 <+24>: mov %rax,(%rsp)
0x0000000000401478 <+28>: lea 0xc(%rsi),%r9
0x000000000040147c <+32>: lea 0x8(%rsi),%r8
0x0000000000401480 <+36>: mov $0x4025c3,%esi
0x0000000000401485 <+41>: mov $0x0,%eax
0x000000000040148a <+46>: callq 0x400bf0 <__isoc99_sscanf@plt>
0x000000000040148f <+51>: cmp $0x5,%eax
0x0000000000401492 <+54>: jg 0x401499 <read_six_numbers+61>
0x0000000000401494 <+56>: callq 0x40143a <explode_bomb>
0x0000000000401499 <+61>: add $0x18,%rsp
0x000000000040149d <+65>: retq
%rbp %rbx %r12~%15 被調(diào)用者保存寄存器
%r10 %r11 調(diào)用者保存寄存器
%rdi %rsi %rdx %rcx %r8 %r9 依次保存輸入數(shù) 1~6
假設(shè)輸入數(shù)據(jù)為 4 3 2 1 6 5
猜測(cè) 0x6032d8 為鏈表首地址,鏈表中每個(gè)節(jié)點(diǎn)占用 12 個(gè) Byte, 前 8 字節(jié)保存兩個(gè) 4 字 Byte 的整型數(shù),剩余的 4Byte 存放下個(gè)節(jié)點(diǎn)地址
GDB 查看使用 7 減去對(duì)應(yīng)的輸入后的數(shù)據(jù)
(gdb) p /x 1 = 0x7fffffffe270
(gdb) x/6dw 0x7fffffffe270
0x7fffffffe270: 3 4 5 6
0x7fffffffe280: 1 2
重新調(diào)整鏈表前的鏈表的結(jié)構(gòu)
(gdb) x/24xw 0x006032d0
0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032f0 0x00000000
0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
0x603320 <node6>: 0x000001bb 0x00000006 0x00000000 0x00000000
保存在棧中鏈表節(jié)點(diǎn)信息
(gdb) x/6xg 0x7fffffffe290
0x7fffffffe290: 0x00000000006032f0 0x0000000000603300
0x7fffffffe2a0: 0x0000000000603310 0x0000000000603320
0x7fffffffe2b0: 0x00000000006032d0 0x00000000006032e0
按照 7 減去對(duì)應(yīng)的輸入后重新調(diào)整鏈表后的鏈表結(jié)構(gòu),索引順序?yàn)?3 4 5 6 1 2
(gdb) x/24xw 0x006032d0
0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
0x6032e0 <node2>: 0x000000a8 0x00000002 0x00000000 0x00000000
0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
0x603320 <node6>: 0x000001bb 0x00000006 0x006032d0 0x00000000
破解思路:
將鏈表中每個(gè)節(jié)點(diǎn)按照前 4 字節(jié)降序排序
3 4 5 6 1 2
因?yàn)樵谇懊媸褂?7 減去對(duì)應(yīng)的值,所以破解密碼
4 3 2 1 6 5
final
啊,終于拆除??了,
╰(°▽°)╯
等等,還漏了什么`? 在 asm 中,可以看到還有 secret_phase 這個(gè)函數(shù),可是這個(gè)函數(shù)的調(diào)用是有技巧的,追蹤發(fā)現(xiàn)是在 phase_defused 中調(diào)用的,同樣,查看字符串,發(fā)現(xiàn)比較了"DrEvil", 以及一個(gè)格式串"%d %d %s", 可能是 phase3,phase4 的數(shù)字加上 DrEvil 輸入. 可是最后我試了很多次都沒(méi)有試出來(lái)。后來(lái)發(fā)現(xiàn)是最后才出現(xiàn),那是第七關(guān),我以為是在輸入 DrEvil 就出現(xiàn)。而且試了是在第四關(guān)后
方法二,gdb 中設(shè)置斷點(diǎn)'b phase_defused', 然后jump secret_phase
最后得到答案是 22
summary
通過(guò)這個(gè) lab, 學(xué)到了 gdb,objdump 等工具的使用,對(duì)匯編語(yǔ)言更熟悉,對(duì)函數(shù)調(diào)用中棧幀的變化,動(dòng)態(tài)變量的理解更加深刻
不得不佩服國(guó)外教學(xué)的質(zhì)量,以及這個(gè) lab 的有趣與實(shí)用