Месяц назад для другого Вечеринка дроидов Старший разработчик Данила Фетисов подробно рассказал о принципе работы сервиса, отвечающего за специальные возможности Android. Вы узнаете, как использовать его для улучшения доступности ваших проектов, а также об опасной уязвимости под названием кликджекинг.
— Меня зовут Данила Фетисов, я из московского офиса Яндекса, точнее из Такси, точнее из Таксометра.
Сегодня мы поговорим о том, что такое доступность Android и почему я решил назвать такую святыню для людей с ограниченными возможностями волком в овечьей шкуре.
Итак, план отчета.
Сначала мы рассмотрим, как эту штуку можно использовать, создавать и настраивать.
Возможно, я подскажу вам пару лайфхаков и продуктовых хитростей.
А потом о самом интересном – о том, чем опасна эта штука.
Как мы вообще можем это применить? В общем, что это такое, для тех, кто не знает? Любые события происходят в системе, они попадают в наш сервис, и мы их обрабатываем.
Как только мы что-то получим, мы можем взять оттуда контент и озвучить его с помощью того же Yandex SpeechKit, Google Text-to-Speech или чего-нибудь еще, что вам нравится.
Но что самое интересное, мы можем не только получать, но и отправлять системное событие.
Есть еще кое-что, что можно сказать.
Закинул мероприятие, нажал кнопку, и все просто отлично, радуешься жизни.
Если говорить об этих двух пунктах, то они по сути являются дефолтными.
Google запустил эту функцию, чтобы ваше приложение могли использовать люди с ограниченными возможностями.
Но как всем известно, мы, разработчики, не хотим скучать: садимся, смотрим на код и думаем: а как его можно применить? И поехали.
Автоматизация, тестирование путем моделирования действий пользователя, контекстная реклама.
Сами понимаете: поскольку мы получаем контент с экрана, мы можем понять, как запугать этого пользователя.
Что еще интересно? Обработка USSD-запросов.
К сожалению, нормальный API появился только с SDK 26, и разработчикам как-то надо выживать.
И вот представьте, они серьезно парсят USSD-запросы, парсят UI с помощью AccessibilityService. Шестая точка – многоточие.
Почему? Потому что после этого отчета у вас будет примерное понимание, как им пользоваться и зачем.
А потом вы буквально открываете свое воображение, берете чашку чая, кофе и начинаете кодировать свои крутые фичи.
С чего начать? Следующий слайд будет до боли банален.
Берем сервис, наследуем от AccessibilityService и радуемся жизни.
Потом этот сервис кидаем в Манифест, и что тут интересного? По сути, обычная трудовая книжка.
Но обратите внимание на поле метки.
Сейчас я не скажу вам, что это такое.
Помните, это произойдет немного позже.
Дальше по Манифесту у нас просто конфиг, тоже ничего интересного.
Да и сам конфиг-файл выглядит немного страшнее.
Из того, что вам понадобится, скорее всего, процентов 85–90 — это поле настройки фильтра входящих событий.
Допустим, мы хотим получать абсолютно все события.
Вы можете установить фильтр только по кликам, по изменению контента или по чему-то еще.
Далее идет фильтр пакетов приложений.
Для чего это? Вы сами прекрасно понимаете, что получение событий абсолютно от всех приложений системы для одного приложения будет слишком большим.
Поэтому Google решил как-то ограничить это.
Добавил фильтр.
Дальше описание.
Было поле метки, но теперь используется описание.
По сути, они создают пару, которая затем сообщает пользователю, почему ему необходимо включить вашу услугу.
И последний момент: нужен или нет контент из открытого в данный момент окна.
Если вы просто хотите понять, что произошло какое-то событие, установите значение false и не мучайте лишний раз пользователя.
Включение услуги.
К сожалению, чтобы включить эту штуку, придется помучить пользователя и заставить его пройти семь кругов ада настроек, условно говоря.
Во-первых, мы открываем для него особые возможности.
Cool AccessibilityService — это именно тот ярлык из манифеста, о котором я рассказывал на предыдущих слайдах.
Дальше.
Пользователю необходимо выбрать ваш сервис, а затем он начинает читать описание, почему вы хотите включить этот сервис и получить некоторый контроль над устройством.
Хорошо, он включается.
Но не тут-то было.
Выскакивает какой-то страшный диалог, в котором говорится: «Чувак, если ты включишь его сейчас, мы возьмем на себя полный контроль над твоим приложением, условно говоря, все будет страшно».
Пользователи не всегда все это читают, они просто нажимают «ОК», чтобы мы могли их оставить.
Так мы и живём.
Итак, где же мы на самом деле выполняем обработку событий? Следующий слайд немного умнее первого слайда про сервис, но всё же.
Вот наш DummyAccessibilityService, и мы туда кидаем два метода, в которых всё и напишем.
По сути, прерывание — это метод, при котором вам нужно очистить ссылки, остановить подписки или что-то еще.
Самое интересное — это попавший к нам класс AccessibilityEvent. Что мы можем от этого получить?
Для начала мы можем понять, что на самом деле произошло в вашей системе.
Берем EventType, и что мы здесь получаем? И обнаруживаем, что там открылась какая-то Активность, или Диалог, или Всплывающее окно, или даже уведомление слетело.
Всё падает прямо туда на window_state_changed. Далее мы понимаем, что изменилось содержимое какого-то представления.
Мы его переместили, вставили какую-то строку в текстовое представление или что-то в этом роде.
И тогда мы узнаем, когда пользователь нажимает или выбирает представление.
На мой взгляд, с помощью этих типов событий вы покроете 85, а то и 98, наверное, процентов основных продуктовых задач.
Но если вам их недостаточно, пожалуйста, вы можете зайти в документацию, я покажу вам ссылку в конце отчета, и вы, конечно же, скачаете отчет и сможете перейти туда.
Просто читаю за весь вечер, там огромный список.
Серьезно, за один присест этого не сделать.
Теперь наш вопрос: как найти представление? Мы узнали, что произошло.
Теперь давайте разберемся, с каким видом, с каким компонентом это произошло.
Давайте возьмем наше AccessibilityEvent. Берем у него Исходник, и, вуаля, метаинформация о представлении у нас уже есть.
Но что, если вы хардкорный разработчик и вам не хватает информации об одном представлении, вы хотите понять, что в принципе сейчас происходит на экране? Ограничение на SDK есть, но оно незначительное.
Мы берём наш AccessibilityService и по сути получаем ссылку на корневой элемент во всей иерархии на текущем экране.
И только тогда мы получаем нашу метаинформацию.
Это, конечно, круто, но теперь у вас в голове должен возникнуть вопрос: ну вот, мы получили ссылку на корневой элемент. Что нам делать дальше?
Если вы хотите пойти безопасным путем, выберите первый вариант. Возьмите представление ID и просто найдите его, используя один метод.
Если вы думаете, что это как-то скучно, ищите что-то повеселее, то возьмите текст из представления и найдите его по тексту.
Если вам это недостаточно интересно, ну и ладно, ребята, берите Child и Recursion и разбирайтесь.
Тогда вы поймете именно все, что происходит. Большой.
Мы понимаем, как найти вид. Как теперь с ней взаимодействовать?
Мы снова берем нашу AccessibilityNodeInfo и теперь кидаем в нее Action. Какие действия мы можем туда добавить?
Для начала мы можем бросить Click. Почему я в итоге поместил сюда не просто «Клик», а еще «Клик и Выбрать»? Да потому, что есть много угловых случаев, когда обычный Клик вас не спасет. Допустим, пользователь выделил текст, и нажатие на представление полностью удалит выделение из этого текста.
Или на некоторых устройствах вид в принципе не кликабелен, пока на нем не вызовешь Select. В общем, проблем много.
А если хочешь просто попариться, делай Select, делай Click. Два Действия, и всё, счастье есть.
Что нас ждет дальше? И затем мы устанавливаем текст. Здесь тоже все просто.
Берем Action_set_text, создаем Bundle с нашей строкой и живем.
И третий момент — обратиться к документации.
Опять же, это второй вечер, который у вас будет. Много действий, на мой взгляд, даже больше, чем событий.
Ура! Самая скучная часть отчета позади.
Теперь пришло время всяких вкусностей.
Допустим, вы создали сервис, настроили его и добавили обработку событий.
Теперь вам нужно понять, как заставить пользователя, как попросить его включить эту услугу.
Чтобы это понять, нужно выяснить, включена ли служба на самом деле или нет.
Здесь все просто до банальности.
Берём AccessibilityManager и запрашиваем у него все включенные на данный момент сервисы в системе, и там находим свой.
Но все было бы здорово, конечно, если бы AccessibilityManager был нормальным парнем, и не было бы, чтобы ты его просил: «Чувак, дай мне, пожалуйста, все доступные сервисы», а он говорит: «Извини, меня здесь нет».
сегодня.
" в настроении.
Вот тебе пустой список».
А ты сидишь и думаешь: «Блин, мы нормально общались».
Ну да ладно, есть старые добрые друзья — Settings.Secure.getInt и getString. Сначала мы спрашиваем, включены ли вообще службы в системе.
Если они включены, то все скидывается в одну строку, и там ищем свое через какой-то контент. И тогда мы понимаем, что все сделали правильно.
Мы создали конфигурацию, создали всякие события для строительства и включили сервис.
Мы точно видим, что служба включена, но события к нам не приходят. Причем иногда они приходят, иногда нет. В тот момент я подумал, что в моей жизни наступила какая-то черная полоса.
Реальных вариантов не было.
Я думал-думал, исследовал-исследовал, а потом, бинго, понял, что это Xiaomi с их MIUI. Это просто боль, ребята! Серьезно.
Хорошо, мы понимаем, в чем проблема.
Как мы можем решить эту проблему сейчас? К сожалению, на некоторых прошивках MIUI все сделано так, что если ваше приложение не в автозапуске, то система даже не запустит ваш сервис.
Но решение одно – мы просим пользователя добавить ваше приложение в автозагрузку, а сами живём дальше и радуемся жизни.
И вот вишенка на торте.
Почему этот сервис, такой добрый к людям с ограниченными возможностями, — волк в овечьей шкуре? Мне кажется, многие из вас уже догадались, что если пользователь включит эту услугу, то мы легко сможем украсть с его устройства много конфиденциальной информации.
Мы можем его не только украсть, но и куда-то подкинуть, например, разблокировать экран, если он заблокирован ПИН-кодом.
Ну да ладно, давайте разблокируем экран.
Что дальше? Разведем себе рекламу, заработаем много денег, будем просто жить.
И, в конце концов, мы можем, в принципе, имитировать абсолютно любые действия пользователя, и, например, установить какое-нибудь приложение, дать ему права администратора и сказать пользователю: «До свидания.
Попрощайтесь со своим устройством».
Ладно, мы всё это можем, но сейчас ты скажешь: «Ты, конечно, молодец.
Он рассказал нам, как и какие данные мы можем украсть.
Но как заставить пользователя включить ваш AccessibilityService, если там еще и какое-то мошенническое приложение? Ладно, мне кажется, что пользователь просто откроет настройки, поймет, что там написана какая-то ерунда, закроет, удалит приложение и забудет. И знаете, вы будете правы, что первый способ его включения через настройки системы сходит на нет, потому что, сами понимаете, это ерунда какая-то.
И здесь нам на помощь приходит уязвимость, которая по сути называется кликджекингом.
Ребята, многие ли из вас знакомы с кликджекингом? Отлично, это будет интересно.
Итак, на основе этой уязвимости некоторые ребята — я прикрепил небольшую ссылку, потому что все следующие скриншоты будут с ресурса этих ребят — придумали атаку под названием Cloak and Dagger. По сути, имея всего два разрешения и минимальное взаимодействие с пользователем, вы получаете доступ ко всему приложению с самого начала.
Но ладно, что нам нужно сделать, чтобы пользователя все-таки взломать? Загружаем наше приложение в Google Play. Мы надеемся, что у пользователя версия Android ниже 8. Понимаете, совсем немного – на данный момент 95%.
И все, пользователь скачивает наше приложение.
Короче говоря, эта вредоносная программа подсказывает пользователю, как стать хорошим парнем, показывая в самом конце видеоролик.
Теперь вы все увидите сами.
Хорошо, начнем.
Маленький текст. Нам говорят: «Если ты сейчас начнешь обучение, ты станешь хорошим парнем».
Хорошо, конечно, начнем.
Еще немного текста.
Далее люди будут представлены в виде зеленых человечков.
Ну да ладно, нажимаем Далее.
Больше текста.
ХОРОШО.
Сейчас дочитаю и обязательно увижу видео, которое расскажет мне, как стать хорошим парнем.
Нажимаю «ОК», и там начинается видео.
Для нас это не так важно.
Важно то, что на самом деле происходило на устройстве в тот момент. Пользователь запускает приложение, и поскольку мы установили его из Google Play, нам автоматически дается разрешение на наложение.
Вуаля, открываем окно специальных возможностей, а сверху просто оверлей.
Пользователь нажимает «Начать обучение», но на самом деле выбирает нашу AccessibilityService. Ну вы понимаете, что произошло дальше.
Далее нажимаем Далее и выбираем тумблер.
В самом конце мы включаем AccessibilityService, и пользователь даже не подозревает, что это произошло.
Знаете, в чем проблема? Оверлеи устроены таким образом, что они либо полностью поглощают все события, все касания и так далее, либо полностью пропускают. И фишка этой конкретной атаки в том, что мы заполняем оверлей, весь экран кроме одного пробела.
В данном случае это кнопка ОК.
Эта кнопка действительно из диалога.
Когда мы нажимаем на нее, мы получаем событие, указывающее, что произошло прикосновение снаружи, и все в порядке.
Как Google реагирует на все эти проблемы? Вы понимаете, это довольно жестокая уязвимость.
Все началось довольно интересно – и все это с восьми лет молчания.
Google выпустил эту штуку и сказал: «Ребята, используйте.
Это безопасно.
Я тебе точно говорю.
ХОРОШО.
Гугл был взорван.
Те же ребята, которые придумали Cloak и Dagger, также обеспечивали поддержку, отслеживание проблем и ошибок.
Затем Google сказал: «Ладно, ладно, ребята, успокойтесь.
Закрою кликджекинг в Орео».
Ладно, закрыли.
Они до сих пор сидят и думают: «Ну блин, ребята, ведь если злоумышленники заставят пользователя включить специальные возможности, это будет плохо.
разработчики немного.
И присылают письмо: «Сделайте это, я не знаю что, иначе ваше приложение будет удалено из Google Play».
Если кратко, то в письме говорилось следующее: «Ребята, расскажите нам и пользователям, зачем вам нужен AccessibiiltyService».
Как сказать? В каком формате? Где? Понимания нет вообще.
И естественно в письме об этом не указано.
ХОРОШО.
Огромные темы на Reddit, много писем в поддержку.
И тут какой-то разработчик выкладывает письмо на реддит, и там написано: «Там ничего сложного, ребята.
Поместите его в описание, которое я вам показал в манифесте, поместите в описание в Google Play, и все будет хорошо, я вас оставлю в покое».
В тот момент я подумал: ну да ладно, я нашел это письмо в каких-то кулуарах Reddit. Что делать, если я молодой разработчик, только познакомился с AccessibilityService и хочу выпустить с его помощью приложение? Как я узнаю, что мне нужно совершить такие действия, нужно добавить их в описание, Google Play и т.д.? Я думал-думал, искал-искал и, знаете, ребята, ничего не нашел, буквально.
Ну серьезно, нечего.
В основной документации просто есть описание: «Ребята, это чисто для людей с ограниченными возможностями, и точка.
Использовать больше нельзя.
» Но на деле оказывается, что можно.
Что ж, мы подошли к концу.
О чем мы смогли с тобой поговорить? Мы рассказали о том, как это можно использовать, поняли, как это все создавать и настраивать, поняли, как обрабатывать события пользовательского интерфейса.
И, конечно, мы поняли, как можно, но не нужно взаимодействовать с AccessibilityService. Конечно, я вам не рекомендую этого делать, это было просто для информации.
Вот обещанные исходники: — Developer.android.com/guide/topics/ui/accessibility/services — Developer.android.com/reference/android/view/accessibility/AccessibilityEvent — Developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo — Cloak-and-Dagger.org Ребята, спасибо большое за внимание! Теги: #информационная безопасность #Android #Разработка Android #Разработка мобильных приложений #доступность #кликджекинг #сервис доступности
-
Файловая Система Linux
19 Oct, 24 -
Yahoo Догоняет Google?
19 Oct, 24 -
Семь Правил Предпринимателя От Стива Джобса
19 Oct, 24 -
Длинный Ответ На #Fixreplies От Биз Стоун
19 Oct, 24 -
Опубликован Api Google Mirror
19 Oct, 24