Привет! В этой статье, мы поговорим о создании читов. ВНИМАНИЕ: Данная статья не призывает к нарушению закона, а предоставляет информацию для общего развития. Автор не несёт ответственности за ваши действия. Любого рода значения хранятся в оперативной памяти. Читы внедряются в память другого процесса и изменяют определёные значения по определёному адресу. Если чит создан для online-игры, то он внедряется в сетевой протокол и особым образом изменяет его. В этой статье мы поговорим исключительно о читах для offline игр. Есть 2 основных метода взаимодействия чита с оперативной памятью, это из вне процесса и из самого процесса. Мы рассмотрим только метод из вне. Другой пожалуй, рассмотрим в следующей части. Как я сказал выше, любого рода значения хранятся в оперативной памяти, наша задача изменить это значение на нужное нам. Чтобы внедряться в память другого процесса есть специальное WinAPI, оно носит название "OpenProcess". Ниже я написал небольшой шаблон, если вы его модифицируете под себя, то получите полноценный чит. /*Библиотеки*/ #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <tlhelp32.h> /*Прототипы функций*/ int initialization(void); //Функция инициализации. void modificate(HANDLE, bool); //Функция, которая заменяет значения. int errExit(int); //Функция выхода с ошибкой. DWORD GetModuleBase(LPSTR, DWORD); //Вспомогататльная функция получения реального адреса ячейки. int main(void){ HANDLE process = initialization(void); //Инициализация modificate(process, /*TRUE если адрес значения статичен, т.е. при каждом запуске один и тот же, а FALSE, если адрес динамичен. Предположим, что адрес статичен. */ TRUE); return(0); } HANDLE initialization(void){ HWND headW; HANDLE process; DWORD pid; headW = FindWindowA(NULL, "Заголовок окна игры"); //Получаем окно игры. GetWindowThreadProcessId(headW, &pid); //Получаем pid игры. if(pid == NULL) //Если ошибка, то выход с ошибкой. errExit(1); process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //Получаем доступ записи в процесс. if(process == NULL) //Если ошибка, то выход с ошибкой. errExit(2); return(process); //Возвращаем ссылку на процесс. } void modificate(HANDLE process, bool is_static){ int PatchMoney = 999999; //Количество необходимых нам денег. if(is_static == TRUE){ //Если включён статический режим, то именяем значение. WriteProcessMemory(process, (LPCVOID)(/*Адрес до ячейки. Предположим, что он 0x12345678.*/0x12345678), &PatchMoney, 4, NULL); } else if(is_static == FALSE){ //Если включён динамический способ, то изменяем значение другим способом. WriteProcessMemory(process, (LPCVOID)(GetModuleBase("/*Точка отсчёта смещения. Предположим, что это MoneyModule.dll.*/MoneyModule.dll", pid ) + /*Смещение. Предположим, что оно 0x12345678.*/ 0x12345678), &PatchMoney, 4, NULL); } } int errExit(int code){ if(code == 1){//Если код ошибки 1, то выводим ошибку. printf( "[-] Error! Cannot to get pid of the game.\n"); exit(1); } else if(code == 2){ printf("[-] Error! Cannot to get access to the process.\n"); exit(2); } } Код /*Библиотеки*/ #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <tlhelp32.h> /*Прототипы функций*/ int initialization(void); //Функция инициализации. void modificate(HANDLE, bool); //Функция, которая заменяет значения. int errExit(int); //Функция выхода с ошибкой. DWORD GetModuleBase(LPSTR, DWORD); //Вспомогататльная функция получения реального адреса ячейки. int main(void){ HANDLE process = initialization(void); //Инициализация modificate(process, /*TRUE если адрес значения статичен, т.е. при каждом запуске один и тот же, а FALSE, если адрес динамичен. Предположим, что адрес статичен. */ TRUE); return(0); } HANDLE initialization(void){ HWND headW; HANDLE process; DWORD pid; headW = FindWindowA(NULL, "Заголовок окна игры"); //Получаем окно игры. GetWindowThreadProcessId(headW, &pid); //Получаем pid игры. if(pid == NULL) //Если ошибка, то выход с ошибкой. errExit(1); process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //Получаем доступ записи в процесс. if(process == NULL) //Если ошибка, то выход с ошибкой. errExit(2); return(process); //Возвращаем ссылку на процесс. } void modificate(HANDLE process, bool is_static){ int PatchMoney = 999999; //Количество необходимых нам денег. if(is_static == TRUE){ //Если включён статический режим, то именяем значение. WriteProcessMemory(process, (LPCVOID)(/*Адрес до ячейки. Предположим, что он 0x12345678.*/0x12345678), &PatchMoney, 4, NULL); } else if(is_static == FALSE){ //Если включён динамический способ, то изменяем значение другим способом. WriteProcessMemory(process, (LPCVOID)(GetModuleBase("/*Точка отсчёта смещения. Предположим, что это MoneyModule.dll.*/MoneyModule.dll", pid ) + /*Смещение. Предположим, что оно 0x12345678.*/ 0x12345678), &PatchMoney, 4, NULL); } } int errExit(int code){ if(code == 1){//Если код ошибки 1, то выводим ошибку. printf( "[-] Error! Cannot to get pid of the game.\n"); exit(1); } else if(code == 2){ printf("[-] Error! Cannot to get access to the process.\n"); exit(2); } } А как получить эти самые адреса и смещения? Запускаем Cheat Engine и ищем адрес значения, которое мы и будет менять. Если адрес зелёный, то он статичен. Если адрес динамичен, то нажимаем двойным кликом по нему и получаем что-то похожее на это "*.dll" + 0x11223344. Вот эту "*.dll" в коде выше нужно вствить вместо MoneyModule.dll, а 0x11223344 нужно вставить вместо 0x12345678. Ну, на этом всё. Спасибо за внимание.