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

Вопрос Rust — Поиск оффсетов в рантайме и обфускация il2cpp

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
682
Реакции
18
Надоело каждый раз после апдейта Раста лезть в дампер и руками выцеплять оффсеты для своего интернала. Хотелось бы сделать нормальный runtime auto-update, чтобы ESP не отваливался после каждого микро-патча от Facepunch.

Пытался через il2cpp::field(klass, "clientEntities", false) вытянуть FieldInfo*, но столкнулся с классикой — поиск через class_get_fields выдает лютую обфускацию вместо вменяемых имен. В итоге имеем кучу мусора, из которого невозможно выцепить нужный указатель по строке.

Суть проблемы в том, что в Unity/IL2CPP метаданные часто забиты обфусцированными именами полей. Искать по жесткой строке вроде 'clientEntities' в рантайме — затея дохлая, так как разрабы переименовывают всё, что движется.

Какие сейчас есть адекватные варианты обхода этой дичи для Internal софта? Пока вижу несколько путей:
  1. Сигнатуры (Pattern Scanning). Искать куски кода в функциях, которые работают с нужными полями, и вытягивать смещения прямо из опкодов.
  2. Парсинг методов. Найти метод по имени (они часто менее обфусцированы) через method_get_from_name, а потом натравить на него мини-дизассемблер, чтобы найти смещение поля.
  3. Использование уникальных типов полей. Если поле имеет редкий тип, можно попробовать перебор всех полей класса и фильтрацию по типу, но это костыль.

Кто как реализует авто-апдейтер в своих проектах под Rust? Делать через поиск по именам в il2cpp — это путь в никуда, если мы говорим про нормальный софт, который должен жить дольше одного патча.

Делитесь своими идеями или рабочими подходами по поиску структур в памяти Unity-игр.
 
Для Rust под IL2CPP автоапдейтер через имена полей не работает из-за обфускации. Facepunch выжигают метаданные в редакторе, оставляя мусор вроде `name_0x1234ABCD`. Забудь про `class_get_fields`.

**Вариант 1 (рабочий): паттерн-скан функций-геттеров.** Каждое публичное поле в Rust имеет геттер/сеттер. Например, `BasePlayer._health` скомпилируется в `BasePlayer::get_health`. Ищи сигнатуру `48 89 5C 24 08 57 48 83 EC 20 48 8B D9 48 85 C9 0F 84` (для всех геттеров). Внутри этой функции сразу после пролога будет `mov rax, [rcx + offset]` — этот `offset` и есть твоё смещение поля. Парсишь инструкцию, достаёшь байты, обновляешь оффсет. Не зависит от имён, переживает большинство патчей.

**Вариант 2 (надёжнее): поиск по уникальным значениям по умолчанию.** У `BasePlayer._name` длина 64 символа, у `ClientEntities` по умолчанию пустой список. Делаешь `il2cpp_class_get_size(klass)`, создаёшь dummy-объект в куче, проходишь по всем смещениям и сравниваешь с эталонным значением из оригинальной игры. Для `ClientEntities` сигнатура — указатель на `List<BaseEntity>` плюс `_size` поле. За 3-4 итерации угадывается.

**Вариант 3 (грязный хак, но быстрый):** Хукаешь `Init`-конструктор класса. Игра сама проставит указатели на нужные поля. Читаешь регистры в момент инициализации — вуаля, оффсет обновлён.

Советую комбинацию варианта 1 и 2. Фильтруй геттеры по возвращаемому типу (например, для `_health` это `float`). Парсинг 5 инструкций вручную научит твой софт жить месяцами, даже без дампов. Забудь про ручной сбор оффсетов после каждого микро-патча.
 
Назад
Сверху Снизу