Содержание статьи
Другие статьи цикла о написании читов
Античит
Итак, античит — это некая программа, которая мешает игрокам в онлайновые игры получать нечестное преимущество за счет использования стороннего ПО. Не буду пытаться объяснить это на абстрактном примере, лучше давай сразу перейдем к практике. По дороге все поймешь!
Quick Universal Anti-Cheat Kit
Так как нет (или я просто не нашел) античитов уровня ядра с открытым исходным кодом, то выбирать будем из опенсорсных античитов, в которых присутствует только античит пользовательского уровня. Мой выбор пал на античит Quick Universal Anti-Cheat Kit (далее Quack).
Сразу предупреждаю, что Quack — это лишь простенькая опенсорсная демонстрация концепции. Обойти ее проще, чем системы, которые используются в популярных играх. Все коммерческие античиты работают как на пользовательском уровне, так и на уровне ядра. Причем самые важные защитные функции обычно реализованы именно в виде драйвера.
Однако для обучения Quack сгодится как нельзя лучше, и изложенное дальше должно стать фундаментом для будущих изысканий.
warning
Статья имеет ознакомительный характер и предназначена для оценки защищенности кода игр. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Обратная разработка античитов нарушает пользовательские соглашения игр, поэтому, повторяя описанное в этой статье на практике, ты действуешь на свой страх и риск!
Архитектура Quack
Давай посмотрим на общую архитектуру античита глазами ее автора. Далее я объясню, для чего нужен каждый выделенный на схеме компонент.

Зеленым цветом я выделил клиентскую часть (то, что будет работать на компьютере игрока):
- Protected video game — игра, которую мы запускаем на своем компьютере и которую будет защищать античит;
- Anti-cheat .DLL — пользовательская часть античита, DLL, которая существует в контексте созданного процесса игры и которая отвечает за защиту памяти процесса игры;
- Standalone usermode anti-cheat process — пользовательская часть античита. Это главный модуль античита (оркестратор), который общается с пользовательской и ядерной частями, а также держит связь с сервером античита;
- Kernel mode anti-cheat — ядерная часть античита. Отвечает за защиту двух других модулей античита. Не реализовано.
Синим цветом я выделил серверную часть (то, что будет работать вне компьютера игрока):
- Master server — отвечает за хранение учетной записи игрока и управление ею;
- Game server — отвечает за отслеживание состояния элементов в игре, а также местоположения игроков и врагов на карте;
- Anti-cheat database — база данных игроков.
Настраиваем Quack
Если после развертывания Quack (как это сделать, смотри в руководстве на GitHub и на YouTube) у тебя ничего работает, то советую повнимательнее изучить следующие файлы и настроить сетевые адреса и порты в соответствии с реальными условиями.
GameDevCAServer\Program.cs
var settings = MongoClientSettings.FromConnectionString(env["DB_URI"]);settings.ServerApi = new ServerApi(ServerApiVersion.V1);var mongoClient = new MongoClient(settings);database = mongoClient.GetDatabase(env["DB_NAME"]);
Quack-server\src\main.js
class Config { static DB_URI = process.env.DB_URI static DB_NAME = process.env.DB_NAME static PORT = process.env.PORT static CLIENT = new MongoClient(this.DB_URI) static DEV_MODE = true static VERSION = process.env.npm_package_version}
Quack-internal\constants.hpp
namespace constants { const LPCWSTR W_DLL_NAME { L"Quack-internal" }; const LPCSTR DLL_NAME{ "Quack-internal" }; const std::string VERSION { "0.6.5" }; constexpr unsigned IPC_PORT = 5175; // Local machine communications port constexpr unsigned NET_PORT = 7982; // Foreign network communications port static constexpr bool DBG = false;}
Quack-client\constants.hpp
namespace constants { const std::string VERSION{ "0.4.2" }; const std::string NAME{ "Quack" }; constexpr unsigned IPC_PORT = 5175; // Local machine communications port constexpr unsigned NET_PORT = 7982; // Foreign network communications port static constexpr bool DBG = false;}
Quack-client\flashpoint.cpp
http::Client cli{ "localhost", constants::NET_PORT };
Проверяем работоспособность Quack
Для начала нам нужно убедиться в том, что все работает. Для этого так же, как и автор античита, будем использовать его игру Inertia, инжектор Destroject и внутренний чит Inertia-cheat. Подключимся к серверу по адресу lh (localhost) с ником xakep0.

В консоли игрового сервера видим, что произошло подключение.

Также в базе данных античита видим, что появилась запись.

Начинаем тест. Для этого в командной строке выполним Destroject.
(не забыв рядом положить Inertia-cheat.
). Видим, что инжект чита успешно выполнен.

Активируем чит нажатием клавиши E.

Видим, что чит активирован, но сразу же происходит бан.

Посмотрев в БД античита, мы можем узнать, из‑за чего нас забанили.

Пробуем сменить никнейм, но нас все равно не пускают.

Если попытаться открыть Cheat Engine, он через пару секунд закроется, но бан не прилетит.
Unity
Прежде чем расчехлять IDA Pro и приступать к реверсу античита, сделаем небольшое отступление. Если ты уже заглянул в код чита, то мог заметить следующий участок:
Inertia-cheat\player.cpp
std::optional<Player> GetPlayer() { auto start_point = reinterpret_cast<std::uintptr_t>(GetModuleHandleA("UnityPlayer.dll")); start_point += offsets::player.start_point; // Get a pointer to health const auto health_ptr = TraverseChain(start_point, offsets::player.ptr_chain).value_or(0u); if (!health_ptr) return std::nullopt; const auto ammo_ptr = health_ptr - 0x4; const Player player{ .health = reinterpret_cast<std::int32_t*>(health_ptr), .ammo = reinterpret_cast<std::int32_t*>(ammo_ptr) }; return player;}
Здесь стоит обратить внимание на строчку "UnityPlayer.
. Дело в том, что игра написана на движке Unity.
Inertia-cheat\data.cpp
namespace offsets { PointerChain player = { .start_point = 0x13A1340, .ptr_chain { 0xC2C, 0xDC8, 0xEA8, 0x18, 0x38 } };}
Также мы имеем цепочку указателей для UnityPlayer.
. Откроем ее в IDA Pro по адресу base+0x13A1340
. Видим, что здесь размещено значение переменной из стека и дальше поиск класса игрока идет в стеке.

Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»