ユーザー・モードのルートキットは高レベルのAPIを横取り
ルートキットの仕組みをさらに詳しく見ていこう。最初に,ユーザー・モードのルートキットを説明したい。図2で示したように,最も高いレベルのAPIレイヤーは,ユーザー・モードのWindows APIレイヤーである。このレイヤーは,「Platform Software Development Kit(SDK)」でマイクロソフトが解説しているベースOS APIで構成されている。ディレクトリのファイルをリスト表示するWindows APIには,FindFirstFileとFindNextFileがあり,いずれも\windows\system32\kernel32.dllというDLLファイルに実装されている。Windowsエクスプローラやコマンド・プロンプトといったアプリケーションは,kernel32.dllから静的または動的に同APIをインポートして利用している。
△ 図をクリックすると拡大されます |
図3●kernel32のFindFirstFile関数をインポートする実行ファイル |
△ 図をクリックすると拡大されます |
図4●メモ帳(Notepad.exe)プログラムがFindFirstFileを静的にインポートしている様子 |
一方,動的インポートは,実行中のプロセスがWindowsのLoadLibrary関数を使用してDLLをロードし,GetProcAddress関数を使用して,DLLが持つエクスポートされた関数のアドレスを取得することでその関数が利用できるようになる。Webサイトで入手できるDependency Walkerというツールを使うと,実行イメージの静的インポートとエクスポートの状況を確認できる。さらにプロファイリング機能によって実行プログラムにおける動的インポートの状況をキャプチャすることも可能だ。図4に,メモ帳(Notepad.exe)プログラムがFindFirstFileを静的にインポートしている様子を示した。
マルウエアを隠すために多くのルートキットで使われている手法の1つに,プロセスのインポート・テーブルをスキャンし,キーとなるシステムDLL関数への参照を,ルートキットの関数へのポインタに置き換えるというものがある。ルートキットの関数はルートキット自身のDLLに実装されていたり,プロセスのアドレス空間に直接書き込まれたりする。
△ 図をクリックすると拡大されます |
図5●FindFirstFileをフックするルートキットの仕組み |
ほとんどのファイル関連,メモリー関連,そしてプロセス関連のWindows APIは,\Windows\system32\ntdll.dllによってエクスポートされる低レベルAPIに依存している。ntdll.dllは,OSのカーネルが公開するユーザー・モードのネイティブAPIに対するインターフェースを提供する。タスク・マネージャはntdll.dllに装備されたNtQuerySystemInformation APIを利用して,アクティブなプロセスを検索している。つまり,プロセスを隠すときルートキットはこの関数の処理を横取りし,その出力からマルウエア・プロセスが取り除かれるように手を加える。
前述したWindowsのファイル・リスト表示APIは,ntdll.dllのNtQueryDirectoryFileを使用するので,NtQueryDirectoryFileから返されるデータを操作することで,FindFirstFileとFindNextFileが返すデータに影響を及ぼせる。しばしばルートキットは,比較的高いレベルの関数の処理を横取りする(低レベルのntdll.dllは必要最小限しか処理を横取りしない)。これは,概して容易に行えるし,多くのシステム・ユーティリティが高レベル関数だけを使用しているためだ。
もう1つ,ユーザー・モードのルートキットのテクニックに,ユーザー・モードのWindows APIとネイティブAPI関数にパッチを当てる(部分修正を加える)というものがある。有名なHacker Defenderというルートキットはこの手法を採用する。部分修正では,標的となるプロセスにルートキット・コードを書き込むとともに,そのプロセスにある改ざん対象の関数の最初の数バイトを変更する。これは,ルートキットのコードに制御を移行させるために行われる。そして,ルートキットのコードは制御を得ると,未変更バージョンの関数を呼び出し,呼び出し元に返される前の関数を操作する。
筆者紹介 |