マニュアル

10種類のプロセスインジェクション技術:一般的および最新のプロセスインジェクション技術に関する技術調査

編集者注:Elasticは2019年10月にEndgameと提携し、Endgameブログの一部をelastic.co/jp/に移行しました。当社の統合セキュリティソリューションの詳細についてはElastic Securityをご覧ください。

プロセスインジェクションは、マルウェアやファイルレス攻撃者の手口でよく用いられる、広く普及している防御回避技術であり、別のプロセスのアドレス空間内でカスタムコードを実行するものです。プロセスインジェクションはステルス性を向上させ、一部の手法では永続性も実現します。プロセスインジェクションの手法は数多く存在しますが、このブログでは、実際に確認されている、別のプロセスに代わってマルウェアコードを実行する10種類の手法を紹介します。また、これらの手法の多くについてスクリーンショットを掲載し、リバースエンジニアリングやマルウェア解析を容易にすることで、これらの一般的な手法に対する検出と防御を支援します。

1. CREATEREMOTETHREADとLOADLIBRARYによる従来のDLLインジェクション

この手法は、マルウェアを別のプロセスに注入するために使用される最も一般的な手法の1つです。マルウェアは、悪意のあるダイナミックリンクライブラリ(DLL)へのパスを別のプロセスの仮想アドレス空間に書き込み、ターゲットプロセスにリモートスレッドを作成して、リモートプロセスに確実にロードさせます。

マルウェアはまず、注入するプロセス(例:svchost.exe)を標的にする必要があります。これは通常、CreateToolHelp32Snapshot、Process32First、Process32Nextの3つのアプリケーションプログラムインターフェース(API)を呼び出してプロセスを検索することによって行われます。CreateToolHelp32Snapshotは、指定されたプロセスまたはすべてのプロセスのヒープまたはモジュールの状態を列挙するために使用されるAPIで、スナップショットを返します。Process32は、最初にスナップショット内の最初のプロセスに関する情報を取得し、次にProcess32Nextをループで使用してそれらを反復処理します。マルウェアは、標的のプロセスを発見した後、OpenProcessを呼び出して対象プロセスのハンドルを取得します。

図1に示すように、マルウェアはVirtualAllocexを呼び出して、DLLへのパスを書き込むためのスペースを確保します。その後、マルウェアはWriteProcessMemoryを呼び出して、割り当てられたメモリにパスを書き込みます。最後に、マルウェアはコードを別のプロセスで実行させるために、CreateRemoteThread、NTCreateThreadEx、RTLCreateUserThreadなどのAPIを呼び出します。後者の2つは文書化されていません。ただし、一般的な考え方は、LoadLibraryのアドレスをこれらのAPIの1つに渡して、リモートプロセスがマルウェアに代わってDLLを実行できるようにすることです。

CreateRemoteThreadは、多くのセキュリティ製品によって追跡され、フラグが付けられています。さらに、検出される可能性のある悪質なDLLがディスク上にある必要があります。攻撃者は防御を回避するためにコードを挿入することが最も多いことを考えると、高度な攻撃者はおそらくこのアプローチを使用しないでしょう。下のスクリーンショットは、この手法を実行しているRebhipという名前のマルウェアを示しています

図1:典型的なDLLインジェクションを実行するRebhipワーム
Sha256: 07b8f25e7b536f5b6f686c12d04edc37e11347c8acd5c53f98a174723078c365

2. ポータブル実行可能インジェクション(PEインジェクション)

LoadLibraryのアドレスを渡す代わりに、マルウェアは悪意のあるコードを既存の開いているプロセスにコピーして実行させることができます (小さなシェルコードを使用するか、CreateRemoteThreadを呼び出すことによって)。LoadLibrary手法に対する PE インジェクションの利点の 1 つは、マルウェアが悪意のある DLL をディスクにドロップする必要がないことです。最初の手法と同様に、マルウェアはホストプロセス (たとえば VirtualAllocEx) でメモリを割り当て、「DLLパス」を書き込む代わりに、WriteProcessMemoryを呼び出して悪意のあるコードを書き込みます。ただし、このアプローチの障害は、コピーされたイメージのベースアドレスの変更です。マルウェアがPEを別のプロセスに注入すると、予測不可能な新しいベースアドレスを持つため、PEの固定アドレスを動的に再計算する必要があります。これを克服するために、マルウェアはホストプロセスで再配置テーブルのアドレスを見つけ、再配置記述子をループしてコピーされたイメージの絶対アドレスを解決する必要があります。

この手法は、リフレクティブDLLインジェクションやメモリモジュールといった他の手法と同様に、ディスクにファイルをドロップしないという点で共通しています。ただし、メモリモジュールやリフレクティブDLLインジェクションの手法は、さらに巧妙です。 これらは、メモリ内で自身をロードして実行するため、追加のWindows API(CreateRemoteThreadやLoadLibraryなど)に依存しません。リフレクティブDLLインジェクションは、Windowsのローダーに依存するのではなく、実行時に自身をメモリにマッピングするDLLを作成することで機能します。メモリモジュールは、DLL自体がターゲットDLLをメモリにマッピングするのではなく、インジェクターまたはローダーがターゲットDLLをメモリにマッピングする責任を負う点を除けば、リフレクティブDLLインジェクションと似ています。以前のブログ記事で、これら2つのメモリ内アプローチについて詳しく説明しました。

PEインジェクションを分析する際、CreateRemoteThreadの呼び出しの前にループ(通常は2つの「for」ループ、一方が他方にネストされている)が見られることはよくあります。この手法は、クリプター(マルウェアを暗号化および難読化するソフトウェア)の間で非常に人気があります。図2のサンプルユニットテストでは、この手法が利用されています。コードには、WriteProcessMemoryとCreateRemoteThreadの呼び出しの前に見られる、再配置テーブルを調整するための2つのネストされたループがあります。「and 0x0fff」命令も、最初の12ビットが、格納されている再配置ブロックの仮想アドレスへのオフセットを取得するために使用されていることを示すもう1つの良い指標です。マルウェアは必要なすべてのアドレスを再計算したので、あとは開始アドレスをCreateRemoteThreadに渡して実行させるだけです。

図2:CreateRemoteThread呼び出し前のPEインジェクション用ループの構造例
Sha256: ce8d7590182db2e51372a4a04d6a0927a65b2640739f9ec01cfd6c143b1110da

3. プロセスホローイング(別名:プロセス置換およびRUNPE)

マルウェアは、ホストプログラムにコードを注入する(DLLインジェクションなど)代わりに、プロセスホローイングと呼ばれる手法を実行することがあります。プロセスホローイングとは、マルウェアがターゲットプロセスのメモリから正規のコードをアンマップ(空洞化)し、ターゲットプロセス(svchost.exeなど)のメモリ空間を悪意のある実行ファイルで上書きする手法です。

マルウェアはまず、中断モードで悪意のあるコードをホストする新しいプロセスを作成します。図3に示すように、これはCreateProcessを呼び出し、プロセス作成フラグをCREATE_SUSPENDED (0x00000004) に設定することによって行われます。新しいプロセスのプライマリスレッドは中断状態で作成され、ResumeThread関数が呼び出されるまで実行されません。次に、マルウェアは正規ファイルの内容を悪意のあるペイロードと置き換える必要があります。これは、ZwUnmapViewOfSectionまたはNtUnmapViewOfSectionを呼び出してターゲットプロセスのメモリをアンマップすることによって行われます。これらの2つのAPIは基本的に、セクションが指すすべてのメモリを解放します。メモリがアンマップされたので、ローダーはVirtualAllocExを実行してマルウェア用に新しいメモリを割り当て、WriteProcessMemoryを使用してマルウェアの各セクションをターゲットプロセス空間に書き込みます。マルウェアはSetThreadContextを呼び出して、エントリポイントを自身が書き込んだ新しいコードセクションに向けます。最後に、マルウェアはResumeThreadを呼び出してプロセスを中断状態から復帰させることで、中断されたスレッドを再開します。

図3: Ransom.Cryakがホローイング処理を実行中
Sha256: eae72d803bf67df22526f50fc7ab84d838efb2865c27aef1a61592b1c520d144

4. スレッド実行ハイジャック(別名:サスペンド、インジェクト、レジューム(SIR))

この手法は、以前に説明したプロセスホローイング手法といくつかの類似点があります。スレッド実行ハイジャックでは、マルウェアはプロセスの既存のスレッドを標的とし、ノイズの多いプロセスやスレッドの作成操作を回避します。そのため、解析時には、CreateToolhelp32SnapshotとThread32Firstの呼び出しに続いてOpenThreadが呼び出されていることが確認できるでしょう。

マルウェアは、ターゲットスレッドへのハンドルを取得した後、SuspendThread を呼び出してスレッドをサスペンドモードにし、インジェクションを実行します。このマルウェアは、VirtualAllocExとWriteProcessMemoryを呼び出してメモリを割り当て、コードインジェクションを実行します。コードには、シェルコード、悪意のあるDLLへのパス、およびLoadLibraryのアドレスが含まれる可能性があります。

図4は、この手法を用いた一般的なトロイの木馬を示しています。スレッドの実行を乗っ取るために、マルウェアはSetThreadContextを呼び出すことで、ターゲットスレッドのEIPレジスタ(次の命令のアドレスを含むレジスタ)を変更します。その後、マルウェアはスレッドを再開し、ホストプロセスに書き込んだシェルコードを実行します。攻撃者の視点から見ると、SIRアプローチは、システムコールの途中でスレッドを中断および再開するとシステムがクラッシュする可能性があるため、問題となる場合があります。これを回避するため、より高度なマルウェアは、EIPレジスタがNTDLL.dllの範囲内にある場合は、再開して後で再試行します。

図4 :汎用トロイの木馬がスレッド実行ハイジャックを実行
Sha256: 787cbc8a6d1bc58ea169e51e1ad029a637f22560660cc129ab8a099a745bd50e

5. SETWINDOWSHOOKEXによるフックインジェクション

フッキングは、関数呼び出しを傍受するために使用される手法です。マルウェアはフック機能を利用して、特定のスレッドでイベントがトリガーされたときに悪意のあるDLLをロードできます。これは通常、SetWindowsHookExを呼び出してフックルーチンをフックチェーンにインストールすることによって行われます。SetWindowsHookEx関数は4つの引数を取ります。最初の引数はイベントの種類です。イベントは多彩なフックの種類を反映しており、キーボードのキーを押す(WH_KEYBOARD)からマウス(WH_MOUSE)、CBTなどへの入力まで多岐にわたります。2番目の引数は、イベント実行時にマルウェアが呼び出す関数へのポインタです。3番目の引数は、その関数を含むモジュールです。そのため、SetWindowsHookExを呼び出す前にLoadLibraryとGetProcAddressを呼び出すのが一般的です。この関数の最後の引数は、フックプロシージャを関連付けるスレッドです。この値をゼロに設定すると、イベントがトリガーされたときにすべてのスレッドがアクションを実行します。しかし、マルウェアは通常、ノイズを減らすために単一のスレッドを標的とするため、SetWindowsHookExの前にCreateToolhelp32SnapshotとThread32Nextが呼び出され、単一のスレッドを見つけて標的にすることがあります。DLL が注入されると、マルウェアは、そのthreadIdが SetWindowsHookEx関数に渡されたプロセスに代わって悪意のあるコードを実行します。図5では、Locky Ransomwareがこの手法を実装しています。

図5 : Locky Ransomwareがフックインジェクションを使用
Sha256: 5d6ddb8458ee5ab99f3e7d9a21490ff4e5bc9808e18b9e20b6dc2c5b27927ba1

6. レジストリの変更による注入と永続化(例:APPINIT_DLLS、APPCERTDLLS、IFEO)

Appinit_DLL、AppCertDlls、およびIFEO(イメージファイル実行オプション)はすべて、マルウェアがインジェクションと永続化の両方に使用するレジストリキーです。これらのエントリは次の場所にあります。

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_DLLs

マルウェアは、Appinit_Dllsレジストリキーの下に悪意のあるライブラリの場所を挿入し、別のプロセスにそのライブラリをロードさせることができます。このレジストリキーの下にあるすべてのライブラリは、User32.dllをロードするすべてのプロセスにロードされます。User32.dll は、ダイアログボックスなどのグラフィック要素を格納するために使用される非常に一般的なライブラリです。したがって、マルウェアがこのサブキーを変更すると、ほとんどのプロセスが悪意のあるライブラリをロードすることになります。図6は、トロイの木馬Ginwuiがインジェクションと永続化のためにこの手法を利用していることを示しています。これは、RegCreateKeyEx を呼び出して Appinit_Dlls レジストリ キーを開き、RegSetValueExを呼び出してその値を変更するだけです。

図6 : GinwuiがAppIniti_DLLsレジストリキーを改変
Sha256: 9f10ec2786a10971eddc919a5e87a927c652e1655ddbbae72d376856d30fa27c

AppCertDlls

この方法はAppInit_DLLs方法と非常によく似ていますが、このレジストリキーの下にあるDLLは、Win32 API関数CreateProcess、CreateProcessAsUser、CreateProcessWithLogonW、CreateProcessWithTokenW、およびWinExecを呼び出すすべてのプロセスにロードされる点が異なります。

イメージファイル実行オプション(IFEO)

IFEOは通常、デバッグ目的で使用されます。開発者はこのレジストリキーの下にある「デバッガー値」を設定することで、デバッグのために別の実行可能ファイルにプログラムをアタッチできます。そのため、実行可能ファイルが起動されるたびに、アタッチされたプログラムが起動されます。この機能を使用するには、デバッガーへのパスを指定し、解析したい実行可能ファイルにアタッチするだけです。マルウェアはこのレジストリキーを変更して、ターゲットの実行可能ファイルに自身を挿入することができます。図7では、Diztakunトロイの木馬がタスクマネージャのデバッガー値を変更することで、この手法を実装しています。

図7 : Diztakunトロイの木馬がIFEOレジストリキーを改変
Sha256: f0089056fc6a314713077273c5910f878813fa750f801dfca4ae7e9d7578a148

7. APCインジェクションとアトムボンビング

マルウェアは非同期プロシージャ呼び出し (APC) を利用して、ターゲット スレッドの APC キューにカスタム コードを追加することで、別のスレッドにカスタム コードの実行を強制することができます。各スレッドには、ターゲット スレッドが変更可能な状態になったときに実行を待機する APC のキューがあります。スレッドは、SleepEx、SignalObjectAndWait、MsgWaitForMultipleObjectsEx、WaitForMultipleObjectsEx、または WaitForSingleObjectEx 関数を呼び出すと、アラート可能な状態になります。マルウェアは通常、変更可能な状態にあるスレッドを探し、OpenThreadとQueueUserAPCを呼び出して、スレッドにAPCをキュー追加します。QueueUserAPC は、1) ターゲットスレッドへのハンドル、2) マルウェアが実行したい関数へのポインタ、3) 関数ポインタに渡されるパラメーターの3つの引数を取ります。図8では、AmanaheマルウェアはまずOpenThreadを呼び出して別のスレッドのハンドルを取得し、次にLoadLibraryAを関数ポインタとしてQueueUserAPCを呼び出して、悪意のあるDLLを別のスレッドに注入します。

アトムボンビングは、enSiloの研究によって初めて導入され、その後Dridex V4で使用された技術です。以前の記事で詳しく説明したように、この技術もAPCインジェクションに依存しています。ただし、別のプロセスのメモリに書き込むためにアトムテーブルを使用します。

図8 : AlmanaheがAPCインジェクションを実行
Sha256: f74399cc0be275376dad23151e3d0c2e2a1c966e6db6a695a05ec1a30551c0ad

8. SETWINDOWLONGによる追加ウィンドウメモリ注入(EWMI)

EWMIはエクスプローラーのトレイウィンドウの追加ウィンドウメモリへの注入に依存しており、GapzやPowerLoaderなどのマルウェアファミリーで何度か使用されています。ウィンドウクラスを登録する際、アプリケーションは追加ウィンドウメモリ(EWM)と呼ばれる追加メモリのバイト数を指定できます。しかし、EWMには十分な空き容量がありません。この制限を回避するため、マルウェアはexplorer.exeの共有セクションにコードを書き込み、SetWindowLongとSendNotifyMessageを使用してシェルコードを指す関数ポインタを取得し、それを実行します。

このマルウェアは、共有セクションへの書き込みに関して2つの選択肢を持っています。1つは、共有セクションを作成して自身と他のプロセス(explorer.exeなど)の両方にマッピングする方法、もう1つは、既に存在する共有セクションを開く方法です。前者は、ヒープ領域の割り当てやNTMapViewOfSectionの呼び出し、その他いくつかのAPI呼び出しといったオーバーヘッドが発生するため、後者の方法がより頻繁に用いられます。 マルウェアは、共有セクションにシェルコードを書き込んだ後、GetWindowLongとSetWindowLongを使用して「Shell_TrayWnd」の追加ウィンドウメモリにアクセスし、変更します。GetWindowLongは、ウィンドウクラスオブジェクトの追加ウィンドウメモリ内の指定されたオフセットにある32ビット値を取得するために使用されるAPIであり、SetWindowLongは、指定されたオフセットにある値を変更するために使用されます。このようにして、マルウェアはウィンドウクラス内の関数ポインタのオフセットを簡単に変更し、共有セクションに書き込まれたシェルコードを指すようにすることができます。

上記で述べた他のほとんどの手法と同様に、マルウェアは自身が記述したコードを実行する必要があります。これまで説明した手法では、マルウェアはCreateRemoteThread、QueueUserAPC、SetThreadContextなどのAPIを呼び出すことでこれを実現していました。この手法では、マルウェアは代わりにSendNotifyMessageを呼び出すことで注入されたコードを実行します。SendNotifyMessageが実行されると、Shell_TrayWndはSetWindowLongによって以前に設定された値が指すアドレスに制御を受け取り、そのアドレスに制御を移します。図9では、PowerLoaderというマルウェアがこの手法を使用しています。

図9: PowerLoaderがシェルトレイウィンドウの余剰ウィンドウメモリに注入
Sha256: 5e56a3c4d4c304ee6278df0b32afb62bd0dd01e2a9894ad007f4cc5f873ab5cf

9. SHIMSを使用したインジェクション

Microsoftは、主に後方互換性のために開発者向けにShimsを提供しています。Shimsを使用すると、開発者はコードを書き直すことなくプログラムに修正を適用できます。Shimsを活用することで、開発者はオペレーティングシステムにアプリケーションの処理方法を指示できます。Shimsは基本的に、API にフックして特定の実行可能ファイルをターゲットにする手段です。マルウェアはShimsを利用して、永続化とインジェクションの両方を目的として実行可能ファイルをターゲットにすることができます。Windowsはバイナリをロードする際にShim Engineを実行し、適切な修正を適用するためにShimデータベースをチェックします。

適用できる修正方法は多数ありますが、マルウェアが好むのはセキュリティ関連の修正方法です (例: DisableNX、DisableSEH、InjectDLL など)。シミングデータベースをインストールするために、マルウェアはさまざまなアプローチを展開できます。たとえば、一般的なアプローチの 1 つは、単に sdbinst.exe を実行し、悪意のある sdb ファイルを指定することです。図 10 では、アドウェア「Search Protect by Conduit」が永続性と注入のためにシムを使用しています。Google Chrome に「InjectDLL」シムを実行して vc32loader.dll をロードします。sdb ファイルを分析するための既存のツールはいくつかありますが、以下にリストされている sdb の分析にはpython-sdbを使用しました。

図10 : Search Protectがインジェクション目的で使用するSDB
Sha256: 6d5048baf2c3bba85adc9ac5ffd96b21c9a27d76003c4aa657157978d7437a20

10. IATフッキングとインラインフッキング(別名:ユーザーランドルートキット)

IATフッキングとインラインフッキングは、一般的にユーザーランドルートキットとして知られています。IATフッキングは、マルウェアがインポートアドレステーブルを変更するために使用する手法です。正規のアプリケーションがDLL内のAPIを呼び出すと、元の関数ではなく、変更された関数が実行されます。一方、インラインフッキングでは、マルウェアはAPI関数自体を変更します。 図11では、マルウェアFinFisherがCreateWindowExが指す場所を変更することによってIATフックを実行します。

図11 : FinFisherがCreateWindowExが指す場所を変更してIATフックを実行
Sha256: f827c92fbe832db3f09f47fe0dcaafd89b40c7064ab90833a1f418f2d1e75e8e

まとめ

この記事では、マルウェアが別のプロセス内で自身の活動を隠蔽するために用いる10種類のテクニックについて解説しました。一般的に、マルウェアはシェルコードを別のプロセスに直接注入するか、あるいは別のプロセスに自身の悪意のあるライブラリを強制的に読み込ませます。表1では、これらのさまざまなテクニックを分類し、本記事で取り上げた各注入手法を観察するための参考となるサンプルを掲載しています。本記事に掲載された図は、研究者がマルウェアのリバースエンジニアリングを行う際に、さまざまな手法を認識するのに役立つでしょう。

表1 : プロセスインジェクションは、別のプロセスにコードを直接注入するか、別のプロセスにDLLの読み込みを強制することで実行可能

攻撃者や研究者は定期的にインジェクションやステルスを可能にする新しい技術を発見しています。この記事では、一般的かつ新興の10の手法について詳しく説明しましたが、COMハイジャックなど他にもいくつかあります。防御者はステルスプロセス注入を検知し防止する任務を決して「終わらせる」ことはありません。なぜなら敵対者は決して革新をやめないからです。

Endgameでは、常に高度なステルス技術を研究し、製品に防護を導入しています。私たちは、持続性にロードされる悪意のあるDLL(AppInit DLL、COMハイジャックなど)を検出する機能を構築し、特許取得済みのシェルコード注入保護によって多くの形態のコード注入をリアルタイムで防止し、特許出願中のファイルレス攻撃検出技術を通じて、上記の技術を通じてメモリ上で実行される悪意のある注入ペイロードを検出します。 このアプローチにより、当社のプラットフォームはコードインジェクションからの防御において市場にある他の製品よりも効果的であると同時に、新興のコードインジェクション技術によるバイパスに対する耐性も最大化します。