DynamoRIOで始めるDBI
Posted on
DynamoRIOとは
DynamoRIOは、Dynamic Binary Instrumentation (DBI)ツールの1つです。DBIとは実行中のプログラムに対して任意の部分でのコード変換/挿入を行い、バイナリの挙動を分析する為の手法です。 DynamoRIO APIは、バイナリの動的分析をサポートするインターフェースを提供しています。
今回は、WinAFLにてFuzzingを行う際のCoverageを確認するためにDynamoRIOをソースからビルドしていきます。
DynamoRIOビルド手順
DynamoRIOのレポジトリ上にあるHow To Buildに記載された以下のソフトウェアをインストールします。
- Visual Studio 2017. Other versions are not officially supported as our automated tests use VS 2017.
- CMake. 3.7+ is required. When prompted, we recommend adding it to your PATH.
- Git. Any flavor should do, includingGit on Windowsor Cygwin git.
- Perl. We recommend eitherStrawberry Perlor Cygwin perl.
- (optional) Cygwin. Only needed for building documentation. Select the doxygen package if you do install it. (You can also select Cygwin’s perl and git as alternatives to the links above.)
上記のソフトウェアがインストール出来たら、32-bit DynamoRIOをビルドしていきます。
32-bit DynamoRIO
スタートメニュー > すべてのアプリケーション > Visual Studio 2017 > x86 Native Tools Command Promptを開きます。
x86 Native Tools Command Prompt上で以下のコマンドを実行します。
$ git clone https://github.com/DynamoRIO/dynamorio.git
$ cd dynamorio && mkdir build32 && cd build32
$ cmake -G"Visual Studio 15" ..
$ cmake --build . --config RelWithDebInfo
$ bin32\drrun.exe notepad.exe
最後のコマンド実行によりnotepad.exeが起動すればDynamoRIOが問題なくビルドできていることが分かります。
続いて64-bit DynamoRIOをビルドします。
64-bit DynamoRIO
スタートメニュー > すべてのアプリケーション > Visual Studio 2017 > x64 Native Tools Command Promptを開きます。
x64 Native Tools Command Prompt上で以下のコマンドを実行します。
$ cd C:\dynamorio && mkdir build64 && cd build64
$ cmake -G"Visual Studio 15 Win64" ..
$ cmake --build . --config RelWithDebInfo
$ bin64\drrun.exe notepad.exe
32-bitビルドと同様、最後のコマンド実行によりnotepad.exeが起動すればDynamoRIOが問題なくビルドできていることが分かります。
お試し
DynamoRIOにはAPIを利用するサンプルプログラムが複数用意されています。
ここでは、その一つであるcountcalls.dllを使ってみたいと思います。
countcalls.dllは、対象プログラム内のnear callのdirect callおよびindirect call、そしてreturnの3種類のopcode数をカウントすることができます。
以下のコマンドでnotepad.exeに対してcountcalls.dllを実行します。
$ cd dynamorio\build
$ bin32\drrun.exe -c api\bin\countcalls.dll -- notepad
上記コマンドを実行すると以下のようなポップアップで結果が得られます。
countcalls.dllのソースコードであるcountcalls.cを見てみると、以下の様にif
およびelse if
の分岐にて対象プログラム内のnear callのdirect callおよびindirect call、そしてreturnの3種類のopcode数をカウントしていることが分かります。
/* instrument calls and returns -- ignore far calls/rets */
if (instr_is_call_direct(instr)) {
insert_counter_update(drcontext, bb, instr,
offsetof(per_thread_t, num_direct_calls));
} else if (instr_is_call_indirect(instr)) {
insert_counter_update(drcontext, bb, instr,
offsetof(per_thread_t, num_indirect_calls));
} else if (instr_is_return(instr)) {
insert_counter_update(drcontext, bb, instr, offsetof(per_thread_t, num_returns));
}
さらにinstr_is_call_direct()
をDynamoRIOのAPI documentで調べてみると引数instr
のopcodeがOP_call
またはOP_call_far
の場合にtrue
を返すことが分かります。
このようにサンプルコードで使われているAPIを確認していくことでDynamoRIO APIで出来ることがつかめると思います。