CS:APP 二進(jìn)制炸彈拆解全解析

花了一段時(shí)間做完了暑假作業(yè), 二進(jìn)制炸彈破解的過程可謂苦盡甘來

現(xiàn)在把自己寫的解析報(bào)告放上來, 純原創(chuàng), 沒有參考任何關(guān)于此炸彈的解析

可能會與你拿到的炸彈有所不同, 本文只提供思路


第一關(guān) 字符串比較

1.??? 通過read_line從標(biāo)準(zhǔn)輸入流輸入測試字符串例如: 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)字符串(密碼)的長度

6.??? 進(jìn)入第二個(gè)stirng_length函數(shù), 根據(jù)add 與 jne 指令判斷該函數(shù)通過遍歷字符數(shù)組到’\0’來計(jì)算長度, 易知 %ebx 存儲該數(shù)組的首地址

7.??? 遍歷完成后得到 %eax 值為 41, 表明密碼字符串長度為41,

8.??? restart 程序并執(zhí)行到第6步

9.??? 運(yùn)用 print $ebx 得到起始地址 134521080

10.??? 通過 x/41cb (x查看內(nèi)存值 41表明單位個(gè)數(shù)c以字符形式顯示b表明每次取一個(gè)字節(jié)長度) 指令 得到密碼字符串的內(nèi)容

第一關(guān)密鑰的內(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ù)的定義, 如下

第二關(guān)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)密鑰執(zhí)行結(jié)果

第二關(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ù)原型, 如下

第三關(guān)sscanf函數(shù)原型

3.??? 可知這關(guān)密碼的格式是 整數(shù)空格字符空格整數(shù)

4.??? 退出重新進(jìn)入, 輸入測試字符串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.??? 猜測一共有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)密鑰執(zhí)行結(jié)果

第三關(guān)密鑰 ( 之一)

1 q 190


第四關(guān) 遞歸調(diào)用和棧

1.??? 同樣, 輸入測試字符進(jìn)入sscanf函數(shù), 輸入s指令觀察到sscanf函數(shù)的原型

第四關(guān)sscanf函數(shù)原型

2.??? 重新進(jìn)入, 輸入測試字符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存儲函數(shù)參數(shù)值, %eax為返回值, %ebx與%esi分別存儲函數(shù)中間值, 并賦初始值分別為0和14, %edx作為函數(shù)比較的中間值, 其作為中轉(zhuǎn)站與%eax性質(zhì)相同

6.??? 通過分析比較代碼, 可以大致推斷出原函數(shù)的算法如下, 其中以origin作為%esi存儲的值, 以sub作為%ebx的值, 以center作為%eax和%edx所存儲的值, 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;?????????//對應(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)密鑰執(zhí)行結(jié)果

第四關(guān)密鑰

10 5


第五關(guān) 指針

1.??? 進(jìn)入read_line函數(shù)后進(jìn)入phase5中的sscanf函數(shù), 按下s得到sscanf的函數(shù)原型

第五關(guān)sscanf函數(shù)原型

2.??? 可知本關(guān)依然需要兩個(gè)整數(shù)作為密鑰

3.??? 重新進(jìn)入, 輸入測試數(shù)據(jù)1和2并觀察函數(shù)執(zhí)行情況

4.??? 根據(jù)下方的 mov <地址>(, %eax, 4 ) 可以推斷出輸入的第一個(gè)整數(shù)作為地址的偏移量

即整形數(shù)組中的下標(biāo)

5.??? 利用 gdb x/70cb <地址> 指令查看程序內(nèi)部提供整形數(shù)組的所有值, 并記錄為表格如下

查看內(nèi)存中數(shù)組的存儲情況
數(shù)組下標(biāo)與元素對應(yīng)情況

6.??? 根據(jù)后續(xù)的 jne $0xf 以及對起計(jì)數(shù)作用的%edx中的值可知, 該程序進(jìn)行15次循環(huán)后使得%eax的值為15, 即通過15次對地址的重新計(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)密鑰執(zhí)行情況

第五關(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ù), 并輸入測試數(shù)字組1 2 3 4 5 6

3.??? 進(jìn)入phase函數(shù)并跳過read_six_numbers函數(shù), 就來到了本關(guān)的第一個(gè)循環(huán)判斷, 如下

第六關(guān)第一個(gè)坎

以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)鏈表初始地址每次移動(array[x] – 1) 個(gè)8字節(jié)后得到值依次保存于棧幀中. 原理可用下述公式表示, 在這里觀察到 0x8(%edx) 直接就是移動到下一個(gè)結(jié)點(diǎn)的首地址了, 而每個(gè)結(jié)點(diǎn)所占空間是12個(gè)字節(jié), 推翻上述分析, 移動8個(gè)地址后即是下一個(gè)結(jié)點(diǎn)首地址,從而構(gòu)成單向鏈表.

即此部分是取第array [? x ] 個(gè)結(jié)點(diǎn)值并依次保存

第六關(guān)第二個(gè)坎

6.??? 通過 x/18dw 指令觀察鏈表六個(gè)結(jié)點(diǎn)首元素的值:

鏈表node1 - 6

從上圖可以看出:

鏈表node1 - 6

7.??? 下述代碼作為此關(guān)的終極武器, 經(jīng)過寄存器值的查看即跳轉(zhuǎn)條件分析, 只有滿足存入棧幀的結(jié)點(diǎn)降序排列才可躲避phase_6+219的爆炸函數(shù)

第六關(guān)第三個(gè)坎

8.??? 手動排序, node6 > node4 > node1> node5 > node2 > node3

????? 整理得最終結(jié)果與輸入值的對應(yīng)關(guān)系如下

輸入值的變化過程
第六關(guān)密鑰執(zhí)行結(jié)果

第六關(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.??? 猜測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è)字符串.

隱藏關(guān)sscanf函數(shù)原型

4.??? 重新開始, 第四關(guān)密鑰處輸入測試字符串 "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ìn)入隱藏關(guān)的密鑰

據(jù)此寫出%s的內(nèi)容: DrEvil.

看起來像一個(gè)人名, 猜測這個(gè)彩蛋密鑰應(yīng)該算類似“炸彈制作者名單”

6.??? 重新進(jìn)入該phase_defused函數(shù), 進(jìn)行到puts函數(shù), 發(fā)現(xiàn)了進(jìn)入隱藏關(guā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)制, 查看原型:

隱藏關(guān)strtol函數(shù)原型

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ù)……$%!&^%!*#&^%

fun7函數(shù)

11.??? 經(jīng)過一定觀察, 發(fā)現(xiàn)fun7函數(shù)比第四關(guān)的fun4函數(shù)簡單了不少, 長舒一口氣

整理得到fun7函數(shù)所描述的算法如下

middle = array [ 0 ];?? //array首地址存儲在%edx中, middle存儲在middle中

fun7 ( input ) {??? ? ? ? //input存儲在%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中的部分值

數(shù)組array

根據(jù)遞推關(guān)系36→ 8 →22 可知需要用戶輸入的值為22

隱藏關(guān)密鑰:

22


[完結(jié)]

破解二進(jìn)制炸彈
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容