ShellCraftでアセンブリを読む

## ShellCraftとは？
原義の「シェルコード」を指します。
悪いコードというイミでなく、**シェルを呼び出す関数**です。

## ShellCraftが実行するコード
```shellcraft.asm
   /* execve(path='/bin///sh', argv=['sh'], envp=0) */
    /* push '/bin///sh\x00' */
    push 0x68
    push 0x732f2f2f
    push 0x6e69622f
    mov ebx, esp
    /* push argument array ['sh\x00'] */
    /* push 'sh\x00\x00' */
    push 0x1010101
    xor dword ptr [esp], 0x1016972
    xor ecx, ecx
    push ecx /* null terminate */
    push 4
    pop ecx
    add ecx, esp
    push ecx /* 'sh\x00' */
    mov ecx, esp
    xor edx, edx
    /* call execve() */
    push SYS_execve /* 0xb */
    pop eax
    int 0x80
```

## 要約すると、
「`/* execve(path='/bin///sh', argv=['sh'], envp=0) */`」
execveは、システムコールです。OSが用意してる関数みたいなもんです。
これを召喚すればシェルやスクリプトを実行してくれるわけです。
【引数】
第一引数 : 実行したいファイルの**パス**（実行バイナリやスクリプト）
第二引数 : プログラムに渡す配列（NULLポインタが終端）。`ls -l`とか
第三引数 : プログラムに渡す環境変数（NULLポインタが終端）

### 目標として、
`eax(ebx, ecx, edx)` の形式になることを確認できれば👌
↑ は、
`execve("/bin///sh", "sh", 0)` と同じイミ

それぞれのレジスタ（`e[a-d]x`）に文字とかを格納できれば👌


## スタックを追う
スタックつうのは`print("HelloWorld!!")`するならこんな感じになります。
引数→リターンアドレスの順に、先端へ積んでいくわけです。ジェンガと同じで、先端から取り出します。底の方から取り出すことはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/b14d187a-4af4-4f68-2a67-cefc9647f33d.png)


アセンブリで簡易に表すと ↓
```HelloWorld!!.asm
push 00!!
push dlroW
push olleH
call print
```
`push` : スタックに積め、という命令
`pop` : スタックから取り出せ、という命令。`push`の逆の操作
**00** : 終端文字。コンピュータが`文字列`と`命令文`を区別するために文字列の終端に供えます。16進数「**\x00**」はASCIIで「**NULL**」を指します。

<br>では、セクションごとに見ていきましょう。

## ①/* push '/bin///sh\x00' */
第一引数として、「**/bin///sh**」という文字列をスタックに追加すると言っています。

```
/* push '/bin///sh\x00' */
push 0x68
push 0x732f2f2f
push 0x6e69622f
mov ebx, esp
```
スタックは4バイト度()にアドレスが割り振られており、`0x68`(1バイト)は残りの3バイト分を`000000`で埋めます。これが終端文字**NULL**に該当します。
0x00000068 : nullnullnull**h**
0x732f2f2f : **s///**
0x6e69622f : **nib/**

1バイト区切りで[**逆さ**](https://rainbow-engine.com/little-endian-big-endian/)から読めば「**/bin///sh**」という文字列の完成です。ASCII表で`16進数`と`アルファベット`の対応を確認できます。例えば「`2f`」は「`/`」に対応しています。

このパスのシェルを呼び出すようですね。

現在のスタックはこのようになっています。👌
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/117d1f85-5faa-f59e-9f5f-be89230f4680.png)



`mov ebx, esp`は、`ebx`というレジスタに`esp`のアドレスを格納する命令です。「`esp`」というのは常に**スタックの先端アドレス**を指すポインタです。
今、このアドレスには「**nib/**」が格納されており、ここから逆さに文字を辿っていくと、「**/bin///sh**」と第一引数が完成します🎉



## ②/* push argument array ['sh\x00'] */
第二引数として、「**sh**」という文字列をスタックに追加すると言っています。

```
/* push argument array ['sh\x00'] */
/* push 'sh\x00\x00' */
push 0x1010101
xor dword ptr [esp], 0x1016972
xor ecx, ecx
push ecx /* null terminate */
push 4
pop ecx
add ecx, esp
push ecx /* 'sh\x00' */
mov ecx, esp
xor edx, edx
```
<br>
ただ先ほどと違って命令が多いです。順を追って見ましょう。

```
push 0x1010101
xor dword ptr [esp], 0x1016972
```
0x1010101を`push`してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/552280a2-eed7-16e4-0206-74cd527ddb85.png)


次の命令は、`esp`と`0x1016972`で**xor**をとり、その計算結果を`esp`に代入するようです。
`esp`には`0x1010101`が格納されているので
```
esp = 0x1010101 xor 0x1016972
```
という命令になります。
`0x6873`という値が得られるはずです。ASCIIでいう「**sh**」に対応します。

`esp`に「**sh**」を代入すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/56e7d589-95a7-b118-ef58-879762b8fc3d.png)
となります。👌

※**dword ptr**は、`esp`を4バイトとして扱います。`esp = 0x1010101`は7バイト(7桁)なので`0x01010101`という風に8バイトで表現します。計算結果は変わりません。

<details><summary>ちょっとした疑問と予想</summary>

そもそも`esp`はポインタであり、「データの**アドレス**」を指しています。しかし、今回のxor演算では「データ**そのもの**（0x1010101）」を表していました。これは、**dword**を宣言することで`esp`を「アドレスとして」でなく、「ポインタが指すデータそのものとして」扱わせているのかも🤔
</details>

<br>😎
<br>😎
<br>😎

```
xor ecx, ecx
push ecx /* null terminate */
```
同じ値で**xor**をとると値は必ず`0`になります。`ecx`には`0`が代入され、
それを`push`すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/0f45f5a0-db75-3fca-3a1e-9b7de268677a.png)
となります。👌
この`0`が第二引数「**sh**」の終端文字NULLだそうですね。

<br>😎
<br>😎
<br>😎

```
push 4
pop ecx
add ecx, esp
push ecx /* 'sh\x00' */
mov ecx, esp
xor edx, edx
```

`push 4`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/c82f5626-d31d-2439-fb3a-2db199fa268b.png)
しました👌


`pop ecx` （`pop`した値を`ecx`に格納）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/2ef4087a-88fd-94e8-afa5-8cbad8ede744.png)
しました👌

`add ecx, esp`
今、以下の値を足して`ecx`に格納しようとしています。
`ecx` = `4`
`esp` = `0を格納しているアドレス`
すると、、
`ecx`には「`esp`に4足したアドレス」が格納されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/bab2ac32-a34d-ac81-be95-19d79ea6affa.png)

※アドレスを「足す」と**底**に近づきます。先端に行くほどアドレスは小さくなります。4ずつ。正規分布みたく。
`ecx`には「**sh**」を指すアドレスが格納されました。

`push ecx`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/5658bac7-c751-e4d9-6f42-87bc52cdf61b.png)

`mov ecx, esp`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/c7eabc1f-fb39-500b-e3be-53f5906f1b04.png)


`ecx`には「**sh**を表すアドレスのアドレス」。これが第二引数です。
今、`esp + 4`の位置にある`0`はおそらく、**shのアドレス**の終端文字だと考えられます。

最後に、`xor edx, edx`で`edx` = `0`になります。これが第三引数です。

引数はすべて完了しました。👌
<br>🍵
<br>🍵
<br>🍵
## /* call execve() */
ようやくシステムコールの処理です。
このシステムコールがさっき求めた引数を取ります。

```
/* call execve() */
push SYS_execve /* 0xb */
pop eax
int 0x80
```

`push SYS_execute`・`pop eax`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528316/03fe833c-6f8e-3203-8692-a8342a9682b1.png)
スタックはこうなります。👌

`int 0x80`は、システムコールの呼び出し(重言)命令です。
### 整理

`eax` = **SYS_execute**
`ebx` = **/bin///sh**
`ecx` = **sh**
`edx` =  **0**
`eax(ebx, ecx, edx)`

`execve("bin///sh", "sh", 0)` の完成です。

## 最後に
間違った情報があれば、教えていただきたいです。

今のところ、
"`ecx`に**shのアドレス**が格納されてもなお`ecx`に`esp`を代入して間接的なポインタを作るのはエレガント性に欠けるな～"
くらいです。
これ以外の一連は納得しているつもりです。

「解析」にしては手ごろなサイズだったので、楽しいまま解析し終えました。次はシステムコールがどのように引数を取り、どのような一連を経て実行されるのかが知りたいです。


なにか、疑問点・ここってこうじゃね？的な意見があれば是非コメントお願いします。理解の矯正につながると思います。


51c9670f00071a021114094cc8afa5733d4b6c9f5cee2f71f987c60bd573ffb0