1. はじめに

 最近、業務でマルウェアを解析する機会が増えてきたのですが、最近のマルウェアはどれも様々な解析対策が施されており、数年前と比べて解析がやや面倒になっています。攻撃者はマルウェアの発見を困難にさせたり、セキュリティベンダーらによる解析を遅らせたりするため、エンコーディングやゴミコード挿入などによる難読化、コンポーネントや実態の多段化、デバッガ検出など、様々な解析対策を実装しています。

 今回は、このデバッガ検出を無効にする方法を紹介します。

2. マルウェア解析とAnti-Debugging

 マルウェアを解析する際は、デバッガを使って地道にアセンブリコードを追っていく事になります。デバッガでブレークやステップを繰り返し、フロー、API呼び出し、引数、データの流れなどを確認して行くのですが、その際、何度か先頭から再実行しなければならないという状況に遭遇します。たとえば、「この条件分岐で今度はこちらに飛ばしてみよう」といった場合や、ブレークする位置を間違えて遥か先まで実行させてしまった場合です。その際は、既に解析済みの所はスキップするため、適切な箇所でブレークポイントを設置して再度先頭から実行したりします。

 しかし、マルウェアにデバッガ検出が実装されていると、解析者にとっては一手間発生します。デバッガ検出とは、自身がデバッガで解析されている場合、それを検知して本来とは異なる動作をさせるというものです。例えば、以下のような例が挙げられます。

if (IsDebuggerPresent()==TRUE){
	// デバッガ検知
	偽の処理
}else{
	// デバッガは検知されない
	本来の処理
}

 このような処理は、Anti-Debuggingと呼ばれ、多くのマルウェアが実装しています。Anti-Debuggingのためのデバッガ検知は以下に示すように色々な方法があります。

(1)IsDebuggerPresent()
(2)PEB(Environment Block)のBeingDebuggedフラグを参照
(3)PEBのNtGlobalFlagsフラグを参照
(4)CloseHandle()による例外検出
(5)OutputDebugStringA()の戻り値チェック
(6)デバッガのウィンドウクラス名取得
(7)INT3サーチ
(8)ハードウェアブレークポイント検出
(9)NtQueryInformationProcess()
(10)実行時間計測

・・・などなど

 Nicolas Falliere氏のテクニカルペーパー"Windows Anti-Debug Reference"に上記を含むさまざまな手法が紹介されていますので、興味のある方は参照してみてください。

"Windows Anti-Debug Reference"
http://www.securityfocus.com/infocus/1893

 マルウェアが最も多く利用している手法は(1)、もしくは(2)の手法です。IsDebuggerPresent()は内部的に(2)と同じ動作をしているため、本質的には(2)の手法が最も利用されている事になります(IsDebuggerPresent() APIを利用せず、PEBのBeingDebuggedフラグを直接見に行くケースは最近かなり多くなっているようです)。このAnti-Debuggingを実装したマルウェアを解析する際は、マルウェアをデバッガで起動した直後にPEBのBegingDebuggedフラグをリセットする、あるいは、BegingDebuggedのチェックを行っている箇所で一旦ブレークして処理をスキップさせる必要があります。Anti-Debugging処理を発見できればどちらも技術的に難しくはありませんが、毎回の事になると少々面倒です。