Содержание статьи
info
В предыдущей статье «Чит своими руками. Вскрываем компьютерную игру и пишем трейнер на C++» я заложил базу для будущих читов и объяснил основные понятия. Рекомендую ознакомиться с ней, чтобы лучше понимать, что мы будем сегодня делать.
Выбор игры
Мой выбор пал на AssaultCube — бесплатный многопользовательский шутер от первого лица, основанный на движке CUBE. Используется графическая библиотека OpenGL.
warning
Использование читов нарушает пользовательское соглашение игры и может повлечь юридическое преследование. Мы обсуждаем здесь создание чита исключительно в целях обучения. Автор и редакция не несут ответственности за возможные последствия применения и распространения такого ПО.
Поиск значений
Для начала запустим игру и в настройках выберем оконный режим, ведь нам нужно, чтобы на экране помещалось еще что‑то, кроме игры.
Также создадим локальный сервер. Нужно будет настроить его, а именно задать время игры, чтобы таймер не торопил нас. Конфиг лежит по следующему пути:
C:\Program Files (x86)\AssaultCube 1.3.0.2\config\maprot.cfg
Поменяем время на максимальное — 100 минут.
А после уже запускаем сам сервер.
И подключаемся к нему.
Запускаем Cheat Engine и подключаемся к процессу игры.
Поиск показателя здоровья
Для тестирования нам понадобится второй игрок. Можешь подключиться со второго устройства или, как сделал я, из виртуальной машины. Для поиска показателя здоровья выставляем параметры сканирования в Cheat Engine и вторым игроком наносим урон первому. После этого ищем здоровье в Cheat Engine.
Будем наносить урон до тех пор, пока не найдем адрес, по которому хранится показатель здоровья нашего игрока.
На этом все знакомые по прошлой статье действия в Cheat Engine заканчиваются и начинаются новые. Наша цель — реализовать extrasensory perception и aimbot. Для этого нам нужно узнать класс игрока и его статический адрес. Чтобы найти класс, кликаем правой кнопкой мыши по нашему адресу и выбираем Find out what writes to this address (можно просто нажать F6).
Появится новое окно, где будут отображаться инструкции, которые производят запись по нашему адресу. Чтобы они появились, снова наносим урон вторым игроком первому.
Показатель здоровья записывает всего одна инструкция, она расположена по смещению 0xEC
. Значит, значение, хранящееся в регистре edx
, — это адрес класса игрока (но адрес в куче, а не статический). Поэтому добавим его вручную.
Поиск статического адреса объекта игрока
В прошлый раз я использовал отладчик, чтобы наглядно показать, что собой представляет статический адрес. В этот раз для поиска статического адреса мы будем использовать Cheat Engine. Жмем на ранее добавленный адрес 0x6AED20
правой кнопкой мыши и выбираем Pointer scan for this address.
Как видишь, у нас есть множество параметров для поиска указателя, но нас интересует Max level. Это значение отвечает за то, сколько раз будет разыменован наш указатель (статический адрес). Оно‑то и поможет нам получить искомый адрес.
Исполняемый файл игры занимает мало, и кода в нем тоже негусто. Это наводит на мысль, что классов и структур в игре не так много и не будет большого количества смещений. Поэтому глубину поиска мы установим равной единице.
Мы видим следующий результат. Об адресах вида "ac_client.
мы уже писали в прошлой статье. Именно они нам и понадобятся. А вот адреса формата "THREADSTACKX"-YYYYYYYY
говорят нам о том, что искомый нами адрес был найден в стеке.
Добавим найденные пять адресов в список.
И выставим для каждого адреса смещение до показателей здоровья.
Далее перезапускаем игру, и Cheat Engine предложит сохранить наши адреса. Мы их сохраняем, чтобы загрузить при повторном подключении.
После переподключения к игре в списке адресов Cheat Engine видим, что только два адреса указывают на показатель здоровья: "ac_client.
и "ac_client.
.
Попробуем повторно получить урон и посмотреть, что будет с другими адресами. Как видим, еще в двух адресах появился наш показатель здоровья. Значит, в списке мы оставляем только два упомянутых ранее адреса.
Добавим статический адрес "ac_client.
под именем Player_ptr_1
.
Добавим статический адрес "ac_client.
под именем Player_ptr_2
.
Класс игрока
Предположим, что статический адрес Player_ptr_1
— тот, что мы ищем (что на самом деле не так, правильным статическим адресом будет Player_ptr_2
, но в этом мы убедимся позже). Чтобы просмотреть класс игрока в памяти, нажимаем правой кнопкой мыши на адрес и выбираем Browse this memory region (или жмем Ctrl-B).
К счастью, у Cheat Engine есть инструмент, который позволяет нам лучше визуализировать структуры памяти, а не просматривать байты в дампе. Просто жми правой кнопкой мыши по выделенному байту и выбирай Open in dissect data/structure.
Откроется новое окно с адресом выбранного байта. Нажми Structures, затем Define new structure (или Ctrl-N).
Назовем структуру Player
. Остальные настройки оставим по умолчанию: предположительный тип поля и размер структуры (4096).
Поставив галочку Guess field type, мы попросили Cheat Engine угадать тип поля. И он неплохо с этим справился.
Перейдем по смещению 0xEC
, чтобы убедиться, что там находится показатель здоровья нашего игрока.
Также можно по смещению 0x205
обнаружить имя игрока.
В дальнейшем нам нужен этот класс, но, к сожалению, Cheat Engine не позволяет экспортировать структуру, а делать это вручную — значит подвергать себя мучениям. Это не нужно, поскольку существует готовый инструмент — ReClass.NET. Он дает возможность напрямую выгрузить структуру в виде кода на C++. Скачиваем, устанавливаем и подключаемся к процессу игры.
После присоединения к процессу создается класс по базовому адресу 400000
, он называется N0000004E
. Дважды кликаем по адресу и выставляем нужный нам: 0066ED48
. Аналогично изменяем имя класса на Player
и добавляем для отображения еще 4096 байт.
В данном контексте отображаемое количество байтов СE воспринимает как класс, который мы экспортируем. Если размер нашего класса больше, чем стандартное количество отображаемых байтов, нужно вручную увеличить размер.
Переходим к смещению 0xEC
, к показателю здоровья. Меняем значение типа поля на DWORD
(мы выставим значения типов для смещений, что позволит нам в дальнейшем экспортировать класс с нужными полями).
Поиск координат
Начиная с этого места, мы будем искать значения, нужные непосредственно для реализации ESP и aimbot. Для ESP нам понадобятся координаты самого игрока и его головы в трехмерном пространстве.
www
Тем, кто не знает или забыл, как работает трехмерная система координат в компьютерной графике, рекомендую статью «3D своими руками» на «Хабрахабре».
Для реализации aimbot нам понадобятся значения тангажа (pitch), рысканья (yaw) и крена (roll). Не знаешь, что это? Давай покажу на примере игрового движка Godot.
Запись координат может разниться в зависимости от движка. Часто различается направление осей и то, какая из них считается высотой.
Для демонстрации возьмем с GitHub готового персонажа и посмотрим, как он будет двигаться, если менять координаты.
Тангаж — движение персонажа относительно оси X. Нижняя стрелка — фактическое движение персонажа в данный момент, верхняя — другой вариант движения.
Рысканье — движение персонажа относительно оси Y.
Крен — движение персонажа относительно оси Z.
Поиск координат игрока
С новыми знаниями возвращаемся к игре и окну Cheat Engine. Начинаем перемещаться по карте и вертеть мышкой из стороны в сторону, а также вверх и вниз. В окне Cheat Engine можем видеть три последовательности из значений с плавающей запятой, которые менялись при наших действиях. Значит, это координаты игрока, координаты головы игрока и его поворот относительно осей.
Можно заметить, что два набора из трех повторяются по X и Y, а вот координата Z у них разная. Отсюда мы можем сделать вывод, что один набор — это координаты игрока, а второй — головы. Так как в OpenGL в качестве высоты используется координата Z, мы попытаемся поменять высоту для каждого набора. Начнем с первого, но после попытки поменять значение c -0.5 на другое оно снова станет прежним. Значит, это координаты головы, второй набор — координаты игрока, а третий — движение относительно осей. Но мы в этом еще должны убедиться.
Теперь давай попробуем сделать для второго набора то, что мы делали для первого.
Для наглядной демонстрации встанем на ящик, а в Cheat Engine будем смотреть на значение по смещению 0x30
.
Попробуем изменить это значение и увидим, как наш персонаж провалился сквозь ящик.
Это значит, что наши предположения верны.
Вернемся в окно ReClass.NET и выберем типы для этих смещений.
Поиск pitch, yaw, roll
Сделаем такую же проверку. Веди мышью из стороны в сторону, а потом вверх и вниз. Попробуем поменять значения, и оказывается, что наши предположения были верны.
Вернемся в окно ReClass.NET и выберем типы для этих смещений.
Вот так теперь выглядит наш класс. Но что за VTable
? Это поле не нужно, я добавил его для красоты. Подробнее о том, что это и зачем, можешь прочитать в статье Understandig Virtual Tables in C++.
Теперь экспортируем наш класс (нажми на него правой кнопкой мыши и выбери соответствующий пункт меню). Можешь видеть, что есть поля, которые мы с тобой не искали: armor
, team
и прочие. Думаю, ты при желании сможешь найти их сам.
Entity List
С нашим игроком мы разобрались, а как быть с другими игроками? Обычно где‑то есть огромный список всех игровых сущностей, в который входят и персонажи игроков. Можно предположить, что где‑то в коде должен существовать и цикл, который перебирает игроков, и дальше с их данными как‑то взаимодействует логика игры. Попробуем оттолкнуться от показателя здоровья и поискать, какие инструкции его запрашивают.
С наскока ничего найти не удается, но наметанный глаз заметит, что доступ к показателям здоровья нашего игрока идет через какой‑то статический адрес. Оказывается, мы выбрали неправильный! Правильный адрес такой: "ac_client.
.
Попробуем теперь поискать через имя игрока, которое находится по смещению 0x205
.
И получим список инструкций, которые обращаются к имени.
Перебираем варианты и находим такой, где доступ происходит в цикле.
Те, кто знаком с ассемблером, понимают, что в регистре ebx
находится адрес первого элемента, esi
— это индекс, а умножение индекса говорит нам о типе данных, в данном случае это 4, DWORD.
Таким образом, статический адрес списка сущностей будет таким:
"ac_client.exe"+0018AC04
Убедиться в этом можно, проверив по смещению 0x205
имя игрока.
Также нам понадобится общее количество игроков. Полистав вывод дизассемблера, в конце цикла увидим проверку. В регистре edi
хранится текущее количество игроков.
Немного подебажив, замечаем, что выше цикла находится статический адрес количества игроков: "ac_client.
.
Перезапустим и проверим, что адреса правильные.
Поиск View Matrix
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»