---
tags: jserv
---
# Bomb Lab 實作紀錄
本次實驗中,參考資料有
* 以往同學在 ARM 環境下已 qemu 模擬的[紀錄](https://hackmd.io/s/HJe2aUvFf)
* [如何以 qemu 模擬 AArch64環境](https://blahcat.github.io/2018/01/07/building-a-debian-stretch-qemu-image-for-aarch64/)
## 實驗目的
1. 了解 Aarch64 及 arm 中的[差異](https://en.wikipedia.org/wiki/ARM_architecture#AArch64_features),AArch64 為後來提出的指令集架構,熟悉AArch64 指令集,並分析 assembly code 實作 bomb lab 需求
2. 以 qemu 模擬 AArch64 硬體平台,進一步以 GDB 分析 register 和 assembly code
## 以 qemu 模擬 AArch64 硬體平台
1. 我們一開始參考老師給我們的[連結](https://blahcat.github.io/2018/01/07/building-a-debian-stretch-qemu-image-for-aarch64/),試著一步一步照著上面給定的步驟去走,不過最後失敗了,我們最後是以[這個連結](http://www.cnblogs.com/wangaohui/p/5184476.html)中的教學,改裝 ubuntu image 才順利成功。
2. 我們有嘗試過在 VM 內,實際編譯程式碼,並以 GDB debug 但 GCC 和 GDB 在 VM 內都裝不起來,後來有想那是不是可以從 VM 內啟動一個 debug server 再從 host 去連,但依然失敗。
3. 最後我們效法之前同學做的作法不在 VM 內,而是以 `qemu-aarch64 -L /usr/aarch64-linux-gnu/ my_elf` 實際 run 起 process 等待連接,並以 `aarch64-gdb my_elf` 連接我們想要監控的進程。
## aarch64-gdb, aarch64-gcc
我們一開始參考了[這個網站](https://www.archlinux.org/packages/community/x86_64/aarch64-linux-gnu-gdb/)想要安裝 aarch64-linux-gnu-gdb,但是 apt install 時卻找不到這包 package,於是後來在[這裡](https://releases.linaro.org/components/toolchain/binaries/latest-5/aarch64-linux-gnu/)的[這個連結](https://releases.linaro.org/components/toolchain/binaries/latest-5/aarch64-linux-gnu/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu.tar.xz)中下載解壓縮後在 `gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin` 中找到了 `aarch64-linux-gnu-gdb`並且將它軟連結至 `/usr/bin`
```shell
$ cd /usr/bin
$ ln -s ~/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb aarch-gdb
```
這樣的話之後想要開啟 aarch64 gdb 就只要
```shell
$ aarch-gdb my_elf
```
同理我們的 aarch-gcc 也是相同的做法
```
$ ln -s ~/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc aarch-gcc
$ aarch-gcc my_file.c
```
## 利用 AArch64 gdb 監控執行 bomb
我們設計的 bomb.c 有兩個 phase:
- phase 1 為字串比對,如果輸入字串為 ubuntu 的話,就通過 phase 1,反之則爆炸
- phase 2 為數字的比對,如果輸入的數字符合我們設計的數字 0xAAAAAAAAAAAAAAAA ,也就是奇數位皆是 1 的話就通過 phase 2 並結束程式,反之則會爆炸
```C=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
void phase_1(char *user_input) {
char *ans = "ubuntu";
if(strcmp(user_input, ans)) {
printf("Bomb explode !!!!!! hahahaha\n");
exit(1);
} else {
printf("phase_1 pass!!\n");
}
}
void phase_2(uint64_t user_input) {
if(!(user_input ^ 0xAAAAAAAAAAAAAAAA))
printf("phase_2 pass !!\n");
else {
printf("Bomb explode !!!!!! hahahaha\n");
exit(1);
}
}
int main() {
printf("Start to defuse bomb!!!\n");
char p1_input[100];
printf("enter a string\n");
scanf("%s", p1_input);
phase_1(p1_input);
printf("phase 1 defuse !!!\n");
uint64_t p2_input;
printf("enter a long unsigned integer\n");
scanf("%lu", &p2_input);
phase_2(p2_input);
printf("phase 2 defuse !!!\n");
return 0;
}
```
使用 aarch-gcc 來編譯上面這段程式碼
```shell
$ aarch-gcc bomb.c
```
先背景執行程式在 port 1234
```shell
$ qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ a.out
```
開啟 aarch-gdb 來觀察執行時期的行為
```shell
$ aarch-gdb ./a.out
```
進入 gdb,連上 port 1234
```shell
$ target remote :1234
```
成功訊息
![](https://i.imgur.com/XfPYSFv.png)
設定 break point
``` shell
(gdb) break phase_1
Breakpoint 1 at 0x400798
(gdb) break phase_2
Breakpoint 2 at 0x4007ec
```
再輸入
```shell
(gdb) continue
```
在另外一個 terminal 輸入 'test'
```shell
$ qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ a.out
Start to defuse bomb!!!
enter a string
test
```
接著雖然 'test' 跟我們設定的 'ubuntu' 不一樣,但因為進入了 break point 所以還沒爆炸,這時候我們可以去看這時候的 assemble code
```shell
(gdb) disassemble
Dump of assembler code for function phase_1:
0x0000000000400790 <+0>: stp x29, x30, [sp, #-48]!
0x0000000000400794 <+4>: mov x29, sp
=> 0x0000000000400798 <+8>: str x0, [x29, #24]
0x000000000040079c <+12>: adrp x0, 0x400000
0x00000000004007a0 <+16>: add x0, x0, #0x970
0x00000000004007a4 <+20>: str x0, [x29, #40]
0x00000000004007a8 <+24>: ldr x0, [x29, #24]
0x00000000004007ac <+28>: ldr x1, [x29, #40]
0x00000000004007b0 <+32>: bl 0x400610 <strcmp@plt>
0x00000000004007b4 <+36>: cmp w0, wzr
0x00000000004007b8 <+40>: b.eq 0x4007d0 <phase_1+64> // b.none
0x00000000004007bc <+44>: adrp x0, 0x400000
0x00000000004007c0 <+48>: add x0, x0, #0x978
0x00000000004007c4 <+52>: bl 0x400600 <puts@plt>
0x00000000004007c8 <+56>: mov w0, #0x1 // #1
0x00000000004007cc <+60>: bl 0x4005b0 <exit@plt>
0x00000000004007d0 <+64>: adrp x0, 0x400000
0x00000000004007d4 <+68>: add x0, x0, #0x998
0x00000000004007d8 <+72>: bl 0x400600 <puts@plt>
0x00000000004007dc <+76>: ldp x29, x30, [sp], #48
0x00000000004007e0 <+80>: ret
End of assembler dump.
```
執行 stepi 直到 0x00000000004007b0 這個位址
```shell
(gdb) stepi
```
這時候去看 x0 跟 x1 這兩個暫存器
```shell
(gdb) x/s $x0
0x40007ffc40: "test"
(gdb) x/s $x1
0x400970: "ubuntu"
```
如果直接將 $x1 的值 assign 給 $x0 並執行 strcmp 的話就能順利通過 phase 1
```shell
(gdb) set $x0 = $x1
(gdb) continue
```
在另外一個 terminal 就能看到成功的指示
```shell
$ qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ a.out
Start to defuse bomb!!!
enter a string
test
phase_1 pass!!
phase 1 defuse !!!
enter a long unsigned integer
```
接著進入 phase 2
```shell
$ qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ a.out
Start to defuse bomb!!!
enter a string
test
phase_1 pass!!
phase 1 defuse !!!
enter a long unsigned integer
55
```
並在另外一邊觀察 phase_2 的 assembly code
```shell
(gdb) disassemble
Dump of assembler code for function phase_2:
0x00000000004007e4 <+0>: stp x29, x30, [sp, #-32]!
0x00000000004007e8 <+4>: mov x29, sp
=> 0x00000000004007ec <+8>: str x0, [x29, #24]
0x00000000004007f0 <+12>: ldr x1, [x29, #24]
0x00000000004007f4 <+16>: mov x0, #0xaaaaaaaaaaaaaaaa // #-6148914691236517206
0x00000000004007f8 <+20>: cmp x1, x0
0x00000000004007fc <+24>: b.ne 0x400810 <phase_2+44> // b.any
0x0000000000400800 <+28>: adrp x0, 0x400000
0x0000000000400804 <+32>: add x0, x0, #0x9a8
0x0000000000400808 <+36>: bl 0x400600 <puts@plt>
0x000000000040080c <+40>: b 0x400824 <phase_2+64>
0x0000000000400810 <+44>: adrp x0, 0x400000
0x0000000000400814 <+48>: add x0, x0, #0x978
0x0000000000400818 <+52>: bl 0x400600 <puts@plt>
0x000000000040081c <+56>: mov w0, #0x1 // #1
0x0000000000400820 <+60>: bl 0x4005b0 <exit@plt>
0x0000000000400824 <+64>: ldp x29, x30, [sp], #32
0x0000000000400828 <+68>: ret
End of assembler dump.
```
在以上這邊觀察到如果輸入的數字為 0xaaaaaaaaaaaaaaaa ,則會執行 0x0000000000400800 ~ 0x000000000040080c 這段並且跳過 exit 直接到 0x0000000000400824;如果輸入的數字錯誤的話,則會在 0x00000000004007fc 這裡直接跳到 0x0000000000400810 ~ 0x0000000000400820 並離開這支程式。
先執行幾次 stepi 直到 0x00000000004007f8
```shell
(gdb) stepi
```
並觀察 x0 及 x1
```
(gdb) x/s $x0
0xaaaaaaaaaaaaaaaa: <error: Cannot access memory at address 0xaaaaaaaaaaaaaaaa>
(gdb) x/s $x1
0x37: <error: Cannot access memory at address 0x37>
```
一樣直接將 $x0 的值 assign 給 $x1
```shell
(gdb) set $x1 = $x0
```
就會在另外一邊看到 phase 2 成功的指示
```shell
$ qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu/ a.out
Start to defuse bomb!!!
enter a string
test
phase_1 pass!!
phase 1 defuse !!!
enter a long unsigned integer
55
phase_2 pass !!
phase 2 defuse !!!
```