Code:
#include <Windows.h>
#include <TlHelp32.h>
typedef HMODULE(WINAPI *pLoadLibraryA)(LPCSTR);
typedef FARPROC(WINAPI *pGetProcAddress)(HMODULE, LPCSTR);
typedef BOOL(WINAPI *PDLL_MAIN)(HMODULE, DWORD, PVOID);
typedef struct _MANUAL_INJECT
{
PVOID ImageBase;
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_BASE_RELOCATION BaseRelocation;
PIMAGE_IMPORT_DESCRIPTOR ImportDirectory;
pLoadLibraryA fnLoadLibraryA;
pGetProcAddress fnGetProcAddress;
}MANUAL_INJECT, *PMANUAL_INJECT;
unsigned long __stdcall LoadDll(PVOID p)
{
PMANUAL_INJECT ManualInject;
HMODULE hModule;
DWORD i, Function, count, delta;
DWORD* ptr;
WORD* list;
PIMAGE_BASE_RELOCATION pIBR;
PIMAGE_IMPORT_DESCRIPTOR pIID;
PIMAGE_IMPORT_BY_NAME pIBN;
PIMAGE_THUNK_DATA FirstThunk, OrigFirstThunk;
PDLL_MAIN EntryPoint;
ManualInject = (PMANUAL_INJECT)p;
pIBR = ManualInject->BaseRelocation;
delta = (DWORD)((LPBYTE)ManualInject->ImageBase - ManualInject->NtHeaders->OptionalHeader.ImageBase); // Calculate the delta
// Relocate the image
while (pIBR->VirtualAddress)
{
if (pIBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))
{
count = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
list = (PWORD)(pIBR + 1);
for (i = 0; i<count; i++)
{
if (list[i])
{
ptr = (PDWORD)((LPBYTE)ManualInject->ImageBase + (pIBR->VirtualAddress + (list[i] & 0xFFF)));
*ptr += delta;
}
}
}
pIBR = (PIMAGE_BASE_RELOCATION)((LPBYTE)pIBR + pIBR->SizeOfBlock);
}
pIID = ManualInject->ImportDirectory;
// Resolve DLL imports
while (pIID->Characteristics)
{
OrigFirstThunk = (PIMAGE_THUNK_DATA)((LPBYTE)ManualInject->ImageBase + pIID->OriginalFirstThunk);
FirstThunk = (PIMAGE_THUNK_DATA)((LPBYTE)ManualInject->ImageBase + pIID->FirstThunk);
hModule = ManualInject->fnLoadLibraryA((LPCSTR)ManualInject->ImageBase + pIID->Name);
if (!hModule)
{
return FALSE;
}
while (OrigFirstThunk->u1.AddressOfData)
{
if (OrigFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
// Import by ordinal
Function = (DWORD)ManualInject->fnGetProcAddress(hModule, (LPCSTR)(OrigFirstThunk->u1.Ordinal & 0xFFFF));
if (!Function)
{
return FALSE;
}
FirstThunk->u1.Function = Function;
}
else
{
// Import by name
pIBN = (PIMAGE_IMPORT_BY_NAME)((LPBYTE)ManualInject->ImageBase + OrigFirstThunk->u1.AddressOfData);
Function = (DWORD)ManualInject->fnGetProcAddress(hModule, (LPCSTR)pIBN->Name);
if (!Function)
{
return FALSE;
}
FirstThunk->u1.Function = Function;
}
OrigFirstThunk++;
FirstThunk++;
}
pIID++;
}
if (ManualInject->NtHeaders->OptionalHeader.AddressOfEntryPoint)
{
EntryPoint = (PDLL_MAIN)((LPBYTE)ManualInject->ImageBase + ManualInject->NtHeaders->OptionalHeader.AddressOfEntryPoint);
return EntryPoint((HMODULE)ManualInject->ImageBase, DLL_PROCESS_ATTACH, NULL); // Call the entry point
}
return TRUE;
}
unsigned long __stdcall LoadDllEnd() {
return 0;
}
void ManualMap(const char* dll, unsigned long pid)
{
PIMAGE_DOS_HEADER pIDH;
PIMAGE_NT_HEADERS pINH;
PIMAGE_SECTION_HEADER pISH;
HANDLE hProcess, hThread, hFile, hToken;
PVOID buffer, image, mem;
DWORD i, FileSize, ProcessId, ExitCode, read;
TOKEN_PRIVILEGES tp;
MANUAL_INJECT ManualInject;
if (OpenProcessToken((HANDLE)-1, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid.LowPart = 20;
tp.Privileges[0].Luid.HighPart = 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
CloseHandle(hToken);
}
hFile = CreateFile(dpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // Open the DLL
FileSize = GetFileSize(hFile, NULL);
buffer = VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ReadFile(hFile, buffer, FileSize, &read, NULL);
CloseHandle(hFile);
pIDH = (PIMAGE_DOS_HEADER)buffer;
pINH = (PIMAGE_NT_HEADERS)((LPBYTE)buffer + pIDH->e_lfanew);
ProcessId = pid;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
image = VirtualAllocEx(hProcess, NULL, pINH->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Allocate memory for the DLL
pISH = (PIMAGE_SECTION_HEADER)(pINH + 1);
for (i = 0; i<pINH->FileHeader.NumberOfSections; i++) {
WriteProcessMemory(hProcess, (PVOID)((LPBYTE)image + pISH[i].VirtualAddress), (PVOID)((LPBYTE)buffer + pISH[i].PointerToRawData), pISH[i].SizeOfRawData, NULL);
}
mem = VirtualAllocEx(hProcess, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Allocate memory for the loader code
memset(&ManualInject, 0, sizeof(MANUAL_INJECT));
ManualInject.ImageBase = image;
ManualInject.NtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)image + pIDH->e_lfanew);
ManualInject.BaseRelocation = (PIMAGE_BASE_RELOCATION)((LPBYTE)image + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
ManualInject.ImportDirectory = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)image + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
ManualInject.fnLoadLibraryA = LoadLibraryA;
ManualInject.fnGetProcAddress = GetProcAddress;
WriteProcessMemory(hProcess, mem, &ManualInject, sizeof(MANUAL_INJECT), NULL); // Write the loader information to target process
WriteProcessMemory(hProcess, (PVOID)((PMANUAL_INJECT)mem + 1), LoadDll, (DWORD)LoadDllEnd - (DWORD)LoadDll, NULL); // Write the loader code to target process
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((PMANUAL_INJECT)mem + 1), mem, 0, NULL); // Create a remote thread to execute the loader code
if (!hThread) {
MessageBox(0, L"Error: Unable to execute loader code (%d)\n", L"ERROR_EXECUTE_FAIL", MB_ICONEXCLAMATION);
VirtualFreeEx(hProcess, mem, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, image, 0, MEM_RELEASE);
CloseHandle(hProcess);
VirtualFree(buffer, 0, MEM_RELEASE);
return -1;
}
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &ExitCode);
if (!ExitCode) {
VirtualFreeEx(hProcess, mem, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, image, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
VirtualFree(buffer, 0, MEM_RELEASE);
return -1;
}
CloseHandle(hThread);
VirtualFreeEx(hProcess, mem, 0, MEM_RELEASE);
CloseHandle(hProcess);
VirtualFree(buffer, 0, MEM_RELEASE);
ZeroMemory(&pid, sizeof(pid));
ZeroMemory(&dpath, sizeof(dpath));
return 0;
}