Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд №2 Bounds ESP - Создание экстернал чита на официальный Rust

PoC Life
Премиум
Премиум
Статус
Онлайн
Регистрация
22 Авг 2022
Сообщения
1,184
Реакции
164
В прошлом гайде мы научились получать сущностей. В этом гайде я расскажу как создать ESP бокс используя Bounds (AKA AxisAlignedBoundingBox). Подробнее о том, как это устроено я рассказывал в этой теме

Камера
Камера лежит в статичном поле класса MainCamera. Как всегда они сюда накидали несколько камер, трансформов и тд:
Pasted image 20260211210241.png

Работаем по старой схеме:
Переходим по RVA
Pasted image 20260211234905.png

Pasted image 20260211235011.png

Заходим в любой хреф и получаем необходимый оффсет.
Pasted image 20260211235031.png

Теперь у нас есть камера. Для World to Screen функции проекции точки на экран необходима view * projection матрица. Я нашёл projection matrix:
Pasted image 20260212002041.png

и остальные. Но при переходе в данную функцию я вижу resolve icall:
Pasted image 20260212002116.png

icall ищет адрес функции по названию из UnityPlayer.dll. Данная dll лежит рядом с игрой и для неё доступны debug символы - pdb. Скачать их можно через любую утилиту, я лично
Пожалуйста, авторизуйтесь для просмотра ссылки.

После загрузки длл с дебаг символами нам доступны все названия функций.

На самом деле есть матрица, которая сразу считает view * projection - она называется World to Clip. Сохраняется она в функции Camera::GetCullingMatrix по оффсету 0x30C:
Pasted image 20260212002557.png

В функции GetWorldToClipMatrix идёт перемножение view матрицы (по оффсету 0x80) на projection (полученной в результате функции Camera::GetProjectionMatrix):
Pasted image 20260212002713.png

Перемножение тут с использованием SSE. Первым аргументом если что идёт внутренний указатель на камеру, как его получать я писал ниже (уже лень переписывать)

Сортировка сущностей
Каждый раз при чтении сущности из массива мы получаем указатель на структуру BaseNetworkable_o:
Pasted image 20260212002918.png

Самое первое поле - klass - это указатель на typeinfo класса. Таким образом мы можем прочитать этот klass и сравнить его с typeinfo BasePlayer'а.

Коробка
Основной элемент есп это конечно же 2д (а иногда 3д) коробка. Многие читы добиваются её эффекта вычисляя позицию ног и головы, однако я считаю такой способ кринжовым и поддерживаю более верный способ через хитбоксы. В unity, Axis Aligned Bounding Box называется структурой Bounds, которая состоит из center и extents вектора. Там также есть функции получения вершин минимума и максимума. Не вижу смысла показывать некрасивый SSE код, покажу сразу их реализацию:
Pasted image 20260212003515.png

Поле bounds лежит в классе BaseEntity.

Далее по принципу из, повторюсь, этой темы вычисляем коробку. Единственное с чем вы можете столкнуться, так это с получением поворота и позиции Transform.
В unity компонент Transform есть у каждого игрового объекта. Для его получения мы можем изучить функцию GetTransformFromComponentOrGameObject
Pasted image 20260212004236.png

Сразу скажу, что функция принимает внутренний object и отдаёт тоже внутреннюю структуру Transform, а не тот класс, что мы видим в il2cpp дампе. Получить внутренний object от сущности можно прочитав его через entity+0x10. 0x10 это самое первое поле любого класса. Объясню почему так, как я уже сказал, каждая сущность - это указатель на BaseNetworkable_o:
Pasted image 20260212005507.png

Структура BaseNetworkable_Fields имеет очень много наследований:
BaseNetworkable_Fields -> BaseMonoBehaviour_Fields -> FacepunchBehaviour_Fields -> UnityEngine_MonoBehaviour_Fields -> UnityEngine_Behaviour_Fields -> UnityEngine_Component_Fields -> UnityEngine_Object_Fields
Pasted image 20260212005618.png

что в конечном итоге приведёт нас к UnityEngine_Object_Fields без наследований, где первое поле это m_CachedPtr - указатель на внутренний object игры.

Получить позицию и ротацию можно через функцию Transform::GetPositionAndRotation:
IMG_1966.jpeg

которая внутри вызывает функцию CalculateGlobalPositionAndRotation, передавая в первый аргумент transform+0x38. Результат должен записаться по указателям во второй и третий аргумент.

IMG_1967.jpeg

Внутри функция выглядит как-то так, дописываю с телефона, поэтому полного скриншота нету. Но логика такая:
1. В a1+8 лежит индекс текущего трансформа в массиве трансформов
2. Сам a1 указывает на внутреннюю структуру в которой +0x18 возвращает массив трансформов по 48 байт каждый (vector4f позиция, quaternionf поворот и vector4f размер)
3. Из v4+0x20 мы найдем индексы прошлых трансформов (например если бы это была рука, то надо было найти прошлые трансформы: человека, мира и тд). Используя индекс полученный из пункта 1 мы получим индекс прошлого трансформа
4. Если индекс прошлого трансформа >= 0 то мы перечисляем все дочерние трансформы, прибавляем позицию, перемножаем поворот и применяем размер, пока предыдущий трансформ ещё существует
5. Возвращаем результат после всех операций
Таким образом мы сможем использовать эти значения для воссоздания матрицы трансформа, чтобы в дальнейшем перемножить её на вершину в aabb.

IMG-1954.jpg
 
В прошлом гайде мы научились получать сущностей. В этом гайде я расскажу как создать ESP бокс используя Bounds (AKA AxisAlignedBoundingBox). Подробнее о том, как это устроено я рассказывал в этой теме

Камера
Камера лежит в статичном поле класса MainCamera. Как всегда они сюда накидали несколько камер, трансформов и тд:
Посмотреть вложение 327348
Работаем по старой схеме:
Переходим по RVA
Посмотреть вложение 327349
Посмотреть вложение 327350
Заходим в любой хреф и получаем необходимый оффсет.
Посмотреть вложение 327351
Теперь у нас есть камера. Для World to Screen функции проекции точки на экран необходима view * projection матрица. Я нашёл projection matrix:
Посмотреть вложение 327352
и остальные. Но при переходе в данную функцию я вижу resolve icall:
Посмотреть вложение 327353
icall ищет адрес функции по названию из UnityPlayer.dll. Данная dll лежит рядом с игрой и для неё доступны debug символы - pdb. Скачать их можно через любую утилиту, я лично
Пожалуйста, авторизуйтесь для просмотра ссылки.

После загрузки длл с дебаг символами нам доступны все названия функций.

На самом деле есть матрица, которая сразу считает view * projection - она называется World to Clip. Сохраняется она в функции Camera::GetCullingMatrix по оффсету 0x30C:
Посмотреть вложение 327354
В функции GetWorldToClipMatrix идёт перемножение view матрицы (по оффсету 0x80) на projection (полученной в результате функции Camera::GetProjectionMatrix):
Посмотреть вложение 327355
Перемножение тут с использованием SSE. Первым аргументом если что идёт внутренний указатель на камеру, как его получать я писал ниже (уже лень переписывать)

Сортировка сущностей
Каждый раз при чтении сущности из массива мы получаем указатель на структуру BaseNetworkable_o:
Посмотреть вложение 327356
Самое первое поле - klass - это указатель на typeinfo класса. Таким образом мы можем прочитать этот klass и сравнить его с typeinfo BasePlayer'а.

Коробка
Основной элемент есп это конечно же 2д (а иногда 3д) коробка. Многие читы добиваются её эффекта вычисляя позицию ног и головы, однако я считаю такой способ кринжовым и поддерживаю более верный способ через хитбоксы. В unity, Axis Aligned Bounding Box называется структурой Bounds, которая состоит из center и extents вектора. Там также есть функции получения вершин минимума и максимума. Не вижу смысла показывать некрасивый SSE код, покажу сразу их реализацию:
Посмотреть вложение 327357
Поле bounds лежит в классе BaseEntity.

Далее по принципу из, повторюсь, этой темы вычисляем коробку. Единственное с чем вы можете столкнуться, так это с получением поворота и позиции Transform.
В unity компонент Transform есть у каждого игрового объекта. Для его получения мы можем изучить функцию GetTransformFromComponentOrGameObject
Посмотреть вложение 327358
Сразу скажу, что функция принимает внутренний object и отдаёт тоже внутреннюю структуру Transform, а не тот класс, что мы видим в il2cpp дампе. Получить внутренний object от сущности можно прочитав его через entity+0x10. 0x10 это самое первое поле любого класса. Объясню почему так, как я уже сказал, каждая сущность - это указатель на BaseNetworkable_o:
Посмотреть вложение 327359
Структура BaseNetworkable_Fields имеет очень много наследований:
BaseNetworkable_Fields -> BaseMonoBehaviour_Fields -> FacepunchBehaviour_Fields -> UnityEngine_MonoBehaviour_Fields -> UnityEngine_Behaviour_Fields -> UnityEngine_Component_Fields -> UnityEngine_Object_Fields
Посмотреть вложение 327360
что в конечном итоге приведёт нас к UnityEngine_Object_Fields без наследований, где первое поле это m_CachedPtr - указатель на внутренний object игры.

Получить позицию и ротацию можно через функцию Transform::GetPositionAndRotation:
Посмотреть вложение 327361
которая внутри вызывает функцию CalculateGlobalPositionAndRotation, передавая в первый аргумент transform+0x38. Результат должен записаться по указателям во второй и третий аргумент.

Посмотреть вложение 327362
Внутри функция выглядит как-то так, дописываю с телефона, поэтому полного скриншота нету. Но логика такая:
1. В a1+8 лежит индекс текущего трансформа в массиве трансформов
2. Сам a1 указывает на внутреннюю структуру в которой +0x18 возвращает массив трансформов по 48 байт каждый (vector4f позиция, quaternionf поворот и vector4f размер)
3. Из v4+0x20 мы найдем индексы прошлых трансформов (например если бы это была рука, то надо было найти прошлые трансформы: человека, мира и тд). Используя индекс полученный из пункта 1 мы получим индекс прошлого трансформа
4. Если индекс прошлого трансформа >= 0 то мы перечисляем все дочерние трансформы, прибавляем позицию, перемножаем поворот и применяем размер, пока предыдущий трансформ ещё существует
5. Возвращаем результат после всех операций
Таким образом мы сможем использовать эти значения для воссоздания матрицы трансформа, чтобы в дальнейшем перемножить её на вершину в aabb.

IMG-1954.jpg
годно
 
Назад
Сверху Снизу