連載
» 2011年11月18日 00時00分 UPDATE

リバースエンジニアリング入門(4):Undocumentedなデータ構造体を知る (1/3)

コンピュータウイルスの解析などに欠かせないリバースエンジニアリング技術ですが、何だか難しそうだな、という印象を抱いている人も多いのではないでしょうか。この連載では、「シェルコード」を例に、実践形式でその基礎を紹介していきます。(編集部)

[川古谷裕平,日本電信電話株式会社]

オリジナルコードを頭からガブリ!

 第3回ではシェルコードの中身の解析に入りました。シェルコードのデコーダ部分のコードを実際に解析し、IDCによりオリジナルのアセンブリコードを復元してみました。

 続く今回は、デコーダによる処理が終わった後のオリジナルコードの先頭から解析を行っていきたいと思います。

実行プロセスからAPIが呼ばれるまで

 さて、アセンブリコードの解析に入る前に、まずAPI(Application Programming Interface)の話をします。

 第1回で“シェルコードの役割は「ファイルをダウンロードする」「ダウンロードしたファイルを実行する」の2つである”とご紹介しました。これらファイルのダウンロード、ファイルの実行は、基本的にはWindowsのAPIを呼び出すことで行います。今回はこのAPIの呼び出しメカニズムに焦点を当てて説明し、その仕組みを理解したところでシェルコードの解析に入っていきます。

 Windowsの場合、基本的にAPIは、実行ファイルとは別にDLL(Dynamic Link Library)として実装されています(注1)。Windowsのローダはファイルが実行されるとその実行ファイル中で使われているAPIを調べ上げ、そのAPIを実装しているDLLをメモリにロードし、アドレス解決を行い、実行ファイルからDLL内に実装されているAPIを呼び出せるようにします。

 ではIDAImmunity Debuggerを利用して、実行ファイルからkernel32.dll内に実装されているCreateFileA APIを呼び出すところを具体的に見てみましょう。

 図1は、CreateFileAを呼び出すだけの単純なプログラムの逆アセンブリです。ソースコードはこちらになります。

図1 CreateFileAの呼び出し(クリックすると拡大します) 図1 CreateFileAの呼び出し(クリックすると拡大します)

 図1の(1)にあるように、.text:00401020でCreateFileAを間接コールしています。この間接コールで参照している. idata:0040A004のメモリの値(図2の(2))を見てみると、まだ値が格納されていないことが分かります(図3の(3))。これは、CreateFileAの実体はDLL(kernel32.dll)内にあり、kernel32.dllは実行時にロードされるまでメモリ上のアドレスが決定していないためです。

図2 CreateFileAのアドレス(アセンブリ)(クリックすると拡大します) 図2 CreateFileAのアドレス(アセンブリ)(クリックすると拡大します)
図3 CreateFileAのアドレス(メモリダンプ)(クリックすると拡大します) 図3 CreateFileAのアドレス(メモリダンプ)(クリックすると拡大します)

 次に、同じ実行ファイルをImmunity Debuggerで読み込んでみます。Immunity Debuggerは、デフォルトの設定では実行ファイルをローダがメモリ上に展開した後に停止させてくれるため、ローダによるアドレス解決が行われた後の様子を見ることができます(注2)。

図4 Immunity Debuggerでロードした後のCreateFileA呼び出し(クリックすると拡大します) 図4 Immunity Debuggerでロードした後のCreateFileA呼び出し(クリックすると拡大します)

 図4の(4)(5)を見てください。IDAで見たときは空だったアドレスに「24 1A 80 7C」の値が設定されています。この値はリトルエンディアンなので、4バイト整数として解釈すると、7C801A24hになります。このアドレスの個所を詳しく見てみると、CreateFileAだということが分かります(図5の(6))。

図5 CreateFileAのアドレスが設定されている様子(クリックすると拡大します) 図5 CreateFileAのアドレスが設定されている様子(クリックすると拡大します)

 ディスク上にファイルとして存在している実行ファイルをIDAで見たときは、まだAPIのアドレス解決は行われていません。一方、Immunity Debuggerで読み込んだ後は実行ファイルがメモリ上に展開され、ローダによりAPIのアドレス解決が行われています。そのため、IDAで見た時は空であった値が、Immunity Debuggerで見るとCreateFileAを指している、つまりアドレス解決が行われていることが見て取れると思います。

 このアドレス解決は、基本的にはプログラムの起動時に、ローダにより一度だけ行われます。そのため、起動済みのプロセスの脆弱性を突いて挿入されるシェルコード内からAPIを呼び出そうとしても、APIのアドレスが分からないといった問題が生じます。

 さて、シェルコードはいかにしてAPIの呼び出しを実現しているのでしょうか?

注1:多くのDLLはC:\Windows\system32に保存されています。
注2:うまくいかない時は、Immunity Debuggerのメニューの[Options]→[Debugging Options]→[Events]タブで、「Make first pause at:」が「Entry point of main module」になっていることを確認してください

       1|2|3 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。