DLL Injection Class
DLL injection class for C++. The class only uses low level win32 API calls.
This class is written and tested in Windows XP. You need at least Windows 2000 to use this class. In order to check if the system meets the operating system requirements you might use the GetVersion/GetVersionEx function from the win32 API.
Source file and the header file with a test project you can find in the attachment.
injector.cpp
/* Copyright (c) 2009, J. "abort" Dijkstra
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY J. Dijkstra ''AS IS'' */
#include "injector.h"
// Constructor
CInjector::CInjector(DWORD dwPid, LPWSTR pwszLibrary, bool fAdjustPrivileges = false, bool fExecuteFunctions = false) {
if (dwPid == 0)
throw string("No Process ID specified");
if (!pwszLibrary)
throw string("No library specified");
// Open the process handle by it's Process ID
hProcess = OpenProcess(INJECT_ACCESS, FALSE, dwPid);
if (!hProcess)
throw string("Failed to open process");
// Calculate memory size for the library string, including terminating null
int nSize = (lstrlenW(pwszLibrary)+1)*sizeof(WCHAR);
if (nSize == sizeof(WCHAR))
throw string("Invalid library specified");
// Try to allocate memory for the library string
try {
this->pwszLibrary = new WCHAR[nSize];
} catch (bad_alloc& e) {
UNREFERENCED_PARAMETER(e);
throw string("Insufficient memory to allocate library string");
}
// Store the library string in the current instance
if (wcscpy_s(this->pwszLibrary, nSize, pwszLibrary))
throw string("Failed to copy library string");
// Adjust privileges if defined and pass on the exceptions
if (fAdjustPrivileges)
{
string szError;
if (!adjustPrivileges(szError))
throw szError;
}
// If the class user wants to execute functions
if (fExecuteFunctions)
{
if (GetFileAttributesW(pwszLibrary) == INVALID_FILE_ATTRIBUTES)
throw string("Failed to retrieve Dynamic Link Library");
hLibrary = LoadLibraryW(pwszLibrary);
if (!hLibrary)
throw string("Failed to load Dynamic Link Library");
this->fExecuteFunctions = true;
}
dwBaseAddress = 0;
}
// Free up memory after destroying the instance
CInjector::~CInjector() {
if (hProcess)
CloseHandle(hProcess);
if (fExecuteFunctions && hLibrary)
FreeLibrary(hLibrary);
delete[] pwszLibrary;
}
// Find the Process ID by executable name
DWORD CInjector::getProcessIdByName(LPWSTR pwszProcess, string& szError) {
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hSnap || hSnap == INVALID_HANDLE_VALUE)
{
szError = "Failed to create snapshot of processes";
return 0;
}
PROCESSENTRY32W pe;
pe.dwSize = sizeof(PROCESSENTRY32W);
DWORD dwPid = 0;
BOOL bResult = Process32FirstW(hSnap, &pe);
while (bResult)
{
if (!lstrcmpW(pe.szExeFile, pwszProcess))
{
dwPid = pe.th32ProcessID;
break;
}
bResult = Process32NextW(hSnap, &pe);
}
CloseHandle(hSnap);
return dwPid;
}
// Adjust the privileges to enable access to processes like windows services
bool CInjector::adjustPrivileges(string& szError) {
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
// Open process token to adjust the privileges
if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
szError = "Failed to open process token";
return false;
}
// Request the current privileges
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
szError = "Failed to lookup current privilege";
return false;
}
// Change current privilege variables
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
// enable the privilege to access system services
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Apply the changed privileges to the current process token
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
szError = "Failed to adjust token privileges";
return false;
}
return true;
}
// Inject the library into the open process
bool CInjector::injectLibrary(string& szError) {
HANDLE hThread; // Remote thread handle
LPWSTR pwszLibString; // Parameter for remote LoadLibrary function
LPVOID pLoadLibrary; // Pointer to remote LoadLibrary function
HINSTANCE hKernelLib; // Instance of kernel library
DWORD dwExitCode; // Remote thread exit code
size_t nSize; // Size of zero terminated library path
// Calculate length of the library string
nSize = (lstrlenW(pwszLibrary)+1)*sizeof(WCHAR);
if (nSize == sizeof(WCHAR))
{
szError = "Failed to retrieve length of library string";
return false;
}
// Retrieve handle to the kernel library
hKernelLib = GetModuleHandleW(KERNEL_LIB);
if (!hKernelLib)
{
szError = "Failed to retrieve kernel32 handle";
return false;
}
// Get the address of the loadlibrary function
pLoadLibrary = (LPVOID)GetProcAddress(hKernelLib, LOADLIBRARY_FUNCTION);
if (!pLoadLibrary)
{
szError = "Failed to retrieve remote load library address";
return false;
}
// Allocate remote memory for the library string
pwszLibString = (LPWSTR)VirtualAllocEx(hProcess, NULL, nSize, MEM_COMMIT, PAGE_READWRITE);
if (!pwszLibString)
{
szError = "Failed to allocate remote memory";
return false;
}
// Write the library string to the allocated remote memory
if (!WriteProcessMemory(hProcess, pwszLibString, (LPVOID)pwszLibrary, nSize, NULL))
{
szError = "Failed to write remote process memory";
return false;
}
// Start a remote loadlibrary thread with the library string as a parameter
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pwszLibString, 0, NULL);
if (!hThread)
{
szError = "Failed to create remote thread";
return false;
}
// Wait for the remote thread to be terminated
if (WaitForSingleObject(hThread, THREAD_WAIT) != WAIT_OBJECT_0)
{
szError = "Failed to wait for thread to exit";
return false;
}
// Retrieve the loadlibrary exit code (which is the address of the library)
if (!GetExitCodeThread(hThread, &dwExitCode))
{
szError = "Failed to retrieve thread exit code";
return false;
}
// Free up the remotely allocated memory
// No need to check for errors as it has no influence on the injection
VirtualFreeEx(hProcess, pwszLibString, 0, MEM_RELEASE);
if (!dwExitCode)
{
szError = "Failed to inject library into process";
return false;
}
// Store the dll base address in the current instance
dwBaseAddress = dwExitCode;
return true;
}
// Retrieve the base address of the injected library
DWORD CInjector::getBaseAddress() {
return dwBaseAddress;
}
// Start a remote library function
DWORD CInjector::startFunction(LPVOID pFunction, LPVOID pParameter, string& szError) {
if (!fExecuteFunctions)
{
szError = "This instance has no remote function execution enabled";
return 0;
}
if (!dwBaseAddress)
{
szError = "Can not execute function as the library is not injected yet";
return 0;
}
HANDLE hThread;
DWORD dwExitCode = 0;
// Calculate the absolute function address of the function
pFunction = (LPVOID)((DWORD)pFunction + (DWORD)dwBaseAddress);
// Start the remote function
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunction, NULL, 0, NULL);
if (!hThread)
{
szError = "Failed to create remote thread";
return 0;
}
// Wait for the remote thread to exit
if (WaitForSingleObject(hThread, THREAD_WAIT) != WAIT_OBJECT_0)
{
szError = "Failed to wait for remote thread";
return 0;
}
// Retrieve the exit code of the remote thread
if (!GetExitCodeThread(hThread, &dwExitCode))
{
szError = "Failed to retrieve thread exit code";
return 0;
}
// Return thread exit code to be able to check for successful execution
return dwExitCode;
}
// Retrieve the relative address of an exported function
LPVOID CInjector::getRelativeAddress(char* pwszExportName, string& szError) {
if (!fExecuteFunctions || !hLibrary)
{
szError = "This instance has no remote function execution enabled";
return NULL;
}
// Retrieve the absolute address of the given function
LPVOID pFunction = GetProcAddress(hLibrary, pwszExportName);
if (!pFunction)
{
szError = "Failed to retrieve DLL Entry Function";
return NULL;
}
// Calculate the relative function address of the function
pFunction = (LPVOID)((DWORD)pFunction - (DWORD)hLibrary);
return pFunction;
}
injector.h
#ifndef INJECTOR_H_
#define INJECTOR_H_
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define DEFAULTBASE_ADDRESS 268435456
#define KERNEL_LIB L"kernel32.dll"
#define LOADLIBRARY_FUNCTION "LoadLibraryW"
#define INJECT_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
#define THREAD_WAIT 5000
#include <windows.h>
// Required for making a snapshot of the processes
#include <tlhelp32.h>
// Required for errors
#include <string>
using namespace std;
class CInjector {
public:
// Have an instance to store and maintain a handle to the process
CInjector(DWORD dwPid, LPWSTR pwszLibrary, bool fAdjustPrivileges, bool fExecuteFunctions);
// Free some memory
~CInjector();
// Inject the given library in to the open process
bool injectLibrary(string& szError);
// Start a function in the injected library
DWORD startFunction(LPVOID pFunction, LPVOID pParameter, string& szError);
// Get relative address of a certain function
LPVOID getRelativeAddress(char* pwszExportName, string& szError);
// Get the process id by executable name
static DWORD getProcessIdByName(LPWSTR pwszProcess, string& szError);
// Get the base address of the injected library
DWORD getBaseAddress();
private:
HANDLE hProcess; // Process handle
HINSTANCE hLibrary; // The local library instance
DWORD dwBaseAddress; // The injected library's base address
LPWSTR pwszLibrary; // Store the path to the library
bool fExecuteFunctions; // Enable function executing, so we can load it locally
// Adjust privileges to gain access to e.g. winlogon.exe
bool adjustPrivileges(string& szError);
};
#endif
Please register or login to download attachments.