GREM FOR610 5日目 Examining Self-Defending Malwareのメモ。
FS:[30h]はPEBを指しており、そのオフセット2にはBeingDebuggedフラグの値が格納されている
FSセグメント FS:[30h]
はPEB (Process Environment Block)を指しており、そのオフセット2に格納されているBeingDebuggedフラグの値を確認することで、マルウェアは自身がデバッグされているか確認できる。デバッグされている場合、BeingDebuggedの値は1となり、デバッグされていない場合は値は0となる。以下はPEBのBeingDebuggedフラグを確認するアセンブリ・コードの例。
MOV EAX, FS:[30h]
MOV EAX, [EAX+2]
TEST EAX, EAX
デバッガを検知するAPI関数
- IsDebuggerPresent
- CheckRemoteDebuggerPresent
- NtQueryInformationProcess / ZwQueryInformationProcess
- 第2引数に7という値を渡すとプロセスのデバッガのポート番号を取得する
- 戻り値が0以外だった場合、プロセスがデバッグされていることを意味する
- OutputDebugString
- この関数はデバッガに出力するためのメッセージを送る
- プロセスがデバッグされていた場合、OutputDebugStringは正常に終了する
- プロセスがデバッグされていなかった場合、OutputDebugStringはエラーコードをセットする
- OutputDebugStringを呼び出した後にGetLastErrorでエラーコードの値を確認することでプロセスがデバッグされているか判断できる
- Practical Malware AnalysisのLab 16-2はOutputDebugStringによるアンチ・デバッグを取り扱っている。
プログラムが実行されてからの経過時間を確認してデバッガの有無を判断する
プログラムが実行されて、ある処理から別の処理に移るまで一定時間以上かかった場合、自身がデバッガによってステップインあるいはステップオーバー実行されていると判断して処理を終了する。
- プログラムの起動時にGetTickCount、GetLocalTime、GetSystemTime、NtQuerySystemTimeなどでシステムの現在時刻を取得する
- 再度、同様の関数を呼び出してシステムの現在時刻を取得する
- 最初に取得した時刻と後から取得した時刻の差分をとって、一定時間以上経過していた場合はデバッグされていると判断して処理を終了する
- 例に挙げたAPI関数のほかにRDTSC (Read Time-Stamp Counter) というアセンブリ命令も利用できる
ScyllaHideを使って手っ取り早くアンチ・デバッグを回避する
アンチ・デバッグのコードを見つけて、それを回避するためのパッチングを行う労力をかけたくない場合はScyllaHideというプラグインを使えば手っ取り早くアンチ・デバッグを回避できる。
以下はx32dbg (x64dbg)の場合
- Plugins > ScyllaHide > Options
- 有効化したいアンチ・デバッグ対策のチェックボックスをチェックする (ただし有効化するチェックを増やすほどプログラムが予期しない動作をする可能性が高まる)
- GREMのコースでは最初の1列のチェックボックスはすべて有効化することを推奨していた
- OKをクリックして完了 (デバッガや解析対象のプロセスを再起動する必要はない)
サンドボックス等の解析環境を検知する
以下のようなチェックを行って、マルウェアは自身がサンドボックスなどの解析環境で実行されていないか確認する。
- クリップボードは空か
- 実際のシステムならクリップボードに何らかのデータが存在するはず
- CountClipboardFormats
- CPUのコア数
- サンドボックスはシングルコアの場合が多い
- 実際のシステムはマルチコアのはず
- マウス・カーソルは動いているか
- 実際のシステムならマウス・カーソルは頻繁に動いているはず
- GetCursorPos
- ディスクのサイズが極端に小さくないか
- サンドボックスなどの解析マシンはあまり大きなディスクサイズを割り当てないはず
- フォアグラウンド・ウィンドウは変化しているか
- 実際のシステムならアクティブ・ウィンドウが頻繁に切り替わるはず
- GetForegroundWindow
- システムの稼働時間が極端に短くないか
- 実際のシステムなら一定時間以上稼働しているはず
- GetTickCount
DS:[7FFE02D4]の値を確認してカーネルモード・デバッガを検知する
DS:[7FFE02D4]
にはKdDebuggerEnabledフラグの値が格納されている- カーネルモード・デバッガが存在する場合、このフラグの値は3となり、そうでない場合は0となる
DS:[7FFE02D4]
に格納されている値を確認することでカーネルモード・デバッガの存在を検知できる
以下はアセンブリコードの例。
CMP BYTE PTR DS:[7FFE02D4], 3
SEHを悪用して悪意のあるコードを実行する
Structure Exception Handling (例外処理、以降SEH)とはプログラムがエラーに遭遇した際、エラーをどう処理するか規定すること。32ビット・プログラムではSEHに関するデータはスタックに格納される。SEHは以下の2つの要素から成る構造体である。
- 以前に規定したSEH構造体へのポインタ
- 例外処理コードへのポインタ
SEH構造体は以前に規定したSEH構造体へのポインタを保持しているので、複数のSEH構造体を連結してリンクトリストとすることが出来る。FS:[0]
には最も新しく追加されたSEH構造体へのポインタが格納されている。
+----------------------------------------------+
| Pointer to first structure (Stored in FS:[0])|___
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |___
|----------------------------------------------| |
| Pointer to Handler | |
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |___
|----------------------------------------------| |
| Pointer to Handler | |
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |
|----------------------------------------------|
| Pointer to Handler |
+----------------------------------------------+
SEHのリンクトリストに悪意のあるSEH構造体を追加した後に、わざとプログラムがクラッシュするような命令 (書き込み不可能なメモリ領域への書き込み等)を実行して例外処理を発生させることで、悪意のあるSEH構造体が保持している悪意のあるコードへのポインタに処理を飛ばすことが出来る。
+----------------------------------------------+
| Pointer to first structure (Stored in FS:[0])|___
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |___
|----------------------------------------------| | Intentionally cause exception handler and
| Pointer to malicious code! | | branch to malicious code
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |___
|----------------------------------------------| |
| Pointer to Handler | |
+----------------------------------------------+ |
|
+----------------------------------------------+___|
| Pointer to previous defined structure |
|----------------------------------------------|
| Pointer to Handler |
+----------------------------------------------+
マルウェアにFS:[0]
を参照しているアセンブリコードがあった場合、SEH構造体への干渉を試みている可能性が高い。以下はSEHのリンクトリストに悪意のあるSEH構造体を追加するアセンブリコードの例。
MOV EAX, [0xDEADBEEF] ;SEH handler 0xDEADBEEF contains malicious code
PUSH EAX ;push the malicious SEH handler to the stack
PUSH DWORD PTR FS:[0] ;push the address of the current start of the SEH chain to the stack
MOV DWORD PTR FS:[0], ESP ;Set FS:[0] to point to the new SEH structure
XOR EAX, EAX
MOV DWORD PTR DS:[EAX], ECX ;cause an exception by trying to write to inaccessible memory (DS:[0] is write protected hence this instruction will cause an exception)
※ Practical Malware AnalysisのLab 15-3はこのSEH構造体の書き換えをテーマにしている。
解析のTIP
例外処理発生時に実行される不正コードの位置を特定してブレークポイントをセットすれば、不正コードのデバッグができる。上記のコード例だと0xDEADBEEFが悪意のあるコードへのポインタになっているので、このアドレスにブレークポイントをセットする