Часто сижу на форумах читеров, не потому что нравится, а просто разработчику 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. Об этом тоже узнали из форумов, изучили механизмы работы и оперативно выкатили обновление — но об этом и других кейсах уже в следующий раз. Руководитель техотдела