高機能トレーサーqiraを使ってみる
qira(QEMU Interactive Runtime Analyser)は、George Hotz(geohot)氏が開発している高機能トレーサーである。 qiraは実行時のレジスタ、メモリ操作をすべて記録することにより、特定の命令アドレスを実行しているタイミングや特定アドレスのメモリ読み書きが行われているタイミングを検索することができる。 また、複数回の実行におけるトレース結果を互いに比較することができる。 ここでは、簡単なプログラムコードを用いてqiraを使った解析をやってみる。
環境
Ubuntu 14.04.4 LTS 64bit版
$ uname -a Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.4 LTS Release: 14.04 Codename: trusty $ gcc --version gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
qiraのインストール
GithubリポジトリのREADMEを参考にインストールする。
$ git clone https://github.com/BinaryAnalysisPlatform/qira.git $ cd qira/ $ ./install.sh
ヘルプを表示してみると次のようになる。
$ ./qira --help usage: qira.py [-h] [-s] [-t] [--gate-trace ADDRESS] [--flush-cache] [--pin] [--host HOST] [--web-port PORT] [--socat-port PORT] [-S] [--engine ENGINE] binary [args [args ...]] Analyze binary. Like "qira /bin/ls /" positional arguments: binary path to the binary args arguments to the binary optional arguments: -h, --help show this help message and exit -s, --server bind on port 4000. like socat -t, --tracelibraries trace into all libraries --gate-trace ADDRESS don't start tracing until this address is hit --flush-cache flush all QIRA caches --pin use pin as the backend, requires ./pin_build.sh --host HOST listen address for web interface and socat. 0.0.0.0 by default --web-port PORT listen port for web interface. 3002 by default --socat-port PORT listen port for socat. 4000 by default -S, --static enable static2 --engine ENGINE static engine to use with static2 (builtin or r2)
qiraを使って解析してみる
ここでは、「angrでシンボリック実行をやってみる」でも用いた、次のような簡単な認証を行うプログラムを用いて解析してみる。
/* test.c */ #include <stdio.h> #include <string.h> void succeeded() { puts("auth succeeded!"); } void failed() { puts("auth failed."); } int main(int argc, char *argv[]) { char username[256]; char password[256]; printf("Enter username: "); scanf("%s", username); printf("Enter password: "); scanf("%s", password); if (strcmp(username, "admin") == 0 && strcmp(password, "letmein") == 0) { succeeded(); } else { failed(); } return 0; }
上のコードをコンパイルし、qiraのもとで実行してみる。
$ gcc test.c -o test $ ./qira -s ./test *** program is /home/user/tmp/qira/test with hash e4f0fd7d15338ed95f7fe2914cd19152c0df1251 **** using /home/user/tmp/qira/tracers/qemu/qemu-2.1.3/x86_64-linux-user/qemu-x86_64 for 0x3e no qira server found, starting it *** deleting old runs **** listening on <socket fileno=6 sock=0.0.0.0:4000> ****** starting WEB SERVER on 0.0.0.0:3002
このとき、TCP 4000番ポートでプログラムの標準入出力、TCP 3002番ポートでWeb UIの待ち受けが行われる。
TCP 4000番ポートに接続し、適当な入力を行ってみる。
$ nc -v localhost 4000 nc: connect to localhost port 4000 (tcp) failed: Connection refused Connection to localhost 4000 port [tcp/*] succeeded! AAAA BBBB Enter username: Enter password: auth failed.
ここで、Google ChromeからWeb UIを開くと、次のようなトレース結果が表示される。
画面と操作方法について、簡単にまとめると次のようになる。
- 左上からタイムライン、メモリマップ、control、命令ダンプ、レジスタ、変更リスト、strace、メモリダンプが表示されている
- controlの各テキストボックスには、現在参照しているchangelist number(青)、fork number(グレー)、iaddr(赤、命令アドレス)、daddr(黄、データアドレス)が表示される
- 命令ダンプは現在のchangelist number周辺が表示される
- メモリダンプは現在のdaddr周辺が表示される
- タイムラインにおいて
- 緑の明るさは関数の深さ
- 青のバーはchangelist numberのポイント
- 赤のバーはiaddrを通過しているポイント
- 明るい黄色のバーはdaddrに書き込んでいるポイント
- 暗い黄色のバーはdaddrが読み込まれているポイントを表す
- 変更リストはそのchangelist numberでのメモリの操作内容を表す
- 赤色のアドレスについて、クリックで現在のiaddr、右クリックで現在のdaddrをそのアドレスに変更
- 黄色のアドレスについて、クリックで現在のdaddrをそのアドレスに変更
- 上下キーで青のバー、j/kで赤のバー、Shift+j/kで黄色のバーを前後に移動、Escで戻る
- m/,で関数の末尾、先頭に移動
- gでchangelist number(数字)やiaddr(アドレスあるいは名前)への移動
- nでiaddrのリネーム、:でコメント
- タイムラインについて、ドラッグ選択でズームイン、zでズームアウト
g main
と入力しmain関数が実行されたポイントに移動した後、適当に操作することにより、strcmp関数でAAAA
とadmin
が比較されていることが確認できる(上記スクリーンショット)。
そこで、あらためてTCP 4000番ポートに接続し、次のような入力を行ってみる。
$ nc -v localhost 4000 nc: connect to localhost port 4000 (tcp) failed: Connection refused Connection to localhost 4000 port [tcp/*] succeeded! admin BBBB Enter username: Enter password: auth failed.
少し待つと、次のスクリーンショットに示すように、Web UIの左側にあるタイムラインが2列に更新される。
タイムラインの各列はそれぞれの接続ごとの実行結果を表しており、左右キーで互いに切り替えることができる。
2列目のタイムラインに切り替え、適当に操作することにより、2回目のstrcmp関数でBBBB
とletmein
が比較されていることが確認できる(上記スクリーンショット)。
再度TCP 4000番ポートに接続し、次のような入力を行うと、認証を通過することが確認できる。
$ nc -v localhost 4000 nc: connect to localhost port 4000 (tcp) failed: Connection refused Connection to localhost 4000 port [tcp/*] succeeded! admin letmein Enter username: Enter password: auth succeeded!
なお、次のように起動時に-S
オプションをつけることで静的解析によるグラフ表示を行うことも可能である。
$ ./qira -Ss ./test *** using static
上のスクリーンショットにおいて、右上はグラフビュー、右下はテキストビューとなっており、Spaceを押すことで操作に追従するビューを切り替えることができる。
関連リンク
- Timeless Debugging (USENIX Enigma 2016)
- qira - ezhpQIRAwriteup.wiki
- qira - justifyQIRAwriteup.wiki
- pwnable.kr geohot - YouTube
- pwnable.kr geohot2 - YouTube
- pwnable.kr geohot3 - YouTube
- geohot @ overthewire vortex part 1 #livectf - YouTube
- geohot @ overthewire vortex part2 - YouTube
- geohot @ overthewire.org vortex part 3 - YouTube
- GDBで歴史をさかのぼれるように!なりました! GDB 7.0 の新機能Reverse Debuggingを使ってみた - 日記を書く [・w・] はやみずさん
- rr: lightweight recording & deterministic debugging