// dll_injector.cpp — Generic LoadLibraryA DLL Injector
// Usage: set TARGET_PROCESS and DLL_NAME, build and run as admin.
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
// ── Config ────────────────────────────────────────────────────────────────────
constexpr const char* TARGET_PROCESS = "target.exe";
constexpr const char* DLL_NAME = "payload.dll";
// ─────────────────────────────────────────────────────────────────────────────
// Find PID by process name (returns 0 if not found)
static DWORD FindPID(const char* name)
{
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snap == INVALID_HANDLE_VALUE) return 0;
PROCESSENTRY32 pe{ sizeof(pe) };
for (BOOL ok = Process32First(snap, &pe); ok; ok = Process32Next(snap, &pe))
{
char buf[MAX_PATH];
wcstombs_s(nullptr, buf, pe.szExeFile, MAX_PATH);
if (!lstrcmpA(buf, name))
{
CloseHandle(snap);
return pe.th32ProcessID;
}
}
CloseHandle(snap);
return 0;
}
// Copy DLL to %TEMP% to avoid file-lock issues, returns path in out[]
static bool CopyToTemp(const char* src, char* out)
{
char tempDir[MAX_PATH], tempFile[MAX_PATH];
GetTempPathA(MAX_PATH, tempDir);
GetTempFileNameA(tempDir, "inj", 0, tempFile);
lstrcpyA(out, tempFile);
lstrcatA(out, ".dll");
return CopyFileA(src, out, FALSE);
}
// Open file dialog to pick a DLL (fallback when DLL_NAME not found alongside exe)
static bool PickDll(char* out)
{
OPENFILENAMEA ofn{};
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = "DLL Files (*.dll)\0*.dll\0All Files\0*.*\0";
ofn.lpstrFile = out;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST;
return GetOpenFileNameA(&ofn);
}
// Core injection: WriteProcessMemory + CreateRemoteThread(LoadLibraryA)
static bool Inject(HANDLE hProc, const char* dllPath)
{
SIZE_T len = lstrlenA(dllPath) + 1;
void* remote = VirtualAllocEx(hProc, nullptr, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remote) return false;
if (!WriteProcessMemory(hProc, remote, dllPath, len, nullptr))
{
VirtualFreeEx(hProc, remote, 0, MEM_RELEASE);
return false;
}
FARPROC loadLib = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (!loadLib) return false;
HANDLE hThread = CreateRemoteThread(hProc, nullptr, 0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(loadLib), remote, 0, nullptr);
if (!hThread) return false;
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
// Note: remote memory is intentionally left allocated — LoadLibraryA needs the string
// only during the call, but freeing early can race. Free here if your DLL is
// guaranteed loaded by the time WaitForSingleObject returns (it is).
VirtualFreeEx(hProc, remote, 0, MEM_RELEASE);
return true;
}
int main()
{
// 1. Resolve DLL path (next to exe → file dialog fallback)
char dllPath[MAX_PATH]{};
GetFullPathNameA(DLL_NAME, MAX_PATH, dllPath, nullptr);
if (GetFileAttributesA(dllPath) == INVALID_FILE_ATTRIBUTES)
{
std::cout << "[!] " << DLL_NAME << " not found, opening file dialog...\n";
if (!PickDll(dllPath)) { std::cout << "[-] Cancelled.\n"; return 1; }
}
// 2. Find target process
DWORD pid = FindPID(TARGET_PROCESS);
if (!pid) { std::cout << "[-] Process not found: " << TARGET_PROCESS << "\n"; return 1; }
std::cout << "[+] PID: " << pid << "\n";
// 3. Open process
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProc) { std::cout << "[-] OpenProcess failed: " << GetLastError() << "\n"; return 1; }
// 4. Copy DLL to temp to avoid source-file locking
char tempDll[MAX_PATH]{};
if (!CopyToTemp(dllPath, tempDll)) { std::cout << "[-] CopyToTemp failed.\n"; return 1; }
std::cout << "[+] Temp DLL: " << tempDll << "\n";
// 5. Inject
if (!Inject(hProc, tempDll))
std::cout << "[-] Injection failed: " << GetLastError() << "\n";
else
std::cout << "[+] Inject OK.\n";
CloseHandle(hProc);
std::cin.get();
return 0;
}