Следующая новость
Предыдущая новость

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

29.11.2018 18:02
Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

Содержание статьи

  • Почитать
  • Как Google борется с малварью
  • Huawei и платная разблокировка загрузчика
  • Как использовать Frida для обхода упаковщиков
  • Разработчику
  • Трюки с Kotlin
  • Профайлинг сетевых функций приложения
  • Не используй массивы в data-классах
  • Parallelism vs concurrency
  • Трюки с короутинами Kotlin
  • Удобочитаемый logcat
  • Инструменты
  • Библиотеки

Сегодня в выпуске: история о том, как Google безуспешно борется с малварью, статья о платной разблокировке загрузчика Huawei, гайд по борьбе с упаковщиками с помощью Frida. А также: подборка трюков и советов для Kotlin-программистов, инструменты профайлинга сетевых функций, лучшее объяснение отличия короутин от потоков и, конечно же, очередная подборка свежих библиотек и инструментов.

Почитать

Как Google борется с малварью

Combating Potentially Harmful Applications with Machine Learning at Google: Datasets and Models — рассказ разработчиков команды безопасности Android о том, как работает система Google Play Protect, которая выявляет вредоносные приложения в Google Play и на смартфонах пользователей. Несколько тезисов:

  • Google анализирует не только приложения из Google Play, но и любые APK-файлы, найденные в интернете.
  • Для каждого приложения запускаются процедуры статического и динамического анализа, которые выявляют определенные шаблоны: запрашиваемые разрешения, поведение приложения в тех или иных обстоятельствах.
  • Данные, полученные от статических и динамических анализаторов, передаются ИИ, натренированному на выявление определенных типов зловредных приложений: SMS-фрод, фишинг, повышение привилегий.
  • Кроме данных о самих приложениях, Google также собирает и агрегирует данные о приложении из Google Play: средняя оценка приложений разработчика, рейтинги, количество установок и удалений; эта информация также передается ИИ.
  • На основе всех этих данных ИИ выносит решение о том, может ли приложение быть потенциально зловредным.
  • Google постоянно совершенствует ИИ, скармливая ему данные свежевыявленных зловредов.

На фоне всей этой бравады стоит напомнить, что в тестах антивирусов Google Play Protect набирает 0 очков и плетется в конце рейтинга. По информации на январь 2018-го он смог обнаружить лишь 63% вирусов.

Huawei и платная разблокировка загрузчика

Bootloader unlocking is still possible for Huawei and Honor devices, but it’ll cost you — интересная заметка о страданиях владельцев смартфонов Huawei, желающих разблокировать загрузчик своего устройства.

В мае этого года Huawei официально заявила, что больше не будет предоставлять коды для разблокировки загрузчиков своих смартфонов (а также смартфонов своего суббренда Honor). Загрузчик отвечает за проверку целостности и цифровой подписи ядра ОС, а также за возможность прошивки устройства, так что те, кто не успел получить свой код разблокировки, теперь не могут установить на нее кастомную прошивку или даже получить права root с помощью Magisk.

Выяснилось, однако, что совсем недавно сервис FunkyHuawei, занимающийся выпуском утилит для восстановления окирпиченных смартфонов и смены их региона, начал предоставлять возможность разблокировки загрузчика всех моделей Huawei, включая самые свежие. Но есть один нюанс: стоимость кода разблокировки составляет 55 долларов, и он привязан к IMEI устройства, а значит, не может быть использован повторно.

В комментариях к статье уже появились шутки о том, что FunkyHuawei принадлежит самой Huawei и таким образом она пытается дополнительно заработать на пользователях. Шутки шутками, но вопрос о том, где сервис берет коды разблокировки, весьма серьезный. Либо это действительно Huawei, либо коды у нее просто крадут, либо алгоритм их генерации настолько слабый, что его удалось подобрать. Все три варианта не в пользу компании.

Как использовать Frida для обхода упаковщиков

How-to Guide: Defeating an Android Packer with FRIDA — вводная статья об использовании Frida для помощи в анализе вируса.

Дано: вредоносное приложение с подозрительным файлом внутри пакета и небольшим сильно обфусцированным исполняемым dex-файлом. Анализ логов запуска logcat показывает, что приложение при работе создает и загружает еще один dex-файл (запакованный в JAR), а это значит, что, скорее всего, первый исполняемый файл — это всего лишь загрузчик (а точнее, упаковщик), а найденный ранее подозрительный файл — зашифрованный код приложения. При загрузке приложения упаковщик дешифрует файл и загружает его. Но есть одна проблема — сразу после загрузки дешифрованный файл удаляется и его невозможно проанализировать.

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

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

console.log("[*] FRIDA started"); console.log("[*] skip native unlink function");  var unlinkPtr = Module.findExportByName(null, 'unlink');  Interceptor.replace(unlinkPtr, new NativeCallback(function (){       console.log("[*] unlink() encountered, skipping it."); }, 'int', [])); 
Трассировочный листинг, показывающий создание и удаление файла с расшифрованным кодом приложения

Разработчику

Трюки с Kotlin

Kotlin fun and education on Twitter — создатель Kotlin Academy и автор книги «Android Development with Kotlin» Марсин Москала (Marcin Moskala) рассказывает об интересных трюках, которые можно провернуть в Kotlin.

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

В Kotlin fun — это зарезервированное ключевое слово, но его можно использовать, если заключить в обратные кавычки или написать с большой буквы. Те же правила действуют в отношении любых других ключевых слов.

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

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

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

Как и многие другие языки, Kotlin поддерживает перегрузку операторов.

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

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

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin

Еще несколько полезных функций для выполнения операций над несколькими последовательными элементами.

Профайлинг сетевых функций приложения

Various methods to debug HTTP traffic in Android applications — статья о том, как выполнять профайлинг сетевых функций приложения. Автор предлагает использовать пять различных методов.

  • Android Profiler — включен в состав Android Studio. Он показывает объем входящих и исходящих данных, задержки и даже позволяет взглянуть на сами данные (если приложение использует HttpURLConnection или OkHttp). По умолчанию сетевой профайлер отключен. Чтобы включить его, необходимо зайти в меню Run → Edit Configurations, открыть таб Profiling и поставить галочку напротив Enable advanced profiling. После этого он появится в окне стандартного профайлера (запускается через нижнюю панель Android Studio).

  • OkHttp Profiler plugin — плагин Android Studio для отладки реквестов OkHttp. Умеет показывать JSON в виде дерева и генерировать модели для парсера GSON. Недостаток: требуется установка плагина и модификация приложения.

  • Stetho — инструмент отладки приложений с помощью Chrome DevTools. Кроме инструментов для анализа лайотов и баз данных, включает в себя мощный сетевой профайлер. Требует установки библиотеки и модификации приложения.

  • Charles Proxy — десктопный прокси со встроенным сниффером и множеством дополнительных функций: это мониторинг сокетов, модификация сетевых пакетов, генератор реквестов и многое другое. Требует настройки на эмуляторе/телефоне прокси и установки SSL-сертификата (в случае если требуется отладка HTTPS-трафика). К тому же стоит 50 долларов (есть триальная версия).

  • AppSpector — инструменты профайлинга для Android и iOS. Позволяют просматривать логи, изучать базы данных и сетевые запросы. Необходима модификация приложения и регистрация на сайте. Управление только через веб-сайт разработчиков, так что возникает вопрос о конфиденциальности данных.

Android: борьба Google с малварью, платная разлочка Huawei и множество советов по языку Kotlin
Network Profiler в Android Studio

Не используй массивы в data-классах

What you didn’t know about arrays in Kotlin — познавательная и полезная заметка о том, почему не стоит использовать массивы в data-классах в Kotlin.

Data-классы в Kotlin — очень полезный элемент языка, позволяющий быстро создавать классы, не обременяя себя написанием однотипного кода. Возьмем, к примеру, следующий код:

data class NumArray(val name: String, val values: IntArray) 

Он объявляет data-класс NumArray с двумя полями. Это всего одна строка кода, но в результате ты получишь класс с уже реализованными геттерами, сеттерами и функциями equals(), hash(), toString(). Тебе не придется писать их самому, и это сильно облегчает жизнь.

Но есть одна проблема: если ты создашь два одинаковых объекта этого класса и попробуешь их сравнить, то получишь отрицательный ответ:

val n1 = NumArray("1", intArrayOf(1,2,3,4)) val n2 = NumArray("1", intArrayOf(1,2,3,4)) val result = n1==n2 println("result=$result") 

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

Поэтому вместо массивов лучше использовать списки:

data class NumList(val name: String, val values: List<Int>)) 

Parallelism vs concurrency

Concurrent Coroutines — Concurrency is not Parallelism — одна из лучших статей для тех, кто хочет разобраться, что такое короутины Kotlin. Вместо того чтобы рассказывать о стейт-машинах и математических алгоритмах, автор говорит о том, что надо просто осознать разницу между понятиями concurrency и parallelism.

Роб Пайк, один из разработчиков Unix, Plan 9 и языка Go, говорит об этих понятиях так: concurrency — это когда ты имеешь дело со множеством вещей одновременно, а parallelism — это когда ты делаешь множество вещей одновременно. Продемонстрируем это утверждение кодом:

fun main() = runBlocking<Unit> {     val time = measureTimeMillis {         val one = async { doSomethingUsefulOne() }         val two = async { doSomethingUsefulTwo() }         println("The answer is ${one.await() + two.await()}")     }     println("Completed in $time ms")     }  suspend fun doSomethingUsefulOne(): Int {     delay(1000L)     return 13 }  suspend fun doSomethingUsefulTwo(): Int {     delay(1000L)     return 29 } 

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

Приложение заканчивает свою работу ровно за одну секунду, что абсолютно логично. Но есть один важный нюанс: оно работает в одном потоке. Когда одна из дочерних короутин блокируется (в данном случае с помощью delay, а в реальном приложении из-за ожидания данных из сети или с диска), основная короутина продолжает свою работу. Это и есть тот случай, когда приложение «имеет дело» с множеством вещей, а не делает их одновременно.

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

val time = measureTimeMillis {     val one = async(Dispatchers.Default) { doSomethingUsefulOne() }     val two = async(Dispatchers.Default) { doSomethingUsefulTwo() }     println("The answer is ${one.await() + two.await()}") } 

Такой код запускает каждую короутину в отдельном потоке (Dispatchers.Main — основной поток приложения, Dispatchers.Default — один из фоновых), и да, теперь приложение делает несколько вещей одновременно.

В этом примере от такой замены нет никакой пользы, но в реальном приложении в фоновые потоки можно отправить тяжелые вычисления, а запускать код, ожидающий данные из сети или с диска (или просто часто спящий), эффективнее в основном потоке. В конце концов, nginx, один из самых производительных веб-серверов, однопоточный (точнее, он использует по одному потоку на ядро, но сути это не меняет).

Трюки с короутинами Kotlin

Advanced Kotlin Coroutines tips and tricks — еще одна статья о короутинах, в этот раз с советами по использованию.

1. Проблемы с Java API. Возьмем следующий пример:

runBlocking(Dispatchers.IO) {     withTimeout(1000) {         val socket = ServerSocket(42)         socket.accept()     } } 

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

Но этого не произойдет, потому что socket.accept() заблокирует поток короутины, до тех пор пока кто-нибудь действительно не подключится.

Обойти эту проблему можно с помощью suspendCancellableCoroutine. Создадим небольшую функцию-помощник:

public suspend inline fun <T : Closeable?, R> T.useCancellably(         crossinline block: (T) -> R ): R = suspendCancellableCoroutine { cont ->     cont.invokeOnCancellation { this?.close() }     cont.resume(use(block)) } 

И слегка изменим наш пример:

runBlocking(Dispatchers.IO) {     withTimeout(1000) {         val socket = ServerSocket(42)         socket.useCancellably { it.accept() }     } } 

Теперь все работает как надо.

2. launch vs. async. Это два самых используемых короутин-билдера в Kotlin. И тот и другой порождают новую короутину, но работают немного по-разному:

  • любое необработанное исключение в блоке launch будет воспринято как необработанное вообще и уронит приложение; исключение в блоке async можно обработать за пределами этого блока;
  • launch не позволит короутинам-родителям завершиться, пока короутины-потомки, запущенные с помощью launch, не завершатся;
  • async позволяет вернуть значение, launch — нет.

Удобочитаемый logcat

How To Customize Logcat Appearance in Android Studio — короткая заметка о том, как раскрасить вывод logcat в Android Studio для более удобного чтения. Для этого достаточно перейти в настройки, набрать в поиске logcat, и ты увидишь список уровней логирования от Debug до Assert. Выбирай один из них, отключай галочку Inherit values from и в опциях Foregraund, Background и других выбирай нужные цвета.

Автор статьи предлагает следующую схему цветов:

  • ASSERT: #bb2b2f;
  • DEBUG: #1194d6;
  • ERROR: #db332f;
  • INFO: #0c890d;
  • VERBOSE: #a8a8a8;
  • WARNING: #bb7000.

Также он создал цветовую схему на базе тем Default и Dracula.

Инструменты

  • frida-snippets — набор скриптов Frida для Android, iOS и Windows;
  • MagiskFrida — скрипт для запуска сервера Frida при загрузке с помощью Magisk;
  • ADBHoney — ханипот, эмулирующий доступный на 5555-м порте демон ADB;
  • ish — приложение для запуска Linux-окружения в iOS (использует эмуляцию x86 и трансляцию системных вызовов Linux → XNU);
  • androix-migration — скрипт для автоматической миграции с support-библиотек на AndroidX, по словам автора, работает лучше, чем аналогичный конвертер в Android Studio;
  • autoplay — плагин Gradle для автоматической публикации приложений в Google Play.

Библиотеки

  • AndroidVeil — библиотека для создания и анимации скелетов интерфейса, который пользователь видит до окончания загрузки данных;
  • MultiLamp — подсвечивает несколько View одновременно, может быть полезна для создания визардов;
  • JustifiedTextView — TextView, который выравнивает текст по ширине экрана (официально Android поддерживает эту функцию с Android 8);
  • PrettyStateView — позволяет одной строкой кода добавить отображение состояния к любому View: загрузка, ошибка, пусто и так далее;
  • CookieBar2 — окно с сообщением в верхней или нижней части экрана;
  • BezierSeekBar — настраиваемый SeekBar;
  • NomtekUtills — библиотека для управления тулбаром и статусбаром;
  • RandomGenKt — Kotlin-порт библиотеки для генерации случайных инстансов любых классов;
  • simplegraph — библиотека для отображения графиков;
  • slidetoact — виджет Slide to Unlock;
  • ElasticViews — позволяет добавить к любому View «эластичную анимацию кликов»;
  • spectrum — библиотека для транскодинга изображений;
  • AutoDSL — генератор простых DSL (Domain Specific Language) с помощью аннотаций;
  • librootjava — библиотека автора SuperSU для запуска кода Java и Kotlin с правами root;
  • ModernAndroidPreferences — позволяет создавать окна настроек с использованием специального DSL и Kotlin;
  • MotionLayoutCarousel — приложение-пример, которое демонстрирует карусель из элементов интерфейса с помощью MotionLayout.

Источник

Последние новости