2018
11
30

いろいろなプロセス・インジェクションの手法

プロセス・インジェクションの手法についてまとめてみました。
といっても、こちらの記事の内容をざっくり翻訳しただけですが。

1. CreateRemoteThread関数およびLoadLibrary関数を用いたDLLインジェクション

多分、最も一般的(?)な方法。正規のプロセスに不正なDLLを読み込ませて悪いことをします。
大まかな仕組み:
ターゲット・プロセス上にLoadLibrary関数経由で不正なDLLを読み込ませるスレッドを作成することで実現します。

手順としては:
1. APIを用いてターゲットとなるプロセスを探し出し、OpenProcess関数を用いてターゲット・プロセスのハンドルを取得します。
2. VirtualAllocEx関数でターゲット・プロセス上のメモリ領域を確保します。
3. 2.で確保したメモリ領域にWriteProcessMemory関数で不正なDLLへのパス名をターゲット・プロセス上に書き込みます。
4. GetProcAddress関数でLoadLibrary関数のアドレスを取得します。
5. ターゲット・プロセスのハンドル、LoadLibrary関数のアドレス、ターゲット・プロセス上に書き込まれた不正なDLLへのパス名へのポインタを引数に渡して、CreateRemoteThread関数を呼び出します。これにより、ターゲット・プロセスが不正なDLLをロードします。(もう少し厳密に言うとターゲット・プロセス上に不正なDLLをLoadLibrary関数経由でロードするスレッドが作成されます。)

CreateRemoteThread関数の詳細はこちら
※ CreateRemoteThread関数のかわりにNtCreateThreadEx関数やRtlCreateUserThread関数が使われる場合もあります。

DLLがロードされるとOSはDLL中のDllMain関数を自動的に実行します。そのため攻撃者は新しく関数を定義しなくてもDllMain関数に不正なコードを埋め込むことで目的を達成できます。

解析のチートシート
・ターゲット・プロセス名を特定したい場合は、strncmpやmemcmpなどの値の比較を行う関数を確認してみること。これらの関数にターゲット・プロセス名が値として渡されている事が多い。
・不正なDLLの名前を特定したい場合は、WriteProcessMemory関数の呼び出し部分にブレークポイントをセットし、スタックの内容をダンプすること。


2. Portable Executable (PE) インジェクション

LoadLibrary関数を実行し不正なDLLを読み込ませるのではなく、ターゲット・プロセスに不正なコードをコピーしてシェルコードやCreateRemoteThread関数を介して実行する手法です。1.の手法との大きな違いは不正なDLLをディスク上に作成する必要がないという点です。
手順としては:

1. VirtualAllocEx関数でターゲット・プロセス上のメモリ領域を確保します。
2. 1.で確保したメモリ領域にWriteProcessMemory関数で不正なコードをコピーします。
3. CreateRemoteThread関数 (あるいはNtCreateThreadEx関数やRtlCreateUserThread関数)を用いてターゲット・プロセス上で不正なコードを実行します。

この手法の留意点として、他のプロセスにPEをコピーするとベース・アドレスが新しいものに変わります。そのため攻撃者は不正コードを実行する前にターゲット・プロセス上のrelocation tableのアドレスを探し出し、relocation tableをもとにコピーされた不正コードの絶対アドレスを取得する必要があります。


3. Process Hollowing (プロセス・ホロウイング)

正規のプロセスのメモリ領域をアンマップして空いたメモリ領域に不正なコードを書き込む手法です。正規のプロセスをまるごと不正なプロセスに上書きするイメージです。
手順としては:

1. まず正規のプロセスをサスペンド・モードで立ち上げます。CreateProcess関数をCREATE_SUSPENDEDフラグ付きで呼び出す(dwCreationFlagsを0x4に設定)ことで実現します。サスペンド・モードで立ち上げられたプロセスはResumeThread関数が呼び出されるまで実行されません。
2. 1.で立ち上げた正規プロセスのメモリ領域をZwUnmapViewOfSection関数やNtUnmapViewOfSection関数を用いてアンマップ(空っぽ)にします。
3. 2.で空いたメモリ領域上にVirtualAllocEx関数を用いて不正コードを書き込むためのメモリ領域を確保し、WriteProcessMemoryで不正コードを書き込みます。
4. ResumeThread関数でプロセスをサスペンド・モードから実行状態に移します。

書き換えられたプロセスは書き換え前と同じ権限レベルで実行されます。


4. スレッド実行ハイジャック (またはSUSPEND, INJECT AND RESUME (SIR))

先述したProcess Hollowingと似た挙動をします。スレッド実行ハイジャックでは、マルウェアは既存のプロセスのスレッドを標的にします。
手順としては:

1. CreateToolhelp32Snapshot関数とThread32First関数を呼び出したあとにOpenThread関数を呼び出し、標的スレッドのハンドルを取得します。
2. SuspendThread関数を呼び出して標的スレッドをサスペンド・モードにします。
3. VirtualAllocEx関数でメモリ領域を確保し、WriteProcessMemory関数で不正なコードを書き込みます。
4. 3.で書き込まれる不正コードはシェルコード、不正なDLLへのパス情報、LoadLibrary関数のアドレス情報などです。
5. 標的スレッドをサスペンド・モードから実行状態に移します。


5. SetWindowsHookEx関数を用いたフック・インジェクション

フックとは関数が呼び出された際に割り込みをかける手法です。マルウェアはフックを利用して、特定のスレッドで特定のイベントが起きたときに不正なDLLをロードさせることができます。
この手法では主にSetWindowsHookEx関数が用いられます。SetWindowsHookEx関数は4つの引数を受け取ります。

1つ目の引数:イベント・タイプ。キーボードの押下(WH_KEYBOARD)、マウスの動作(WH_MOUSE)など様々なタイプのイベントがあります。
2つ目の引数:特定のイベントが発生した際に実行させたい関数へのポインタ。
3つ目の引数:関数を含んでいる不正なモジュールまたはDLLへのハンドル。
※対象のモジュールやDLLへのハンドル、関数のアドレスを特定するため、SetWindowsHookEx関数を呼び出す前にLoadLibrary関数(モジュールやDLLのハンドルを取得する)およびGetProcAddress関数(関数のアドレスを取得する)への呼び出しが行われることが多々あります。
4つ目の引数:フックしたいスレッド。もし、この値が0に設定されていた場合は目的のイベントが発生した際にすべてのスレッドでアクションが起きます。ただし通常マルウェアは1つのスレッドを標的とします。そのため標的スレッドを特定するため、SetWindowsHookEx関数を呼び出す前にCreateToolhelp32Snapshot関数とThread32Next関数を呼び出すことが多いです。

6. レジストリを介したインジェクションおよび常駐化 (APPINIT_DLLS, APPCERTDLLS, IFEOなど)

Appinit_DLL、 AppCertDlls、IFEO (Image File Execution Options)はマルウェアがインジェクションや常駐化を図るためによく利用するレジストリ・キーです。
以下に配置されています:

HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls
HKLM\Software\Microsoft\Windows NT\currentversion\image file execution options

Appinit_DLL
マルウェアは不正なライブラリをAppinit_DLLレジストリ配下に配置することにより、他のプロセスに不正ライブラリをロードさせることができます。User32.dllをロードするプロセスはAppinit_DLLレジストリ配下にあるライブラリも読み込みます。User32.dllはダイアログボックスなどのグラフィカルな処理をする際に頻繁に使用されるライブラリです。そのためマルウェアによってAppinit_DLL レジストリが編集された場合、大半のプロセスが不正なライブラリをロードすることになります。

AppCertDlls
AppInit_DLLsを悪用した手法と類似した手法です。AppCertDllsレジストリ配下のDLLはプロセスが以下の関数を呼び出した際にロードされます:
CreateProcess
CreateProcessAsUser
CreateProcessWithLogonW
CreateProcessWithTokenW
WinExec

Image File Execution Options (IFEO)
IFEOは主にデバッグ目的で使用されます。開発者はIFEOレジストリ・キーの“Debugger”の値を編集して実行ファイルに別のプログラムをアタッチすることによってデバッグを行うことができます。デバッグ対象の実行ファイルが起動すると、その実行ファイルにアタッチされたプログラム(通常であればデバッガ)が実行されます。
やり方はシンプルで標的となる実行ファイルにデバッガのパスを渡すだけです。ただしWindowsは渡されたプログラムが本当にデバッガなのかという確認まではしません。ただ単純に“Debugger Value”に設定されているプログラムを渡すだけです。なので例えば HKLM\Software\Microsoft\Windows NT\currentversion\image file execution options\calc.exeの“Debugger”の値をnotepad.exeに設定すると電卓プログラムを起動しようとするたびにメモ帳が起動されることになります。
マルウェアはIFEOレジストリ・キーの“Debugger”の値を編集することにより、任意のプログラムの起動時に不正なプログラムを実行させることができます。

こちらの記事でIFEOレジストリを編集して、Windowsのログオン画面のスクリーンショットを取る方法が紹介されています。


7. APCインジェクションおよびATOMBOMBING

Asynchronous Procedure Calls (APC)を利用する手法です。マルウェアは任意のスレッドのAPCキューにコードをアタッチすることによって、そのスレッドにコードを実行させることができます。
各スレッドには実行待ちのAPCキューが存在します。スレッドが変更可能状態になるとキューされたAPCを実行できます。マルウェアは変更可能状態にあるスレッドを見つけるとOpenThread関数およびQueueUserAPC関数を呼び出してAPCをスレッドにキューさせます。
QueueUserAPC関数は以下の3つの引数を受け取ります:

1つ目の引数: 標的となるスレッドのハンドル
2つ目の引数:マルウェアが実行させたい関数へのポインタ
3つ目の引数:関数のポインタに渡すパラメータ

具体例として、Amanaheマルウェアは最初にOpenThread関数を呼び出して標的スレッドのハンドルを取得し、次にQueueUserAPC関数の引数にLoadLibraryA関数へのポインタを渡して呼び出し、不正なDLLをスレッドに注入します。

AtomBombingはatomテーブルを用いて不正なコードを他のプロセスに注入する手法です。atomテーブルとはOSによって提供されている機能で、アプリケーションはこのテーブルにデータを格納したり、テーブル内のデータにアクセスすることができます。またatomテーブルを利用してアプリケーション同士でデータを共有することもできます。
AtomBombingとはatomテーブルに不正なコードを書き込んで、正規のプロセスにテーブル内の不正なコードを読み込ませ、さらに実行させる手法です。


8. SETWINDOWLONG関数を用いた拡張ウィンドウ・メモリへのインジェクション

エクスプローラーの拡張ウィンドウ・メモリにインジェクトする手法です。ウィンドウ・クラスを使用する際、アプリケーションは追加のメモリのバイト数を指定することができます。これを拡張ウィンドウ・メモリ (Extra Window Memory (EWM))と呼びます。しかし拡張ウィンドウ・メモリはそれほど大きくはありません。そこでマルウェアはexplorer.exeの共有セクションにコードを書き込み、SetWindowLong関数とSendNotifyMessage関数を使用してシェルコードへのポインタを作成し、シェルコードを実行します。

マルウェアが共有セクションへ書き込むには2通り方法があります。1つは共有セクションを作成しマルウェア自身と他のプロセス(例:explorer.exe)をそこにマッピングする方法で、もう1つはすでに存在している共有セクションに書き込む方法です。前者よりも後者のほうが手順としては簡易なため、後者の方法が用いられることが多いです。
マルウェアは共有セクションに不正なコードを書き込んだ後、GetWindowLong関数とSetWindowLong関数を使用して“Shell_TrayWnd”の拡張ウィンドウ・メモリにアクセス・変更します。GetWindowLong関数は拡張ウィンドウ・メモリ内の指定されたオフセットにあるデータ (32ビット値)を取得するための関数で、SetWindowLong関数は指定されたオフセットの値 (32ビット値)を変更するための関数です。これらの関数を使用してマルウェアはウィンドウ・クラス内の関数ポインタのオフセットを変更し、共有セクションに書き込まれたシェルコードにポイントさせることができます。

これまで紹介した手法では不正コードを実行するためにCreateRemoteThread関数、QueueUserAPC関数、SetThreadContext関数などを利用していましたが、拡張ウィンドウ・メモリ・インジェクションでは不正コードの実行にSendNotifyMessage関数を利用します。SendNotifyMessage関数が実行されるとShell_TrayWndはSetWindowLong関数によって設定されたアドレス (この場合はシェルコードへのアドレス)に制御を渡します。


9. SHIMを用いたインジェクション

ShimとはMicrosoftが提供している互換性に関する問題を解決するための仕組みです。Shimを利用することによって開発者はコードを書き直すことなくプログラムを修正することができます。Shimは基本的に対象となるプログラムのAPIコールをフックすることによって様々な制御を行います。
※Shimについては、こちらの記事でも取り上げています。

マルウェアはShimを悪用することによりプログラムへのインジェクションやマルウェア自身の常駐化を達成することができます。もっとも代表的なShimの悪用方法はsdbinst.exeを実行して不正なsdbファイルを読み込ませる方法です。
例として、あるアドウェアは“InjectDLL” shim(プロセスに特定のDLLを読み込ませるためのShim)を利用してGoogle Chromeブラウザ・アプリケーションに不正なDLLを読み込ませます。


10. IATフックおよびインライン・フック

IATフックはマルウェアがIAT (Import Address Table)を書き換える手法のことです。IATフックによってIATの内容が書き換えられると、正規のプログラムがDLL内のAPIを呼び出した際に、正規の関数ではなく、書き換えられた関数が実行されます。
インライン・フックでは、マルウェアはAPI関数そのものを編集します。

プロセス・インジェクションの主な目的は正規のプロセスに不正なコードを注入することによって、検知を回避する、あるいは困難にすることです。
大抵の場合、攻撃者はインジェクションを行うためのファイルやスクリプト(インジェクター)を用意する必要があります。さらにインジェクションを継続的に行いたい場合はインジェクターを常駐化する必要がありますが、多くの場合、Runレジストリキーやスケジュールタスク、Windowsサービスなど通常のマルウェアが使用するような常駐化のメカニズムを用いるので、仮にプロセス・インジェクションそのものの検知が困難であったとしてもインジェクターを特定することによって不正活動を検知することができます。

以上。
Comment



Only the blog author may view the comment.


Trackback
Trackback URL

«  | HOME |  »

奇妙な風景 Unique Scene
<< >>

プロフィール


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


スポンサード リンク


FC2カウンター


検索フォーム


RSSリンクの表示


リンク


ブロとも申請フォーム


QRコード