任意の Windows アプリケーションにたいして、 DLL Injection を行って処理を差し込んでみよう!という記事です。
あくまで DLL Injection についての解説記事であって、ウィルスの作成だったりチートを助長するような目的ではありませんのであしからず。
DLL Injection といってもいくつか方法があるようですが、今回は LoadLibrary
と CreateRemoteThread
を使った方法の紹介です。
次回は任意の処理の置き換えについて書きますが、今回は Injection するところまで。
Inject させる側は、以下のようなコードで実現が可能です。
#include <clocale> #include <cstdio> #include <iostream> #include <Windows.h> int main(int argc, char* argv[]) { char path[MAX_PATH]; GetCurrentDirectoryA(MAX_PATH, path); strcat_s(path, sizeof(path), "\\path\\to\\inject.dll"); const auto pid = strtoul(argv[1], nullptr, 0); const auto hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!hProcess) return EXIT_FAILURE; const auto lpBaseAddress = VirtualAllocEx(hProcess, nullptr, sizeof(path) + 1, MEM_COMMIT, PAGE_READWRITE); if (!lpBaseAddress) return EXIT_FAILURE; WriteProcessMemory(hProcess, lpBaseAddress, path, sizeof(path) + 1, nullptr); const auto kernel32 = LoadLibraryW(L"kernel32"); if (!kernel32) return EXIT_FAILURE; const auto address = GetProcAddress(kernel32, "LoadLibraryA"); const auto hThread = CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)address, lpBaseAddress, 0, nullptr); if (!hThread) return EXIT_FAILURE; const auto hResult = WaitForSingleObject(hThread, INFINITE); if (!hResult) return EXIT_FAILURE; CloseHandle(hThread); return EXIT_SUCCESS; }
やっていることとしては、
OpenProcess
で指定されたプロセスにたいして、プロセスをオープンしプロセスハンドル (hProcess
) を取得するVirtualAllocEx
で、上で取得したプロセス内で、メモリを確保するWriteProcessMemory
で対象プロセスのメモリ上にロードしたい DLL のパスを書き込む- 絶対パスで無いと動かないので注意してください
kernel32.dll
のLoadLibrary
をCreateRemoteThread
のスレッド開始ルーチンをして渡すLPTHREAD_START_ROUTINE
はDWORD WINAPI SomeFunction(LPVOID parameter)
の形であれば良いので、同じ関数シグネチャーをもつHMODULE LoadLibrary(PLCWSTR lpLibFileName)
が実行可能
WaitForSingleObject
でスレッドの完了まで待つ
といった感じ。
Inject される側のコードは通常の DLL を作るのと同じで良いですが、あえて載せるとこんな感じ:
// dllmain.cpp : Defines the entry point for the DLL application. #include "pch.h" #include <Windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) // NOLINT(hicpp-multiway-paths-covered) { case DLL_PROCESS_ATTACH: OutputDebugString("Hello, World!"); break; default: break; } return TRUE; }
デバッガーをアタッチするのが面倒なら、 MessageBoxA
とかでも良いです。
これで、 injector.exe PID
とかすると、指定されたプロセスに読み込まれ、 Hello, World!
が何らかの方法で表示されます。
ということで、 DLL Injection の方法のメモでした。
次回は、任意の処理の置き換えについて書く予定です。