# Bomb lab ###### tags: `ryanpatiency` [原 CMU 課程網站資料 - IA32 Assembly](http://csapp.cs.cmu.edu/2e/labs.html) [成大資工 Wiki 資料 - ARM Assembly](http://wiki.csie.ncku.edu.tw/embedded/Lab34) * 目的 * 複習 ARM 處理器和指令集,並深入 stack 和執行時期的行為 * 熟悉 objdump、gdb 等工具,並利用上述工具分析執行檔 * 環境安裝 * [Download bomb lab (NCKU)](http://wiki.csie.ncku.edu.tw/embedded/Lab34/bomb.tar.gz) * Download tools: ``` $ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf $ sudo apt-get install qemu-user qemu-system-arm qemu ``` * [Download Arm gdb](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm) * 加入 Path * `$ vim ~/.bashrc` * 加入 `export PATH=$PATH:(你的資料路徑)/gcc-arm-none-eabi-7-2017-q4-major/bin` * `$ source ~/.bashrc` 如果以上有多餘或缺少的,請幫我更正,謝謝 ## 第1題模擬和練習 * 到 bomb 資料夾 * 請先觀察 bomb.c `$ gedit ./bomb.c` ```clike= read_line(input); phase_1(input); printf("Phase 1 defused.\n"); ... read_line(input); phase_4(input); printf("Phase 4 defused.\n"); printf("Congratulations! You've defused the bomb!\n"); ``` 可以發現 read_line(input) 後,下一個 function 是 phase_1, 這個 function 會檢查你的 input ,如果和預設值不同,就會爆炸 * 實際執行看看 ``` $ qemu-arm -L /usr/arm-linux-gnueabihf/ ./bomb Example phase 0, please type in help ``` 這時游標會停在新的一行空白行,意思是叫你輸入密碼。我們隨便輸入看看: * 測試 abc ``` $ qemu-arm -L /usr/arm-linux-gnueabihf/ ./bomb Example phase 0, please type in help abc Bomb explode! ``` 所以現在要做的就是讓炸彈不爆炸,我們輸入正確答案 "help" ``` $ qemu-arm -L /usr/arm-linux-gnueabihf/ ./bomb Example phase 0, please type in help help Phase 0 defused. It's your turn now, cheer up =) ``` 但這時游標會停在新的一行空白行,意思是叫你輸入phase 1 的密碼。我們如果亂輸入的話: ``` $ qemu-arm -L /usr/arm-linux-gnueabihf/ ./bomb Example phase 0, please type in help help Phase 0 defused. It's your turn now, cheer up =) abc Bomb explode! ``` 炸彈又爆炸了 再看看 bomb.c ,我們會發現共有 5 個 phase, 全都過關後,才會輸出: ```clike= printf("Congratulations! You've defused the bomb!\\n"); ``` 由於我們不知道 phase_1 到 phase_4 的密碼,我們需要 gdb 的幫助 * 先背景執行程式在 port 1234: ``` $ qemu-arm -g 1234 -L /usr/arm-linux-gnueabihf/ ./bomb ``` * 開啟 gdb: (需要另外開一個終端機) ``` $ arm-none-eabi-gdb ./bomb ``` * 產生 `(gdb) ` 等你輸入指令 * 在 gdb 中,連上 port 1234 ``` (gdb) target remote :1234 ``` * 成功訊息 ``` Remote debugging using :1234 warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration of GDB. Attempting to continue with the default arm settings. 0xf67d6a40 in ?? () (gdb) ``` 現在可以開始學習 gdb 的常用指令了[link](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) 看過一遍後,你知道可以使用 gdb 來跑程式,於是你可以在 gdb 輸入 `(gdb) continue` 你會發現 gdb 不再出現 (gdb) 的符號,因為程式會一直執行到結束,回到原本的 terminal, 會發現他和原本的程式行為一樣。你可以隨便輸入,直到爆炸。 爆炸後 gdb 顯示 ``` [Inferior 1 (Remote target) exited with code 010] (gdb) ``` 程式結束錯誤,你再重開就好,先再執行程式的終端機輸入 ``` $ qemu-arm -g 1234 -L /usr/arm-linux-gnueabihf/ ./bomb ``` 然後在 gdb 輸入 ``` (gdb) target remote :1234 ``` 於是你知道用 continue 前,應該用 break * 在 gdb 輸入 ``` (gdb) break phase_0 ``` * 再輸入 ``` (gdb) continue ``` * 再另外一個 terminal 輸入 ``` $ qemu-arm -g 1234 -L /usr/arm-linux-gnueabihf/ ./bomb Example phase 0, please type in help abc ``` 按下 enter 後,你會發現,雖然我亂輸入 abc, 他還沒有爆炸。因為進入斷點,你成功進去 phase_0 的函式裏面了,為了觀察 assembly: ``` (gdb) disassemble ``` 可看到 ``` Dump of assembler code for function phase_0: 0x000087d8 <+0>: push {r7, lr} 0x000087da <+2>: sub sp, #16 0x000087dc <+4>: add r7, sp, #0 0x000087de <+6>: str r0, [r7, #4] 0x000087e0 <+8>: movw r3, #35628 ; 0x8b2c => 0x000087e4 <+12>: movt r3, #0 0x000087e8 <+16>: str r3, [r7, #12] 0x000087ea <+18>: ldr r0, [r7, #4] 0x000087ec <+20>: ldr r1, [r7, #12] 0x000087ee <+22>: blx 0x84c8 <strcmp@plt> 0x000087f2 <+26>: mov r3, r0 0x000087f4 <+28>: cmp r3, #0 0x000087f6 <+30>: beq.n 0x87fc <phase_0+36> 0x000087f8 <+32>: bl 0x87c0 <explode_bomb> 0x000087fc <+36>: adds r7, #16 0x000087fe <+38>: mov sp, r7 0x00008800 <+40>: pop {r7, pc} End of assembler dump. ``` 這時候你就應該要去學 arm-assembly 了 reference: * gnu arm assembler: http://www.ic.unicamp.br/~celio/mc404-2014/docs/gnu-arm-directives.pdf * official document https://www.scss.tcd.ie/~waldroj/3d1/arm_arm.pdf 如果你看懂 assembly 後,你會發現重點是這三行 ``` 0x000087ea <+18>: ldr r0, [r7, #4] 0x000087ec <+20>: ldr r1, [r7, #12] 0x000087ee <+22>: blx 0x84c8 <strcmp@plt> ``` 不斷執行 **(執行 4 次)** ``` (gdb) stepi ``` 直到做字串比較前 ``` => 0x000087ee <+22>: blx 0x84c8 <strcmp@plt> ``` 輸入 ``` (gdb) set $r1 = $r0 ``` 然後 ``` (gdb) continue ``` 你應該能成功通過 phase_0 ,雖然你沒有輸入 help 如果你成功到達這一步驟,剩下的主要就是學習 arm assembly 而已,祝你成功拆除炸彈 [解題嘗試](https://hackmd.io/s/r1pQi7JTf)