Download - 64ビット対応Dllインジェクション
動作イメージ
各プロセスのメモリ空間内には、当該プロセスの独自コード・カーネル・DLLがロード
プロセスBプロセスA
カーネルコード
プロセスAのコード
Other.dll
user32.dll
kernel32.dll
カーネルコード
プロセスBのコード
test.dll
user32.dll
kernel32.dll
ダイナミックにロードする
//test.dllをロードする HMODULE hDll = ::LoadLibrary( "test.dll" ); if ( hDll != NULL ){ //DLLを使用するコードをここに記述 //test.dllをアンロードする ::FreeLibrary( hDll ); }
他プロセスでスレッド実行
HANDLE CreateRemoteThread( HANDLE hProcess, // 挿入先プロセスハンドル LPSECURITY_ATTRIBUTES lpAttr,// セキュリティ属性 DWORD dwStackSize, // スタックサイズ LPTHREAD_START_ROUTINE lpAddr,//関数ポインタ LPVOID lpParameter, // 引数ポインタ DWORD dwCreationFlags, // 作成フラグ LPDWORD lpThreadId // スレッド識別子 );
LPTHREAD_START_ROUTINE lpAddr,//関数ポインタ
LPTHREAD_START_ROUTINE 型
typedef DWORD (
__stdcall *LPTHREAD_START_ROUTINE)
( [in] LPVOID lpThreadParameter );
HMODULE LoadLibrary( LPCTSTR lpFileName //モジュール名 ); BOOL FreeLibrary( HMODULE hModule // DLLハンドル );
関数のアドレス
カーネルコード
プロセスAのコード
0x75230000 kernel32.dll
カーネルコード
プロセスBのコード
0x75230000 kernel32.dll
0x75230xxx
Loadribrary()
0x75230xxx
Loadribrary()
プロセスBプロセスA
インジェクション・コード //kernel32のモジュールハンドル取得 IntPtr m = GetModuleHandle("kernel32.dll"); //LoadLibrary()のアドレス取得 UIntPtr a = GetProcAddress(m, "LoadLibraryA"); //スレッド実行 IntPtr t = CreateRemoteThread( hProcess,IntPtr.Zero, 0, a, param, 0, out b); //スレッド完了待ち(DllMainから返るのを待つ) WaitForSingleObject(t,INFINITE); //DLLハンドルの取得 if (GetExitCodeThread(t, out hDll)) { if(hDll!=IntPtr.Zero)result = true;//成功 } //スレッドクローズ CloseHandle(t);
LoadLibraryのパラメータ
HMODULE hDll = ::LoadLibrary( "test.dll" );
自プロセスのメモリ空間に展開された文字列へのポインタ プロセスBのスレッドにはプロセスB上のアドレスが必要
プロセスA
0x02583000
“test.dll”
プロセスB
0x02583000
Int x=100
他プロセスでメモリ操作 VirtualAllocEx() 挿入先プロセスでメモリ確保
プロセスA プロセスB
VirtualAllocEx
WriteProcessMemory() 挿入先のメモリ空間に書き込む
WriteProcessMemory
書き込んだメモリを使用する Loadribrary()のパラメータ
VirtualFreeEx() 確保したメモリの開放
0x000034000
“test.dll”
メモリ操作・コード UInt32 MEM_COMMIT = 0x1000; UInt32 PAGE_EXECUTE_READWRITE = 0x40; IntPtr m = (IntPtr)VirtualAllocEx( hProcess, IntPtr.Zero, (uint)len, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (m != IntPtr.Zero) { //確保した挿入先の領域にDLL名を書き込む WriteProcessMemory( hProcess, m, dllName, (UIntPtr)len, out b); //確保したメモリをここで使用する //(挿入先でLoadLibraryを呼び出す) //確保したメモリの開放 VirtualFreeEx(hProcess, m, 0, 0x8000); }
64bitOSの問題(混在) 64ビットOSでは、従来の32ビットプログラムもWOW64によりそのまま使用することができるため、両者が混在している
64ビットEXEは、64ビットDLLのみ使用可能 32ビットEXEは、32ビットDLLのみ使用可能
Dllインジェクションも、挿入先に合わせたDLLが必要
64bitOSの問題 (ERROR_ACCESS_DENIED)
WOW64上からは、CreateRemoteThread()は、 ERROR_ACCESS_DENIEDが発生して使用できません。 使用できないという正規のドキュメントは、見つけられませんでしたが、 同一趣旨のコメントが多数検索にヒットします。
64bit上では、64bitのEXEしか使用できない
64bitOSの問題 (kernel32.dllのアドレスが違う)
WOW64上の32bitプロセスは、違うkernel32.dllを ロードしている。
64ビット上から32ビットプロセスのアドレスが分からない
c:¥>listdlls POWERPNT.EXE 32ビットプロセス
ListDLLs v3.1 - List loaded DLLs
Base Size Path
0x00000000776b0000 0x160000 C:¥Windows¥SysWOW64¥ntdll.dll
0x0000000075230000 0x110000 C:¥Windows¥syswow64¥kernel32.dll
>ListDlls notepad 64ビットプロセス
ListDLLs v3.1 - List loaded DLLs
Base Size Path
0x0000000077650000 0x186000 C:¥Windows¥system32¥ntdll.dll
0x00000000771c0000 0x12d000 C:¥Windows¥system32¥kernel32.dll
64bitOSの問題(まとめ) マトリックスにしてみると、下記の3種類しか動作できないことが分かる
挿入先に応じたDLLが必要 WOW64で動作させない 64bitのEXE上で32bitのkernel32ロードのアドレスが必要
WOW64で動作させない OSに合わせたEXEを用意する
.NETの「AnyCPU」で作成すれば解決
//ポインタが8バイトの場合 If(IntPtr.Size == 8){ //64bit環境で動作中 }
64bitから32bitの kernel32.dllのアドレス取得
32bitでコンパイルした下記のEXEを実行して アドレスを取得する
参考「64bitプロセスから32bitプロセスにDLL Injection (C言語) 」http://nazochu.blogspot.com/2011/09/64bit32bitdll-injection.html
#include <windows.h>
int main(int, char**){
return(int) =
GetProcAddress(
GetModuleHandle(“kernel32”), “LoadLibraryA”);
}
4G超のアドレスに注意が必要
kernel32.dllのアドレスは幸い32bitで表現可能だった
>ListDlls notepad 64ビットプロセス
ListDLLs v3.1 - List loaded DLLs
Base Size Path
0x0000000077650000 0x186000 C:¥Windows¥system32¥ntdll.dll
0x00000000771c0000 0x12d000 C:¥Windows¥system32¥kernel32.dll
Dllハンドルは32bitで表現できない