Android: security-новшества Android 11 и нативная версия трояна Joker

Сегодня в выпуске: security-новшества Android 11, анализ нативной версии трояна Joker, советы о хранении секретных данных в приложении, способ усовершенствовать обфускацию кода на Kotlin, а также лучшие инструменты разработчика для Android и очередная подборка полезных библиотек.

ПОЧИТАТЬ

Security-новшества Android 11 DP1

Turning it up to 11: the first Developer Preview of Android 11 — статья о новшествах Android 11 Developer Preview 1. Мы, как обычно, сконцентрируемся на приватности и безопасности.

  • Одноразовые разрешения. Начиная с Android 11 пользователь сможет дать разрешение на ту или иную операцию только на один раз. Как только приложение будет свернуто, оно потеряет разрешение, и его придется запрашивать снова.
  • Scoped Storage. Android 11 закроет приложениям прямой доступ к файлам на внутренней и внешней картах памяти, но только в том случае, если target API приложения равен 30.
  • Расширенный API биометрической аутентификации. В API BiometricPrompt, реализующем диалог биометрической аутентификации, появилась поддержка трех типов аутентификации: надежные, слабые и учетные данные устройства.
  • Новые средства защиты от эксплоитов. Разработчики расширили применение механизмов защиты, работающих на этапе компиляции: CFI (Control Flow Integrity), BoundSan, IntSan (Integer Overflow Sanitization) и ShadowCallStack. Для выявления проблем при работе с памятью в приложениях включена проверка указателей в куче на основе привязанных к ним тегов (heap pointer tagging). Также разработчики могут использовать специальный системный образ, в котором включен отладочный механизм HWAsan (Hardware-assisted AddressSanitizer).
  • API для безопасного обмена данными. Появился API BlobStoreManager для безопасного обмена бинарными данными между приложениями. Его можно использовать, например, для передачи моделей данных машинного обучения.
  • Хранилище документов. Добавилась поддержка безопасного хранения и извлечения проверяемых идентификационных документов, таких как электронные водительские удостоверения.
Одноразовые разрешения в Android 11
Одноразовые разрешения в Android 11

Как работают одноразовые разрешения Android 11

Exploring the Android 11 Developer Preview: Permission Changes — статья, поясняющая работу одноразовых разрешений. Основные моменты:

  • Одноразовое разрешение будет отозвано, как только запросившая разрешение активность (экран) приложения уйдет в фон (пользователь вернется на домашний экран или откроет другое приложение).
  • Если у приложения есть foreground-сервис, который был активен в момент ухода активности в фон и ее возврата, то одноразовое разрешение будет возвращено этой активности.
  • В предыдущих версиях Android пользователь мог запретить повторный показ запроса определенного разрешения с помощью чекбокса Don’t ask again. Android 11 заблокирует повторный показ запроса, если пользователь два раза откажется предоставлять разрешение.
  • Исключение из предыдущего правила: если пользователь нажмет кнопку «Назад», чтобы закрыть диалог запроса разрешения, это будет интерпретировано как отказ предоставлять разрешение, но запрос будет появляться снова. Однако это не относится к тем диалогам запроса разрешений, которые перекидывают пользователя в настройки.

Отдельно автор отмечает, как изменилась работа разрешения на доступ к местоположению в фоне. Это разрешение появилось в Android 10, но начиная с Android 11 приложение не может запросить его у пользователя. Единственный способ получить разрешение — перекинуть пользователя в окно настроек приложения и попросить включить его вручную.

Как работает отказ предоставлять разрешение
Как работает отказ предоставлять разрешение

Анализ нативной версии трояна Joker

A closer look at the native speaking Android Joker malware from Google Play — анализ новой версии трояна Joker, большая часть кода которого вынесена в нативную библиотеку.

Впервые Joker (или Bread в терминологии Google) обнаружили в 2017 году. Это был троян, распространяющийся через Google Play и подписывающий пользователя на разного рода платные услуги, в том числе требующие подтверждения по SMS (он умел перехватывать сообщения и анализировать их содержимое).

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

Одно из приложений, внутри которого обнаружили новую версию Joker, — VPN-клиент Fast VPN. По сути, это перепакованная версия приложения Thunder VPN, которая при старте приложения запускает в фоне зловредный код. Часть функциональности трояна при этом вынесена в нативную библиотеку libpdker.so, пропущенную через обфускатор на базе LLVM.

Нативная библиотека включает в себя базовую функциональность трояна, например функции для работы с SIM-картами и обработки SMS (которые троян получает с помощью доступа к уведомлениям). Также нативная библиотека отвечает за прием команд от управляющего сервера (C&C). Набор команд и их формат, в сущности, остался прежним, как и использование голого HTTP в качестве протокола.

Интересно, что в отличие от прошлых версий трояна эта версия не использует какой-то специальной формы обфускации имен методов. Некоторые имена просто случайны (Kanble, Yunbe, PtCher, VenNor), другие похожи на слегка измененные (QertOptor — QueryOperator, ReterString — ReturnString, WenNoti — WhenNotified, pdker — Joker?), еще одни никак не изменены (BigConfig, BleOpenSettings, HuOpenSettings). Но обфускация строк стала еще более запутанной.

В целом эта версия трояна больше похожа на эксперимент, чем на развитие.

РАЗРАБОТЧИКУ

Как хранить секреты

Protecting secrets in an Android project — статья о том, как правильно хранить секреты, например ключи API, в своем приложении.

Все секретные строки лучше вынести в отдельный файл, который хранится вне системы контроля версий. Это позволит избежать недоразумений, когда разработчик заливает код в открытый репозиторий и таким образом выставляет ключи на всеобщее обозрение. Также такой подход позволяет расшаривать ключи между несколькими приложениями. Секреты можно хранить, например, в файле ~/.gradle/gradle.properties:

GameCatalogueApp_UploadKeystore_KeyPassword=aaaabbbbcccc
GameCatalogueApp_AuthClientSecret=123456789
GameCatalogueApp_Pusher_APIKey=ksldjalksdjskald

Чтобы сделать их доступными в исходном коде, можно использовать приблизительно такой трюк (пример для скрипта Gradle на Kotlin):

defaultConfig {
  buildConfigField(
    "String", 
    "AUTH_CLIENT_SECRET", 
    buildConfigProperty("GameCatalogueApp_AuthClientSecret")
  )

  resValue(
    "string", 
    "pusher_key", 
    propertyOrEmpty("GameCatalogueApp_Pusher_APIKey")
  )
}

fun Project.buildConfigProperty(name: String) = "\"${propertyOrEmpty(name)}\""

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

Обфускация кода Kotlin

Is Your Kotlin Code Really Obfuscated? — статья, посвященная обфускации кода на языке Kotlin, а точнее тому, когда эта обфускация может не сработать. Автор приводит следующий пример кода:

class SomeClass {
    lateinit var importantVar: String

    fun funcWithParams(importantString: String, importantList: List<Int>) {
    }

    fun String.importantExtensionFunc() {
    }
}

Если скомпилировать этот код, а затем декомпилировать его в Java, мы получим следующую картину:

public final class SomeClass {
   @NotNull public String importantVar;

   @NotNull
   public final String getImportantVar() {
      String var10000 = this.importantVar;
      if (var10000 == null) {
         Intrinsics.throwUninitializedPropertyAccessException("importantVar");
      }
      return var10000;
   }

   public final void funcWithParams(@NotNull String importantString, @NotNull List importantList) {
      Intrinsics.checkParameterIsNotNull(importantString, "importantString");
      Intrinsics.checkParameterIsNotNull(importantList, "importantList");
   }

   public final void importantExtensionFunc(@NotNull String $this$importantExtensionFunc) {
      Intrinsics.checkParameterIsNotNull($this$importantExtensionFunc, "$this$importantExtensionFunc");
   }
}

Обрати внимание, что появилась проверка параметров функций на null с помощью методов объекта Intrinsics. Это часть особенности Kotlin под названием null safety, которая гарантирует, что ты не сможешь обратиться к методам или полям null-объекта или случайно присвоить объекту значение null.

А теперь посмотри на тот же код, но после обфускации с помощью ProGuard (в новых версиях Android Studio его работу выполняет оптимизатор R8):

public final class a {
   public String a;

   public final String a() {
      String var1 = this.a;
      if (var1 == null) {
         b.b("importantVar");
      }
      return var1;
   }

   public final void a(String var1) {
      b.b(var1, "$this$importantExtensionFunc");
   }

   public final void a(String var1, List var2) {
      b.b(var1, "importantString");
      b.b(var2, "importantList");
   }

   public final void b() {
      String var1 = this.a;
      if (var1 == null) {
         b.b("importantVar");
      }
      this.a(var1);
   }
}

Снова обрати внимание на вызов функций Intrinsics, которые теперь имеют имя вроде b.b. Несмотря на то что в результате обфускации параметры функций получили имена var1 и var2, функция проверки на null все равно выдает их реальные имена (importantVarimportantList и так далее).

Побороть эту проблему можно, отключив саму функцию проверки на null в продакшен-коде. Это никак не повлияет на стабильность приложения, поскольку код проверки на null в рантайме нужен лишь в качестве средства отладки/диагностики, а не защиты от падения или обеспечения правильной работоспособности (фактически эти функции просто завершают приложение с исключением IllegalStateException).

Итак, открываем файл proguard-rules.pro приложения и добавляем в него следующие строки:

-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
    public static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
    public static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
    public static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    public static void checkNotNull(java.lang.Object);
    public static void checkNotNull(java.lang.Object, java.lang.String);
    public static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
    public static void checkNotNullParameter(java.lang.Object, java.lang.String);
    public static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
    public static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
    public static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    public static void throwUninitializedPropertyAccessException(java.lang.String);
}

Инструменты разработчика в 2020 году

Our Android 2020 development stack — статья разработчиков компании Karumi об используемых инструментах разработки. Десятки инструментов разбиты на семь категорий.

Статический анализ и сборка:

  • Ktlint — лучший линтер для языка Kotlin;
  • Android Lint — стандартный линтер Android;
  • Lin — инструмент, позволяющий удобно создавать кастомные правила для линтера;
  • Ribbonizer — плагин Gradle, автоматически добавляющий отметку Beta или Debug к иконке приложения;
  • Play publisher — автоматизирует процесс публикации новой версии в Google Play Store.

Инструменты для работы с сетью:

  • Retrofit — существенно упрощает реализацию REST API;
  • OkHTTP — лучший HTTP-клиент;
  • Gson — известная библиотека для трансляции JSON в объекты Java/Kotlin.

Хранение данных:

  • Room — обертка для SQLite, развиваемая Google;
  • SQLDelight — генерирует Kotlin API для SQL-запросов.

Разрешения:

  • Dexter — библиотека, позволяющая обрабатывать запросы разрешений с помощью колбэков вместо неудобного в использовании onActivityResult.

Пользовательский интерфейс:

  • Data Binding — библиотека биндинга View (часть Android Jetpack);
  • Lifecycle Observer — обсервер данных для UI (Android Jetpack);
  • Appcompat — библиотека совместимости для старых версий Android (Android Jetpack);
  • ConstraintLayout — подстраиваемый под ситуацию лейаут (Android Jetpack);
  • Glide — библиотека загрузки изображений;
  • Renderers — одна из лучших библиотек для работы с RecyclerView;
  • Calligraphy — библиотека для работы с кастомными шрифтами (Android поддерживает аналогичную функцию с 2017 года);
  • Material Components — компоненты в стиле Material Design (Android Jetpack);
  • Snacky — библиотека для показа снекбаров (небольшое сообщение в нижней части экрана);
  • Lottie — библиотека для рендеринга анимации, созданной в Adobe After Effects.

Основные инструменты:

  • Kotlin — без комментариев;
  • Kotlin Coroutines — лучший инструмент асинхронного программирования;
  • Timber — расширяемый логгер;
  • Libphonenumber — лучший инструмент для работы с номерами телефонов;
  • OneSignal — один из лучших провайдеров push-уведомлений;
  • Kodein — фреймворк для Dependency Injection;
  • ThreeTenABP — бэкпорт функций для работы со временем из Java 8;
  • Crashlytics — один из лучших инструментов для создания отчетов об ошибках и работы с ними;
  • Arrow — библиотека функционального программирования для Kotlin;
  • Leakcanary — лучший инструмент детекта утечек памяти.

Тестирование:

  • JUnit — классический инструмент запуска тестов;
  • Shot — библиотека для тестирования по скриншотам;
  • Kotlin Snapshot — библиотека для снапшот-тестирования;
  • Kotlin Test — фреймворк для тестирования кода на Kotlin;
  • Mockito — mock-фреймворк;
  • MockWebServer — виртуальный веб-сервер для тестирования;
  • Robolectic — фреймворк для тестирования, позволяющий запускать тесты быстро без использования полноценного эмулятора;
  • Espresso — библиотека UI-тестирования;
  • Barista — упрощает создание тестов с использованием Espresso;
  • Jacoco — инструмент оценки покрытия кода тестами;
  • Bitrise — лучшая платформа для CI- и CD-разработки.

ИНСТРУМЕНТЫ

  • FRIDA-DEXDump — скрипт Frida для поиска dex-файлов в оперативной памяти, может быть использован для борьбы с упаковщиками.

БИБЛИОТЕКИ

  • OpenPush — фреймворк для реализации push-уведомлений с использованием собственного сервера;
  • Dependency-analysis-android-gradle-plugin — плагин Gradle для анализа зависимостей и связи между ними;
  • Rainbow — создание градиентного фона для любого View;
  • KaMPKit — темплейт для создания мультиплатформенного приложения на Kotlin;
  • Kronos-Android — SNTP-библиотека на языке Kotlin;
  • RateBottomSheet — диалог «Оцените приложение»;
  • Android-NFC — библиотека для работы с NFC;
  • Cycler — библиотека для декларативной конфигурации RecyclerView (разработчик: Square);
  • Madman-android — библиотека для показа видеорекламы;
  • CurveGraphView — компонент, отображающий сглаженные графики;
  • FragNav — компонент для управления различными стеками фрагментов;
  • Time — мультиплатформенная библиотека для измерения времени на Kotlin;
  • Wormhole — библиотека, позволяющая использовать некоторые API из новых версий Android в старых версиях;
  • Android-framer — скрипт для добавления фрейма телефона вокруг скриншотов;
  • LiveStream-kt — реактивная библиотека для обмена данными между компонентами приложения;
  • CustomEditTextOulinedBorder — поле ввода с обводкой, меняющей цвет в зависимости от введенных данных;
  • FacebookLikeReaction — кнопки реакций на манер Facebook;
  • Android-Localization — библиотека для смены языка приложения на лету;
  • Filebox — библиотека для асинхронной загрузки файлов из сети.

Источник — xaker.ru

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*