Привет, сегодня мы создадим наш первый External-чит для ксго. Создавать мы будем вх, так как вх - идеален, чтобы рассматривать его как основу. Я постараюсь расписать все максимально понятно и по шагам, чтобы вы поняли как что работает, а не просто спастили код и ничему не научились.
Итак, приступим.
1. Создаем простой C++ проект в Visual Studio.
2. Создаем файл
main.cpp, здесь и будет весь наш код.
3. Пишем в начало файла следующий код:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <thread>
здесь мы подключили нужные библиотеки для работы, если у вас какой-то нет, то скачайте или подключите через параметры проекта (можете посмотреть в интернете уроки, если не знаете, как это делать, их полно).
4. Теперь самое время сделать переменные с оффсетами. Почему именно переменные? Да потому что их легко обновлять, и не нужно лазить по всему коду и вспоминать, какой оффсет для чего и где.
const DWORD dwLocalPlayer = 0xCBD6A4;
const DWORD dwEntityList = 0x4CCDCBC;
const DWORD m_iTeamNum = 0xF4;
const DWORD m_iGlowIndex = 0xA3F8;
const DWORD dwGlowObjectManager = 0x520DAE0;
разберем каждое ключевое слово в коде:
const - мы делаем именно константы (не переменные), чтобы им нельзя было присвоить другие значения, кроме тех, которые мы уже задали.
DWORD - класс. Переменные имеют тип экземляра именно класса DWORD.
5. Сейчас мы определим переменные, с которыми мы будем работать на протяжении всего написания чита.
HANDLE process; // непосредственно сам процесс CSGO
DWORD clientBase; // клиентская часть
DWORD engineBase; // игровая часть (движок)
Мы объявили необходимые переменные, комментарии, обозначающие "что зачем и почему" я написал в самом коде.
6. Что же, теперь приступим к написанию нашего чита непосредственно.
Первое, что нам нужно - это возможность включать или выключать те или иные функции (в нашем случае - вх).
Если вы подумали о переменной типа boolean, определяющей статус функции - вы правы.
Мы объявили переменную, которая определяет статус функции, по умолчание вх выключено, значит значение переменной false.
7. Так как мы создаем External-чит, нам нужно читать память и изменять ее.
Добавим следующий код, необходимый нашему читу. Что и зачем расскажу по ходу дела.
DWORD getModuleBaseAddress(DWORD pid, const char* name)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
MODULEENTRY32 mEntry;
mEntry.dwSize = sizeof(MODULEENTRY32);
do
{
if (!strcmp(mEntry.szModule, name))
{
CloseHandle(snapshot);
return (DWORD)mEntry.modBaseAddr;
}
} while (Module32Next(snapshot, &mEntry));
}
данный код находит в нашей оперативной памяти именно то приложение, которое нам нужно (по его id - pid, который передается функции).
template <typename T>
T readMem(DWORD address)
{
T buffer;
ReadProcessMemory(process, (LPVOID)address, &buffer, sizeof(buffer), 0);
return buffer;
}
template <typename T>
void writeMem(DWORD address, T value)
{
WriteProcessMemory(process, (LPVOID)address, &value, sizeof(value), 0);
}
эти стандартные функции читают и пишут память, именно с помощью них мы будем взаимодействовать с игрой.
8. Теперь создадим входную точку, без которой не будет работать ни одно приложение C++. Это int main().
int main() {
SetConsoleTitle("Top non-pasted shit 1337"); // устанавливаем заголовок нашей консоли
std::cout << "Open CS:GO\n"; // выводим в консоль сообщение о том, что надо открыть ксго
HWND hwnd;
do {
hwnd = FindWindowA(0, "Counter-Strike: Global Offensive"); // ищем ксго, если находим - выходим из цикла
Sleep(50); // таймаут (чтобы не грузить процессор)
} while (!hwnd);
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid); // получаем id приложения
process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // заходим в кс го его id
std::cout << "Csgo started, pid " << pid << ".\n"; // выводим сообщение о том, что ксго запущена
do {
clientBase = getModuleBaseAddress(pid, "client_panorama.dll"); // ищем клиент кс го
Sleep(50);
} while (!clientBase);
do {
engineBase = getModuleBaseAddress(pid, "engine.dll"); // ищем движок кс го
Sleep(50);
} while (!engineBase);
}
весь код с комментариями, его нам еще придется обновлять. Что мы в нем сделали? Мы нашли ксго, интегрировали чит с игрой, получили необходимые базы (клиент и движок).
9. Теперь пора создать сам вх. Создадим метод (пусть будет wallhack())
void wallhack()
{
while (true) // создаем бесконечный цикл
{
Sleep(10); // таймаут 10 мс, чтобы не грузить процессор под 100
if (!wallhack && !readMem<DWORD>(readMem<DWORD>(clientBase + dwLocalPlayer) + 0xED)) // если вх выключено или не удается прочитать память - выходим из цикла
continue;
DWORD glowObj = readMem<DWORD>(clientBase + dwGlowObjectManager); // создаем объект glowObj из модельки игрока
DWORD myTeam = readMem<DWORD>(readMem<DWORD>(clientBase + dwLocalPlayer) + m_iTeamNum); // создаем объект тиммейтов
for (int x = 0; x < 32; x++) // сам вх
{
DWORD player = readMem<DWORD>(clientBase + dwEntityList + x * 0x10); // обычный игрок
if (player == 0)
continue;
bool dormant = readMem<bool>(player + 0xED); // спектатор
if (dormant)
continue;
DWORD team = readMem<DWORD>(player + m_iTeamNum); // тиммейт
if (team != 2 && team != 3)
continue;
DWORD currentGlowIndex = readMem<DWORD>(player + m_iGlowIndex); // текущий индекс игрока
if (team != myTeam) // если игрок не тиммейт
{
// делаем его обводку красным
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x4, 255); // red
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x8, 0); // green
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0xC, 0); // blue
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x10, 255);
writeMem<bool>(glowObj + currentGlowIndex * 0x38 + 0x24, true);
writeMem<bool>(glowObj + currentGlowIndex * 0x38 + 0x25, false);
}
else // если игрок тиммейт
{
// делаем его обводку синим
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x4, 0); // red
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x8, 0); // green
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0xC, 255); // blue
writeMem<float>(glowObj + currentGlowIndex * 0x38 + 0x10, 255);
writeMem<bool>(glowObj + currentGlowIndex * 0x38 + 0x24, true);
writeMem<bool>(glowObj + currentGlowIndex * 0x38 + 0x25, false);
}
}
}
}
10. Теперь нам нужно где-то вызывать наш метод. Конечно же в main()!
Теперь вызовем наш метод:
std::thread whThread(wallhack)
И создадим в нашем главном методе бесконечный цикл.
while(true)
{
if (GetAsyncKeyState(VK_F9)) // если нажали f9
{
wh = !wh; // заменяем значение переменной на противоположное
if (wh)
std::cout("wh: on\n"); // если wallhack - true, то пишем, что вх включен
else
std::cout("wh: off\n"); // иначе пишем, что вх выключен
Sleep(100); // таймаут, чтобы сбросить нагрузку
}
}
Вроде все, спасибо за внимание