Содержание статьи
info
В предыдущей статье «Чит своими руками. Вскрываем компьютерную игру и пишем трейнер на C++» я заложил базу для будущих читов и объяснил основные понятия. Рекомендую ознакомиться с ней, чтобы лучше понимать, что мы будем сегодня делать.
Выбор игры
Мой выбор пал на AssaultCube — бесплатный многопользовательский шутер от первого лица, основанный на движке CUBE. Используется графическая библиотека OpenGL.
warning
Использование читов нарушает пользовательское соглашение игры и может повлечь юридическое преследование. Мы обсуждаем здесь создание чита исключительно в целях обучения. Автор и редакция не несут ответственности за возможные последствия применения и распространения такого ПО.
Поиск значений
Для начала запустим игру и в настройках выберем оконный режим, ведь нам нужно, чтобы на экране помещалось еще что‑то, кроме игры.
![Оконный режим Оконный режим](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30402/1-windowed.png)
Также создадим локальный сервер. Нужно будет настроить его, а именно задать время игры, чтобы таймер не торопил нас. Конфиг лежит по следующему пути:
C:\Program Files (x86)\AssaultCube 1.3.0.2\config\maprot.cfg
![Стандартные настройки времени Стандартные настройки времени](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30401/2-default-settings-maps.png)
Поменяем время на максимальное — 100 минут.
![Новые настройки времени Новые настройки времени](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30400/3-new-settings-maps.png)
А после уже запускаем сам сервер.
![Запуск сервера Запуск сервера](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30399/4-start-server.png)
И подключаемся к нему.
![Подключение к серверу Подключение к серверу](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30398/5-join-server.png)
Запускаем Cheat Engine и подключаемся к процессу игры.
![Подключимся к процессу игры Подключимся к процессу игры](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30356/6-attach-process.png)
Поиск показателя здоровья
Для тестирования нам понадобится второй игрок. Можешь подключиться со второго устройства или, как сделал я, из виртуальной машины. Для поиска показателя здоровья выставляем параметры сканирования в Cheat Engine и вторым игроком наносим урон первому. После этого ищем здоровье в Cheat Engine.
![Получение урона Получение урона](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30397/7-get-damage.png)
Будем наносить урон до тех пор, пока не найдем адрес, по которому хранится показатель здоровья нашего игрока.
![Найденный адрес HP Найденный адрес HP](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30396/8-find-hp.png)
На этом все знакомые по прошлой статье действия в Cheat Engine заканчиваются и начинаются новые. Наша цель — реализовать extrasensory perception и aimbot. Для этого нам нужно узнать класс игрока и его статический адрес. Чтобы найти класс, кликаем правой кнопкой мыши по нашему адресу и выбираем Find out what writes to this address (можно просто нажать F6).
![Поиск места, где идет запись по адресу Поиск места, где идет запись по адресу](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30395/9-write-address.png)
Появится новое окно, где будут отображаться инструкции, которые производят запись по нашему адресу. Чтобы они появились, снова наносим урон вторым игроком первому.
![Найденная инструкция Найденная инструкция](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30394/10-player-base.png)
Показатель здоровья записывает всего одна инструкция, она расположена по смещению 0xEC
. Значит, значение, хранящееся в регистре edx
, — это адрес класса игрока (но адрес в куче, а не статический). Поэтому добавим его вручную.
![Структура Структура](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30393/11-add-player.png)
Поиск статического адреса объекта игрока
В прошлый раз я использовал отладчик, чтобы наглядно показать, что собой представляет статический адрес. В этот раз для поиска статического адреса мы будем использовать Cheat Engine. Жмем на ранее добавленный адрес 0x6AED20
правой кнопкой мыши и выбираем Pointer scan for this address.
![Выбор сканирования адреса Выбор сканирования адреса](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30392/12-pointerscan.png)
Как видишь, у нас есть множество параметров для поиска указателя, но нас интересует Max level. Это значение отвечает за то, сколько раз будет разыменован наш указатель (статический адрес). Оно‑то и поможет нам получить искомый адрес.
![Стандартные настройки сканирования указателя Стандартные настройки сканирования указателя](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30391/13-default-pointerscan-option.png)
Исполняемый файл игры занимает мало, и кода в нем тоже негусто. Это наводит на мысль, что классов и структур в игре не так много и не будет большого количества смещений. Поэтому глубину поиска мы установим равной единице.
![Новые настройки сканирования указателя Новые настройки сканирования указателя](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30390/14-new-pointerscan-option.png)
Мы видим следующий результат. Об адресах вида "ac_client.
мы уже писали в прошлой статье. Именно они нам и понадобятся. А вот адреса формата "THREADSTACKX"-YYYYYYYY
говорят нам о том, что искомый нами адрес был найден в стеке.
![Результаты сканирования указателя Результаты сканирования указателя](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30389/15-pointerscan-result.png)
Добавим найденные пять адресов в список.
![Добавленные указатели Добавленные указатели](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30388/16-added-ptrs.png)
И выставим для каждого адреса смещение до показателей здоровья.
![Добавленный указатель на HP Добавленный указатель на HP](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30387/17-add-offset-hp.png)
Далее перезапускаем игру, и Cheat Engine предложит сохранить наши адреса. Мы их сохраняем, чтобы загрузить при повторном подключении.
![Сохраняем наш cheat table Сохраняем наш cheat table](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30386/18-keep-list.png)
После переподключения к игре в списке адресов Cheat Engine видим, что только два адреса указывают на показатель здоровья: "ac_client.
и "ac_client.
.
![После перезапуска AC После перезапуска AC](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30385/19-reattach.png)
Попробуем повторно получить урон и посмотреть, что будет с другими адресами. Как видим, еще в двух адресах появился наш показатель здоровья. Значит, в списке мы оставляем только два упомянутых ранее адреса.
![Повторное получение урона Повторное получение урона](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30384/20-base-damage.png)
Добавим статический адрес "ac_client.
под именем Player_ptr_1
.
![Добавляем первый указатель Добавляем первый указатель](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30381/21-player-ptr-1.png)
Добавим статический адрес "ac_client.
под именем Player_ptr_2
.
![Добавляем второй указатель Добавляем второй указатель](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30380/22-player-ptr-2.png)
Класс игрока
Предположим, что статический адрес Player_ptr_1
— тот, что мы ищем (что на самом деле не так, правильным статическим адресом будет Player_ptr_2
, но в этом мы убедимся позже). Чтобы просмотреть класс игрока в памяти, нажимаем правой кнопкой мыши на адрес и выбираем Browse this memory region (или жмем Ctrl-B).
![Открытие региона памяти Открытие региона памяти](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30379/23-browse-region-memory.png)
К счастью, у Cheat Engine есть инструмент, который позволяет нам лучше визуализировать структуры памяти, а не просматривать байты в дампе. Просто жми правой кнопкой мыши по выделенному байту и выбирай Open in dissect data/structure.
![Открытие анализа структур Открытие анализа структур](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30378/24-open-dissect-structure.png)
Откроется новое окно с адресом выбранного байта. Нажми Structures, затем Define new structure (или Ctrl-N).
![Создание структуры Создание структуры](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30343/25-dissect-structure.png)
Назовем структуру Player
. Остальные настройки оставим по умолчанию: предположительный тип поля и размер структуры (4096).
![Создание класса игрока Создание класса игрока](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30383/26-new-structure.png)
Поставив галочку Guess field type, мы попросили Cheat Engine угадать тип поля. И он неплохо с этим справился.
![Полученная структура Полученная структура](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30382/27-player-dissect.png)
Перейдем по смещению 0xEC
, чтобы убедиться, что там находится показатель здоровья нашего игрока.
![Проверка класса Проверка класса](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30377/28-player-hp.png)
Также можно по смещению 0x205
обнаружить имя игрока.
![Имя игрока Имя игрока](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30376/29-player-name.png)
В дальнейшем нам нужен этот класс, но, к сожалению, Cheat Engine не позволяет экспортировать структуру, а делать это вручную — значит подвергать себя мучениям. Это не нужно, поскольку существует готовый инструмент — ReClass.NET. Он дает возможность напрямую выгрузить структуру в виде кода на C++. Скачиваем, устанавливаем и подключаемся к процессу игры.
![Подключение к процессу Подключение к процессу](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30375/30-reclass-attach.png)
После присоединения к процессу создается класс по базовому адресу 400000
, он называется N0000004E
. Дважды кликаем по адресу и выставляем нужный нам: 0066ED48
. Аналогично изменяем имя класса на Player
и добавляем для отображения еще 4096 байт.
В данном контексте отображаемое количество байтов СE воспринимает как класс, который мы экспортируем. Если размер нашего класса больше, чем стандартное количество отображаемых байтов, нужно вручную увеличить размер.
![Настройка ReClass.NET Настройка ReClass.NET](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30342/31-reclass-conf.png)
Переходим к смещению 0xEC
, к показателю здоровья. Меняем значение типа поля на DWORD
(мы выставим значения типов для смещений, что позволит нам в дальнейшем экспортировать класс с нужными полями).
![Присвоение типа Присвоение типа](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30374/32-hp-change-type.png)
Поиск координат
Начиная с этого места, мы будем искать значения, нужные непосредственно для реализации ESP и aimbot. Для ESP нам понадобятся координаты самого игрока и его головы в трехмерном пространстве.
www
Тем, кто не знает или забыл, как работает трехмерная система координат в компьютерной графике, рекомендую статью «3D своими руками» на «Хабрахабре».
Для реализации aimbot нам понадобятся значения тангажа (pitch), рысканья (yaw) и крена (roll). Не знаешь, что это? Давай покажу на примере игрового движка Godot.
![Координаты XYZ Координаты XYZ](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30354/33-xyz-coord.png)
Запись координат может разниться в зависимости от движка. Часто различается направление осей и то, какая из них считается высотой.
![Вариации координат Вариации координат](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30355/34-diff-coords.png)
Для демонстрации возьмем с GitHub готового персонажа и посмотрим, как он будет двигаться, если менять координаты.
![Персонаж на нулевых координатах Персонаж на нулевых координатах](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30353/35-xyz-character.png)
Тангаж — движение персонажа относительно оси X. Нижняя стрелка — фактическое движение персонажа в данный момент, верхняя — другой вариант движения.
![Pitch Pitch](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30352/36-pitch-character.png)
Рысканье — движение персонажа относительно оси Y.
![Yaw Yaw](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30351/37-yaw-character.png)
Крен — движение персонажа относительно оси Z.
![Roll Roll](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30350/38-roll-character.png)
Поиск координат игрока
С новыми знаниями возвращаемся к игре и окну Cheat Engine. Начинаем перемещаться по карте и вертеть мышкой из стороны в сторону, а также вверх и вниз. В окне Cheat Engine можем видеть три последовательности из значений с плавающей запятой, которые менялись при наших действиях. Значит, это координаты игрока, координаты головы игрока и его поворот относительно осей.
Можно заметить, что два набора из трех повторяются по X и Y, а вот координата Z у них разная. Отсюда мы можем сделать вывод, что один набор — это координаты игрока, а второй — головы. Так как в OpenGL в качестве высоты используется координата Z, мы попытаемся поменять высоту для каждого набора. Начнем с первого, но после попытки поменять значение c -0.5 на другое оно снова станет прежним. Значит, это координаты головы, второй набор — координаты игрока, а третий — движение относительно осей. Но мы в этом еще должны убедиться.
![Неправильный выбор числа Неправильный выбор числа](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30341/39-intresting-value-fail.png)
Теперь давай попробуем сделать для второго набора то, что мы делали для первого.
![Правильный выбор Правильный выбор](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30373/40-intresting-value-succes.png)
Для наглядной демонстрации встанем на ящик, а в Cheat Engine будем смотреть на значение по смещению 0x30
.
![Становимся на высоту Становимся на высоту](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30372/41-z-coord.png)
Попробуем изменить это значение и увидим, как наш персонаж провалился сквозь ящик.
![Изменение высоты игрока Изменение высоты игрока](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30371/42-change-z.png)
Это значит, что наши предположения верны.
![Наши координаты Наши координаты](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30370/43-xyz.png)
Вернемся в окно ReClass.NET и выберем типы для этих смещений.
![Переименовываем и задаем тип Переименовываем и задаем тип](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30368/44-rename-xyz.png)
Поиск pitch, yaw, roll
Сделаем такую же проверку. Веди мышью из стороны в сторону, а потом вверх и вниз. Попробуем поменять значения, и оказывается, что наши предположения были верны.
![Наши значения Наши значения](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30369/45-possible-pitch-yaw.png)
Вернемся в окно ReClass.NET и выберем типы для этих смещений.
![Переименовываем и задаем тип Переименовываем и задаем тип](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30367/46-yaw-pitch.png)
Вот так теперь выглядит наш класс. Но что за VTable
? Это поле не нужно, я добавил его для красоты. Подробнее о том, что это и зачем, можешь прочитать в статье Understandig Virtual Tables in C++.
![Наш класс Наш класс](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30357/47-structure.png)
Теперь экспортируем наш класс (нажми на него правой кнопкой мыши и выбери соответствующий пункт меню). Можешь видеть, что есть поля, которые мы с тобой не искали: armor
, team
и прочие. Думаю, ты при желании сможешь найти их сам.
![Экспортируем Экспортируем](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30348/48-export-class.png)
Entity List
С нашим игроком мы разобрались, а как быть с другими игроками? Обычно где‑то есть огромный список всех игровых сущностей, в который входят и персонажи игроков. Можно предположить, что где‑то в коде должен существовать и цикл, который перебирает игроков, и дальше с их данными как‑то взаимодействует логика игры. Попробуем оттолкнуться от показателя здоровья и поискать, какие инструкции его запрашивают.
![Доступ к адресу со здоровьем Доступ к адресу со здоровьем](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30366/49-access-hp.png)
С наскока ничего найти не удается, но наметанный глаз заметит, что доступ к показателям здоровья нашего игрока идет через какой‑то статический адрес. Оказывается, мы выбрали неправильный! Правильный адрес такой: "ac_client.
.
![Правильный адрес Правильный адрес](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30365/50-possible-right-static-addr.png)
Попробуем теперь поискать через имя игрока, которое находится по смещению 0x205
.
![Имя игрока Имя игрока](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30364/51-player-name.png)
И получим список инструкций, которые обращаются к имени.
![Добавляем адрес Добавляем адрес](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30363/52-add-player-name.png)
![Ищем доступ к адресу Ищем доступ к адресу](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30362/53-player-name-access.png)
Перебираем варианты и находим такой, где доступ происходит в цикле.
![Цикл сущностей Цикл сущностей](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30339/54-entity-loop.png)
Те, кто знаком с ассемблером, понимают, что в регистре ebx
находится адрес первого элемента, esi
— это индекс, а умножение индекса говорит нам о типе данных, в данном случае это 4, DWORD.
Таким образом, статический адрес списка сущностей будет таким:
"ac_client.exe"+0018AC04
![Список сущностей Список сущностей](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30360/55-another-player-in-entity.png)
Убедиться в этом можно, проверив по смещению 0x205
имя игрока.
![Имя другого игрока Имя другого игрока](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30361/56-name-another-player.png)
Также нам понадобится общее количество игроков. Полистав вывод дизассемблера, в конце цикла увидим проверку. В регистре edi
хранится текущее количество игроков.
![Количество игроков Количество игроков](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30359/57-player-connected.png)
Немного подебажив, замечаем, что выше цикла находится статический адрес количества игроков: "ac_client.
.
![Статический адрес для игроков Статический адрес для игроков](https://static.xakep.ru/images/7b9b9fe3097c3f9c4084de4f20d834a9/30358/58-count-player-connected.png)
Перезапустим и проверим, что адреса правильные.
Поиск View Matrix
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»