断片

です・ます調が記事によって違ったりするブログ

DLLインジェクションの検証

これはMCC Advent Calendar10日目の記事です.
前回はUm6ra1(@v1ru5) さんによる,LinuxのUSBドライバを書いてみよう ~RTL2832uでLチカ~でした.

はじめに

本記事では,DLLインジェクションを実際に実装・検証していきます.DLLインジェクションとは,Windowsにおいて,プロセスに意図しないDLL(Dynamic Link Library)を埋め込む攻撃手法です.この手法はUser Mode Rootkit等のマルウェアでよく用いられるテクニックでもあります.

環境

以下の環境で検証を行いました.実装はC++を使用しました.

OS Windows10 Pro x86-64
Visual Studio Community 2015 Version 14.025431.01 Update 3

手順

基本方針としては,DLLパスを攻撃対象プロセスの仮想アドレス空間のメモリ領域に書き込み,リモートスレッドを生成する形でDLLコードを実行します.具体的には以下の手順で攻撃対象へDLLインジェクションを行います.

1. プロセスへのアタッチ -> OpenProcess()
HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // アクセスフラグ
  BOOL bInheritHandle,    // ハンドルの継承オプション
  DWORD dwProcessId       // プロセス識別子
);

https://msdn.microsoft.com/ja-jp/library/cc429278.aspx

2. プロセスの仮想アドレス空間内のメモリ領域確保 -> VirtualAllocEx()
LPVOID VirtualAllocEx(
  HANDLE hProcess,         // 割り当てたいメモリを保持するプロセス
  LPVOID lpAddress,        // 割り当てたい開始アドレス
  DWORD dwSize,            // 割り当てたい領域のバイト単位のサイズ
  DWORD flAllocationType,  // 割り当てのタイプ
  DWORD flProtect          // アクセス保護のタイプ
);

https://msdn.microsoft.com/ja-jp/library/cc430225.aspx

3. 確保済みメモリ領域へDLLパスのコピー -> WriteProcessMemory()
BOOL WriteProcessMemory(
  HANDLE hProcess,               // プロセスのハンドル
  LPVOID lpBaseAddress,          // 書き込み開始アドレス
  LPVOID lpBuffer,               // データバッファ
  DWORD nSize,                   // 書き込みたいバイト数
  LPDWORD lpNumberOfBytesWritten // 実際に書き込まれたバイト数
);

https://msdn.microsoft.com/ja-jp/library/cc429067.aspx

4. リモートスレッドの生成(DLLコードの実行) -> CreateRemoteThread()
HANDLE CreateRemoteThread(
  HANDLE hProcess,        // 新しいスレッドを稼働させるプロセスを識別するハンドル
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
                            // スレッドのセキュリティ属性へのポインタ
  DWORD dwStackSize,     // 初期のスタックサイズ (バイト数)
  LPTHREAD_START_ROUTINE lpStartAddress,
                           // スレッド関数へのポインタ
  LPVOID lpParameter,     // 新しいスレッドの引数へのポインタ
  DWORD dwCreationFlags,  // 作成フラグ
  LPDWORD lpThreadId      // 取得したスレッド識別子へのポインタ
);

https://msdn.microsoft.com/ja-jp/library/cc429075.aspx

CreateRemoteThread関数の実行において,lpStartAddressにLoadLibraryのアドレス,lpParameterにプロセスの仮想アドレス空間のメモリ領域に書き込まれたDLLパスのアドレスを指定するようにします.こうすることでリモートスレッドのエントリポイントがLoadLibraryによってロードされたDLLのDllMain関数となります.

HMODULE LoadLibrary(
  LPCTSTR lpFileName   // モジュールのファイル名
);

https://msdn.microsoft.com/ja-jp/library/cc429241.aspx

今回は検証用DLL(dllexample.dll)をメモ帳(notepad.exe)にインジェクションします.検証用DLLのDllMain関数部分は以下の通りです. gist.github.com また,インジェクション実行のプログラム(injector.cpp)は以下の通りです. gist.github.com 以上のプログラムを実行すると以下のような結果になり,メモ帳に対してDLLインジェクションが成功したことが確認できました. f:id:epcnt19:20171209221922p:plain

参考

おわりに

DLLインジェクションの攻撃手法自体は以前から知っていましたが,手を動かして検証したことがなかったのでやってみました.

次回はsasamijpさんによる,街中謎解きゲームの話です.
今年は某先輩専用のAdvent Calendarが開催されなかったことが残念でなりません.