В один из вечеров школьного лета, у меня появилась потребность в мапхаке для DayZ Mod (Arma 2 OA). Поискав информацию по теме, я понял, что связываться с античитом Battleye не стоит, ибо нет ни знаний, ни опыта для обхода защитного драйвера ядра, который вежливо расставил кучу хуков на доступ к процессу игры. DayZ одна из немногих игр, где расположение важных для игрового процесса объектов, меняется не часто и сохраняется после перезахода(базы не двигаются, большинство техники тоже много времени стоит на месте). Этот факт открывает возможность атаки через дамп оперативной памяти. Все ссылки в конце. Получить снимок памяти в рантайме без обхода античита, врядли получится. Поэтому ищем другие тактики. Первое, что находим это хабрастатья, из которой становится понятно куда копать.  Получить образ памяти через описанный в статье хотресет, загрузку с Ubuntu CyberPack (IRF) и получение образа через fmem, мне не удалось, по невыясненным причинам fmem зависал.
Немного погуглив находим альтернативную тулзу, с таким же функционалом LiME ~ Linux Memory Extractor. Теперь её нужно было собрать и запустить на livecd.
Выбор дистрибутива пал на TinyCore(TinyCorePure64, если сдампить нужно более 3 ГБ). Загрузившись с него качаем и устанавливаем пакеты. Далее монтируем флешку с сорцами, куда также будем скидывать дамп, собираем через make и получаем образ Теперь этот файл нужно кому-то скормить, чтобы на выходе получить память нужного нам процесса. Для этого нам должен был подойти Volatility Framework с плагином memdump. Или Rekall Framework, который является его форком и активно развивается, в отличии от самого volatility Однако что я бы не делал, заводиться он не захотел и я продолжил копать. При работе с Rekall на windows 10, при первом поиске чего-либо по дампу может появиться сообщение вида: А в следующий раз, он может упасть с такой ошибкой: Если это произошло, при запуске вам нужно указать параметр --profile со значением профиля, который вам вывело в первый раз. Для получения наиболее полного снимка памяти можно воспользоваться файлом hiberfil.sys, в который сохраняется вся память при переходе винды в гибернацию. Здесь всё ещё проще, переходим в режим гибернации, загружаемся с любого livecd (в моём случае, всё тот-же TinyCore), монтируем системный диск(Read-Only) и флешку, копируем нужный файл.  Для TinyCore не забываем установить пакет для поддержки ntfs. Через fdisk -l, находим нужные нам логические разделы и монтируем их Копируем Дальше этот файл можно было скормить volatility (поддерживает файл гибернации с win7 или ранее). Поскольку у меня win10, мне этот вариант не подошёл.
Я попробовал отдать файл программе Hibr2bin, которая раньше была тем самым Sandman Framework. Но та выдала непонятный output, с которым отказались работать фреймворки для анализа.
На помощь пришёл Hibernation Recon с Free версией, который без проблем дал читаемый для фреймвоков выхлоп.
На выходе с memdump мы получаем файл с самой памятью процесса и файл с соотношением виртуальных адресов к адресам в файле. Для GUI я выбрал Qt. Для начала пишем удобную обёртку для обращения к виртуальной памяти в файле через таблицу. Каждую строчку idx-файла мы представляем в виде простой структуры. Все функции чтения данных по виртуальным адресам сводятся к вызову этой функции с нужными параметрами. Конвертация адреса проходит простым поиском нужного смещения в массиве (можно было бы применить бинарный поиск, но нет). Теперь сделаем структуру, в которой будем хранить данные каждого объекта в игре. Далее пишем класс, в котором будем хранить состояние мира (все объекты). Здесь происходит вся работа с дампом памяти и загрузка информации о всех объектах. Инициализируем смещения Здесь остановимся поподробнее. Вся информация о мире игры хранится в примерно такой структуре (Основано на дампе, найденном на форуме).  Получить доступ к этой структуре можно по указателю, который лежит по статическому для каждой версии игры смещению (смещение можно загуглить или самому найти через реверс, но это уже совсем другая история). Это смещение мы храним в переменной objTableAddress. В masterOffsets мы храним смещения на 3 таблицы, относительно этой структуры. В свою очередь каждая таблица хранит в себе ещё по 4 таблицы с длиной (смещения на эти таблицы мы храним в tableOffsets).
Теперь мы можем итерироваться по всем объектам в игре. Разберём функцию, которая обрабатывает каждую сущность.  Каждая сущность представляет собой примерно такую структуру Здесь нам интересны все три указателя. Из CfgVehicle мы читаем имя и тип. Из EntityVisualState мы читаем вектор координат, который представляет собой структуру из трёх переменных. Здесь нам нужны только x и y(на самом деле z), поэтому читаем их так: Кстати, в карту additionalFields, которая в EntityData, на этом этапе можно записать любую дополнительную информацию. Например, содержимое инвентаря или скорость перемещения. Сейчас мы получили и классифицировали информацию о всех сущностях в игровом мире, теперь её нужно как-то отобразить, для этого я использовал QPainter. Создаём класс виджета для рисования. Метки с техникой я рисую поверх картинки с картой. Метки на карте для текущего масштаба я кэширую в QPixmap (дорого рисовать заново несколько сотен или тысяч объектов при каждом сдвиге камеры). Для выбора типов сущностей, которые нужно отображать и других настроек, я использую QCheckBox-ы на боковой панели (их реализацию можно будет глянуть на гитхабе). Для связи отрисовки с настройками, я сначала использовал голый QSettings, но оказалось, что он не кэширует настройки в памяти, а напрямую работает с реестром, поэтому мне пришлось написать обёрточный синглтон с кэшем, который также при обновлении параметров посылает сигнал на перерисовку. Для удобного просмотра карты я реализовал масштабирование на курсор (на колёсико мыши) и сдвиг (с зажатым лкм-ом). Ещё одна важная фича — просмотр полных характеристик и игровых координат сущностей (при нажатии скм в район нужных объектов). Просмотр характеристик реализован с помощью фреймворка QtConcurrent, посредством модели MapReduce. Входной класс состоит из указателя на категорию сущностей и точки для поиска. В Map функции, мы проходим по всем объектам в категории, если сущность находится в константном радиусе от позиции курсора, то возвращаем полное описание объекта (название + дополнительные поля) и игровые координаты. На этом я заканчиваю свой рассказ. Кому не трудно, гляньте код, укажите на возможные косяки.
Заинтересованные могут добавить чтение дополнительных характеристик объектов и кинуть pull-request. Ссылки: C++/Qt, Python/Django