花了一段時(shí)間做完了暑假作業(yè), 二進(jìn)制炸彈破解的過程可謂苦盡甘來
現(xiàn)在把自己寫的解析報(bào)告放上來, 純?cè)瓌?chuàng), 沒有參考任何關(guān)于此炸彈的解析
可能會(huì)與你拿到的炸彈有所不同, 本文只提供思路
第一關(guān) 字符串比較
1.??? 通過read_line從標(biāo)準(zhǔn)輸入流輸入測(cè)試字符串例如: 1234567
2.??? 進(jìn)入phase_1 函數(shù)
3.??? 進(jìn)入strings_not_equal 函數(shù)
4.??? 進(jìn)入第一個(gè)string_length函數(shù)
5.??? 根據(jù)string_length函數(shù)返回值 %eax = 7 推斷第二個(gè)string_length函數(shù)計(jì)算的是標(biāo)準(zhǔn)字符串(密碼)的長(zhǎng)度
6.??? 進(jìn)入第二個(gè)stirng_length函數(shù), 根據(jù)add 與 jne 指令判斷該函數(shù)通過遍歷字符數(shù)組到’\0’來計(jì)算長(zhǎng)度, 易知 %ebx 存儲(chǔ)該數(shù)組的首地址
7.??? 遍歷完成后得到 %eax 值為 41, 表明密碼字符串長(zhǎng)度為41,
8.??? restart 程序并執(zhí)行到第6步
9.??? 運(yùn)用 print $ebx 得到起始地址 134521080
10.??? 通過 x/41cb (x查看內(nèi)存值 41表明單位個(gè)數(shù)c以字符形式顯示b表明每次取一個(gè)字節(jié)長(zhǎng)度) 指令 得到密碼字符串的內(nèi)容
第一關(guān)密鑰:
For NASA, space is still a high priority.
第二關(guān) 循環(huán)
1.??? 進(jìn)入read_line函數(shù), 隨便輸入幾個(gè)字符 "asdasfa"
2.??? 進(jìn)入, read_six_numbers函數(shù)
3.??? 按s繼續(xù)執(zhí)行,進(jìn)入sscanf函數(shù)
4.??? 繼續(xù)按s可以看到sscanf函數(shù)的定義, 如下
5.??? 可知應(yīng)該輸入6個(gè)數(shù)字, 每個(gè)數(shù)字用空格隔開
6.??? 重新進(jìn)入read_line, 按n后輸入數(shù)字1 2 3 4 5 6
7.??? 繼續(xù)執(zhí)行到sscanf后, 易知0x4(%esp)取輸入的第一個(gè)數(shù)字, 即1, 并與1比較,相等即繼續(xù)執(zhí)行
8.??? 通過觀察寄存器值的變化, 可以判斷出phase_2 + 54 到 phase_2 + 73為循環(huán)過程, 遍歷我們剛剛輸入的6個(gè)數(shù), 整理循環(huán)的運(yùn)行邏輯如下, 以a1 – a6 表示他們.
start = a1;
x = a2;
if (start == 1)
??????? do {
??????????????? start += start;
??????????????? if ( start != x );
??????????????? BOOM!!!;
??????????????? x = a.next;
??????? } while ( x != a6 )
else??????? BOOM!!!!;
9.??? 根據(jù)上述算法依次類推, 即可得到應(yīng)該輸入的密碼為 1 2 4 8 16 32.
第二關(guān)密鑰:
1 2 4 8 16 32
第三關(guān) 條件/分支
這一關(guān)通得很快, 因?yàn)橛卸嘟? 碰巧湊了一個(gè), 感覺運(yùn)氣成分比較大 (逃
1.??? 同上, 進(jìn)入read_line函數(shù)后隨便輸入一串字符? "hahaha"
2.??? si 進(jìn)入sscanf函數(shù), 再按一次s可以調(diào)出sscanf函數(shù)原型, 如下
3.??? 可知這關(guān)密碼的格式是 整數(shù)空格字符空格整數(shù)
4.??? 退出重新進(jìn)入, 輸入測(cè)試字符串1<空格>a<空格>2
( 體現(xiàn)運(yùn)氣的時(shí)刻到了)
5.??? 通過 cmpl $0x7, 0x4(%esp) <換行> ja blabla 語句可知, 第一個(gè)數(shù)字需要小于7
6.??? 通過 jmp *0x804a160 (, %eax, 4) 語句可知跳轉(zhuǎn)目的語句與第一個(gè)數(shù)字的值有關(guān)
7.??? 猜測(cè)一共有7種破解密碼, 我這里遇到的是第2種(第一個(gè)數(shù)字為1)
8.??? 跳轉(zhuǎn)到phase_3+113, 將第二個(gè)整數(shù)與0xbe (即190 ) 作比較, 相等即可繼續(xù)進(jìn)行, 由此推斷 第二個(gè)整數(shù)是0xbe, 即190
9.??? 觀察跳轉(zhuǎn)到phase_3+323后需要將%al中的值與字符參數(shù)做比較相等才可以完成密碼匹配
10.? 通過 print $al 查看寄存器中的值, 發(fā)現(xiàn)為113, 查ASCII碼表, 發(fā)現(xiàn)為字符’q’
那么, 1 q 190即為解之一
第三關(guān)密鑰 ( 之一)
1 q 190
第四關(guān) 遞歸調(diào)用和棧
1.??? 同樣, 輸入測(cè)試字符進(jìn)入sscanf函數(shù), 輸入s指令觀察到sscanf函數(shù)的原型
2.??? 重新進(jìn)入, 輸入測(cè)試字符1 2
3.??? 根據(jù)phase_4+78的 cmp $0x5, %eax 語句以及 cmpl $0x5, 0x8(%esp) 語句, 可以推斷出以第一個(gè)數(shù)字為參數(shù)的fun4函數(shù)返回值應(yīng)該為5, 第二個(gè)數(shù)字的值應(yīng)該為5
4.??? 進(jìn)入fun函數(shù),觀察%eax, %ebx, %esi, %ecx的變化
5.??? 經(jīng)過初步推斷, %ecx存儲(chǔ)函數(shù)參數(shù)值, %eax為返回值, %ebx與%esi分別存儲(chǔ)函數(shù)中間值, 并賦初始值分別為0和14, %edx作為函數(shù)比較的中間值, 其作為中轉(zhuǎn)站與%eax性質(zhì)相同
6.??? 通過分析比較代碼, 可以大致推斷出原函數(shù)的算法如下, 其中以origin作為%esi存儲(chǔ)的值, 以sub作為%ebx的值, 以center作為%eax和%edx所存儲(chǔ)的值, x為函數(shù)參數(shù), 也就是我們輸入的第一個(gè)數(shù)字
origin = 14;
center = origin;
sub = 0;
fun4 ( int x ) {
??????? center = ( origin – sub ) / 2 + sub;??? //函數(shù)的開頭計(jì)算用于比較的center值( %eax )
??????? if ( x == center ) return 0;?????????//對(duì)應(yīng)匯編代碼fun4 + 0 ---- fun4 + 33
??????? else if ( x < center ) {?????????????????? ??
??????????????? center -= 1;???????????????? //匯編代碼fun4+ 40
??????????????? origin = center;????????????? //匯編代碼push%edx
??????????????? return 2 * fun ( x ) ;?????????? //匯編代碼 fun4 +54 add指令
??????? }??????????????????????????????
??????? else if ( x > center ) {?????????????
?????????????? center += 1;???????????????? //匯編代碼fun4+ 71
?????????????? sub = center;??????????????? //匯編代碼push %edx
?????????????? return 2 * fun ( x ) + 1;??????? //匯編代碼fun4 + 84
??????? }
}
7.??? 根據(jù)上述代碼, 反向遞推, 令最后返回的%eax值為5
5 = 2 * 2 * ( 2 * 0 + 1 ) + 1, 只有10可以滿足左側(cè)遞推式
第四關(guān)密鑰
10 5
第五關(guān) 指針
1.??? 進(jìn)入read_line函數(shù)后進(jìn)入phase5中的sscanf函數(shù), 按下s得到sscanf的函數(shù)原型
2.??? 可知本關(guān)依然需要兩個(gè)整數(shù)作為密鑰
3.??? 重新進(jìn)入, 輸入測(cè)試數(shù)據(jù)1和2并觀察函數(shù)執(zhí)行情況
4.??? 根據(jù)下方的 mov <地址>(, %eax, 4 ) 可以推斷出輸入的第一個(gè)整數(shù)作為地址的偏移量
即整形數(shù)組中的下標(biāo)
5.??? 利用 gdb x/70cb <地址> 指令查看程序內(nèi)部提供整形數(shù)組的所有值, 并記錄為表格如下
6.??? 根據(jù)后續(xù)的 jne $0xf 以及對(duì)起計(jì)數(shù)作用的%edx中的值可知, 該程序進(jìn)行15次循環(huán)后使得%eax的值為15, 即通過15次對(duì)地址的重新計(jì)算得到最終值15, 下標(biāo)為5, 按此邏輯寫出該程序段的大致算法如下:
result = input ( 第一個(gè)參數(shù));
counter = 0;
sum = 0;
do{
?????? counter ++;
?????? result= array [ result ];
?????? sum+= result;
while?( result != 15 && counter != 15 );
7.??? 按照上述算法, 從15開始遞推 15次, 得到第一次result的值, 也就是我們需要輸入的一個(gè)整數(shù)值為5.
15 6 14 2 1 10 0 8 4 9 13 11 7 3 12 ? array [ 5 ] = 12
8.??? 又根據(jù) cmp 0x8 ( %esp ), %ecx 可知, 第二個(gè)參數(shù)需要與sum值相同, 即所有遍歷過的值的和, 15 + 6 + ……+ 12 = 115
第五關(guān)密鑰
5 115
第六關(guān) 鏈表/指針/結(jié)構(gòu)
1.??? 進(jìn)入read_line函數(shù), 根據(jù)phase_6 + 26的read_six_numbers函數(shù), 根據(jù)第二關(guān)已知, 需要輸入6個(gè)數(shù)字.
2.??? 重新進(jìn)入函數(shù), 并輸入測(cè)試數(shù)字組1 2 3 4 5 6
3.??? 進(jìn)入phase函數(shù)并跳過read_six_numbers函數(shù), 就來到了本關(guān)的第一個(gè)循環(huán)判斷, 如下
以array數(shù)組表示用戶輸入的六個(gè)數(shù)字,該部分代碼可用以下算法來描述
for ( int I = 0; I < = 5 ; I ++ ) {
?????? if ( array [ I ] <= 6 ) {
????????????? for ( int m = I + 1; m <=5; m ++ )
???????????????????? if( array [ I ] == array [ m ] )
??????????????????????????? BOOM!!!;
?????? }
?????? else??? BOOM!!!;
}
根據(jù)該段代碼可知用戶輸入的每個(gè)數(shù)字都應(yīng)該小于6并且各數(shù)字互不相等
4.??? phase_6+104 ~ phase_6+115是7減去原來每個(gè)數(shù)后重新存入源地址中, 算法不贅述, 即phase[x] = 7 – phase [7]
5.??? phase_6+124 ~ phase_6+167是通過計(jì)算好的新數(shù)組, 將一個(gè)六結(jié)點(diǎn)鏈表初始地址每次移動(dòng)(array[x] – 1) 個(gè)8字節(jié)后得到值依次保存于棧幀中. 原理可用下述公式表示, 在這里觀察到 0x8(%edx) 直接就是移動(dòng)到下一個(gè)結(jié)點(diǎn)的首地址了, 而每個(gè)結(jié)點(diǎn)所占空間是12個(gè)字節(jié), 推翻上述分析, 移動(dòng)8個(gè)地址后即是下一個(gè)結(jié)點(diǎn)首地址,從而構(gòu)成單向鏈表.
即此部分是取第array [? x ] 個(gè)結(jié)點(diǎn)值并依次保存
6.??? 通過 x/18dw 指令觀察鏈表六個(gè)結(jié)點(diǎn)首元素的值:
從上圖可以看出:
7.??? 下述代碼作為此關(guān)的終極武器, 經(jīng)過寄存器值的查看即跳轉(zhuǎn)條件分析, 只有滿足存入棧幀的結(jié)點(diǎn)降序排列才可躲避phase_6+219的爆炸函數(shù)
8.??? 手動(dòng)排序, node6 > node4 > node1> node5 > node2 > node3
????? 整理得最終結(jié)果與輸入值的對(duì)應(yīng)關(guān)系如下
第六關(guān)密鑰:
1 3 6 2 5 4
隱藏關(guān)卡
1.??? 進(jìn)入phase4的defused函數(shù), 觀察到一條指令?
cmpl $0x6, 0x804c3cc
使用x指令查看地址0x804c3cc中的值, 發(fā)現(xiàn)這個(gè)值記錄的是輸入字符串的個(gè)數(shù)
也就是在輸入6個(gè)字符串, 即通過6個(gè)關(guān)卡后才可以跳轉(zhuǎn)到下方的sscanf函數(shù)附近
2.??? 猜測(cè)defused函數(shù)中的sscanf函數(shù)記錄著有關(guān)隱藏關(guān)的密碼
3.??? 繼續(xù)進(jìn)行到第六關(guān), 重新進(jìn)入phase_defused函數(shù), 進(jìn)入sscanf函數(shù)使用 s 指令查看到
有關(guān)隱藏關(guān)密鑰的格式, 即我們需要在第四關(guān)密鑰后加一個(gè)字符串.
4.??? 重新開始, 第四關(guān)密鑰處輸入測(cè)試字符串 "10 5 haha" , 進(jìn)入到第六關(guān)后的pahse_defused函數(shù), 進(jìn)入其中的strings_not_equal函數(shù).
5.??? 按照第一關(guān)流程, 直接進(jìn)入第二個(gè)string_length函數(shù), 使用
x/8cb $edx
指令查看%s, 即第四關(guān)密鑰后需要輸入什么字符串
據(jù)此寫出%s的內(nèi)容: DrEvil.
看起來像一個(gè)人名, 猜測(cè)這個(gè)彩蛋密鑰應(yīng)該算類似“炸彈制作者名單”
6.??? 重新進(jìn)入該phase_defused函數(shù), 進(jìn)行到puts函數(shù), 發(fā)現(xiàn)了進(jìn)入隱藏關(guān)的提示語
不慌, 繼續(xù)執(zhí)行進(jìn)入secret_phase函數(shù)
7.??? read_line函數(shù), 輸入一行字符串, "lstnb"
8.??? 進(jìn)入到strtol函數(shù), 該函數(shù)是將字符串轉(zhuǎn)化為數(shù)字, base參數(shù)表明進(jìn)制, 查看原型:
base = 10, 由此可知將輸入數(shù)字轉(zhuǎn)化為十進(jìn)制整數(shù)
9.??? 根據(jù)?? cmp $0x3e8, %eax / jbe ~~
可知輸入一個(gè)小于等于1000的數(shù)字可以避免爆炸
10.??? 重新開始, 輸入1000, 進(jìn)入fun7函數(shù), 發(fā)現(xiàn)fun7又是一個(gè)遞歸函數(shù)……$%!&^%!*#&^%
11.??? 經(jīng)過一定觀察, 發(fā)現(xiàn)fun7函數(shù)比第四關(guān)的fun4函數(shù)簡(jiǎn)單了不少, 長(zhǎng)舒一口氣
整理得到fun7函數(shù)所描述的算法如下
middle = array [ 0 ];?? //array首地址存儲(chǔ)在%edx中, middle存儲(chǔ)在middle中
fun7 ( input ) {??? ? ? ? //input存儲(chǔ)在%ecx中
? ? ?? if( input == middle ) return 0;
?????? else if ( input < middle) middle = *( array + 1 ) return 2 * fun ( input ) ;
?????? else middle = *(array + 2)return 2 * fun ( input ) + 1;
? ?}
12.??? 根據(jù)secretphase函數(shù)中的 cmp 0x2 %eax 指令, 可知fun7返回值應(yīng)為2
2 = 2 * ( 2 * 0 + 1) 進(jìn)行兩次遞歸調(diào)用, 利用x指令查看array中的部分值
根據(jù)遞推關(guān)系36→ 8 →22 可知需要用戶輸入的值為22
隱藏關(guān)密鑰:
22