Bomblab


這個實驗曾經做過

這次又做了一遍,對之前的過程作了補充

binary bomb

一、實驗目的

增強對程序機器級表示、匯編語言、調試器和逆向工程等理解。

二、實驗要求

      1熟練使用gdb調試器和objdump;

2單步跟蹤調試每一階段的機器代碼;

3理解匯編語言代碼的行為或作用;

4“推斷”拆除炸彈所需的目標字符串。

5在各階段的開始代碼前和引爆炸彈函數前設置斷點,便於調試。

三、實驗內容

准備:

使用objdump –d bomb > asm.txt命令,將bomb程序逆成匯編代碼,分析匯編代碼。

Phase_1:

       匯編代碼如圖

代碼分析:

 

這是一個字符串比較,所以應該是和內存中的已有內容比較。

有一個內存地址,我們去看一下內存0x804a124的內容

 

 

找到字符串,輸入之后

 

 

通過。

 

phase_2:

 

代碼分析:

 

push   %esi

push   %ebx

sub    $0x34,%esp

lea    0x18(%esp),%eax

mov    %eax,0x4(%esp)

mov    0x40(%esp),%eax

mov    %eax,(%esp)

call   804911c <read_six_numbers>  ;讀入6個數

cmpl   $0x0,0x18(%esp)             ;第一個數和0比較

jne    8048bdb <phase_2+0x27> ;如果不等於0就爆炸,所以第一個為0

cmpl   $0x1,0x1c(%esp)  ;第二個數和1比較

je     8048bfa <phase_2+0x46> ;如果等於1就跳走了,不等於就爆炸了

call   80490f5 <explode_bomb> ;爆炸

jmp    8048bfa <phase_2+0x46>

mov    -0x8(%ebx),%eax  ;eax = a[i-2] 存上上個數

add    -0x4(%ebx),%eax      ;eax = a[i - 2] + a[i - 1] 存上上個數與

cmp    %eax,(%ebx)  ;相當於把eax賦給ebx,也就是把當前位置的相鄰

je     8048bf1 <phase_2+0x3d> ;ebx必須和eax相等,否則就爆炸

call   80490f5 <explode_bomb>

add    $0x4,%ebx  ;ebx+4,ebx指向了新的位置

cmp    %esi,%ebx ;ebx是否和ebx+30相等,不等就跳回到8048be2,循環

jne    8048be2 <phase_2+0x2e>

jmp    8048c04 <phase_2+0x50>;相等,結束

lea    0x20(%esp),%ebx  ;ebx指向新的地址

lea    0x30(%esp),%esi  ;esi始終存的是地址esp+30

jmp    8048be2 <phase_2+0x2e>

 

add    $0x34,%esp

pop    %ebx

pop    %esi

ret   

根據規律得出最后是a[i] = a[i - 2] + a[i - 1],而且第一個數是0,第二個數是1,遞推出

 0 1 1 2 3 5

輸入

 

 

通過。

Phase_3:

截取部分代碼:

 

 

 

代碼分析:

sub    $0x2c,%esp

lea    0x1c(%esp),%eax

mov    %eax,0xc(%esp)

lea    0x18(%esp),%eax

mov    %eax,0x8(%esp)

movl   $0x804a2ef,0x4(%esp)

 

mov    0x30(%esp),%eax

mov    %eax,(%esp)

call   8048860 <__isoc99_sscanf@plt> ; 輸入

cmp    $0x1,%eax                     ;至少輸入2個數

jg     8048c3b <phase_3+0x31> ;否則就爆炸

call   80490f5 <explode_bomb>

 

cmpl   $0x7,0x18(%esp);  <=7

ja     8048c7e <phase_3+0x74> ;如果第一個操作數大於7 ,就爆炸

 

mov    0x18(%esp),%eax

jmp    *0x804a180(,%eax,4) ;后面有截圖,可以看到,在這個地址處存放着一些地址,根據輸入的eax的值,跳到相應位置

;下面是8種情況  后面依次根據第一個數的內容跳到相應位置

 

mov    $0x90,%eax ;第一個數是0,跳到這里,將0x90放到eax中

jmp    8048c8f <phase_3+0x85>

 

mov    $0x166,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x160,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x1e2,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x2c5,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x2e0,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x3d8,%eax

jmp    8048c8f <phase_3+0x85>

 

call   80490f5 <explode_bomb>

 

mov    $0x0,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x15d,%eax

;---------------------------------------------------------所有的條件最后都匯總到這里,判斷第二個數

cmp    0x1c(%esp),%eax ;將輸入的第二個數字和從對應地址賦值的數比較,不相等就爆炸

je     8048c9a <phase_3+0x90>

call   80490f5 <explode_bomb>

add    $0x2c,%esp

ret 

 

用gdb看看內存里位置0x804a180位置處的內容是:

 

 

里面存的都是代碼的地址,也就是要跳的位置

這個是條件判斷,根據輸入的第一個數,看第二個數是不是和程序的賦給的內容一樣。

所以一共有8種情況,任意輸入一種即可

如果第一個數是0,跳到0x8048c4d位置,把0x90給了eax,所以第二個就是0x90,也就是十進制的144

輸入 0 144

 

 

通過

 

Phase_4:

這個是一個遞歸

代碼截圖:

 

 

 

 

代碼分析:

sub    $0x2c,%esp

lea    0x1c(%esp),%eax

mov    %eax,0xc(%esp)

lea    0x18(%esp),%eax

mov    %eax,0x8(%esp)

movl   $0x804a2ef,0x4(%esp)

 

mov    0x30(%esp),%eax

mov    %eax,(%esp)

call   8048860 <__isoc99_sscanf@plt>;輸入

 

cmp    $0x2,%eax ;輸入兩個數,不是的話就爆炸

jne    8048d2e <phase_4+0x33>

 

cmpl   $0xe,0x18(%esp)  ;第一個數小於等於14,否則爆炸

jbe    8048d33 <phase_4+0x38>

call   80490f5 <explode_bomb>

 

movl   $0xe,0x8(%esp) ;舊[esp+8] = e

 

movl   $0x0,0x4(%esp) ;舊[esp+4] = 0

 

mov    0x18(%esp),%eax

mov    %eax,(%esp)

call   8048c9e <func4> ;調用func4

 

cmp    $0xb,%eax  ;func4返回的一定是11,否則爆炸

jne    8048d5b <phase_4+0x60>

cmpl   $0xb,0x1c(%esp) ;第二個數一定是11,否則就爆炸

je     8048d60 <phase_4+0x65>

call   80490f5 <explode_bomb>

add    $0x2c,%esp

ret   

 

phase_4函數其中還調用了一個函數func4(),func4()返回的值是11,我們進行推斷可以得出輸入時0 11或者1 11

分析着很麻煩,發現第二個數必須是0xb,一定是11,前面有第一個數必須小於15,一共沒幾個情況,一個個試一下唄!發現很幸運的輸入 0 11就過了!

 

 

 

Phase5:

代碼如下:

 

 

代碼分析:

08048d64 <phase_5>:

 8048d64:      53                        push   %ebx

 8048d65:      83 ec 18                    sub    $0x18,%esp

 8048d68:      8b 5c 24 20                 mov    0x20(%esp),%ebx

 8048d6c:      89 1c 24                    mov    %ebx,(%esp)

 8048d6f:       e8 57 02 00 00       call   8048fcb <string_length>

 

 8048d74:      83 f8 06             cmp    $0x6,%eax ;輸入字符串長度一定是6,否則爆炸

 8048d77:      74 05                      je     8048d7e <phase_5+0x1a>

 8048d79:      e8 77 03 00 00       call   80490f5 <explode_bomb>

 

 8048d7e:      ba 00 00 00 00       mov    $0x0,%edx  ;賦初值

 8048d83:      b8 00 00 00 00       mov    $0x0,%eax  ;賦初值

 

 8048d88:      0f b6 0c 03          movzbl (%ebx,%eax,1),%ecx                        ;0擴展,

; ecx = ebx + eax

 8048d8c:      83 e1 0f             and    $0xf,%ecx              

                                                         ;ecx = ecx & 0xf ,和0xf按位與,控制在0~15之間

 8048d8f:       03 14 8d a0 a1 04 08   add    0x804a1a0(,%ecx,4),%edx ;     

;在內存中相應位置取出數字加到edx       中

 8048d96:      83 c0 01                    add    $0x1,%eax

                                   ;eax自加

 8048d99:      83 f8 06             cmp    $0x6,%eax                                         

                                                         ;eax和6比較,一共循環6次

 8048d9c:      75 ea                      jne    8048d88 <phase_5+0x24>

 

 8048d9e:      83 fa 2d                    cmp    $0x2d,%edx 

                                                 ;最后的edx中一定是0x2d,我們要找到這樣的組合即可

 8048da1:      74 05                      je     8048da8 <phase_5+0x44>

 8048da3:      e8 4d 03 00 00       call   80490f5 <explode_bomb>

 8048da8:      83 c4 18                    add    $0x18,%esp

 8048dab:      5b                        pop    %ebx

 8048dac:      c3                        ret   

經過分析得出,我們要輸入6個字符,然后對每個字符對16取模之后得到[0,15]的數,推測內存里應該有16個數,代碼里還有一個內存地址,把取模后的數作為偏移地址,在內存中找到相應的值,加到一起,和是45就可以。

看一下內存地址有啥

 

 

前16個看起來靠譜,和我們得到的結論一樣。

現在只需要湊出6個數之和是45就行,湊個777888,然后在內存里這個數組中看一下,有7和8,下標分別是9和13,然后這6個數都是對16取模之后的下標,讓他們幾個都同時加32,得到41 41 41 45 45 45,對應的ascii表中的字符就是 )))--- ,輸入后通過

 

 

同理,然后還可以加32 + 16,得到 57 57 57 61 61 61,對應的ascii碼表中的字符就是===999,輸入后:

 

 

通過

Phase_6:

 

 

 

 

 

 

 

代碼分析:

輸入6個數后,先進行了兩個判斷:1、判斷是否都是在[1,6]上的數   2、判斷有沒有重復

 

              ;判斷是否在[1,6]內

 8048dcf:       83 e8 01                   sub    $0x1,%eax                       ;eax--

 8048dd2:      83 f8 05             cmp    $0x5,%eax                            ;如果eax是小於等於0的數,減一后和5無符號比較,是大於5的;

                                                                                                                       ;如果eax是大於6的數,減一后還是大於5;

                                                                                                                      ;所以 輸入的數字一定要  在區間 [ 1 , 6 ]  內  

 8048dd5:      76 05                      jbe    8048ddc <phase_6+0x2f>      ;無符號比較<=

 8048dd7:      e8 19 03 00 00       call   80490f5 <explode_bomb>

 

 8048ddc:      83 c6 01                    add    $0x1,%esi                       ;esi作為偏移

 8048ddf:       83 fe 06             cmp    $0x6,%esi                      ;一共循環6次

 

 8048de2:      75 07                      jne    8048deb <phase_6+0x3e>

 8048de4:      bb 00 00 00 00       mov    $0x0,%ebx                         ;6次循環結束

 8048de9:      eb 38                      jmp    8048e23 <phase_6+0x76>         ;跳出循環

              ;判斷是都有重復的

 8048deb:      89 f3                       mov    %esi,%ebx

 8048ded:      8b 44 9c 10                 mov    0x10(%esp,%ebx,4),%eax   ;根據ebx取出一個輸入的數

 8048df1:       39 44 b4 0c                 cmp    %eax,0xc(%esp,%esi,4)     ;取出的每個數都依次和其他的每個數字比較

 8048df5:       75 05                      jne    8048dfc <phase_6+0x4f>

 8048df7:       e8 f9 02 00 00       call   80490f5 <explode_bomb>    ;每個數字不能重復,否則爆炸

 8048dfc:       83 c3 01                    add    $0x1,%ebx

 8048dff:        83 fb 05                    cmp    $0x5,%ebx

 8048e02:      7e e9                      jle    8048ded <phase_6+0x40>

 8048e04:      eb c5                      jmp    8048dcb <phase_6+0x1e>

 ;判重結束;

 

接着根據輸入構建一個鏈表

8048e12: ba 3c c1 04 08       mov    $0x804c13c,%edx  ;將第一個元素的下標放到edx里

 8048e17:      89 54 b4 28                 mov    %edx,0x28(%esp,%esi,4) ;把下一個的地址放到棧里 

 8048e1b:      83 c3 01                    add    $0x1,%ebx                      ;ebx++

 8048e1e:      83 fb 06                    cmp    $0x6,%ebx                            ;循環6次

 8048e21:      74 17                      je     8048e3a <phase_6+0x8d> 

 ;兩個判斷結束后跳到這里

 8048e23:      89 de                      mov    %ebx,%esi                      ;esi = ebx

 8048e25:      8b 4c 9c 10          mov    0x10(%esp,%ebx,4),%ecx   ;依次取出輸入的幾個數

 8048e29:      83 f9 01             cmp    $0x1,%ecx

 8048e2c:       7e e4                      jle    8048e12 <phase_6+0x65> ;如果取出的數是1,跳到0x8048e12

 8048e2e:      b8 01 00 00 00       mov    $0x1,%eax

 8048e33:      ba 3c c1 04 08       mov    $0x804c13c,%edx  ;將第一個元素的下標放到edx里

 8048e38:      eb cc                      jmp    8048e06 <phase_6+0x59>

 

 ;根據輸入的6個數構建一個鏈表

 8048e3a:      8b 5c 24 28                 mov    0x28(%esp),%ebx         ;取出下一個地址

 8048e3e:      8d 44 24 2c                 lea    0x2c(%esp),%eax       

 8048e42:      8d 74 24 40                 lea    0x40(%esp),%esi

 8048e46:      89 d9                      mov    %ebx,%ecx

 

 8048e48:      8b 10                      mov    (%eax),%edx            ;將下一個地址放到edx中

 8048e4a:      89 51 08                   mov    %edx,0x8(%ecx)       ;將這個地址給ecx+8

 8048e4d:      83 c0 04                    add    $0x4,%eax ;指向下一個元素

 8048e50:      39 f0                       cmp    %esi,%eax ;走到最后一個跳出

 8048e52:      74 04                      je     8048e58 <phase_6+0xab>

 8048e54:      89 d1                      mov    %edx,%ecx              ;把下一個地址給ecx

 8048e56:      eb f0                      jmp    8048e48 <phase_6+0x9b>

 

 8048e58:      c7 42 08 00 00 00 00   movl   $0x0,0x8(%edx) 

 8048e5f:       be 05 00 00 00       mov    $0x5,%esi

要求鏈表的值是遞減的

;這個鏈表中的值一定要是降序的

 8048e64:      8b 43 08                   mov    0x8(%ebx),%eax       ;下個元素的地址給eax

 8048e67:      8b 00                      mov    (%eax),%eax            ;取出下個元素的地址的值

 8048e69:      39 03                      cmp    %eax,(%ebx)           ;ebx的值>=eax  成功跳轉,否則爆炸;也就是一定要滿足降序規則 

 8048e6b:      7d 05                      jge    8048e72 <phase_6+0xc5>           

 8048e6d:      e8 83 02 00 00       call   80490f5 <explode_bomb>

 8048e72:      8b 5b 08                   mov    0x8(%ebx),%ebx ;讀入下一個地址

 8048e75:      83 ee 01                   sub    $0x1,%esi  

 8048e78:      75 ea                      jne    8048e64 <phase_6+0xb7>  ;zf=0跳,也就是esi不等於1時跳

                                                               ;esi等於1時結束,循環5次,相繼讀入下一個元素的值

 8048e7a:      83 c4 44                    add    $0x44,%esp

 8048e7d:      5b                        pop    %ebx

 8048e7e:      5e                        pop    %esi

 8048e7f:       c3                        ret   

用gdb看一下內存里這幾個元素里的東西

 

 

每個node的結構應該是這樣

struct{

       int value;

       int id;

       int* next;

}

根據降序排列,順序是0x3a9 0x39f 0x32f 0x2a0 0x22f 0x5c,對應的順序是6 3 4 5 2 1

輸入:

 

 

通過。

secret phase:

 

 

 

代碼分析:

Defuse中:

movl   $0x804c4d0,(%esp)

 80492a8:      e8 b3 f5 ff ff           call   8048860 <__isoc99_sscanf@plt>

 80492ad:      83 f8 03             cmp    $0x3,%eax              ;如果檢測到輸入的內容是3個,就會將內存中的內容取出來進行比較。有內存地址0x804a352

 80492b0:      75 35                      jne    80492e7 <phase_defused+0x81>

 80492b2:      c7 44 24 04 52 a3 04   movl   $0x804a352,0x4(%esp)

 80492b9:      08

 80492ba:      8d 44 24 2c                 lea    0x2c(%esp),%eax

 80492be:      89 04 24                   mov    %eax,(%esp)

 80492c1:       e8 24 fd ff ff           call   8048fea <strings_not_equal>

 80492c6:       85 c0                      test   %eax,%eax

 80492c8:       75 1d                      jne    80492e7 <phase_defused+0x81>

 80492ca:       c7 04 24 18 a2 04 08   movl   $0x804a218,(%esp)

 80492d1:      e8 1a f5 ff ff            call   80487f0 <puts@plt>

 80492d6:      c7 04 24 40 a2 04 08   movl   $0x804a240,(%esp)

 80492dd:      e8 0e f5 ff ff            call   80487f0 <puts@plt>

 80492e2:      e8 ea fb ff ff            call   8048ed1 <secret_phase>

Gdb查看0x804a352:

 

 

特殊字符串是 DrEvil

Secrer_phase:

 

 

 

在第四關加上該字符串,在解決6個之后就會出現提示破解秘密phase

調用phase

Fun4函數分析:

 

 

經過推測,輸入1001

 

 

通過。

 

四、實驗結果

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM