pyrebox 超入門３　～pyrebox scriptingの入り口編～

#この記事の読み方
* pyreboxを試してみたいだけという人　⇒後ろの[補足１](https://qiita.com/najayama/items/632366e8022c46471d33#%E8%A3%9C%E8%B6%B3%EF%BC%91%E3%81%8A%E8%A9%A6%E3%81%97%E7%92%B0%E5%A2%83%E5%B0%8E%E5%85%A5%E6%B3%95)にお試し環境導入法をまとめといたのでそこから読んでください。
* もうpyreboxをガンガン使うと決めた人　⇒[超入門1](https://qiita.com/najayama/items/8d9a97d70216999e4792)から読むといいと思います。

#はじめに
* このシリーズの目標は、pyrebox独特の部分をなるべく解説し、読んだ方が普通のpythonモジュールの使い方を勉強するかの如くpyrebox scriptingを勉強していけるようにすることです。
* この記事は、**超入門1,2を読んだ方向けです。**また、基本的に[**このPDF**](https://media.readthedocs.org/pdf/pyrebox/latest/pyrebox.pdf)を見つつ書いたので、さらなる情報はそちらを見てください。この記事を見ればそこまで読むのに苦労しないはずです。（それを目標に作ってます。）

#1. スクリプトの置き場とロード方法
スクリプトの置き場は、`pyrebox/scripts/`が一般的と思われます。
ロードの方法は大きく分けて二つあります。

###pyrebox.confに記述しておく方法
`pyrebox/scripts/script_example.py`をロードしたいなら、`pyrebox.conf`の`[module]`セクションに以下のように書きます。

```pyrebox.conf
[MODULES]
scripts.script_example_min: True

[VOL]
（以下略）
```

###qemu monitorからインポートする方法
`pyrebox/scripts/script_example.py`をロードしたいなら、qemu monitor で以下のように入力
`(qemu) import_module scripts.script_example`

また、`list_moduleでモジュールを確認`

```
(qemu) list_module
+-----+----------------------------+--------+
| Hdl |        Module name         | Loaded |
+-----+----------------------------+--------+
|  1  | scripts.script_example_min |  Yes   |
|  2  | scripts.script_helloworld  |   No   |
|  3  |   scripts.script_example   |  Yes   |
|  4  |    plugins.guest_agent     |  Yes   |
+-----+----------------------------+--------+
```

アンロード、リロードは上の表のHdl番号で指定します。具体的には、
アンロード：`(qemu) reload_module 2`
リロード：`(qemu) reload_module 2`


#2. スクリプティングのルール、知っておくといいこと
全てのpyreboxスクリプトは以下の二つを含まなければなりません。

* initialize_callbacks()の定義：読み込み時に実行される関数です。
* clean()の定義：アンロードするときに実行される関数です。

こう聞くととっつきにくいと思うかもしれませんが、`pyrebox/scripts/script_example_min.py`が雛形用に提供されているので、はじめはそれを使えば問題ないです。また、`pyrebox/scripts/script_exapmple.py`がチュートリアルを含んでいるので、自分で何か書く前にそれを読むと参考になると思います。さらに、`pyrebox/pyrebox_test/`下にデモンストレーションがいくつかあるので参考にできるはずです。

#3. 自前のコマンドを定義してみよう
まずはpyrebox shell上から使えるコマンドを新たに作ってみましょう。
これのためには以下のような形式に従います。

```コマンド作成の形式
def do_”コマンド名”(line):
    ```カンタンなコマンドの説明

    ```

    以下あなたのコマンドの処理
```

カンタンなコマンドの説明は、標準的なpython docstringです。pyreboxがロード時に勝手に読み込んでくれるのできちんと書きましょう。
また、line はpyrebox shellから渡されるコマンドライン引数です。

百聞は一見に如かず、やってみるのが手っ取り早いと思います。
`scripts`ディレクトリに移動して、雛形をコピー

```bash:
$ cd ~/pyrebox/scripts/
$ cp script_example_min.py script_helloworld.py
```
script_helloworld.pyの８７行目に以下のような部分があるはずです。

```python:script_helloworld.py　（87行目あたり）
def do_my_command(line):
    ''' Short description of the custom command.

        Long description of the custom command
    '''
    global pyrebox_print
    global cm

    # Implementation of the command functionality
    pyrebox_print("This is a custom command")
```
この部分を以下のように変更してください。

```python:script_helloworld.py(変更後)
def do_helloworld(line):
    ''' This is my helloworld script!.

        This just print first argument 
        and "Hello World". 
    '''
    global pyrebox_print

    if line:
        arg_list = line.split()
        pyrebox_print("first_arg: %s" % (arg_list[0]))

    pyrebox_print("Hello World!")
```

pyrebox 仮想マシンを起動してqemu monitor で以下のようにして実行できます。

```
(qemu) list_modules 
+-----+----------------------------+--------+
| Hdl |        Module name         | Loaded |
+-----+----------------------------+--------+
|  1  | scripts.script_example_min |  Yes   |
+-----+----------------------------+--------+
(qemu) import_module scripts.script_helloworld
[*]  Loading python module scripts.script_helloworld
[scripts.script_helloworld] [*]    Initializing callbacks
[scripts.script_helloworld] [*]    Initialized callbacks
(qemu) list_modules 
+-----+----------------------------+--------+
| Hdl |        Module name         | Loaded |
+-----+----------------------------+--------+
|  1  | scripts.script_example_min |  Yes   |
|  2  | scripts.script_helloworld  |  Yes   |
+-----+----------------------------+--------+
(qemu) sh

[1] pyrebox> %list_commands

（～中略～）
    Use custom <command> <args..>

    helloworld        -  This is my helloworld script!.
    my_command        -  Short description of the custom command.

[2] pyrebox> custom helloworld They are arg for this command.
[scripts.script_helloworld] first_arg: They
[scripts.script_helloworld] Hello World!
```

`list_commnad`の出力に、docstringである`This is my helloworld script!.`が見えると思います。

#4. callbackを作成してみよう
callbackを指定する、というのは、要はなんか起きたとき実行する関数を指定するということです。（投げやり）
pyreboxでコールバックを設定/除去するには、以下のフォーマットに従います。

```
from api import CallbackManager
CallbackManager(Module_hdl).add_callback(CallbackManager.”コールバックの種類”, ”呼び出す関数の名前”, name=”コールバック名”)
CallbackManager(Module_hdl).rm_callback(”コールバック名”)
```

ただし`scripts/script_example_min`等では、cmという変数でCallbackManager(Module_hdl)を参照できるように書かれているので、これをひな形として使うのなら、以下のようにするだけでOKです。また、`name`は任意です。

```
global cm
cm.CallbackManager(Module_hdl).add_callback(CallbackManager.”コールバックの種類”, ”呼び出す関数の名前”)
CallbackManager(Module_hdl).rm_callback(”コールバック名”)
```


pyreboxが提供するコールバックのリストは[pyrebox documentathon(pdf)](https://media.readthedocs.org/pdf/pyrebox/latest/pyrebox.pdf)に譲るとして、ここではキー入力を監視するコールバックマネージャを使って簡単なキーロガーを作ってみようと思います。
まずはひな形をコピーするところから

```bash:
$ cd ~/pyrebox/scripts/
$ cp script_example_min.py keylogger.py
```
keylogger.pyの最後のほうに以下のような部分があるので削除してください。

```python:keylogger.py
def do_my_command(line):
    ''' Short description of the custom command.

        Long description of the custom command
    '''
    global pyrebox_print
    global cm

    # Implementation of the command functionality
    pyrebox_print("This is a custom command")

```
次に以下のコードを末尾に追加してください。

```python:keylogger.py（変更後）
def dump_key(keycode):
    '''callback function for key logger.

    '''

    pyrebox_print("Keystroke occured. keycode: 0x%x\n" % keycode)


def do_start_keylogger(line):
    '''set keylogger that print keycode

    '''

    global cm
    cm.add_callback(CallbackManager.KEYSTROKE_CB, dump_key, name="keystroke")

def do_stop_keylogger(line):
    '''stop keykdump 

    '''
    
    global cm
    cm.rm_callback("keystroke")

```
では実際に起動してみましょう

```
(qemu) import_modules scripts.keylogger
[*]  Loading python module scripts.keylogger
[scripts.keylogger] [*]    Initializing callbacks
[scripts.keylogger] [*]    Initialized callbacks
(qemu) list_modules 
+-----+----------------------------+--------+
| Hdl |        Module name         | Loaded |
+-----+----------------------------+--------+
|  1  | scripts.script_example_min |  Yes   |
|  2  |     scripts.keylogger      |  Yes   |
+-----+----------------------------+--------+
(qemu) sh

[1] pyrebox> custom start_keylogger

[2] pyrebox> q
```
これだけ打ってからVNCクライアントでキーをガチャガチャ押せば、出力が見られるはずです。keyloggerを止めるには、

```
(qemu) sh
[3] pyrebox> custom stop_keylogger

[4]q
(qemu)
```
とすれば大丈夫です。

#5. 終わりに　さらに進むのに読むといい資料
ここまでで、pyrebox独特の話題はほとんど出せたと思います。あとは、普通のpython moduleの使い方を調べるようにして調べていけるはずです。具体的にどこを見るかですが、被ってるのもありますが、ここにまとめておきます。

* 何度も紹介した[pyrebox documentation(PDF)](https://media.readthedocs.org/pdf/pyrebox/latest/pyrebox.pdf): これにつきます。
* `pyrebox/scripts/`下の.pyファイル: 書かれているコメントがチュートリアルになっています。`script_example.py`から読むのがおすすめ。
* `pyrebox/pyrebox_test`下のファイル: これも使用例として使えます。


お疲れさまでした。m(_ _)m

#補足１　お試し環境導入法
ここでは、試してみたい人向けにお試し環境を導入する方法をササッと書きます。コマンドの意味は言わないので知りたい人は[超入門１](https://qiita.com/najayama/items/8d9a97d70216999e4792)、[超入門２](https://qiita.com/najayama/items/9817878be28f06796f9d)を見てください。（結構読むの大変だと思います。）また、現在のところインストーラによるインストールは提供されていないのですが、ひょっとしたら将来されるかもなんで、一度[公式リポジトリ](https://github.com/Cisco-Talos/pyrebox)を見てみるといいかもです。

Debian系（apt-getが使える）OS向けです。また、仮想マシンを扱うので、メモリが１GBないと苦しいかもしれません２GBあれば安心。
まずはpyreboxをクローン

```bash:
$ cd ~/
$ git clone:https://github.com/Cisco-Talos/pyrebox
```
次に必要なパッケージをインストールしてください。

```bash
# apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip virtualenv python-capstone
```

pyreboxディレクトリに移動してpyrebox用のvirtualenvを作成して必要なモジュールなどをインストール

```bash
$ cd ~/pyrebox/
$ virtualenv pyrebox_venv
$ source pyrebox_venv/bin/activate
$ pip install -r requirements.txt
```

以降pyreboxを使うときは忘れずにvirtualenvをactivateしてください。
`$ source pyrebox_venv/bin/activate`
最後にビルド

```bash
$ ./build.sh
```

これでインストールは完了です。

次に起動したいISOを`~/Download/`下に用意（この記事では[こちらから手に入れた](http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/iso/)arch のISOを使用します。）

ファイルを二つ以下の名前で`~/pyrebox/`下に作って以下の内容を書き込んでください。

```~/pyrebox/pyrebox.conf.Arch
[MODULES]

[VOL]
profile: NA
```

```~/pyrebox/start_archlinux.sh
#!/bin/bash

cp pyrebox.conf.arch pyrebox.conf
./pyrebox-x86_64 -monitor stdio -m 1024 -cdrom ../Downloads/archlinux-2017.10.01-x86_64.iso -boot d
```

あとは仮想マシンを起動

```bash
$ cd ~/pyrebox/
$ ./start_archlinux.sh
[*] Loading python component initialization script
[*] Platform: x86_64-softmmu
[*] Starting python module initialization
[*] Reading configuration from 'pyrebox.conf'
[*] Searching for KDBG...
[*] Initializing scripts...
[*] Finished python module initialization
QEMU 2.10.0 monitor - type 'help' for more information
(qemu) VNC server running on 127.0.0.1:5900
```

一番最後の行にある通りVNCサーバーが127.0.0.1:5900らへんに立ってるのでVNCクライアントで接続。（ポート番号は出力見て変えてください）

```bash
$ vncvvncviewer -encodings raw 127.0.0.1:5900         
```

これで仮想マシンを起動できるはずです。(ハードディスクなしでライブ起動してる状態ですが、この記事の内容を試す分に問題ないです。)

あと、pyrebox shellの起動方法を書いておきます。..といっても `(qemu)`のプロンプトで`sh`と打つだけです。

```bash
$ ./start_archlinux.sh                                       

[*] Loading python component initialization script
[*] Platform: x86_64-softmmu
[*] Starting python module initialization
[*] Reading configuration from 'pyrebox.conf'
[*] Searching for KDBG...
[*] Initializing scripts...
[*] Finished python module initialization
QEMU 2.10.0 monitor - type 'help' for more information
(qemu) VNC server running on 127.0.0.1:5901
sh

[1] pyrebox> q

(qemu) q
$ 
```

これで準備は終わりです。本格的にqemuを導入する場合この章と少しかぶりますが[超入門１](https://qiita.com/najayama/items/8d9a97d70216999e4792)、[超入門２](https://qiita.com/najayama/items/9817878be28f06796f9d)を読んだほうがいいとおもいます。（ステマ）