TRANSFORMERS: Forged to Fight – это 3D-игра в жанре файтинг, где вы берете под контроль одних из самых харизматичных бойцов прямо из вселенной Transformers. Речь идет о таких громких именах, как Оптимус Прайм, Мегатрон, Бамблби, Ратчет, Саундвейв и Гриндор – не меньше. Да, вы не ослышались. Ваши любимые персонажи из любых Transformers
Этот пакет содержит работающую офлайн-загрузку Transformers: Forged to Fight, а также все инструменты, патчи и заметки по обратной разработке, которые к этому привели. Он предназначен для того, чтобы его подхватил кто-то, у кого есть время и энергия сделать следующий, гораздо больший шаг — воссоздать серверную часть игры с нуля. Всё здесь документировано, чтобы вам не пришлось начинать с нуля, как это пришлось мне.
Прочтите весь этот файл, прежде чем что-либо трогать. Раздел «Подводные камни» в частности сэкономит вам дни.
Игра полностью загружается в офлайне и доходит до реального интерактивного главного экрана без каких-либо живых серверов. С главного экрана меню навигируются без вылетов: база, список ботов (с присутствующим в аккаунте ботом), выбор режима боя, экран кристаллов и обычные всплывающие окна и подсказки. Полный процесс входа завершается, каждое онлайн-подсистема подключается, а первый запуск и обучение пройдены. Скриптовый вступительный бой (Оптимус против Старскрима) даже доходит до начала загрузки сражения, и 3D-модели персонажей рендерятся и анимируются.
Это была сложная часть, и она решена. Клиент снова жив в офлайне.
Сам геймплей не работает. В сюжете нет миссий, а бои не могут полностью загрузиться. Это не ошибка и не то, что можно исправить патчем.
Forged to Fight была полностью сервер-авторитарной. Приложение на телефоне — это по сути экран с элементами управления. Почти ничего в игре не хранилось в приложении. Каждая миссия, каждый бой, каждый состав врагов, вся статистика и способности отряда, экономика и весь баланс жили на серверах Kabam и передавались на устройство каждый сеанс. Когда серверы были отключены в начале 2020 года, эта база данных контента исчезла вместе с ними, и она никогда не была выпущена или публично заархивирована где-либо, до чего я могу добраться.
Таким образом, ситуация чётко разделена на две части. Арт и звук сохранились, потому что они поставляются
внутри приложения (см. re_notes/ASSET_INVENTORY.txt). Каждый персонаж — это полноценный пакет ресурсов Unity,
содержащий модель, текстуры, скелет, клипы анимации, контроллеры аниматора, эффекты
и аудио. Окружение, здания, интерфейс, портреты, кат-сцены и диалоги — всё это
тоже есть. Что не сохранилось — это данные, которые сообщали игре, какие из этих ресурсов использовать,
как собрать их в бой или миссию и каковы на самом деле были числовые параметры каждого бота. Все
части на месте. Просто больше не осталось ничего, что знало бы, как их собрать. Воссоздать это — вся работа, что осталась.
Здесь четыре движущиеся части. Вместе они заставляют немодифицированную игру думать, что она общается с Kabam.
Нативные бинарные патчи. Игра использует Unity IL2CPP, поэтому логика находится в скомпилированной ARM
библиотеке libil2cpp.so, а не в редактируемых скриптовых файлах. patches/patch_il2cpp.py переписывает
шесть функций в этой библиотеке, чтобы обойти проверки мёртвых серверов: он обходит два
пути закрепления сертификатов, чтобы наш собственный сертификат TLS был принят, заставляет блок
регистрации менеджера выполняться, даже если живая конфигурация равна null, позволяет входу в систему
завершиться с нашей локальной сессией устройства и подавляет фатальные ошибки подсистем, которые иначе
вызывали бы диалог «не удалось войти». Он также повторно внедряет одну запись зависимостей (см. раздел
«Подводные камни»), чтобы хук времени выполнения действительно загрузился. На выходе — libil2cpp.patched.so.
Поддельный сервер Sparx. server/fakeserver.py заменяет бэкенд Kabam. Он слушает на
TLS 443 и обычном HTTP 80 и отвечает на API-вызовы игры. Заранее подготовленные ответы находятся в
server/responses/, по одному файлу на точку входа, названные по методу и пути, например
GET__account_data.json. Некоторые точки входа обрабатываются динамически в коде, а не
из файла, поскольку игра ожидает, что они будут повторять значения из запроса (точки входа
обучения и точка входа деталей героя). Формат ответа —
{"error":null,"result": ...}. Обратите внимание, что внутри полезной нагрузки ошибки Sparx поле пишется как
err, а не error. Эта деталь важна и её легко пропустить.
Нативный хук времени выполнения. tools/nativehook/ собирает libdothook.so — небольшую библиотеку, которая
загружается в игру при запуске и регистрирует каждый ключ данных, которые игра читает, плюс пару
целевых корректировок поведения. Это была обратная связь, сделавшая всё остальное возможным: она
сообщает вам точно, что игра запрашивает, чтобы вы могли синтезировать ответ и проверить
его. Это чистый хук с перезаписью байтов, установленный до выполнения, потому что обычный
инструмент для этого (Frida) вылетает под эмулятором из-за слоя трансляции ARM.
Настройка устройства. Эмулятор должен направлять домены Kabam на ПК и доверять поддельному
сертификату. tools/provision_ldplayer.sh делает это одной командой: он помещает заплаченную библиотеку
и хук, перенаправляет имена хостов Kabam на LAN-адрес ПК через файл hosts,
монтирует поддельный CA в системное хранилище доверия и ослабляет SELinux. Запускайте его после каждого
перезапуска эмулятора, потому что эти монтирования не переживают перезагрузку.
Поток данных во время выполнения: игра делает HTTPS-вызов к домену Kabam, файл hosts отправляет его
на ПК, поддельный сервер отвечает ответом из server/responses/, заплаченная библиотека принимает сертификат и ответ, а хук регистрирует, что было прочитано. Этот цикл — как был создан каждый экран в этой сборке.
README.md этот файл
TECHNICAL_NOTES.md более глубокое техническое описание: патчи, восстановленные структуры данных, находки
patches/
patch_il2cpp.py шесть нативных патчей плюс повторное внедрение зависимости
disasm_fn.py вспомогательный: дизассемблирование функции по смещению
find_callers.py вспомогательный: поиск вызывающих функций
find_str_ref.py вспомогательный: поиск ссылок на строку
server/
fakeserver.py поддельный сервер Sparx
gen_certs.sh пересоздать сертификат TLS и CA (запустите это, см. ниже)
setup_device.sh справочник по настройке сети и доверия на устройстве
iterate.sh быстрый перезапуск и захват логов
responses/ по одному JSON-файлу на каждую точку входа, вызываемую игрой
tools/
provision_ldplayer.sh однократная перенастройка эмулятора в рабочее состояние
setup_arm64.sh заметки по настройке цепочки инструментов
decompile_targets.py запуск безголового декомпилятора Ghidra по выбранным смещениям
find_xrefs.py поиск перекрёстных ссылок в бинарнике
apply_labels.py применение меток символов IL2CPP
light_analyze.py лёгкие вспомогательные функции статического анализа
frida_attach.py помощники Frida (оставлены для справки, см. примечание о libnb)
frida_run.py
hook_dot.js
nativehook/
hook.c исходник libdothook.so, хук времени выполнения
libdothook.so предварительно собранный хук, arm64
deploy.sh сборка и развёртывание хука
relaunch_and_capture.sh перезапуск игры и захват логов
hook/dothook.c более ранний вариант хука, оставлен для справки
re_notes/
dump.cs полный дамп IL2CPP: каждый класс, метод и поле в игре
decomp_out.c декомпилированные тела ключевых функций
decompile_targets.txt смещения, которые стоит декомпилировать
ASSET_INVENTORY.txt какие арт и аудио уже поставляются внутри приложения
re_notes/dump.cs — самый ценный файл для оставшейся работы. Это
полная модель типов игры: каждый класс, каждый метод и, что критически важно, каждое поле данных,
которое клиент читает с сервера. Это ваша карта всего бэкендного API. Когда вам
нужно узнать, какой формы должен быть ответ, ответ находится там.
Следующее было намеренно исключено, потому что это большое, или защищено авторскими правами, или секретно, или вы должны сгенерировать своё собственное.
com.kabam.bigrobot, версия 9.2.0). Он около 800 МБ. Найдите свою собственную
копию. Имя пакета и версия указаны в TECHNICAL_NOTES.md.libil2cpp.so и игровые ассеты. Оба извлекаются напрямую из APK. Распакуйте
APK, библиотека находится в lib/arm64-v8a/, ассеты — в assets/.server/gen_certs.sh, чтобы создать свою собственную
пару, затем укажите хранилищу доверия устройства на новый CA.patches/patch_il2cpp.py против оригинального
libil2cpp.so из APK.re_notes/dump.cs из библиотеки APK и глобальных метаданных.Вам нужен APK, установленный на эмуляторе с поддержкой трансляции ARM (использовался LDPlayer 9, с root и перезаписываемой системой), Python на ПК и элементы из раздела выше.
bash server/gen_certs.sh.python patches/patch_il2cpp.py path/to/original/libil2cpp.so --apply.tools/nativehook/deploy.sh.python server/fakeserver.py. Он должен быть доступен
на портах 443 и 80 с эмулятора.bash tools/provision_ldplayer.sh <ваш-LAN-IP-ПК>. Повторяйте это
после каждой перезагрузки эмулятора.Если он зависает при входе, сначала проверьте первый пункт в разделе «Подводные камни», прежде чем что-либо делать.
Это те, которые стоили мне часов. Они записаны, чтобы не стоили того же вам.
libdothook.so. Точные байты и смещения документированы в скрипте патча и в
TECHNICAL_NOTES.md.provision_ldplayer.sh, иначе ничего не подключится.err, а не error. Использование неправильного приводит к
ответам, которые клиент молча игнорирует или обрабатывает неправильно.Это настоящая работа, и она объёмна. Вот её структура и с чего начать.
Цель — воссоздать вручную серверный контент, который ранее транслировался клиенту: квесты и миссии, карты и составы врагов, полный список ботов с их статистикой и способностями, боевые формулы и экономику. Ничего этого больше не существует, поэтому всё должно быть создано заново, в точных формах, которые ожидает клиент.
Метод, который работает, — это цикл, вокруг которого построен этот проект. Запустите игру с подключённым
хуком. Хук регистрирует каждый ключ, который читает клиент. Когда клиент запрашивает что-то, чего вы
не предоставили, вы видите именно то, что ему нужно. Затем вы синтезируете ответ в правильной
форме, помещаете его в server/responses/ или добавляете в динамический обработчик в
fakeserver.py, перезапускаете и проверяете, принимает ли его клиент и продвигается ли он дальше. Повторяйте. Каждый
экран в текущей сборке был создан именно таким образом. re_notes/dump.cs подсказывает вам
форму каждой структуры ещё до запуска, потому что он перечисляет каждое поле, которое читает клиент.
Разумный порядок атаки:
decompile_targets.py) и прочитайте
точные поля.ASSET_INVENTORY.txt, поэтому вы
создаёте только числа и определения способностей, а не ассеты.TECHNICAL_NOTES.md для ключей.Будьте реалистичны в масштабах. Даже для игр, где фанаты сохранили данные живого сервера до отключения, поднятие приватного сервера — долгий проект. Здесь нет сохранённых данных, с которых можно начать, поэтому каждое число и каждая способность должны быть исследованы или изобретены заново, а затем проверены на клиенте. Это многолетний проект для нескольких человек, если цель — настоящая игра. Тем не менее, путь больше не является загадкой. Загрузка решена, обратная связь существует, модель типов дампнута, а ассеты целы. Осталась лишь очень большая объёмная работа по тщательному восстановлению данных, а не дальнейшая обратная разработка неизвестного.
Начните с TECHNICAL_NOTES.md. Это более глубокий технический справочник с точными
патчами, восстановленными формами данных и конкретными находками, более подробно, чем этот
README. Затем запустите цикл.
Удачи. Теперь это настоящая машина. Ей просто нужно восстановить свой контент.