深入理解計算機系統BombLab實驗報告
又快有一個月沒寫部落格了,最近在看《深入理解計算機系統》這本書,目前看完了第三章,看完這章,對程式的機器級表示算是有了一個入門,也對 C 語言裡函式棧幀有了一個初步的理解。
為了加深對書本內容的認識,以後每學習完一部分章節,就完成相應書本附帶的實驗題目。
第三章對應的實驗是 BombLab,下面是我做這個實驗的過程。
BombLab 分為 6 個普通關卡和一個隱形關卡,為了開始闖關,得先弄清楚從哪裡開始行動。
首先使用 objdump 命令 objdump -t bomb > bomb_symboltable 來生成 bomb 檔案的符號表(部分),如下:
bomb: file format elf64-x86-64 SYMBOL TABLE:0000000000400238 l d .interp 0000000000000000 .interp 0000000000400254 l d .note.ABI-tag 0000000000000000 .note.ABI-tag 0000000000400274 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id 0000000000400298 l d .gnu.hash 0000000000000000 .gnu.hash 00000000004002c8 l d .dynsym 0000000000000000 .dynsym 00000000004005c8 l d .dynstr0000000000000000 .dynstr 0000000000400736 l d .gnu.version 0000000000000000 .gnu.version ...
...
...
...
... 0000000000000000 F *UND* 0000000000000000 [email protected]@GLIBC_2.3 0000000000603750 g O .bss 0000000000000008 [email protected]@GLIBC_2.2.5 0000000000000000 F *UND* 0000000000000000 [email protected]@GLIBC_2.3.4 0000000000000000 F *UND* 0000000000000000[email protected]@GLIBC_2.2.5
這個檔案內容太多,我們只提取出含有關鍵字 bomb 的行,如下:
0000000000000000 l df *ABS* 0000000000000000 bomb.c 00000000004013ba g F .text 0000000000000002 initialize_bomb_solve 000000000040143a g F .text 0000000000000022 explode_bomb 000000000060375c g O .bss 0000000000000004 bomb_id 00000000004013a2 g F .text 0000000000000018 initialize_bomb
其中 000000000040143a g F .text 0000000000000022 explode_bomb 這一行就是用來引爆炸彈用的,我們可以先記住這個地址,以備用。
下面我們再對 bomb 檔案進行反彙編,使用命令 objdump -d bomb > bomb_disassamble 可以得到 bomb 檔案的反彙編檔案,由於檔案內容太多,這裡就不全部貼出來了,在接下來的闖關中,會陸陸續續的講這個檔案中的一些彙編貼出來使用。
有了這些準備條件,下面我們開始闖關!
注意:接下來所有貼出來的函式的反彙編程式碼,都可以通過對 bomb 檔案進行反彙編得到。
第一關:
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
首先看第一條指令 sub $0x8,%rsp,這條指令用來分配 8 位元組的函式棧幀,指令 mov $0x402400,%esi ,則將立即數 0x402400 傳入暫存器 %esi 中,然後呼叫 strings_not_equal 這個函式, test %eax,%eax 這條指令判斷暫存器 %eax 裡是否為 0,如果為 0,則直接跳到 add $0x8,%rsp ,將函式指標加 8,釋放棧幀。如果不為 0,則執行 callq 40143a <explode_bomb> ,引爆炸彈。
下面對 strings_not_equal 函式的反彙編程式碼進行分析:
1 0000000000401338 <strings_not_equal>: 2 401338: 41 54 push %r12 3 40133a: 55 push %rbp 4 40133b: 53 push %rbx 5 40133c: 48 89 fb mov %rdi,%rbx 6 40133f: 48 89 f5 mov %rsi,%rbp 7 401342: e8 d4 ff ff ff callq 40131b <string_length> 8 401347: 41 89 c4 mov %eax,%r12d 9 40134a: 48 89 ef mov %rbp,%rdi 10 40134d: e8 c9 ff ff ff callq 40131b <string_length> 11 401352: ba 01 00 00 00 mov $0x1,%edx 12 401357: 41 39 c4 cmp %eax,%r12d 13 40135a: 75 3f jne 40139b <strings_not_equal+0x63> 14 40135c: 0f b6 03 movzbl (%rbx),%eax 15 40135f: 84 c0 test %al,%al 16 401361: 74 25 je 401388 <strings_not_equal+0x50> 17 401363: 3a 45 00 cmp 0x0(%rbp),%al 18 401366: 74 0a je 401372 <strings_not_equal+0x3a> 19 401368: eb 25 jmp 40138f <strings_not_equal+0x57> 20 40136a: 3a 45 00 cmp 0x0(%rbp),%al 21 40136d: 0f 1f 00 nopl (%rax) 22 401370: 75 24 jne 401396 <strings_not_equal+0x5e> 23 401372: 48 83 c3 01 add $0x1,%rbx 24 401376: 48 83 c5 01 add $0x1,%rbp 25 40137a: 0f b6 03 movzbl (%rbx),%eax 26 40137d: 84 c0 test %al,%al 27 40137f: 75 e9 jne 40136a <strings_not_equal+0x32> 28 401381: ba 00 00 00 00 mov $0x0,%edx 29 401386: eb 13 jmp 40139b <strings_not_equal+0x63> 30 401388: ba 00 00 00 00 mov $0x0,%edx 31 40138d: eb 0c jmp 40139b <strings_not_equal+0x63> 32 40138f: ba 01 00 00 00 mov $0x1,%edx 33 401394: eb 05 jmp 40139b <strings_not_equal+0x63> 34 401396: ba 01 00 00 00 mov $0x1,%edx 35 40139b: 89 d0 mov %edx,%eax 36 40139d: 5b pop %rbx 37 40139e: 5d pop %rbp 38 40139f: 41 5c pop %r12 39 4013a1: c3 retq
由於 strings_not_equal 函式會用到 string_length 函式,所以將 string_length 函式的反彙編程式碼一併貼出來:
40 000000000040131b <string_length>: 41 40131b: 80 3f 00 cmpb $0x0,(%rdi) 42 40131e: 74 12 je 401332 <string_length+0x17> 43 401320: 48 89 fa mov %rdi,%rdx 44 401323: 48 83 c2 01 add $0x1,%rdx 45 401327: 89 d0 mov %edx,%eax 46 401329: 29 f8 sub %edi,%eax 47 40132b: 80 3a 00 cmpb $0x0,(%rdx) 48 40132e: 75 f3 jne 401323 <string_length+0x8> 49 401330: f3 c3 repz retq 50 401332: b8 00 00 00 00 mov $0x0,%eax 51 401337: c3 retq
程式碼 2 ~ 4 行先儲存相關的暫存器值。
程式碼 5 ~ 6 行將傳給函式的引數儲存進暫存器中。
看到這裡,也許能得到兩個合理的猜想:
- strings_not_equal 函式用來比較兩個字串是否相等,這個函式的一個引數就是在函式呼叫前,通過 mov $0x402400,%esi 這條指令來指定,也許 0x402400 這個值就是已經存放在記憶體中的某個字串的首地址(只是猜想)。
- strings_not_equal 函式的第二個引數是通過 %rdi 來指定,可能就是我們輸入的字串的首地址。
如果是這樣的話,那 0x402400 這個地址處存放的字串就是 phase_1 的答案。
下面我們通過 GDB 來驗證我們的猜想。
首先使用 gdb bomb 來啟動我們需要除錯的程式 bomb(前提是這個程式由 gcc bomb.c -g -o bomb 生成)。
命令列進入下面的模式:
這是我們再輸入:
break explode_bomb
break phase_1
來為程式設定相應的斷點。
然後執行 run 來執行,程式會在第一個斷點處停下,這時需要我們輸入一個字串,由於只是來驗證猜想,先隨便輸入一個字串,接著會到達第二個斷點處,如下:
接下來我們使用 stepi 命令來單步執行,使用 disas 命令可以檢視我們當前執行到什麼地方,最後使用 print 命令來檢視暫存器相關的資訊,如下:
所以字串Border relations with Canada have never been better.就是 phase_1 最終的答案。
第二關
TODO