Hacking:美しき策謀 を読む前に知っておくと良いこと


# はじめに
この記事は[うどん Advent Calendar 2018](https://adventar.org/calendars/3804)13日目の記事です。今のところこの記事のみです。うどんくん頑張って。

最近 **Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際** という本を読んでいます。その中で読む前に知っておけばよかったと思う事柄がいくつかあるので、この場でご紹介します。

# 全くの初心者には難しいかも
この本は「プログラミングとは何か？」から始まり徐々に脆弱性を探っていく構成になっており、丁寧に順序立てされています。冒頭で約10ページ使ってC言語の基本について説明していますが、正直初めてプログラミングをする人には難しいと思います(不可能とは言い切れませんが)。少なくともC言語のポインタあたりまでを別の本で学習してから本題に入っていくことで、理解の速度が劇的に変わるでしょう。

# レジスタ名について
64ビット[^1]のOSを使っていると、本書に出てこないレジスタ名に遭遇します。
[^1]: 64ビットアドレッシング

例として、23ページのfirstprog.cをdisassembleした時のコードを見てみます。
このコードをUbuntu18.04、64ビットで動かします。(私はVirtualBoxで動かしています。仮想環境での学習を強くお勧めします。)

```
$ objdump -M intel -D a.out | grep -A20 main.:
000000000000063a <main>:
 63a:	55                   	push   rbp
 63b:	48 89 e5             	mov    rbp,rsp
 63e:	48 83 ec 10          	sub    rsp,0x10
 642:	c7 45 fc 00 00 00 00 	mov    DWORD PTR [rbp-0x4],0x0
 649:	eb 10                	jmp    65b <main+0x21>
 64b:	48 8d 3d a2 00 00 00 	lea    rdi,[rip+0xa2]        # 6f4 <_IO_stdin_used+0x4>
 652:	e8 b9 fe ff ff       	call   510 <puts@plt>
 657:	83 45 fc 01          	add    DWORD PTR [rbp-0x4],0x1
 65b:	83 7d fc 09          	cmp    DWORD PTR [rbp-0x4],0x9
 65f:	7e ea                	jle    64b <main+0x11>
 661:	b8 00 00 00 00       	mov    eax,0x0

(後略)
```
本書27ページと比較してみてください。eから始まるレジスタ名が、rから始まるレジスタ名に置き換わっています。

気にならないのであれば、そのままeから始まるレジスタ名に読み替えて構いません。ここからは気になる方への簡単な解説です。

32ビットのOSでは、基本的にレジスタを32
ビット分使います。同じように64ビットのOSでは基本的にはレジスタを64ビット分使います。しかし、64ビットのOSであっても32ビットやそれ以下のビット数で事足りる場合には、レジスタの下位ビットのみを使用することがあります。例えばraxというレジスタの下位32ビットだけを使う場合には、eaxという名前で指定します。下図はraxレジスタでの例を簡略化したものです。[^2]
[^2]: http://www.egr.unlv.edu/~ed/x86.html "x86-64 Assembly Language Programming with Ubuntu" 11P
![rax.png](https://qiita-image-store.s3.amazonaws.com/0/163626/d99aec81-9a18-0ee6-c4fc-300d62c4f7f5.png "rax.png")

32ビットのOS(Ubuntu16.04)で同じプログラムを動かすとこのようになります。

```
$ objdump -M intel -D a.out | grep -A20 main.:
0804840b <main>:
 804840b:	8d 4c 24 04          	lea    ecx,[esp+0x4]
 804840f:	83 e4 f0             	and    esp,0xfffffff0
 8048412:	ff 71 fc             	push   DWORD PTR [ecx-0x4]
 8048415:	55                   	push   ebp
 8048416:	89 e5                	mov    ebp,esp
 8048418:	51                   	push   ecx
 8048419:	83 ec 14             	sub    esp,0x14
 804841c:	c7 45 f4 00 00 00 00 	mov    DWORD PTR [ebp-0xc],0x0
 8048423:	eb 14                	jmp    8048439 <main+0x2e>
 8048425:	83 ec 0c             	sub    esp,0xc
 8048428:	68 d0 84 04 08       	push   0x80484d0
 804842d:	e8 ae fe ff ff       	call   80482e0 <puts@plt>
 8048432:	83 c4 10             	add    esp,0x10
 8048435:	83 45 f4 01          	add    DWORD PTR [ebp-0xc],0x1
 8048439:	83 7d f4 09          	cmp    DWORD PTR [ebp-0xc],0x9
 804843d:	7e e6                	jle    8048425 <main+0x1a>
 804843f:	b8 00 00 00 00       	mov    eax,0x0
 8048444:	8b 4d fc             	mov    ecx,DWORD PTR [ebp-0x4]
 8048447:	c9                   	leave  
 8048448:	8d 61 fc             	lea    esp,[ecx-0x4]

```
本書に出てこない命令も出てきますが、見た目は大差がなくなりました。


ここで一つ注意です。32ビットの汎用レジスタの中でもrから始まるものがあります。下図は汎用レジスタの読みかえ表です。
![GPRs.png](https://qiita-image-store.s3.amazonaws.com/0/163626/1afde340-24f4-9ce3-492c-004122ebfcd7.png "GPRs.png")[^3]
前半8つの汎用レジスタはeをrに変えるだけですが、後半8つの汎用レジスタは末尾のdを外すことで区別しています。

[^3]: http://www.egr.unlv.edu/~ed/x86.html "x86-64 Assembly Language Programming with Ubuntu" 10P




# 実行できないプログラムを実行するには
最後はStach Smashingです。VirtualBoxのUbuntuで実行しようとしても最後まで実行されないプログラムがあります。ここでは138ページのoverflow_example.cを例にとります。

```Ubuntu16.04(32ビット)

$ gcc -o overflow_example overflow_example.c
$ ./overflow_example 1234567890
[前] buffer_two は 0xbfffeeb4 にあり、その値は 'two' です
[前] buffer_one は 0xbfffeeac にあり、その値は 'one' です
[前] value は 0xbfffeea8 にあり、その値は 5 (0x00000005) です

[STRCPY] 10 バイトを buffer_two にコピーします

[後] buffer_two は 0xbfffeeb4 にあり、その値は '1234567890' です
[後] buffer_one は 0xbfffeeac にあり、その値は 'one' です
[後] value は 0xbfffeea8 にあり、その値は 5 (0x00000005) です
*** stack smashing detected ***: ./overflow_example terminated
Aborted (core dumped)
```

途中で終了してしまいました。

## Stack Smash Protection(SSP)
最近のOSにはSSP[^4]という機能が組み込まれています。簡単に言うと、スタックに対する攻撃を検知するシステムのことです。これが不正を検知したため、結果を見ることができませんででした。
[^4]: http://gcc.gnu.org/ml/gcc-patches/2004-09/msg00348.html 開発者は日本人のようです。さらに詳しい説明はgray hat hackingという本で、オプションに関する説明は`$ man gcc`で見ることができます。


## SSPの無効化
SSPを無効化するのは簡単です。gccでコンパイルする時に、`-fno-stack-protector`というオプションをつけてみましょう。

```Ubuntu16.04(32ビット)
$ gcc -fno-stack-protector -o overflow_example overflow_example.c
$ ./overflow_example 1234567890
[前] buffer_two は 0xbfffeebc にあり、その値は 'two' です
[前] buffer_one は 0xbfffeec4 にあり、その値は 'one' です
[前] value は 0xbfffeecc にあり、その値は 5 (0x00000005) です

[STRCPY] 10 バイトを buffer_two にコピーします

[後] buffer_two は 0xbfffeebc にあり、その値は '1234567890' です
[後] buffer_one は 0xbfffeec4 にあり、その値は '90' です
[後] value は 0xbfffeecc にあり、その値は 5 (0x00000005) です
```

今度は実行することができました！こちらもやはり仮想環境での実行をお勧めします。

# おわりに
セキュリティに興味が湧いてこの本を読み始めました。とても面白いですね。この後も詰まったところがあったら更新したいと思います。