[Программирование, Разработка под Android] Подменяем Runtime permissions в Android

Автор Сообщение
news_bot ®

Стаж: 6 лет 4 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
07-Дек-2020 15:31
Здравствуйте, меня зовут Виталий.
Немного о себе. Мне 25 лет, закончил магистратуру СПБГЭТУ «ЛЭТИ» в своем родном городе. Уже 10 лет занимаюсь программированием, из которых 4 пишу под Android. Автор многих Homebrew программ, известный под ником VITTACH, для *Sony PlayStation Portable (PSP)*.
Сегодня я бы хотел обсудить с вами проблему безопасности мобильных приложений. Разработчики из Google постоянно улучшают Android, находя и исправляя уязвимости не без помощи обширного сообщества, собранного благодаря программе *Android Security Rewards*, о которой мы поговорим позже. Тем не менее, проблемы все еще остаются, и наша общая задача как коммьюнити сообщать о них, чтобы их своевременно исправляли.
Уязвимость о которой я буду говорить, относится к классу с Priority:​ **P2** и Severity:​ **S2**, что согласно [таблице](https://developers.google.com/issue-tracker/concepts/issues) в широком смысле означает:
* Проблему, которую необходимо решить в разумные сроки;
* Проблему, которая важна для большого процента пользователей и связана с основными функциями.
## Runtime permission
Речь в статье пойдет о такой известной всем разработчикам вещи как Runtime permission, а именно – о возможности введения в заблуждение конечного пользователя путем демонстрации диалогового окна выдачи разрешения со своим текстом и иконкой поверх системного. Нетрудно догадаться, что подобный подход позволил бы разработчикам запрашивать у пользователя разрешение, скажем, к файловой системе, а по факту – к выдаче доступа к геопозиционированию, камере или чему-то еще.
## Это невозможно
Не один раз задавался подобный вопрос на специализированных форумах, в частности на [StackOverflow](https://stackoverflow.com/questions/33266328/how-can-i-customize-permission-dialog-in-android). Единственным правильным ответом было то, что это невозможно. И это действительно так: невозможно подменить текст в самом системном диалоге, но возможно его перекрыть своим.
## Что под капотом
_Runtime Permission_ впервые появились в `Android 6.0` в ответ на потребность повышенного внимания в области выдачи dangerous-разрешений. Фактически основная идея состоит в том, чтобы взаимодействовать с пользователем при запросе разрешений через всплывающее окно. Поэтому теперь разрешения из списка [dangerous](https://developer.android.com/guide/topics/permissions/overview#dangerous-permission-prompt) необходимо запрашивать у пользователя как только они понадобятся приложению.
<details><summary>Dangerous permissions</summary>
-   *android.permission_group.CALENDAR*
    -   android.permission.READ_CALENDAR
    -   android.permission.WRITE_CALENDAR
-   *android.permission_group.CAMERA*
    -   android.permission.CAMERA
-   *android.permission_group.CONTACTS*
    -   android.permission.READ_CONTACTS
    -   android.permission.WRITE_CONTACTS
    -   android.permission.GET_ACCOUNTS
-   *android.permission_group.LOCATION*
    -   android.permission.ACCESS_FINE_LOCATION
    -   android.permission.ACCESS_COARSE_LOCATION
-   *android.permission_group.MICROPHONE*
    -   android.permission.RECORD_AUDIO
-   *android.permission_group.PHONE*
    -   android.permission.READ_PHONE_STATE
    -   android.permission.CALL_PHONE
    -   android.permission.READ_CALL_LOG
    -   android.permission.WRITE_CALL_LOG
    -   android.permission.ADD_VOICEMAIL
    -   android.permission.USE_SIP
    -   android.permission.PROCESS_OUTGOING_CALLS
-   *android.permission_group.SENSORS*
    -   android.permission.BODY_SENSORS
-   *android.permission_group.SMS*
    -   android.permission.SEND_SMS
    -   android.permission.RECEIVE_SMS
    -   android.permission.READ_SMS
    -   android.permission.RECEIVE_WAP_PUSH
    -   android.permission.RECEIVE_MMS
    -   android.permission.READ_CELL_BROADCASTS
-   *android.permission_group.STORAGE*
    -   android.permission.READ_EXTERNAL_STORAGE
    -   android.permission.WRITE_EXTERNAL_STORAGE
</details>
Для отображения системного диалога в Android есть [GrantPermissionsActivity](https://android.googlesource.com/platform/packages/apps/PackageInstaller/+/b11175d/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java), который запускается после запроса на выдачу разрешений и отображает нам диалог со знакомым интерфейсом.
![](https://developer.android.com/images/permissions/runtime_permission_request_2x.png)ActivityCompat.requestPermissions(
    MainActivity.this,
    arrayOf(Manifest.permission.READ_CONTACTS),
    PERMISSION_REQUEST_CODE
)
А раз это _Activity_, которая перекрывает UI нашего приложения, значит можно попробовать пойти тем же путем и создать свою _Activity_, которая уже будет перекрывать системную.
Теперь давайте посмотрим на пример:
Пусть есть _Activity_ с флагом `android:windowIsTranslucent=true` (чтобы сделать _Activity_ с прозрачным фоном, позволяющим видеть, что за ним стоит) и оно запускается другим _Activity_ , который я назову фоновым. Визуально вы все еще можете видеть некоторую часть фонового _Activity_ через прозрачные пиксели в _Activity_ переднего плана.
![](https://c.radikal.ru/c02/2009/0f/f9b598497bef.png)
Синий – это активное Activity с полупрозрачным окном, а фиолетовый – Activity прямо под ним.
Что произойдет с _Activity,_ если вы поместите приложение в фоновый режим?
![](https://c.radikal.ru/c04/2009/69/300b1457d180.png)
Фоновая _активность_, несомненно, будет убита, а передний план _деятельности_ может выжить, пока вы не переключитесь на другое приложение.
И вот что произойдет, когда вы вернете свое приложение на передний план:
![](https://c.radikal.ru/c28/2009/93/b14fcb9569d7.png)
Фоновая _Activity_ создается, а затем `onResume` и `onPause` вызываются по порядку. Затем оживает передний план _Activity_.
Идея заключается в том, чтобы перекрыть эту _Activity_ в стеке своей собственной с кастомным диалогом, но так чтобы оставить возможность взаимодействовать с кнопками системного диалога. И вот это уже – возможно!
## Попробуй сам
Для демонстрации использован язык программирования Kotlin
- Создать стиль
К сожалению, невозможно настроить эти параметры иначе как из стилей
    ```
    <style name="Theme.Transparent" parent="AppTheme">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
    ```
- Прописать в манифесте _Activity_ со стилем
    ```
        ...
        <activity
            android:name=".PermissionActivity"
            android:theme="@style/Theme.Transparent" />
    </application>
    ```
- Создать PermissionActivity со своим _layout_
    В методе onCreate написать код:
    ```
    window.addFlags(FLAG_NOT_FOCUSABLE or FLAG_NOT_TOUCH_MODAL or FLAG_NOT_TOUCHABLE)
    ```
    Здесь мы использую трюк с использованием следующих флагов:
    - `FLAG_NOT_FOCUSABLE`: window, в которой установлен параметр `FLAG_NOT_FOCUSABLE`, не может взаимодействовать с методом ввода;
    - `FLAG_NOT_TOUCH_MODAL`: разрешит отправку любых событий за пределы окна в окна позади него, в противном случае он сам будет использовать все события указателя, независимо от того, находятся ли они внутри окна;
    - `FLAG_NOT_TOUCHABLE`: это окно никогда не может получать события касания.
- В MainActivity вызвать запрос
    ```
    ActivityCompat.requestPermissions(
        MainActivity.this,
        arrayOf(Manifest.permission.READ_CONTACTS),
        REQUEST_CODE
    )
    ```
    И сразу после этого из MainActivity запустить другую активити: PermissionActivity.
    ```
    startActivity(Intent(this, PermissionActivity::class.java))
    ```
PermissionActivity с прозрачным фоном и отсутствием фокуса и прокидыванием событий на _Activity_ позади себя запустится и позволит добиться перекрытия системного диалога с сохранение полного взаимодействия с ним. Результат достигнут!
## Android >=7.1.1
Хотя _Runtime Permission_ появились в версии `Android 6.0`, но до версии `7.1.1` эту уязвимость использовать не получится, т.к. ранние версии Android ругаются на обнаружение перекрытия при попытке нажатия на кнопку `Разрешить`.
Если вы попробуете запустить мой код на версии `Android 6.0`, то получите это предупреждение. По неизвестной мне причине, Google отказался от этих ограничений в новых версиях.
![](https://c.radikal.ru/c13/2009/54/b7415d78a08f.png)
## Android Rewards Programm
Я подал заявку и приложил все объяснительные и демонстрационные документы по данной уязвимости. В данный момент заявка находится в стадии рассмотрения, поэтому я не могу разглашать подробности, потому что подписал соответствующее соглашение.
## А как проще?
Для удобства эксплуатации уязвимости мною была написана [библиотека](https://github.com/VITTACH/FakePermission)
![](https://raw.githubusercontent.com/VITTACH/FakePermission/master/Samples.gif)

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_razrabotka_pod_android (Разработка под Android), #_permissions, #_android, #_runtime_permissions, #_bezopasnost (безопасность), #_ujazvimost (уязвимость), #_google, #_library, #_programmirovanie (
Программирование
)
, #_razrabotka_pod_android (
Разработка под Android
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 18-Июн 17:39
Часовой пояс: UTC + 5