#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#pragma warning(disable : 4244)
#pragma warning(disable : 4005)
#pragma warning(disable : 4477)
#pragma warning(disable : 4311)
#pragma warning(disable : 4302)
#pragma warning(disable : 4313)
#include <Windows.h>
#include <stdio.h>
#include <map>
#include <winternl.h>
#define ADD_RVA true
using namespace std;
typedef HHOOK(__stdcall *NtUserSetWindowsHookExP)(HINSTANCE Mod, PUNICODE_STRING UnsafeModuleName, DWORD ThreadId,
INT HookId, PVOID HookProc, BOOL Ansi);
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))
#define GetImgDirEntryRVA( pNTHdr, IDE ) \
(pNTHdr->OptionalHeader.DataDirectory[IDE].VirtualAddress)
#define GetImgDirEntrySize( pNTHdr, IDE ) \
(pNTHdr->OptionalHeader.DataDirectory[IDE].Size)
LPVOID GetSectionPtr(PSTR name, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
for (unsigned i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++)
{
if (strncmp((char *)section->Name, name, IMAGE_SIZEOF_SHORT_NAME) == 0)
return (LPVOID)(section->PointerToRawData + imageBase);
}
return 0;
}
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
for (unsigned i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++)
{
if ((rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + section->Misc.VirtualSize))) return section;
}
return 0;
}
LPVOID GetPtrFromRVA(DWORD rva, PIMAGE_NT_HEADERS pNTHeader, DWORD imageBase)
{
PIMAGE_SECTION_HEADER pSectionHdr; INT delta;
pSectionHdr = GetEnclosingSectionHeader(rva, pNTHeader);
if (!pSectionHdr) return 0;
delta = (INT)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
return (PVOID)(imageBase + rva - delta);
}
DWORD DumpExportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader, const char *func)
{
PIMAGE_EXPORT_DIRECTORY exportDir; PIMAGE_SECTION_HEADER header;
INT delta; PSTR filename; DWORD i; PDWORD functions; PWORD ordinals; PSTR *name;
DWORD exportsStartRVA, exportsEndRVA;
exportsStartRVA = GetImgDirEntryRVA(pNTHeader, IMAGE_DIRECTORY_ENTRY_EXPORT);
exportsEndRVA = exportsStartRVA + GetImgDirEntrySize(pNTHeader, IMAGE_DIRECTORY_ENTRY_EXPORT);
header = GetEnclosingSectionHeader(exportsStartRVA, pNTHeader);
if (!header) return 0;
delta = (INT)(header->VirtualAddress - header->PointerToRawData);
exportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, base, exportsStartRVA - delta);
filename = (PSTR)(exportDir->Name - delta + base);
functions = (PDWORD)((DWORD)exportDir->AddressOfFunctions - delta + base);
ordinals = (PWORD)((DWORD)exportDir->AddressOfNameOrdinals - delta + base);
name = (PSTR *)((DWORD)exportDir->AddressOfNames - delta + base);
for (i = 0; i < exportDir->NumberOfFunctions; i++)
{
DWORD entryPointRVA = functions[i]; DWORD j;
if (entryPointRVA == 0) continue;
for (j = 0; j < exportDir->NumberOfNames; j++)
{
if (ordinals[j] == i)
{
char fname[55]; sprintf(fname, "%s", name[j] - delta + base);
if (strstr(fname, func) != 0) return entryPointRVA;
}
}
}
return 0;
}
DWORD GetExportAddress(const char *module, const char *function, bool add_rva = false)
{
decltype(auto) ReturnSystemPath = [](const char *dllname)
{
BOOL bIsWow64 = FALSE; char syspath[256];
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
if (NULL != fnIsWow64Process)
{
if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {}
}
sprintf(syspath, "C:\\Windows\\%s\\%s", (bIsWow64 ? "SysWOW64" : "System32"), dllname);
return string(syspath);
};
auto getFileSize = [](FILE *file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
};
FILE *hFile = fopen(ReturnSystemPath(module).c_str(), "rb");
BYTE *fileBuf; long fileSize;
fileSize = getFileSize(hFile);
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, hFile);
fclose(hFile);
PIMAGE_NT_HEADERS pNTHeader;
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)fileBuf;
DWORD base = (DWORD)dosHeader;
pNTHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew);
DWORD funcAddr = 0;
if (add_rva) funcAddr = ((DWORD)GetModuleHandleA(module) + DumpExportsSection(base, pNTHeader, function));
else funcAddr = DumpExportsSection(base, pNTHeader, function);
delete[] fileBuf; return funcAddr;
}
namespace LibCall
{
DWORD __stdcall GetSafeAddress(const char* dllname, const char* func_name, DWORD *syscall, bool prologue = true)
{
decltype(auto) ReturnSystemPath = [](const char *dllname)
{
BOOL bIsWow64 = FALSE; char syspath[256];
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
if (NULL != fnIsWow64Process)
{
if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {}
}
sprintf(syspath, "C:\\Windows\\%s\\%s", (bIsWow64 ? "SysWOW64" : "System32"), dllname);
return string(syspath);
};
auto getFileSize = [](FILE *file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
};
FILE *hFile = fopen(ReturnSystemPath(dllname).c_str(), "rb");
BYTE *fileBuf; long fileSize;
fileSize = getFileSize(hFile);
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, hFile);
fclose(hFile); char newname[256];
sprintf(newname, "proxy_%s", dllname);
hFile = fopen(newname, "wb");
fwrite(fileBuf, 1, fileSize, hFile);
delete[] fileBuf; fclose(hFile);
LoadLibraryExA(newname, 0, DONT_RESOLVE_DLL_REFERENCES);
HMODULE BaseAddress = GetModuleHandleA(newname);
DWORD FuncAddr = (DWORD)GetExportAddress(dllname, func_name, ADD_RVA);
if (syscall != nullptr)
{
DWORD oldP; VirtualProtect((void*)FuncAddr, 4, PAGE_EXECUTE_READWRITE, &oldP);
DWORD RVA = (DWORD)GetExportAddress(dllname, func_name);
memcpy(syscall, (void*)((RVA + (DWORD)BaseAddress) + 0x1), 1);
VirtualProtect((void*)FuncAddr, 4, oldP, &oldP);
}
if (!prologue) FuncAddr += 0x5;
FreeLibrary(BaseAddress); DeleteFileA(newname);
return FuncAddr;
}
constexpr DWORD SYSCALL_SIZE = 15;
DWORD __stdcall CreateSystemCall(const char *procedure)
{
PVOID delegate = VirtualAlloc(0, SYSCALL_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
DWORD service_number = 0x0, service_address = GetSafeAddress("ntdll.dll", procedure, &service_number, true);
memcpy(delegate, (void*)service_address, 15);
BYTE instruction[5] = { 0xB8, 0x00, 0x00, 0x00, 0x00 };
memcpy(&instruction[1], &service_number, 4);
memcpy(delegate, instruction, 5);
memcpy((void*)((DWORD)delegate + 0x5), (void*)(service_address + 0x5), 5);
return (DWORD)delegate;
}
bool __stdcall DestroySystemCall(DWORD address)
{
return VirtualFree((void*)address, 0, MEM_RELEASE);
}
}
void __stdcall EntryPoint()
{
auto GetProcessIdAndTid = []() -> map<DWORD, DWORD>
{
DWORD procID = NULL, TID = NULL;
for (HWND hwnd = 0; hwnd < (HWND)20000000; hwnd++)
{
char strQ[256]; memset(strQ, 0, sizeof(strQ));
GetWindowTextA(hwnd, strQ, 256);
if (strstr(strQ, "San Andreas Multiplayer 0.3.7") != nullptr)
{
TID = GetWindowThreadProcessId(hwnd, &procID);
if (procID != 0) break;
}
}
return map<DWORD, DWORD> { pair<DWORD, DWORD>(procID, TID) };
};
map<DWORD, DWORD> ProcessData = GetProcessIdAndTid();
HMODULE dll = LoadLibraryExA("test.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
if (dll == nullptr) return;
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "NextHook");
if (addr == nullptr) return;
NtUserSetWindowsHookExP NtUserSetWindowsHookEx = (NtUserSetWindowsHookExP)
GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserSetWindowsHook");
typedef void(__stdcall *RtlInitUnicodeStringP)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
RtlInitUnicodeStringP RtlInitUnicodeString = (RtlInitUnicodeStringP)
LibCall::CreateSystemCall("RtlInitUnicodeString");
for (const auto& it : ProcessData)
{
UNICODE_STRING strZ; RtlInitUnicodeString(&strZ, L"test.dll");
HHOOK HookEx = NtUserSetWindowsHookEx(dll, &strZ, it.second, WH_GETMESSAGE, addr, 1);
if (HookEx != nullptr)
{
PostThreadMessageA(it.second, WM_NULL, NULL, NULL);
}
}
LibCall::DestroySystemCall((DWORD)RtlInitUnicodeString);
}
int __stdcall DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)EntryPoint, 0, 0, 0);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return 1;
}