参考サイト: http://furuya02.hatenablog.com/entry/20120114/1326484897
Windowsにおいて、各プロセスはユニークな仮想メモリ空間の中で動作する。 そのため通常は、プロセスがプロセスを操作する状況において、引数として自プロセス内で取得したアドレスを他プロセスに渡してもうまく動作しない。 しかしある種のDLLはすべてのプロセス空間で同一のアドレスにロードされるため、そのDLLからエクスポートされている関数へのアドレスはすべてのプロセスで共通の値をとる。 Loadlibrary()を使ったDLLインジェクションはこの仕組みに着目し、Kernel32.dllからエクスポートされるLoadlibrary()へのアドレスをそのまま他プロセスに渡すことで任意のDLLを読み込ませる手法である。
主な手順は以下である。
- リモートプロセスにオープンまたはアタッチ
- WriteProcessMemoryでリモートプロセスに読み込ませたいDLLのパスを書き込む
- Loadlibrary()へのアドレスを引数としてリモートプロセスに対してCreateRemoteThreadする
- この際、Loadlibrary()の引数に、先ほど書き込んだDLLのパスへのアドレスを指定することで、任意のDLLを読み込ませることが可能
通常プロセス間に限っての話で、システムプロセスなどでは当然アドレスは異なることに留意。
// usage
// ./remote_loadlib.exe [DLLPath] [ProcessID to insert DLL]
#include <windows.h>
int main(int argc, char *argv[])
{
DWORD pid;
HANDLE proc;
LPSTR libPath;
LPSTR remoteLibPath;
DWORD pathSize;
libPath = argv[1];
// 文字列を数値に変換
pid = strtoul(argv[2], NULL, 0);
proc = OpenProcess(
PROCESS_CREATE_THREAD //create remote thread
| PROCESS_VM_OPERATION //VirtualAllocEX
| PROCESS_VM_WRITE, //WriteProcessMemory
FALSE, //InheritHandle
pid);
pathSize = strlen(libPath) + 1;
remoteLibPath = VirtualAllocEx(
proc,
NULL,
pathSize,
MEM_COMMIT,
PAGE_READWRITE);
// リモートプロセスへ読み込ませたいDLLのパスを書き込む
WriteProcessMemory(
proc,
remoteLibPath,
libPath,
pathSize,
NULL);
// 自プロセス内のLoadlibrary()へのアドレスを引数として渡す
CreateRemoteThread(
proc,
NULL,
0,
(LPTHREAD_START_ROUTINE)LoadLibrary,
remoteLibPath,
0,
NULL);
return 0;
}
このDLLがリモートプロセスに読み込まれ、デバッグウィンドウに文字列が出力される。
#include <Windows.h>
int evilcode(void);
int evilCode()
{
char *buf = "Injected!";
OutputDebugString(buf);
}
BOOL WINAPI
DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
evilCode();
}
return TRUE;
}