Взлом игр Unity на примере игры Poker World

Взлом игр Unity на примере игры Poker World

Разработчики игр с удовольствием пользуются теми удобствами, что им предоставляет движок Unity, но, как выяснилось, он столь же удобен и для любого желающего вскрыть эти игры. Для примера я возьму Poker World и покажу на ней, как можно не только менять параметры, но и влезть в саму логику, переиначить все на свой лад и перепаковать APK. Заодно соберем небольшой набор утилит, который поможет в работе с мобильным софтом.

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

Работа работой, а отдыхать тоже нужно. Человек я не азартный, но в карты покидать люблю. Недавно я приметил офлайновое приложение для игры в покер под названием Poker World. У него аскетичный интерфейс, минимальный набор функций, но есть почти все, что мне нужно. Напрягал только повышенный интерес разработчиков к донату. Поэтому с каждой раздачей исследовательская жилка напрягалась и таки не выдержала. Я взялся за клавиатуру с твердой уверенностью раздобыть себе немного виртуальных деньжат.

Первые шаги

Настройки эмулятора MEmu 5.5.1
Настройки эмулятора MEmu 5.5.1

Чтобы начать вивисекцию приложения нам понадобится небольшой стенд. В первую очередь стоит поставить нормальный эмулятор Android. Раньше я использовал Andy, но теперь он скурвился и даже начал пихать майнеры в свои дистрибутивы. Мне в срочном порядке пришлось искать замену. Моя основная ОС — Windows и поэтому все поиски были направлены на дистрибутивы для этой платформы. Я перебрал с десяток вариантов из топа выдачи Google, и все они, культурно выражаясь, оставляли желать лучшего. Однако мои молитвы были услышаны, и я наткнулся на Memu. На момент написания статьи последняя версия была 5.5.1. Тут есть все, что тебе может понадобиться. Создавать можно виртуальные машины Android версий 4.4 и 5.1, а также поддерживает эмуляцию нескольких моделей устройств.

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

Главный экран эмулятора MEmu после запуска
Главный экран эмулятора MEmu после запуска

Что очень важно, MEmu поддерживает установку приложений из файлов APK и, о боги, в нем есть обычные настройки сетевого подключения Android. Это позволяет легко настроить устройство на работу через прокси типа Burp и перехватывать трафик. Ты удивишься, но часть эмуляторов не поддерживала работу через прокси и не имела стандартных сетевых настроек.

В общем, пока у меня не возникало претензий к MEmu. Если ты знаешь о более достойных вариантах, не стесняйся и пиши о них в комментариях.

Главное окно утилиты APK Studio
Главное окно утилиты APK Studio

Еще нам понадобится APK Studio, чтобы иметь возможность удобно распаковывать, пересобирать и подписывать пакеты. Для подписи пакетов к нему потребуется скачать uber-apk-signer и положить в директорию C:\Users\<имя_юзера>\.apkstudio\vendor, предварительно переименовав в uber-apk-signer.jar. Также можешь обновить apktool до последней версии и скопировать в ту же папку.

И, конечно же, само приложение. Его можно скачать из Play Market и App Store, но нам ведь нужен сам дистрибутив. Тут на помощь приходят сайты-агрегаторы приложений. Такого рода сервисы легко гуглятся по запросу apk download. Я, например, остановился на https://apkpure.com/, где помимо текущей версии приложения можно скачать и предыдущие (иногда бывает полезно).

Переходим по ссылке и скачиваем нашего подопытного. На момент написания статьи последняя версия приложения — 1.3.5.

Загрузка игры Poker World 1.3.5 в эмуляторе
Загрузка игры Poker World 1.3.5 в эмуляторе

Теперь можно установить скачанный apk в эмуляторе. Для этого достаточно перетащить его на окно с запущенным MEmu — практически в лучших традициях macOS.

На этом этапе базовые приготовления закончены. Обо всех остальных полезных штуках и утилитах я расскажу в процессе препарирования приложения.

Начинаем веселье в iOS

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

Своеобразный однорукий бандит в Poker World
Своеобразный однорукий бандит в Poker World

Парочку таких я и обнаружил. В игре есть возможность раз в четыре часа крутить однорукого бандита, из которого тебе рандомно выпадают всякие ништяки. Их в игре всего два вида — это деньги и билеты. И те, и другие нужны для участия в турнирах. Так вот в местном аналоге тотализатора можно выиграть небольшое количество денег или один билетик. Количество денег, которые ты можешь срубить, зависит от уровня твоего персонажа. Каждые несколько уровней суммы выигрыша в этой рулетке удваиваются. На самом первом они составляют от $400 до $2000.

Про билет и 2000 баксов можно забыть, за месяц игры и тысячи кручений этой рулетки ни разу ничего подобного мне не выпало. Интересно будет взглянуть на алгоритм.

Эволюция спинов в Poker World
Эволюция спинов в Poker World

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

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

Чтобы бесконечно не переводить время в будущее, можно сделать так:

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

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

Вообще, я сильно удивился тому, какие проблемы может вызвать изменение даты на устройстве с iOS. Например, после того как я выставил 2030, меня разлогинил iCloud и отказывался пускать обратно с неизвестной ошибкой. Я уж было подумал, что мой аккаунт заблокировали за путешествия во времени. Повторно авторизоваться удалось только после перезагрузки девайса.

Два года назад в iOS нашли баг: устройство окирпичивалось, если поставить дату на 1970 год. Можно предположить, что от системной даты многое зависит.

Плюс сама смена даты неудобна — чтобы сменить год, нужно прокрутить все 365 дней. Вот и сиди, вози пальцем как сумасшедший.

Эволюция бесплатных игр в Poker World
Эволюция бесплатных игр в Poker World

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

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

Интересный файл с настройками игры Poker World
Интересный файл с настройками игры Poker World

Но это все цветочки. У меня завалялся старый джейлбрейкнутый айфон, а это значит, что настало время заглянуть поглубже в недра игры и посмотреть, что там творится. Запускаю утилиту Filza и смотрю, где располагаются файлы приложения. У меня это /path. Немного покопавшись, я обнаружил интересный файл com.youdagames.pokerworld.plist.

Редактирование количества денег и билетов у игрока в Poker World
Редактирование количества денег и билетов у игрока в Poker World

Сам файловый менеджер Filza позволяет открывать, редактировать и сохранять файлы plist. В нем располагаются разные настройки, которые касаются игры в целом и текущего пользователя, в частности. Мой взгляд зацепился за парочку интересных переменных с названиями — UserChips, UserTickets. И да, они означают именно то, что ты подумал. Это количество твоих денег (фишек) и билетов. Я поменял значения на нужные и запустил игру.

Добавили себе фишек и билетов
Добавили себе фишек и билетов

И вуаля! Виртуальный миллионер. Помимо этого в файле находится куча интересных параметров — таких как текущий уровень игрока, его позиция в десятке лидеров, какие уровни уже пройдены, лимиты столов и прочее. Если будет интересно, то можешь поэкспериментировать на досуге, а я перехожу к версии приложения для Android и более интересным вещам.

Властвуем в Poker World для Android

Домашняя папка Poker World в Android
Домашняя папка Poker World в Android

Первым делом точно так же проверяем домашнюю папку приложения. Не лежат ли там какие-нибудь интересные файлы? Для этих целей я воспользуюсь файловым менеджером из Cyanogen Mod и перейду в папку /data/data/com.youdagames.pokerworld/shared_prefs/.

Файл с настройками Poker World на Android
Файл с настройками Poker World на Android

Сразу же бросается в глаза файл com.youdagames.pokerworld.v2.playerprefs.xml. Откроем его и убедимся: там все то же самое, что и в iOS, только в формате XML.

Но мы это уже проходили, поэтому ценность этой находки для нас минимальна. Пойдем чуть дальше.

Возможные декомпиляторы на сайте javadecompilers.com
Возможные декомпиляторы на сайте javadecompilers.com

Попробуем декомпилировать apk-файл с игрой. Для этих целей я почти всегда использую замечательный онлайновый сервис javadecompilers.com/apk. Кстати, помимо приложений для Android, он может декомпилировать файлы JAR, причем разными методами. На выбор декомпиляторы JDCore, CFR, Jadx и т.д.

В общем, декомпильнули наш файл, скачали его, распаковали и видим, что ничего особо интересного там нет. Печаль.

Также есть целый фреймворк, который неплохо помогает в исследовании мобильных приложений, он называется Mobile Security Framework, MobSF. Он тоже выполняет декомпиляцию приложения и ищет в получившихся исходниках всякие интересные вещи и потенциальные уязвимости. Рекомендую не брезговать им и натравливать его на исследуемые приложения. Фреймворк легко устанавливается и, помимо этого, существует в виде контейнера Docker, что сводит его установку к одной команде.

[/crayon]

Игра Poker World написана на Unity
Игра Poker World написана на Unity

Но нам это тоже не поможет. У нас здесь игра на движке Unity, на что недвусмысленно намекает наличие характерных файлов.

Декомпиляция Unity файлов из Poker World в ILSpy
Декомпиляция Unity файлов из Poker World в ILSpy

Я, конечно же, слышал про этот игровой движок, но никогда не приходилось иметь с ним дело в плане реверса. Немного покурив мануалы, я узнал, что все самое интересное обычно находится в файлах Assembly-CSharp.dll, Assembly-CSharp-firstpass.dll и Assembly-UnityScript.dll из папки Managed. Как видно из названия, они написаны на C#, поэтому нам нужен соответствующий декомпилятор. Есть несколько классных вариантов, среди них ILSpy и DotPeek. Обе утилиты абсолютно бесплатны и имеют свои фишки; я остановился на ILSpy. Откроем в нем Assembly-CSharp.dll и Assembly-CSharp-firstpass.dll.

Разворачиваем дерево файла Assembly-CSharp.dll и наблюдаем огромное количество классов с интересными названиями. Это абсолютна вся логика игры. Есть где развернуться!

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

Сначала я было расстроился, но немного погуглив, я нашел отличное решение. При помощи утилиты под названием dnSpy мы можем вносить изменения напрямую в DLL, причем так, как если бы мы просто редактировали ее код на C#. Просто магия вне Хогвардса!

Декомпиляция файлов Unity из Poker World в dnSpy
Декомпиляция файлов Unity из Poker World в dnSpy

Скачиваем программу и открываем наши библиотеки в ней.

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

Сначала изменим что-нибудь простое, чтобы понять, сработает ли. Например, я нашел класс, который отвечает за отображение меню настроек игры. В нем есть метод Show(), который отрабатывает при нажатии на кнопку настроек.

/Assembly-CSharp/SettingsMenu.cs

Экран настроек в Poker World
Экран настроек в Poker World

Здесь задается переменная this.version.text, которая содержит номер текущей версии игры. Он выводится в левом нижнем углу на экране настроек.

Добавим к этой строчке что-нибудь свое. Для этого нужно кликнуть правой кнопкой мыши внутри метода и выбрать пункт меню Edit Method (C#) или просто нажать Ctrl-Shift-E.
Контекстное меню выбранного метода

Контекстное меню выбранного метода

Откроется окно для внесения изменений только в выбранный метод. Ты можешь выбрать Edit Class (C#) и редактировать весь класс целиком, но сейчас нам это не нужно.
Окно редактирования выбранного метода в dnSpy

Окно редактирования выбранного метода в dnSpy

Я добавил переменную str3, в которой написал небольшое приветствие.

/Assembly-CSharp/SettingsMenu.cs

После этого нажимаем кнопку Compile. Тут компилятор может вернуть ошибки.
Ошибки компиляции метода в dnSpy

Ошибки компиляции метода в dnSpy

Не будем сильно вдаваться в суть ошибок; посмотрим лучше на место, где они обнаружились. Видишь то же самое имя файла, который мы редактируем, только с постфиксом g? Это означает global, то есть ошибки (по мнению компилятора dnSpy) содержит основной файл класса. Но мы ведь изменяем лишь один метод, а значит этими ошибками можно спокойно пренебречь. Поэтому двойным кликом по сообщению об ошибке, переходим в место, где они обитают, и просто комментируем неугодные строки.
Устраняем ошибки компиляции метода в dnSpy

Устраняем ошибки компиляции метода в dnSpy

После этих действий компиляция прошла успешно. Теперь можешь посмотреть в начало класса и заметить, что те строки, что мы комментировали, находятся в изначальном состоянии.
Состояние класса после рекомпиляции метода

Состояние класса после рекомпиляции метода

Метод перекомпилирован, теперь идем в меню File и выбираем Save Module.
Таким образом, у нас появилась обновленная DLL. Осталось собрать все обратно в APK, чтобы запустить на телефоне. Хоть APK — это обычный архив ZIP, но просто запаковать и изменить расширение недостаточно. Нужен верный манифест-файл и правильная подпись.

В этих делах нам поможет утилита apkstudio. Откроем APK с игрой и распакуем в какую-нибудь папку при помощи пункта меню File → Open → APK.
Меню File утилиты APK Studio

Меню File утилиты APK Studio

В опциях открытия файла в Project Path указываем путь, куда складывать распакованные данные. Также можешь убрать галочки с пунктов Decompile Source и Decode Resources, так как нам не нужно декомпилировать исходники и декодировать ресурсы приложения.
Настройки декодирования APK-файла

Настройки декодирования APK-файла

Теперь жмем Decode и переходим в папку с распакованным приложением. Копируем отредактированный DLL ( Assembly-CSharp.dll) в /assets/bin/Data/Managed с заменой существующей. Снова идем в APK Studio и жмем F5 или выбираем пункт Build из меню Project. В директории, где лежит содержимое APK появился собранная версия. Но просто так установить ее не получится. Остался еще один шаг — подпись.

Сначала нужно сгенерировать ключ. Это можно сделать с помощью входящей в состав Java утилиты keytool. Для создания выполним следующую команду:

Создание ключа для подписи APK
Создание ключа для подписи APK

Выбор ключа для подписи APK
Выбор ключа для подписи APK

Возвращаемся в APK Studio, переходим в меню Project → Sign/Export. Выбираем свежесозданный контейнер и указываем пароль к нему, название ключа и его пароль.

Успешная подпись APK
Успешная подпись APK

Нажимаем Sign. Программа немного подумает и скажет, что все прошло успешно.

Изменили логику работы приложения Poker World
Изменили логику работы приложения Poker World

Вот теперь можно устанавливать получившееся приложение. Запускаем его, переходим в настройки и видим, что наша строка красуется рядом с версией приложения.

Ну что, теперь пора браться за дела покруче, чем простое добавление строчек.
Немного побродив по исходникам, я наткнулся на интересные классы Cheat и CheatMenu. Это менюшка с читами и, судя по методам, есть очень интересные: выиграть текущую игру, показать карты соперников, выиграть текущую игровую зону.

/Assembly-CSharp/CheatMenu.cs

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

В методе Init происходит инициализация меню.

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

Однако просто активировать чит-меню недостаточно. Обрати внимание на метод Update.

Каждый раз вызывается CheckTouches.

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

Активированное чит-меню в Poker World
Активированное чит-меню в Poker World

Сохраняем, билдим, подписываем, устанавливаем, запускаем и видим чит-меню. Можно убедиться, что все кнопочки рабочие.

Игра за столом Poker World
Игра за столом Poker World

Но что-то я не вижу в нем самой интересной функции — показать карты соперников. Нужно исправлять это досадное упущение. Посмотрим на то, как выглядит экран во время игры.

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

/Assembly-CSharp/LastHandMenuButton.cs

Смотрим карты соперника в Poker World
Смотрим карты соперника в Poker World

Пересобираем приложение и теперь при нажатии на нужную кнопку будут показываться карты противников.

РЕКОМЕНДУЕМ:
Как писать читы для игр

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

Выводы

Благодаря таким манипуляциям можно «подправить» почти с любую игру, написанную на Unity, а это, как ты знаешь, очень и очень популярный движок. У dnSpy есть даже специальные билды библиотеки Mono.dll. Заменив оригинальную версию такой библиотеки, можно отлаживать приложение с помощью встроенного в dnSpy дебаггера. Очень удобная вещь.

Лично я получил немало удовольствия от того, что разобрался в логике работы приложения. Надеюсь, тебе тоже понравилось!

Понравилась статья? Поделиться с друзьями:
Комментарии: 2
  1. Александр

    Привет, можешь сделать mod, для андроид онлайн-игры War Robots: https://play.google.com/store/apps/details?id=com.pixonic.wwr, чтобы играть только против ботов (как до 4 уровня, когда только начинаешь игру) ? Для этого требуется отредактировать через dnSpy(к примеру) файл Assembly-CSharp.dll и.т.д. MOD должен получится как на видео: https://www.youtube.com/watch?v=FJNWbtgh8GI

  2. р

    пж зделайте софт для gco бесплатный данат и много разных модов

Добавить комментарий