Как найти массивы объектов (сущностей, врагов) в игре, которую я реверсирую с помощью Cheat Engine?

Я делаю реверс игры с использованием Cheat Engine и OllyDBG, с помощью этого читаются и отслеживаются адреса памяти в FPS игре, эти адреса будут содержать координаты(xyz) врагов.

Моя цель - найти адрес или шаблон, который позволит мне перебрать до 32 врагов, чтобы прочитать все их координаты, для этого я пытался найти шаблон между каждым из их адресов, но безуспешно. Мне удалось собрать 3 различных адреса врагов, эта информация полезна, но поиск 32 адресов - задача, которая требует больше усилий, чем я считаю необходимым.

Как уже было сказано, у меня есть доступ к первым 3 адресам врагов, и если на основе этой информации можно проследить путь до базы либо через Cheat Engine, либо через другое программное обеспечение для обратной разработки, то я был бы признателен за этот процесс.

В конечном итоге мой вопрос заключается в том, есть ли способ обнаружить массив указателей в памяти по одному из его адресов, например, если у меня есть 3 координаты врага, могу ли я каким-то образом отследить место в памяти до адреса, который обращается ко всем 32 адресам врага, будь то с помощью Cheat Engine или другого инструмента реверсинга.

Решение

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

Немного способов найти другие структуры приходит на ум:

Сканирование памяти на наличие сигнатур

Когда у вас есть несколько примеров структур, возможно, самый простой способ найти экземпляры других структур - это найти совпадающие константы во всех трех структурах. Некоторые значения могут быть постоянными, представлять собой свойства, которые применяются ко всем вражеским сущностям в более высокоуровневом классе, передаваемом по наследству.

Плюсы:

  • Это легко реализовать, можно сделать это Cheat Engine.
  • В общем случае он должен пережить перезапуск программы, вам не нужно будет находить три структуры каждый раз, когда вы запускаете игру.

Минусы:

  • Не так надежно. вещи могут меняться между версиями, данные, которые вы считаете постоянными, могут на самом деле измениться в некоторых случаях, на которые вы'не обратили внимания.

Поиск по указателю

Возможно, где-то есть указатель на каждую сущность. Вы можете просто поискать в памяти адреса найденных структур и найти массив/структуру, в которой хранятся все сущности. Вы также можете пройтись по массивам, найденным в самих структурах, возможно, вы смотрите на связный список.

Плюсы:

  • простота реализации.
  • будет немного надежнее, чем предыдущий метод.

Минусы:

  • вам все равно придется каким-то образом находить первые сущности.

Поиск конструктора/конструктороподобной функции

В объектно-ориентированном языке, таком как C++ или ObjC, или в процедурном языке, таком как C, должна быть функция, инициирующая структуру. обычно ее легко найти - первая функция, вызываемая после выделения объекта, довольно характерная сборка - в основном код инициализации.

Если мы говорим об ОО-коде, то поиск таблицы виртуальных функций или аналогичной конструкции позволит вам легко найти функции построения, пройтись по наследованию и найти хотя бы часть манипулирующих функций.

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

Плюсы:

  • достаточно надежный
  • лучшее понимание того, как сущности сохраняются в памяти.

Минусы:

  • Статический RE. обычно сложнее сделать (нужен хороший дизассемблер).

Реверсирование структуры

Этот способ требует немного больше работы по реверсированию, но позволит вам найти лучшие способы поиска сущностей. Используя Cheat Engine и IDA, вручную нанесите на карту структуру, элементы/члены, функции, которые манипулируют структурой.

Если есть какие-либо указатели, следуйте им и реверсируйте другие структуры, которые вам встретятся.

Плюсы:

  • Надежность
  • Правильный способ сделать то, что вы хотите. Действительно понимает, что происходит. облегчает будущие возможности/функции.

Cons:

  • больше работы и сложнее. Много RE.

Примечание

по крайней мере для некоторых из упомянутых мною методов поиск указателей на все сущности при анализе программы может быть только первым шагом. Вы можете искать ссылки на сам список и получить лучший способ автоматического поиска сущностей при каждом перезапуске программы. Это устраняет некоторые из конс.

Комментарии (0)

Сначала найдите адрес, который вы ищете. Затем выполните следующий цикл:

  1. Найдите базу (начало записи).
  2. Разделите память вокруг нее, чтобы распознать массив или связанный список.
  3. Найти в памяти указатель на эту базу.

Пример:

Поиск параметра, находящего адрес 30000032.

Выясните, что основой этой записи является 30000000.

Проверка памяти - ничего причудливого вокруг.

Находим указатель на базу по адресу 20000004.

Выясняем, что основание записи - 20000000.

Проверяем память - по-прежнему ничего...

Находим указатель на базу по адресу 10000008.

Обнаружение базы по адресу 10000000.

Проверяю память - все указатели на искомые объекты находятся на расстоянии 12 байт друг от друга. (Очевидно, что это какая-то коллекция).

Последнее сканирование памяти для указателя, чтобы убедиться, что я не ошибся, на 0000040.

Нахожу указатель на эту коллекцию, а сразу за ним: количество объектов в коллекции.

Перезапустите игру/компьютер несколько раз, чтобы найти последовательный указатель на этот адрес.

Наградить себя пивом за хорошую работу.

Как найти базу: Мне нравится использовать "сканирование указателя", и проверять последнее смещение. Наименьшее из наиболее часто встречающихся, обычно является правильным.

Иногда я пытаюсь найти запись в начале выделенной памяти, и в этом случае я уверен, что что-то является базой.

Другой трюк - найти в памяти две записи, расположенные одна за другой, определить их "максимальный размер", и это означает, что база должна быть не дальше этого числа в памяти.

Как распознать коллекции: Большинство из них ИСКЛЮЧИТЕЛЬНО упорядочены, с определенным смещением, или имеют указатели на однотипные объекты.

Например, если у вас есть:

Pointer to Player 1 data,
4 Bytes
4 Bytes
Pointer to Player 2 data,
4 Bytes
4 Bytes
Pointer to Player 3 data

Это должно прозвенеть.

Имейте в виду, что такое выравнивание может случайно встречаться в источнике, поэтому попробуйте поискать: Данные игрока 3, Данные игрока 3 +/- 4, Данные игрока 3 +/- 8.

В любом случае, если вы найдете что-то подобное, скорее всего, вы действительно близки.

Это работает для меня, надеюсь, это сработает и для вас, ребята.

Комментарии (0)