Как мы «вырастили» и победили читеров в своем онлайн-шутере
Часто сижу на форумах читеров, не потому что нравится, а просто разработчику PvP-шутера всегда нужно быть в тонусе. Некоторые из взломщиков в прямом смысле слова выросли на моих глазах вместе с проектом. Вспоминал эти истории после очередного апдейта в проекте и захотелось ими поделиться.
Несколько лет назад мы написали тестовый прототип шутера, который быстро стал популярным — защиты никакой не было, и некоторые побежали этим пользоваться. Мы затыкали пробоины скотчем, читеры находили новые дыры, а мы учились у них — с помощью социальной инженерии и повышения технических навыков. И в итоге пересмотрели отношение к защите будущих мобильных проектов (об этом — в конце статьи).
До появления мобильной Pixel Gun 3D в 2013 году команда Lightmap писала мини-игры на движке Cocos2d. То есть опыта ни в трехмерных, ни тем более мультиплеерных играх у нас тогда не было. Мы посещали конференции, очень много общались с другими разработчиками и, посмотрев на их опыт, все-таки решили попробовать себя в 3D на Unity.
Изучать движок решили на прототипе шутера, чтобы посмотреть, как отреагируют игроки. В итоге проект выстрелил так, что собирать опытную команду (а на старте было всего 3 разработчика) и разрабатывать качественный продукт с нуля уже не было времени. Всему пришлось учиться на своих ошибках после релиза.
Читеры из младших классов
С самого начала база игроков росла достаточно быстро, а с ними приходили первые читеры. Но из-за ограниченных ресурсов в приоритете стояли совсем другие задачи — на старте было мало контента, игровых механик, да и цельной меты как таковой не было. Только когда в обзорах на YouTube слишком часто стали всплывать упоминания о взломах, пришлось заняться этим вопросом.
То есть изначально мы даже не рассматривали проблему появления читеров, а думали только о том, как сделать интересную мобильную игру на Unity. Возможно это и была первая ошибка, но напомню, что мы впервые собирали подобный прототип.
Первыми атаковали самые настоящие школьники — в прямом и переносном смыслах слова, потому что взломать игру было проще простого. Со многими из них мы познакомились заочно, так как пришлось погрузиться в форумы и чаты, где они делились уязвимостями — было даже интересно наблюдать, как их навыки росли вместе с проектом, а с ними росли наши познания в защите.
Сначала они находили элементарные дыры — это использование простых переменных для данных в оперативной памяти и хранение данных на устройстве в незашифрованном виде. Поэтому тот же GameGuardian легко находил слабые места: валюту, время до конца матча, здоровье и так далее.
Сразу же решили передать хранение прогресса в защищенное зашифрованное значение и переделать все переменные, в которых хранились ответственные данные, на классы, где для скрытия используется рандомная соль. Не обошлось без факапов.
В месте, где валюта переносилась из старого хранилища в новое, мы допустили баг, и когда пользователь, который не входил в игру больше недели, обновлялся до новой версии — то вся его валюта обнулялась. Самым сложным было понять, в чем дело, потому что при наших тестах такой сценарий не воспроизводился. Оказалось, что место отправки аналитики входа в игру после долгого отсутствия (в которой косвенно использовалась валюта по коду) располагалось раньше нашей миграции.
Насчет прогресса тоже оставалась дыра — можно было ломать предыдущие версии и накатываться на новые. Тогда мы параллельно ввели новые валюты и сущности в игре, рассчитывая, что хотя бы их не будут ломать. Ценность старой валюты постепенно снижалась, так как новый контент на нее уже было не приобрести.
Также поставили хоть и локальную, но, все-таки, защиту на взлом инапов через LuckyPatcher. Когда позакрывали места, с которыми мог справиться и первоклассник, к взлому подключились «ученики средних классов».
Читеры постарше
Они начали менять код приложения, дописывать свои менюшки для взлома различных параметров, переподписывать и выкладывать apk, которые пользовались успехом на форумах.
Все старания спрятать в коде проверку подписи быстро находились и вырезались, как и другие проверки на взломы приложения. Для обфускации мы стали использовать появившуюся в Unity IL2cpp, но в итоге выяснилось, что движок хранит в проекте дамп всех методов с адресами памяти — чем стали пользоваться уже «старшеклассники».
Ситуация по сути не менялась, так как мы все время боролись с симптомами, а не с болезнью. Даже не смотря на то, что иногда нам удавалось закрыть уязвимости еще до их использования — для этого приходилось выдавать себя за тех самых читеров.
Социальная инженерия против читеров
Мы следили за взломщиками на форумах, общались, изучали, откуда они черпают знания и старались работать на опережение. У нас натурально были постоянные взломщики, которые на глазах перешли из средней школы в институт, набирались опыта и знаний.
Однажды один из таких ребят начал активно общаться с читером, который «ломал» другие игры. Мы это заметили, скачали его взломы, изучили принцип работы и заранее расставили необходимые детекты по своему приложению. Позже на YouTube мы увидели, что «наш» читер действительно пытался сделать аналогичный мод для Pixel Gun, но ничего рабочего в итоге не получилось.
В другой раз мы увидели анонс чита, который готовил один из игроков. По его нику нашли форум взломщиков и прочитали все его сообщения. Так мы поняли, каким инструментарием он пользуется, и даже без чита на руках смогли закрыть уязвимость и выпустить патч еще до релиза.
Но в итоге все равно различные взломы регулярно выпускались разными известными и не очень взломщиками. Все-таки дыра с валютой была лишь одной из многих на тот момент и далеко не самой опасной, потому что за ее использование надо было платить.
А тут случился еще один серьезный факап с нашей стороны. В сеть утекла версия для разработчиков годовалой давности с дев-консолью, в которой можно было легко намешать любую сущность. К этом моменту CCU в пике доходил до 70 тысяч игроков, а DAU стабильно переваливал за миллион пользователей.
Стало понятно, что дальнейшее развитие приложения невозможно при таком состоянии дел со взломами. Все старания с поднятием уровня основных метрик нивелировались, а часто даже занижались вывешенными взломанными версиями.
Приоритетной задачей стало: убрать возможность читерства из приложения.
Решение
Итак, что мы имели на входе:
Огромное приложение с несколькими годами активной разработки и большим легаси.
Возможность изменения версии и выкладки пользователям.
Хранение прогресса локально на девайсе. Как следствие — отсутствие контроля над обновлениями с прошлых версий, в том числе взломанных.
Синхронизация прогресса между девайсами через сторонние сервисы — прогресс можно было беспрепятственно суммировать между игроками.
Отсутствие надежной возможности бана читера — в измененных версиях его тоже вырезали.
Отсутствие надежного отслеживания фактов читерства.
В качестве игрового сервера — Photon Unity Networking (Cloud), который не имеет серверной логики и, следовательно, не дает возможности контролировать игровую логику.
Наличие измененных версий игры в китайских сторонних сторах.
Связь с сервером через www-запросы, которые легко отследить и подделать.
Возможность подставить из кода любой id, который мы не сможем идентифицировать как подставной.
В итоге: безбожное ломание всего кора и меты игры на тот момент. Поэтому решение тоже должно было быть комплексным — от обфускации кода и переноса хранения прогресса на наш сервер до защиты от переподписывания версий и введения собственной аналитической системы.
Причем эффект от всего этого был бы только в случае одномоментного выпуска всех мер защиты, потому что постепенный ввод изменений в проект значительно облегчил бы отслеживание апдейтов взломщиками, которые и так уже хорошо ориентировались в проекте. Другими словами, время, потраченное на взлом, не должно быть сопоставимо с выгодой.
Началась масштабная работа, для чего практически удвоили команду разработчиков, привлекая их с другого проекта.
Пока кратко о том, что мы сделали для перелома ситуации с читерами:
Для обфускации ввели новые стандарты написания кода, позволяющие плагину обфускации сделать свое дело, и переписали под них все приложение. Задача не особо сложная, но ресурсоемкая, так как кодовая база к этому времени уже была довольно большой.
Переработали хранение данных — еще более глобальная и ресурсоемкая задача. Сущностей к этому времени было несчетное количество, данные сохранялись беспорядочно в произвольных форматах, что никак нам не подходило. Для синхронизации прогресса с сервером реализовали постоянное сокетное соединение, переведя на него все функционалы, связанные с метой игры (ну и, само собой, сам сервер, но это отдельная история). Для игроков оставили возможность поиграть оффлайн в несколько режимов, правда без наград и изменения прогресса.
Чтобы мигрировать прогресс игроков, на время разработки глобальной защиты стали выдавать специальные ключи. Перенести прогресс в результате смогли только те, кто заходил в приложение в этот временной интервал. После релиза новой версии выдачу ключей остановили. И хотя эти ключи выдавались всем — и честным игрокам и читерам — основная цель была: исключить взломы через прошлые версии, так как без ключа прогресс не принимался сервером при миграции.
Реализовали надежную систему бана, которую нельзя было вырезать из клиента, так как у забаненного игрока блочится весь серверный функционал (при том что большая часть логики была перенесена на сервер).
Добавили подсчет хеша всех библиотек и начали сравнивать его с разрешенными при авторизации на сервере, куда они добавляются при сборке релизных билдов.
Расставили в дополнительные места защиту от переподписывания версий, лаунчеров (на Android), твиков (на iOS), спрятав уже в обфусцированном коде.
Для предотвращения взлома игровых параметров серверной логикой ввели Photon Plugin, доступный на тарифе Enterprise Cloud. Он позволяет мониторить пересылаемый между пользователями игровой трафик, чтобы вычислять тех, у кого действия выходят за рамки допустимого (жизни, урон, скорость перемещения/стрельбы, использование запрещенных предметов и так далее). Для возможности отслеживания взломов переписали сетевое взаимодействие игроков.
Добавили серверную валидацию инапов.
Добавили защиту от взлома оперативной памяти.
Практически одномоментно выкатили все в продакшен.
Продолжили реализовывать и улучшать собственную систему аналитики.
Сейчас аналитика — основной инструмент постоянного отслеживания попыток взлома. Мы можем отслеживать все действия каждого конкретного пользователя и реагировать даже на единичные попытки взлома, не давая распространиться лазейкам. А когда-то эту роль для команды играли YouTube и профильные сайты.
Путь проделан не маленький и можно еще многое расписать про подходы, инструменты, нашу архитектуру и инхаус-разработки, вроде аналитики. Но рассказ обо всем сразу будет слишком объемный, поэтому лучше оставлю место для вопросов в комментариях и для будущих материалов.
ААА-защита для мобильных игр
Сейчас игра надежно защищена от взломов, у нее, как минимум, нет распространенных методов взлома. Бывают единичные, но их оперативно отслеживаем и реагируем.
К новым проектам в разработке тоже стали относиться по-другому и сразу пишем их с защитой, почти как у полноценных ААА-игр. Максимально возможное количество защит на старте приложения означает, что у взломщиков слишком большой порог входа, который надо преодолеть — это отпугивает абсолютное большинство.
Также всегда проще писать сразу под необходимые меры защиты, а не переделывать проект под них в будущем.
На текущий момент наша программа-минимум для новых проектов это:
Плагин обфускации для осложнения понимания кода приложения.
Хранение и синхронизация прогресса через наш сервер с использованием валидации всех основных операций.
Зашифрованное хранилище на диске, чтобы исключить перенос данных от девайса к девайсу копированием данных.
Надежная система бана.
Photon Plugin, как минимум, для валидации действий пользователя.
Защита от изменения, переподписывания версий, лаунчеров и твиков.
Серверная валидация инапов.
Повсеместное использование засоленных данных — как защита от изменений в оперативной памяти.
Собственная система аналитики с отслеживанием подозрительных действий конкретных пользователей.
И продолжаем сидеть на форумах под видом читеров, общаться и мониторить новые уязвимости. Например, одна из последних — это скрытие использования тиков после выхода джейлбрейка на свежие версии iOS. Об этом тоже узнали из форумов, изучили механизмы работы и оперативно выкатили обновление —, но об этом и других кейсах уже в следующий раз.