菜鳥做 bomb lab 之第一關

第一題比較簡單,但本菜雞也做了兩個小時(╯‵□′)╯︵┻━┻。。。

首先打開事先已經反彙編的 bomb.s 文件,通過 bomb.c 已經知道每一關都是一個函數,它們的命名都是 phase_x,x 代表該關卡的數字,如果某個關卡輸入的不正確,就會引爆炸彈 explode_bomb。首先看 main 函數的這幾行

400e1e:   bf 38 23 40 00          mov    $0x402338,%edi
400e23:   e8 e8 fc ff ff          callq  400b10 <puts@plt>
400e28:   bf 78 23 40 00          mov    $0x402378,%edi
400e2d:   e8 de fc ff ff          callq  400b10 <puts@plt>
400e32:   e8 67 06 00 00          callq  40149e <read_line>
400e37:   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

打開 gdb,先給這一行打上斷點 break *0x400e23,然後 run 起來。這裏可以看到調用了 puts 這個函數,寄存器 %edi 存儲的是函數的第一個參數,我們把它的結果打印出來 x/s 0x402338x/s 0x402378,發現得到了運行 bomb 後輸出的字符串。說明第一關就是從這裏開始的。

由於返回值是存在 %rax 中的,這裏 mov %rax %rdi,說明輸入的內容傳參給了 phase_1。在 gdb 裏給 phase_1 打斷點 break phase_1

0000000000400ee0 <phase_1>:
    400ee0:   48 83 ec 08             sub    $0x8,%rsp
    400ee4:   be 00 24 40 00          mov    $0x402400,%esi
    400ee9:   e8 4a 04 00 00          callq  401338 <strings_not_equal>
    400eee:   85 c0                   test   %eax,%eax
    400ef0:   74 05                   je     400ef7 <phase_1+0x17>
    400ef2:   e8 43 05 00 00          callq  40143a <explode_bomb>
    400ef7:   48 83 c4 08             add    $0x8,%rsp
    400efb:   c3                      retq

通過這裏的代碼,就可以分析出來,通過調用 string_not_equal 比較輸入的字符串與 0x402400 存儲的字符串是否相等,來決定是不是 explode_bomb。通過這個函數名也可以知道一定要輸入與 0x402400 相同的字符串就可以通過第一關了。所以在這裏打個斷點 break *0x400ee9,然後 x/s 0x402400 打印出來這裏的字符串,我這裏是 Border relations with Canada have never been better.,然後輸入這個字符串,第一關就過了~

string_not_equal

雖然這樣就過關了,但是我還是對這裏的代碼好奇,畢竟是學習嘛,看看這裏的代碼熟悉熟悉彙編。

0000000000401338 <strings_not_equal>:
  401338:   41 54                   push   %r12
  40133a:   55                      push   %rbp
  40133b:   53                      push   %rbx
  40133c:   48 89 fb                mov    %rdi,%rbx
  40133f:   48 89 f5                mov    %rsi,%rbp
  401342:   e8 d4 ff ff ff          callq  40131b <string_length>
  401347:   41 89 c4                mov    %eax,%r12d
  40134a:   48 89 ef                mov    %rbp,%rdi
  40134d:   e8 c9 ff ff ff          callq  40131b <string_length>
  401352:   ba 01 00 00 00          mov    $0x1,%edx
  401357:   41 39 c4                cmp    %eax,%r12d
  40135a:   75 3f                   jne    40139b <strings_not_equal+0x63>
  40135c:   0f b6 03                movzbl (%rbx),%eax
  40135f:   84 c0                   test   %al,%al
  401361:   74 25                   je     401388 <strings_not_equal+0x50>
  401363:   3a 45 00                cmp    0x0(%rbp),%al
  401366:   74 0a                   je     401372 <strings_not_equal+0x3a>
  401368:   eb 25                   jmp    40138f <strings_not_equal+0x57>
  40136a:   3a 45 00                cmp    0x0(%rbp),%al
  40136d:   0f 1f 00                nopl   (%rax)
  401370:   75 24                   jne    401396 <strings_not_equal+0x5e>
  401372:   48 83 c3 01             add    $0x1,%rbx
  401376:   48 83 c5 01             add    $0x1,%rbp
  40137a:   0f b6 03                movzbl (%rbx),%eax
  40137d:   84 c0                   test   %al,%al
  40137f:   75 e9                   jne    40136a <strings_not_equal+0x32>
  401381:   ba 00 00 00 00          mov    $0x0,%edx
  401386:   eb 13                   jmp    40139b <strings_not_equal+0x63>
  401388:   ba 00 00 00 00          mov    $0x0,%edx
  40138d:   eb 0c                   jmp    40139b <strings_not_equal+0x63>
  40138f:   ba 01 00 00 00          mov    $0x1,%edx
  401394:   eb 05                   jmp    40139b <strings_not_equal+0x63>
  401396:   ba 01 00 00 00          mov    $0x1,%edx
  40139b:   89 d0                   mov    %edx,%eax
  40139d:   5b                      pop    %rbx
  40139e:   5d                      pop    %rbp
  40139f:   41 5c                   pop    %r12
  4013a1:   c3                      retq

看代碼,發現很符合書上講的,%r12%rbp%rbx 都是被調用者保存的寄存器。

首先 0x401342 ~ 0x40135a,判斷了它們的長度是不是相同,如果長度不相同,那麼它們必然不是同一個字符串。mov $0x1,%edxmov %edx,%eax 返回了 1。

0x40135c ~ 0x401361 這幾行,判斷了所輸入的字符串的第一個字符是不是 \0。因爲走到這條命令,已經判斷過長度是相同的了,如果其中的一個字符串的首字符是 \0,那麼另外一個必然是一樣的(所有的字符串一定都包含一個 \0),所以這裏直接就返回 0。

0x401361 ~ 0x40137f 是一個循環,它遍歷了兩個字符串,每一個字符是不是相同的,直到遇到 \0

string_length

000000000040131b <string_length>:
  40131b:   80 3f 00                cmpb   $0x0,(%rdi)
  40131e:   74 12                   je     401332 <string_length+0x17>
  401320:   48 89 fa                mov    %rdi,%rdx
  401323:   48 83 c2 01             add    $0x1,%rdx
  401327:   89 d0                   mov    %edx,%eax
  401329:   29 f8                   sub    %edi,%eax
  40132b:   80 3a 00                cmpb   $0x0,(%rdx)
  40132e:   75 f3                   jne    401323 <string_length+0x8>
  401330:   f3 c3                   repz retq
  401332:   b8 00 00 00 00          mov    $0x0,%eax
  401337:   c3                      retq

這個函數就比較簡單了,其實就是找到 \0 的位置,然後返回其餘首地址的差,即長度。這個翻譯成 C 語言可以這麼寫。

int string_length(char *s)
{
    char *b = a;
    
    while (*b != 0)
        b = b + 1;
    
    return (int) (b - a);
}
本文是作者在看《深入理解計算機系統》以及完成 bomb lab 時的理解與總結,謹此記錄下來已被日後翻閱。同時,也分享給各位希望瞭解這些知識的同道者們。由於作者水平有限,如有錯誤之處,望不吝賜教,深表感謝。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章