1. 程式人生 > >CSAPP: Bomb Lab(1)

CSAPP: Bomb Lab(1)

實驗需要掌握的相關工具

一.gdb(除錯工具)

主要作用在於設定斷點除錯程式。

常用命令 舉例
disassemble disassemble phase_1(將函式phase_1反彙編顯示出來)
print或p p/s (char*)0x123456 列印記憶體地址中的內容

詳細見gdb教程

二. objdump(反編譯工具)

主要是兩個命令:

  • objdump -d ./bomb>assemble.txt
    反彙編bomb程式,並且輸出到assemble.txt。該命令將整個程式反彙編(與gdb中disassemble可以協助使用)
  • objdump -t ./bomb
    輸出符號表

三. strings

列印程式中出現的所有的字串

實驗過程

實驗準備

實驗虛擬機器為:ubuntu 14.4 64位
運用objdump將程式反彙編到assemble.txt檔案中
main函式的有用的主要反彙編程式碼如下

    0000000000400da0 <main>:
      400da0:   53                      push   %rbx
      .......
      400e32:   e8 67 06 00 00          callq  40149e <read_line>
      400
e37: 48 89 c7 mov %rax,%rdi 400e3a: e8 a1 00 00 00 callq 400ee0 <phase_1> 400e3f: e8 80 07 00 00 callq 4015c4 <phase_defused> 400e44: bf a8 23 40 00 mov $0x4023a8,%edi 400e49: e8 c2 fc ff ff callq 400b10 <puts@plt> 400
e4e: e8 4b 06 00 00 callq 40149e <read_line> 400e53: 48 89 c7 mov %rax,%rdi 400e56: e8 a1 00 00 00 callq 400efc <phase_2> 400e5b: e8 64 07 00 00 callq 4015c4 <phase_defused> 400e60: bf ed 22 40 00 mov $0x4022ed,%edi 400e65: e8 a6 fc ff ff callq 400b10 <puts@plt> 400e6a: e8 2f 06 00 00 callq 40149e <read_line> 400e6f: 48 89 c7 mov %rax,%rdi 400e72: e8 cc 00 00 00 callq 400f43 <phase_3> 400e77: e8 48 07 00 00 callq 4015c4 <phase_defused> 400e7c: bf 0b 23 40 00 mov $0x40230b,%edi 400e81: e8 8a fc ff ff callq 400b10 <puts@plt> 400e86: e8 13 06 00 00 callq 40149e <read_line> 400e8b: 48 89 c7 mov %rax,%rdi 400e8e: e8 79 01 00 00 callq 40100c <phase_4> 400e93: e8 2c 07 00 00 callq 4015c4 <phase_defused> 400e98: bf d8 23 40 00 mov $0x4023d8,%edi 400e9d: e8 6e fc ff ff callq 400b10 <puts@plt> 400ea2: e8 f7 05 00 00 callq 40149e <read_line> 400ea7: 48 89 c7 mov %rax,%rdi 400eaa: e8 b3 01 00 00 callq 401062 <phase_5> 400eaf: e8 10 07 00 00 callq 4015c4 <phase_defused> 400eb4: bf 1a 23 40 00 mov $0x40231a,%edi 400eb9: e8 52 fc ff ff callq 400b10 <puts@plt> 400ebe: e8 db 05 00 00 callq 40149e <read_line> 400ec3: 48 89 c7 mov %rax,%rdi 400ec6: e8 29 02 00 00 callq 4010f4 <phase_6> 400ecb: e8 f4 06 00 00 callq 4015c4 <phase_defused> 400ed0: b8 00 00 00 00 mov $0x0,%eax

Bomb 1

用於驗證輸入的phase_1()函式反彙編程式碼如下:

(gdb) disassemble phase_1  //反編譯phase_1函式
Dump of assembler code for function phase_1:
        0x0000000000400ee0 <+0>:    sub    $0x8,%rsp 
        0x0000000000400ee4 <+4>:    mov    $0x402400,%esi 
        0x0000000000400ee9 <+9>:    callq  0x401338 <strings_not_equal>
        0x0000000000400eee <+14>:   test   %eax,%eax
        0x0000000000400ef0 <+16>:   je     0x400ef7 <phase_1+23>
        0x0000000000400ef2 <+18>:   callq  0x40143a <explode_bomb>
        0x0000000000400ef7 <+23>:   add    $0x8,%rsp
        0x0000000000400efb <+27>:   retq   
    End of assembler dump.

其中我們可以看到mov $0x402400,%esi,將記憶體地址指向的內容作為strings_not_equal()的第二引數,而在main()的400e37行已經將input變數地址放入rdi中作為第一個引數(相關程式碼段見下面程式碼段)。根據strings_not_equal()函式名可以得到該函式是比較兩個引數所指向的內容是否相等。故我們在gdb中運用print方法獲取

 (gdb) break phase_1 //為函式phase_1設定斷點,當進入phase_1時暫停
    (gdb) si//單步除錯,且函式則進入函式內部
    .........//多次單步除錯
    (gdb) si 
    0x0000000000400ee9 in phase_1 () 
    (gdb) info register //程式執行到400ee9之前的程式暫存器內容列表
    rax            0x603780 6305664
    rbx            0x0  0
    rcx            0x3  3
    rdx            0x1  1
    rsi            0x402400 4203520   //引數2
    rdi            0x603780 6305664   //引數1
    rbp            0x0  0x0
    rsp            0x7fffffffdd20   0x7fffffffdd20
    r8             0x7ffff7ff6004   140737354096644
    r9             0x0  0
    r10            0x7fffffffdab0   140737488345776
    r11            0x7ffff7a45110   140737348129040
    r12            0x400c90 4197520
    r13            0x7fffffffde10   140737488346640
    r14            0x0  0
    r15            0x0  0
    rip            0x400ee9 0x400ee9 <phase_1+9>
    eflags         0x202    [ IF ]
    cs             0x33 51
    ss             0x2b 43
    ds             0x0  0
    es             0x0  0
    fs             0x0  0
    gs             0x0  0
    (gdb) p/s (char*)0x402400 //根據分析列印記憶體地址內容,獲取以下字串
    $1 = 0x402400 "Border relations with Canada have never been better."

根據得到的字串測試bomb確實為正確的結果,解除bomb 1。

Bomb 2

    (gdb) disassemble phase_2
    Dump of assembler code for function phase_2:
       0x0000000000400efc <+0>: push   %rbp
       0x0000000000400efd <+1>: push   %rbx
       0x0000000000400efe <+2>: sub    $0x28,%rsp
       0x0000000000400f02 <+6>: mov    %rsp,%rsi
       0x0000000000400f05 <+9>: callq  0x40145c <read_six_numbers> //讀入,並且判斷是否讀入6個數字
       0x0000000000400f0a <+14>:    cmpl   $0x1,(%rsp) //判斷第一個數字是否為1
       0x0000000000400f0e <+18>:    je     0x400f30  <phase_2+52> //相等則進入迴圈判斷
       0x0000000000400f10 <+20>:    callq  0x40143a <explode_bomb>//第一個不是1,則爆炸
       0x0000000000400f15 <+25>:    jmp    0x400f30 <phase_2+52>
       0x0000000000400f17 <+27>:    mov    -0x4(%rbx),%eax 
       0x0000000000400f1a <+30>:    add    %eax,%eax
       0x0000000000400f1c <+32>:    cmp    %eax,(%rbx) //後一個元素是不是前一個的兩倍,因為第一個是1,所以得到後面的元素一定是2、4、8、16、32
       0x0000000000400f1e <+34>:    je     0x400f25 <phase_2+41>
       0x0000000000400f20 <+36>:    callq  0x40143a <explode_bomb> //不是兩倍則炸彈爆炸
       0x0000000000400f25 <+41>:    add    $0x4,%rbx
       0x0000000000400f29 <+45>:    cmp    %rbp,%rbx
       0x0000000000400f2c <+48>:    jne    0x400f17 <phase_2+27>
       0x0000000000400f2e <+50>:    jmp    0x400f3c <phase_2+64>
       0x0000000000400f30 <+52>:    lea    0x4(%rsp),%rbx
       0x0000000000400f35 <+57>:    lea    0x18(%rsp),%rbp
       0x0000000000400f3a <+62>:    jmp    0x400f17 <phase_2+27>
       0x0000000000400f3c <+64>:    add    $0x28,%rsp
       0x0000000000400f40 <+68>:    pop    %rbx
       0x0000000000400f41 <+69>:    pop    %rbp
       0x0000000000400f42 <+70>:    retq   
    End of assembler dump.

根據callq 0x40145c <read_six_numbers>上下文可以得到這個字串是由6個數字組成,並且在該函式中有函式的401480: mov $0x4025c3,%esi行程式碼中可以讀取輸入的記憶體地址中儲存的字串格式為“%d %d %d %d %d %d”。緊接著對於phase_2函式的彙編程式碼進行閱讀分析,先關重要程式碼註釋見上面程式碼段,可以推測得到第一個數字一定為1,並且後面的數字是第一個數字的兩倍。綜上所述可以得到拆除該炸彈的字串為“1 2 4 8 16 32”

根據驗證,確認為正確答案