Содержание статьи
Другие статьи цикла о написании читов
Античит
Итак, античит — это некая программа, которая мешает игрокам в онлайновые игры получать нечестное преимущество за счет использования стороннего ПО. Не буду пытаться объяснить это на абстрактном примере, лучше давай сразу перейдем к практике. По дороге все поймешь!
Quick Universal Anti-Cheat Kit
Так как нет (или я просто не нашел) античитов уровня ядра с открытым исходным кодом, то выбирать будем из опенсорсных античитов, в которых присутствует только античит пользовательского уровня. Мой выбор пал на античит Quick Universal Anti-Cheat Kit (далее Quack).
Сразу предупреждаю, что Quack — это лишь простенькая опенсорсная демонстрация концепции. Обойти ее проще, чем системы, которые используются в популярных играх. Все коммерческие античиты работают как на пользовательском уровне, так и на уровне ядра. Причем самые важные защитные функции обычно реализованы именно в виде драйвера.
Однако для обучения Quack сгодится как нельзя лучше, и изложенное дальше должно стать фундаментом для будущих изысканий.
warning
Статья имеет ознакомительный характер и предназначена для оценки защищенности кода игр. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Обратная разработка античитов нарушает пользовательские соглашения игр, поэтому, повторяя описанное в этой статье на практике, ты действуешь на свой страх и риск!
Архитектура Quack
Давай посмотрим на общую архитектуру античита глазами ее автора. Далее я объясню, для чего нужен каждый выделенный на схеме компонент.
![Архитектура Quack Архитектура Quack](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35948/1-quack-architecture-info.png)
Зеленым цветом я выделил клиентскую часть (то, что будет работать на компьютере игрока):
- 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.
![Подключение к игровому серверу Подключение к игровому серверу](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35945/2-inertia-connect.png)
В консоли игрового сервера видим, что произошло подключение.
![Лог игрового сервера Лог игрового сервера](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35943/3-game-server-connect.png)
Также в базе данных античита видим, что появилась запись.
![База данных античита База данных античита](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35916/4-ac-databes-first-start.png)
Начинаем тест. Для этого в командной строке выполним Destroject.
(не забыв рядом положить Inertia-cheat.
). Видим, что инжект чита успешно выполнен.
![Внедренный чит Внедренный чит](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35947/5-test-cheat-injected.png)
Активируем чит нажатием клавиши E.
![Активированный чит Активированный чит](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35946/6-test-cheat-injected-on.png)
Видим, что чит активирован, но сразу же происходит бан.
![Сообщение о бане в игре Сообщение о бане в игре](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35942/7-ban-test.png)
Посмотрев в БД античита, мы можем узнать, из‑за чего нас забанили.
![Сообщение о бане в БД Сообщение о бане в БД](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35915/8-ac-ban.png)
Пробуем сменить никнейм, но нас все равно не пускают.
![Попытка смены ника Попытка смены ника](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35941/9-change-nick.png)
Если попытаться открыть 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
. Видим, что здесь размещено значение переменной из стека и дальше поиск класса игрока идет в стеке.
![UnityPlayer.dll без загруженных отладочных символов UnityPlayer.dll без загруженных отладочных символов](https://static.xakep.ru/images/b0021e10df5515e32b3a20e2693767bc/35936/10-unityplayer-before-pdb.png)
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее