
Автор - Александр Ананикян, аналитик PT MAZE
Если вы разрабатываете мобильные приложения и хотите защитить их от реверс-инжиниринга, клонирования и поиска уязвимостей, то вас точно заинтересуют протекторы — инструменты, которые затрудняют статический анализ. Применение различных техник запутывания (обфускации) и упаковки кода способно сделать ваше приложения сложнее для взлома злоумышленниками, а то и вовсе отбить у них всякое желание атаковать.
В исследовании мы проанализировали 95 наиболее популярных Android-приложений магазина RuStore с помощью сканера MobSF — популярного инструмента статического анализа с открытым исходным кодом. В среднем число выявляемых уязвимостей сократилось на 40%. Давайте заглянем за сухую статистику и узнаем, что же дало такой эффект.
В этой статье мы разберем:
Для наглядности рассмотрим категории, для которых протектор показал высокую степень эффективности: Code, Secrets, Firebase URLs, Network.

Рисунок 1. Доля приложений, в которых обнаружен конкретный тип угроз
Байт-код и ресурсы — это самые распространенные места, которые содержат риски любого уровня критичности, в том числе высокого. Данные области являются настоящим сокровищем для специалистов по реверс-инжинирингу. Сканер показал, что все приложения выборки содержат уязвимость или недостаток в этих местах.
По этическим соображениям мы не показываем фрагменты кода с критическими уязвимостями, а используем более нейтральные примеры. Одним из них является использование небезопасных хеш-функций.
Листинг 1. Пример использования небезопасного алгоритма хеширования паролей в исходном коде
hash = bytesToHex(MessageDigest.getInstance("MD5").digest(input.toByteArray(StandardCharsets.UTF_8)))
На рисунках ниже представлены фрагменты декомпилированного кода до и после применения шилдинга. Протектор скрыл упоминание хэш-функции MD5: как в строковых параметрах, так и в названиях классов, методов и полей.
Рисунок 2. Фрагмент декомпилированного кода до шилдинга
Рисунок 3. Фрагмент декомпилированного кода после шилдинга
Firebase позволяет хранить данные, собирать аналитику, отправлять push-уведомления и удалённо изменять поведение приложения без его обновления через магазин. На практике не все разработчики правильно настраивают Firebase, из-за чего возникают недостатки безопасности — например, включённый Remote Config или неправильная обработка соединений с базой Firebase Realtime Database, что может привести к утечке данных.
На рисунках ниже продемонстрированы фрагменты использования Remote Config в коде и ресурсах приложения.
Рисунок 4. Импорт классов com.google.firebase.remoteconfig.* до шилдинга
Рисунок 5. Пустой результат поиска классов com.google.firebase.remoteconfig.* в приложении после шилдинга
После применения протектора использование классов com.google.firebase.remoteconfig.* стало заметно менее очевидным для статического анализа. Протектор обфусцировал прямые ссылки на соответствующие классы Firebase, из-за чего декомпилятор больше не отображают вызовы Remote Config в явном виде.
Также шифрование значение ресурсов скрыло потенциальный Remote Config key — google_api_key. Это делает статический анализ ещё сложнее: ключ присутствует, но его значение невозможно получить привычными методами анализа ресурсов APK-файла.
Рисунок 6. Значение google_api_key хранится в открытом виде до применения протектора
Рисунок 7. Обфусцированное значение google_api_key после применения протектора
Одной из частых проблем реализации безопасного соединения становится неверная конфигурация файла network_security_config.xml. Разработчики могут случайно разрешить незашифрованный трафик (cleartext traffic) или доверять всем системным сертификатам без уточнения, какие именно должны использоваться. Такие упрощённые параметры делают соединение уязвимым для перехвата данных и атак типа Man-in-the-Middle (MITM).
В данном разделе представлен пример использования приложением встроенных сертификатов @raw/<имя> в файле network_security_config.xml и фрагмент содержимого одного из них.
Рисунок 8. Использование встроенных сертификатов до шилдинга
Рисунок 9. Фрагмент встроенного сертификата до шилдинга
Для усложнения статического анализа было применено переименование имени сертификатов и шифрование их содержимого.
Рисунок 10. Содержимое файла network_security_config.xml после шилдинга
Рисунок 11. Фрагмент встроенного сертификата после шилдинга
В приложениях в открытом виде могут оставаться различные секреты: учетные данные, API-ключи, токены интеграций, строки подключения или криптографические ключи в strings.xml, ресурсах res/raw/, бинарных файлах или прямо в исходном коде. Такие данные легко извлекаются из APK-файла и могут быть использованы для несанкционированного доступа к сервисам.
Одним из примеров является хранение в коде строкового значения, которое может заинтересовать злоумышленника из-за схожести с токеном.
Рисунок 12. Строковое значение в коде приложения
Шифрование строк скрыло данный секрет в коде приложения.
Рисунок 13. Пустой результат поиска
В приложении существуют места, искажение которых может нарушить работоспособность приложения, поэтому протектор применяется к ним очень точечно. Например, файл AndroidManifest.xml — «оглавление» всего приложения. И хотя протектор может исказить имена классов, некоторые данные остаются в открытом виде в любом случае. Например, ссылка на assetlinks.json.
Рисунок 14. Хранение домена и схемы, на которые привязан App Link
Хочется пару слов сказать о слабых местах методологии исследования. Несмотря на то, что статические анализаторы могут дать численную оценку улучшения защищенности приложения в целом, стоит всегда помнить о том, что они могут генерировать ложноположительные результаты, и оценка отдельных категорий может быть некорректной.
Далее мы покажем ложноположительное срабатывание MobSF, связанное с якобы отсутствующим на сервере файлом assetlinks.json. Из-за этого сканер ошибочно считает, что злоумышленник может перехватить deep link.
Проверка существования assetlinks.json на сервере была выполнена по сети. В ответе получены идентификатор приложения и отпечаток сертификата SHA-256, которые совпадают с APK-файлом.
Рисунок 15. Проверка существования assetlinks.json
Другим примером такой ситуации является категория Certificate, которая оказалась малопригодной для анализа из-за большого числа ложноположительных срабатываний. Например, MobSF отмечает использование подписи по схеме v1 и автоматически связывает это с уязвимостью Janus, но ручная проверка приложений не подтвердила наличие данного недостатка.
Рисунок 16. Проверка подписи приложения на уязвимость Janus
Теперь вы знаете о том, как работают протекторы и на какие участки мобильного приложения они влияют сильнее всего. Протекторы отлично работают с кодом и ресурсами, так как эта часть приложения хорошо поддается модификациям. Скрывать уязвимости, забытые секреты и интеллектуальную собственность в этих местах можно достаточно серьезными техниками. Но как у любой технологии, у протекторов есть границы применения, и это мы хорошо увидели на примере конфигурации AndroidManifest.xml. И хотя протекторы способны сильно усложнить жизнь хакеру и повысить эффективность аппсек-команды, комплексная безопасность приложения все еще лежит на плечах опытного аппсек-инженера, управляющего такими инструментами.
Кстати, мы намеренно использовали бесплатный открытый сканер MobSF, поэтому Вы можете легко повторить данный эксперимент и проверить, как протектор повлияет именно на ваше приложение.