#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <TlHelp32.h>
#include <psapi.h>
#include <conio.h>
#include <iomanip>
DWORD pid = 0;
struct HookData {
DWORD_PTR targetAddr;
BYTE originalBytes[20];
bool installed;
DWORD oldProtect;
DWORD_PTR trampolineAddr;
int overwrittenBytes;
};
HookData g_hookData = { 0 };
HANDLE g_hProcess = NULL;
void realHandler(DWORD eaxValue) {
if (eaxValue == 0) {
printf("Некорректное значение EAX\n");
return;
}
DWORD accessedAddr = eaxValue + 0x60;
printf("Обращаемый адрес: 0x%p\n", (void*)accessedAddr);
}
__declspec(naked) void CppHookHandler() {
__asm {
push ebp
mov ebp, esp
pushad
pushfd
mov eax, [ebp + 8]
call realHandler
popfd
popad
mov eax, [eax + 0x60]
jmp[g_hookData.targetAddr + 5]
pop ebp
ret
}
}
bool ValidateMemory(HANDLE hProcess, DWORD_PTR addr, DWORD size) {
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQueryEx(hProcess, (LPCVOID)addr, &mbi, sizeof(mbi))) {
return false;
}
return mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_EXECUTE);
}
bool CreateTrampoline(HookData* hook) {
if (!ReadProcessMemory(g_hProcess, (LPCVOID)hook->targetAddr,
hook->originalBytes, 20, NULL)) {
printf("Ошибка чтения байтов: %lu\n", GetLastError());
return false;
}
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQueryEx(g_hProcess, (LPCVOID)hook->targetAddr, &mbi, sizeof(mbi))) {
return false;
}
hook->trampolineAddr = (DWORD_PTR)VirtualAllocEx(
g_hProcess, NULL, 128, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!hook->trampolineAddr) {
printf("Ошибка выделения памяти: %lu\n", GetLastError());
return false;
}
BYTE trampoline[128] = { 0 };
int bytesCopied = 0;
for (int i = 0; i < 20; i++) {
trampoline[i] = hook->originalBytes[i];
bytesCopied++;
if (i >= 2 &&
hook->originalBytes[i - 2] == 0x8B &&
hook->originalBytes[i - 1] == 0x40 &&
hook->originalBytes[i] == 0x60) {
break;
}
}
DWORD_PTR returnAddr = hook->targetAddr + bytesCopied;
INT64 returnOffset = (INT64)returnAddr - (INT64)(hook->trampolineAddr + bytesCopied) - 5;
if (abs(returnOffset) > 0x7FFFFFFF) {
printf("Слишком большое смещение для JMP\n");
return false;
}
trampoline[bytesCopied] = 0xE9;
memcpy(&trampoline[bytesCopied + 1], &returnOffset, 4);
if (!WriteProcessMemory(g_hProcess, (LPVOID)hook->trampolineAddr,
trampoline, 128, NULL)) {
return false;
}
hook->overwrittenBytes = bytesCopied;
return true;
}
bool InstallInlineHook(DWORD_PTR targetFunc) {
g_hookData.targetAddr = targetFunc;
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQueryEx(g_hProcess, (LPCVOID)targetFunc, &mbi, sizeof(mbi))) {
printf("Ошибка VirtualQueryEx: %lu\n", GetLastError());
return false;
}
g_hookData.oldProtect = mbi.Protect;
if (!CreateTrampoline(&g_hookData)) {
return false;
}
INT64 offset = (INT64)g_hookData.trampolineAddr - (INT64)targetFunc - 5;
if (abs(offset) > 0x7FFFFFFF) {
printf("Слишком большое смещение: 0x%llX\n", offset);
return false;
}
BYTE patch[5] = { 0xE9 };
memcpy(&patch[1], &offset, 4);
DWORD tempProtect;
if (!VirtualProtectEx(g_hProcess, mbi.BaseAddress, mbi.RegionSize,
PAGE_EXECUTE_READWRITE, &tempProtect)) {
printf("Ошибка VirtualProtectEx: %lu\n", GetLastError());
return false;
}
if (!WriteProcessMemory(g_hProcess, (LPVOID)targetFunc, patch, 5, NULL)) {
printf("Ошибка записи патча: %lu\n", GetLastError());
return false;
}
Sleep(100);
if (!VirtualProtectEx(g_hProcess, mbi.BaseAddress, mbi.RegionSize,
g_hookData.oldProtect, NULL)) {
DWORD error = GetLastError();
if (error == ERROR_NOACCESS) {
printf("Античит блокирует восстановление прав\n");
}
else {
printf("Ошибка восстановления прав: %lu\n", error);
return false;
}
}
g_hookData.installed = true;
printf("Хук установлен на адрес 0x%p\n", (void*)targetFunc);
return true;
}
void RemoveInlineHook() {
if (g_hookData.installed) {
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQueryEx(g_hProcess, (LPCVOID)g_hookData.targetAddr, &mbi, sizeof(mbi))) {
printf("Ошибка получения информации о памяти\n");
return;
}
if (!WriteProcessMemory(g_hProcess, (LPVOID)g_hookData.targetAddr,
g_hookData.originalBytes, g_hookData.overwrittenBytes, NULL)) {
printf("Ошибка восстановления оригинальных байтов\n");
return;
}
if (g_hookData.trampolineAddr) {
VirtualFreeEx(g_hProcess, (LPVOID)g_hookData.trampolineAddr, 0, MEM_RELEASE);
}
g_hookData.installed = false;
printf("Хук удален\n");
}
}
DWORD GetProcId(const char* ProcName) {
PROCESSENTRY32 pe32;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (_stricmp(pe32.szExeFile, ProcName) == 0) {
CloseHandle(hSnapshot);
return pe32.th32ProcessID;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return 0;
}
DWORD_PTR GetModuleBaseAddress(DWORD processId, const char* moduleName) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (!hProcess) return 0;
HMODULE hMods[1024];
DWORD cbNeeded;
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
char szModName[MAX_PATH];
if (GetModuleBaseNameA(hProcess, hMods[i], szModName, sizeof(szModName))) {
if (_stricmp(szModName, moduleName) == 0) {
DWORD_PTR baseAddr = (DWORD_PTR)hMods[i];
CloseHandle(hProcess);
return baseAddr;
}
}
}
}
CloseHandle(hProcess);
return 0;
}
int main() {
setlocale(LC_ALL, "Russian");
const char* processName = "gta_sa.exe";
DWORD instructionOffset = 0x2008BF;
printf("Ищем процесс: %s\n", processName);
pid = GetProcId(processName);
if (pid == 0) {
printf("Процесс не найден!\n");
return 1;
}
g_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!g_hProcess) {
printf("Не удалось открыть процесс\n");
return 1;
}
DWORD_PTR baseAddr = GetModuleBaseAddress(pid, processName);
if (baseAddr == 0) {
printf("Не удалось получить базовый адрес\n");
CloseHandle(g_hProcess);
return 1;
}
DWORD_PTR targetAddr = baseAddr + instructionOffset;
printf("Базовый адрес: 0x%p\n", (void*)baseAddr);
printf("Целевой адрес: 0x%p\n", (void*)targetAddr);
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQueryEx(g_hProcess, (LPCVOID)targetAddr, &mbi, sizeof(mbi))) {
printf("Информация о регионе:\n");
printf(" BaseAddress: 0x%p\n", mbi.BaseAddress);
printf(" RegionSize: %lu байт\n", mbi.RegionSize);
printf(" Protect: 0x%lx\n", mbi.Protect);
printf(" State: 0x%lx\n", mbi.State);
}
if (!InstallInlineHook(targetAddr)) {
printf("Не удалось установить хук\n");
CloseHandle(g_hProcess);
return 1;
}
printf("Хук установлен. Ожидание...\n");
while (true) {
if (_kbhit()) {
int ch = _getch();
if (ch == '\r' || ch == '\n') {
break;
}
}
Sleep(100);
}
RemoveInlineHook();
CloseHandle(g_hProcess);
printf("Программа завершена\n");
return 0;
}