主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2022/06/15
任意の 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 の方法のメモでした。
次回は、任意の処理の置き換えについて書く予定です。