Код
#define _CRT_SECURE_NO_WARNINGS
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <cstdlib>
#include <Windows.h>
#include <tlhelp32.h>
#define PROCESS_NAME "MetroExodus.exe"
struct ReaderData
{
int FileDescriptor;
long FilePointer;
long FileLength;
};
BYTE *FindTargetFunctionAddress(BYTE *mem, INT length)
{
CONST BYTE pattern[] =
{
'\x83', '\xEC', '\x20', '\x48', '\x89', '\xD6', '\x41', '\xF7',
'\xD8', '\x48', '\x89', '\xCB', '\x48', '\x89', '\xF1', '\x19',
'\xFF', '\x83', '\xE7', '\x20', '\x0F', '\xBA', '\xEF', '\x0F',
'\x89', '\xFA', '\xFF', '\x15', '\xB4', '\xF9', '\x6A', '\x04',
'\x89', '\x03', '\x83', '\xF8', '\xFF', '\x75', '\x35', '\xFF',
'\x15', '\x1F', '\xF9', '\x6A', '\x04', '\x83', '\x38', '\x02',
};
INT i, j;
CONST INT count = sizeof(pattern);
for (i = 0; i <= length - count; ++i)
{
for (j = 0; j < count; ++j)
{
if (mem[i + j] != pattern[j])
{
break;
}
}
if (j == count)
{
return mem + i;
}
}
return NULL;
}
LPVOID GetTargetFunctionAddress()
{
MODULEENTRY32 entry = MODULEENTRY32();
entry.dwSize = sizeof(MODULEENTRY32);
HANDLE hProcess = GetCurrentProcess();
DWORD processId = GetProcessId(hProcess);
HANDLE hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
if (Module32First(hModuleSnapshot, &entry) == FALSE)
{
return NULL;
}
do
{
if (strcmp(entry.szModule, PROCESS_NAME) == 0)
{
return FindTargetFunctionAddress(entry.modBaseAddr, entry.modBaseSize);
}
}
while (Module32Next(hModuleSnapshot, &entry) == TRUE);
return NULL;
}
void Metro_OpenFile(ReaderData *reader, const char *path)
{
int fd = _open(path, _O_BINARY, 0);
if (fd == -1)
{
if (errno == ENOENT)
{
return;
}
Sleep(10);
fd = _open(path, _O_BINARY, 0);
if (fd == -1)
{
return;
}
}
long length = _filelength(fd);
if (length == -1)
{
_close(fd);
return;
}
reader->FileDescriptor = fd;
reader->FileLength = length;
}
BOOL SetHook(LPVOID address, LPVOID detour)
{
DWORD oldProtection;
CONST SIZE_T length = 32;
CONST DWORD64 offset = reinterpret_cast<DWORD64>(detour) - reinterpret_cast<DWORD64>(address) - 9;
if (VirtualProtect(address, length, PAGE_EXECUTE_READWRITE, &oldProtection) != TRUE)
{
return NULL;
}
memset(address, 0x90, length);
CHAR *p = reinterpret_cast<CHAR*>(address);
*reinterpret_cast<BYTE*>(p++) = 0xEB;
*reinterpret_cast<DWORD64*>(p) = offset;
VirtualProtect(address, length, oldProtection, &oldProtection);
return TRUE;
}
INT RoutineItself(LPVOID)
{
LPVOID detour = Metro_OpenFile;
LPVOID target = GetTargetFunctionAddress();
if (target == NULL)
{
std::abort();
}
if (SetHook(target, detour) == FALSE)
{
return ERROR_INVALID_FUNCTION;
}
return ERROR_SUCCESS;
}
bool StartRoutine()
{
if (HANDLE hThread = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(RoutineItself), 0, 0, NULL))
{
return true;
}
return false;
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_ATTACH:
if (!StartRoutine())
{
return FALSE;
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}