Для функционирования программы необходимы права root пользователя.
Краткое описание: Решение проблемы несовместимости приложений из GooglePlay с вашим устройством.
Описание: Пользователи Android иногда сталкиваются с проблемой несовместимости приложений из GooglePlay с их устройствами. Это приложение позволяет смартфону или планшету притвориться другим устройством. Например, пользователь Nexus 7 с помощью Market Helper может «превратить» его в смартфон Galaxy S3. В результате, все приложения несовместимые с нексусом, но поддерживающие S3, можно будет установить на планшет. Market Helper пригодится и пользователям китайских планшетов и смартфонов, совместимость с приложениями, у которых по сравнению с известными флагманами не так высока.
Для работы Market Helper требуется рут-доступ, а самого приложения нет в Google Play. Его можно скачать с сайта разработчика.
Чтобы изменить модель устройства, достаточно запустить Market Helper, выбрать нужный гаджет из списка и нажать кнопку «Activate». После этого нужно открыть страницу профиля Google Play в браузере и убедиться, что модель была изменена.
Для удаления Market Helper и восстановления прежней личности устройства достаточно включить Wi-Fi или 3G, снова запустить приложение, выбрать из списка пункт «Restore», нажать «Activate» и перезагрузить гаджет. На странице профиля Google Play все вернется в первоначальное состояние.
Разработчик уверяет, что Market Helper не вносит изменения в системные файлы Android, и его установка и удаление полностью безопасны. Тем не менее, все вышеописанные действия пользователь выполняет на свой страх и риск. Ответственности за возможные проблемы создатель утилиты не несет.
Источник
Всего лишь меняем модель эмулятора Android устройства
Пролог
Казалось бы, на первый взгляд весьма простая задача. Некоторые читатели могли еще в те бородатые времена лазить по всяким 4пда, рутить свой сенсорный самсунг, менять содержимое файла build.prop и показывать наивным ламерам свой iPhone 15+ Max Pro. Однако, как оказалось, и как оно часто бывает, не все так просто и здесь есть свои подводные камни. Статья призвана помочь простым работягам избежать все кочки да ямы на пути к своей цели!
Дисклеймер
Сразу предупрежу, что люблю писать подобные статьи довольно подробно, не ради объема и многобукав, а ради максимального погружения в проблему и способ ее решения. Обратите внимание, что я работаю на macOS, поэтому все команды в терминале будут ориентированы под данную ОС. Также, следует отметить, что проворачиваю все это для API 30, то есть для самого последнего на момент написания статьи. Как говорят интернеты, сложности по этой теме начались с API 29.
Зачем это нужно?
Предполагаю, что у вас, дорогой читатель, есть на это своя веская причина, иначе не стали бы вы этим заниматься. Наиболее вероятно, что у вас, как и у меня есть программная проверка на модель устройства с которого запущено приложение, примерно как здесь. К слову, таким образом можно будет проверять результат наших трудов. Второй же, и более простой способ проверки модели эмулятора будет через настройки девайса в разделе сведений об устройстве:
Ради контекста вкратце расскажу зачем это понадобилось мне. Я получил .apk с багом где-то внутри приложения. Однако пройти дальше первого экрана в этом приложении я не смог. Дело в том, что при запуске, с сервера приходит список разрешенных для запуска устройств и ни мой народный Ксяоми, ни мой эмулятор в этот список не входит. Вот и додумался поменять имя модели устройства на одно из разрешенных. Рутить свой личный телефон не хотелось, поэтому решил шаманить с эмулятором.
Экран не пустивший меня дальше
Достаем build.prop
Как уже говорилось в начале статьи, за имя производителя и модель устройства отвечает системный файл build.prop, который находится в корне устройства в папке system/. Однако при попытке просмотреть его, не говоря уже о редактировании, мы получим отказ в доступе:
Для решения этой проблемы необходимо в терминале обратиться к adb и запросить root права следующей командой: adb root . И вот и первый подводный камень, а именно вывод следующего сообщения: adbd cannot run as root in production builds . Это из-за того что при создании эмулятора мы выбрали вариант с установленными Google сервисами:
Простое решение — создать эмулятор без установленных Google сервисов, после чего повторить команду adb root . После чего в консоли должно появиться сообщение: restarting adbd as root что говорит об успешном проведении операции. Естественно если с самого начала у вас был эмулятор без Google сервисов, то скорее всего с adb root и выше описанной проблемой вы не столкнулись.
Отлично, теперь мы видим содержимое файла build.prop:
Редактируем build.prop
Сохраним файл build.prop в любое удобное место для дальнейшего редактирования выделенной красным области на скриншоте выше. Я сохранил прямо на рабочий стол:
Вносим необходимые изменения. Просмотрев логи запросов и ответов предоставленного мне .apk я нашел приходящий с сервера список разрешенных устройств. То есть, для моих целей нужно поменять два значения на PIXEL 3A XL (как вы поняли, здесь вы можете указывать необходимую именно вам модель):
Сохраняем изменения и заливаем файл обратно на эмулятор. Делается это при помощи команды adb push (кстати, скачать файл с эмулятора можно при помощи adb pull если у вас вдруг аллергия на GUI).
Вводим команду в терминал: adb push build.prop system/
И получаем ошибку:
adb: error: failed to copy ‘build.prop’ to ‘system/build.prop’: remote couldn’t create file: Read-only file system
Вот здесь и начинается самое интересное! По умолчанию эмулятор запускается в режиме чтения системных файлов, без возможности делать записи. Следовательно, что либо поменять без прав на запись у нас не выйдет. Для этого нам необходимо запустить эмулятор в ручном режиме с доступом на запись системных файлов.
Запускаем эмулятор с доступом на перезапись системных файлов
Для этого нужно выполнить следующую команду в терминале (чтобы скорее всего получить еще одну ошибку):
итак здесь Pixel3XLAPI30 — это название нашего эмулятора который мы будем запускать в режиме записи, получить это имя можно выполнив команду emulator -list-avds
-writable-system — собственно тот самый флаг и виновник торжества.
-no-snapshot -nocache — просто советую ввести чтобы избавиться от любого возможного мусора, который может помешать нашему плану-капкану.
После у нас либо запустится эмулятор (несколько секунд запускается, так что если тупит то так и должно быть) либо получаем ошибку следующего типа:
PANIC: Missing emulator engine program for ‘x86’ CPU.
Что бы и нам решить с этим нужно в файле .bash-profile (или если у вас zsh то в файле .zshenv) находящийся в корне вашего профиля macOS, добавить дополнительные пути. Вот как это выглядит у меня:
есть такая переменная ANDROIDHOME и с ее участием редактируем переменную PATH:
Чтобы изменения вступили в силу перезапускаем терминал (или вводим source
/.bash_profile ) (или source
/.zshenv ). Результат можно проверить выполнив команду echo $PATH и убедиться что в переменной PATH появился добавленный нами путь.
-writable-system make system & vendor image writable after ‘adb remount’
делаем вывод что теперь нам нужно выполнить adb remount . Для этого открываем новое окно терминала и выполняем сначала команду adb root , что бы adb remount сработало.
После adb remount , будет сообщение что эмулятор нужно перезапустить. Сделать это можно командой adb reboot. Но и здесь не все так просто. Очередной подводный камень об который мы разбили еще один ноготь на пальцах ног. Если сделать adb reboot то все просто напросто зависает НАВСЕГДА. Настолько навсегда, что придется удалять эмулятор и создавать его заново. Интернет и с этим столкнулся и даже баг создали на гуглов. И благо нашлось решение. Чтобы эмулятор не зависал нужно добавить пару команд до adb remount .
Итак по порядку:
Делаем adb root
Теперь делаем adb shell avbctl disable-verification
Если вы вдруг остались в shell то введите exit
Перезагружаем эмулятор adb reboot и ждем
Снова делаем adb root
И вот теперь можно делать adb remount
Ура! Теперь мы можем записывать файлы в системную папку нашего эмулятора. Можем пушнуть наш отредактированный build.prop файл: adb push build.prop system/ . Сделаем adb reboot и убеждаемся что ничего не поменялось… Имя модели не изменилось.
Редактируем правильный build.prop
Вернемся к началу и заметим, что значения ro.product.product.name и ro.product.product.model не соответствует тому, что отображается в настройках устройства. Изучив структуру системных папок я заметил, что существует несколько файлов build.prop, которые располагаются в папках: system, system_ext, vendor и product. Эмпирическим методом я скачивал, редактировал и пушил обратно каждый из этих файлов. В конце концов ключевым оказался файл в папке product. Отредактировав его я наконец-то смог изменить название модели эмулятора устройства!
Подводим итоги
Наконец-то я смогу запустить приложение и воспроизвести баг. Подумал я…
Теперь я уперся в то, что запускаю приложение якобы с рутованого девайса (ну да есть такой грешок). И дело даже не в команде adb root , ведь команда adb unroot не помогла. Что ж, опускать руки уже поздно, придется что-то придумать.
О том, как я обходил проверку на рутованность устройства я расскажу в следующей своей статье. Немного реверс инжиниринга и даже такая популярная библиотека как RootBeer не проблема.
Данной статьей я стремился собрать как можно больше проблем по этому вопросу и изложить все в форме step-by-step. Спасибо за ваше внимание и очень надеюсь, что статья оказалась полезной!
Источник
Android Task Hijacking. Разбираем актуальную технику подмены приложений в Android
Содержание статьи
Первоначальное исследование
Первое упоминание об этой уязвимости было опубликовано еще в 2015 году на конференции USENIX Security Symposium 2015, но, к сожалению, не получило широкой огласки и не привлекло к себе должного внимания. Когда мы ознакомились с материалами исследования, первой мыслью было «Да ладно, не может это так работать, это уж слишком. Два года прошло, уже закрыли давно, наверное». Реальность оказалась страшна.
Мало того, что все описанное в статье работает до сих пор, — появилась еще одна, обнаруженная нами, уязвимость, которая делает эксплуатацию намного легче и проще. В статье мы приведем адаптированную информацию из доклада, расскажем про обнаруженную нами уязвимость и попробуем разобраться, как можно защититься от подобных атак.
Немного теории
Если ты профессиональный Android-разработчик, вносишь правки в исходный код Android или пачками репортишь баги, можешь смело пропустить этот раздел и переходить к основной части. В противном случае немного освежим память и рассмотрим, как устроено управление задачами и основные элементы, которые нам потребуются в дальнейшем в системе Android.
Основной компонент, с которым взаимодействует пользователь при работе с приложением, — это Activity. Каждая Activity — это отдельный графический экран со своими элементами, именно их и видит пользователь. Каждое приложение имеет несколько Activity для различных действий, то есть каждый новый экран — это отдельная Activity. Все они описаны в файле манифеста приложения.
Все Activity, которые прошел пользователь за время работы с приложением, располагаются внутри сущности, называемой Task. Activity в Task хранятся в виде строгой последовательности (стека), называемой back stack. При открытии каждого нового экрана создается новый экземпляр Activity и располагается системой на верхушке этого стека. Таким образом, при нажатии на кнопку «Назад» Activity, которая была наверху стека, закрывается (уничтожается) и отображается Activity, которая была под ней. Отсюда и название — back stack.
Activity и back stack
Activity, которую пользователь видит на экране устройства, находится на переднем плане и называется Foreground Activity, а таск, внутри которого находится эта Activity, — Foreground Task. В один момент времени в системе может быть только один Foreground Task и Foreground Activity, все остальные выполняются на заднем плане, то есть в Background. При переходе на задний план Task становится неактивным, состояние его back stack сохраняется в неизменном виде. Таким образом, когда пользователь снова вернется в приложение, состояние останется тем же, и он сможет возвращаться к экранам в том порядке, в каком их открывал.
Activity внутри back stack могут относиться не только к запущенному приложению, но и к сторонним приложениям. Всем известна ситуация, когда из одного приложения мы можем открыть, к примеру, галерею и выбрать новую фотографию на аватарку. Для разработчика приложения нет необходимости самому реализовывать функцию выбора и предварительного просмотра изображения, для этого достаточно вызвать Activity из нужного приложения (или предоставить выбор приложения пользователю).
Таким образом, при вызове функции сторонней программы в back stack помещается ее Activity, и при нажатии на кнопку Back пользователь вернется к приложению, с которым работал ранее. Это сделано для бесшовной интеграции, чтобы создавалось ощущение работы с единым приложением и не было необходимости переключаться между программами для выполнения одноразовых операций.
Запуск Activity стороннего приложения
Важный атрибут taskAffinity характеризует, к какому таску должна присоединиться Activity при запуске. Он представляет собой строку, которая либо определяется в манифесте приложения свойством android:taskAffinity , либо по умолчанию равна ID приложения в системе ( applicationId ). Affinity таска определяется значением taskAffinity его root Activity (нижней в стеке). Если явно указывать значение taskAffinity, то можно заставить запускаться Activity в рамках произвольного таска. Таким образом, каждое приложение может породить произвольное количество тасков.
taskAffinity
WARNING
Техника подмены приложений работает во всех версиях системы, исправлений нет до сих пор. Материал адpесован специалистам по безопасности и тем, кто собираeтся ими стать. Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.
Возвращаемся во вредоносное приложение
За загрузку Activity в Android отвечает Activity Manager Service (AMS). Существует несколько способов запустить Activity в новом таске:
определить launchMode=»singleTask» в манифесте приложения у необходимой Activity;
при запуске Activity указать FLAG_ACTIVITY_NEW_TASK.
Вот что происходит в системе, когда ты нажимаешь на значок приложения.
Если экземпляр Activity уже существует, то AMS находит его и выводит на передний план, а не запускает новый.
Если требуется создание Activity, то AMS выбирает Task, в который необходимо «положить» созданную Activity. Для этого AMS пытается найти «совпадающий» Task. Activity «совпадает» c Task, если у них указано одинаковое свойство taskAffinity. Если найдено совпадение, сервис кладет новую Activity на верхушку стека в выбранный Task.
Если же совпадений не найдено, сервис создает Task, и новая Activity становится root Activity.
Теперь, обладая тайными знаниями, попробуем заставить систему переместить запускаемую Activity на стек условно вредоносного приложения. Предположим, что мы хотим атаковать приложение TargetApp и в числе его возможностей есть просмотр видео при помощи приложения PlayerApp (либо пользователь выбирает это приложение для просмотра из выпадающего списка). При этом в интенте, который запускает Activity стороннего приложения, присутствует FLAG_ACTIVITY\_NEW\_TASK или в сторонней Activity объявлен launchMode=»singleTask» , то есть заданная функция запускается в отдельном таске.
Также на устройстве находится вредоносное приложение (Malware), которое, помимо того что выполняет вполне легитимные функции, при запуске или при включении устройства создает в системе Background Task с taskAffinity=»PlayerApp» .
Вот как выглядит наш AndroidManifest.xml :
А вот MainActivity.java :
Запускаем TargetApp и выбираем просмотр видео. Попробуем пошагово проследить, что произойдет.
Возвращаемся во вредоносное приложение
Activity Manager Service понимает, что ему нужно запустить Activity приложения PlayerApp.
Запущенного экземпляра такой Activity нет в системе, переходим к следующему шагу.
Пытаемся найти в системе Task с соответствующим taskAffinity. AMS находит наш запущенный вредоносный Task и, следуя своей логике, запускает Activity плеера, помещает ее на верхушку стека и выводит на передний план.
Таким образом, запущенная Activity приложения PlayerApp оказывается на верхушке стека условно вредоносного Task. После просмотра видеоролика пользователь нажимает Back, система уничтожает верхнюю Activity и выводит на передний план лежащую под ней (Mal-Activity 2). Пользователь оказывается во вредоносном приложении, которое, в свою очередь, может имитировать интерфейс приложения TargetApp.
Подменяем приложение при запуске
Описанный выше способ имеет свои недостатки: необходимо, чтобы функциональность , реализуемая сторонними приложениями, обязательно запускалась в новом Task, либо в приложении, которое мы указываем как taskAffinity для вредоносной задачи, либо при запуске из приложения, которое мы атакуем. А вот бы сделать так, чтобы сразу запускать вредоносное приложение и вообще не зависеть от реализации атакуемого приложения. Не вопрос! Официальный Android API позволит нам сделать и это.
По умолчанию, как только Activity запускается и ассоциируется с таском, эта связь сохраняется на всем протяжении жизненного цикла Activity. Однако Android API позволяет указать вместе с taskAffinity свойство allowTaskReparenting таким образом, что при появлении в системе Task с аналогичным указанному taskAffinity эта Activity сразу перемещается на верхушку его back stack. Пока в системе не будет зарегистрирован такой Task, Activity будет запускаться в рамках своего приложения. Выглядит очень интересно, попробуем проэксплуатировать разобраться.
Подмена при помощи allowTaskReparenting
Итак, в системе, в Background, запущен вредоносный Task, в его стеке находятся root Activity (Mal-Activity 1) и Mal-Activity 2, имитирующая интерфейс приложения, которое хотим подменить. Также при описании Mal-Activity 2 указаны параметры taskAffinity подменяемого приложения и allowTaskReparenting .
Все приложения, которые запускаются из лаунчера, имеют флаг FLAG_ACTIVITY\_NEW\_TASK , то есть в новом таске. Пользователь хочет открыть свое любимое приложение, нажимает на иконку. Так как запущенного таска с таким taskAffinity в системе нет, он создает новый Task и запускает в нем Activity. В это же время система регистрирует появление Task с taskAffinity, который указан в Mal-Activity 2, и, в соответствии с ожидаемым поведением, помещает вредоносную Activity на верхушку стека и переводит ее в Foreground. Дело сделано, вместо исходной Activity пользователь видит вредоносную. Для него это абсолютно прозрачно: нажимаем иконку — загружается приложение со знакомым интерфейсом. Activity из оригинального приложения пользователь не видит вообще.
Подменяем приложение при запуске. Версия 2
В описанном случае есть интересный нюанс: если пользователь, находясь на подмененном экране, нажмет Back, система закроет вредоносную Activity и пользователь увидит экран обычного приложения. Можно ли как-то этого избежать и контролировать не только запускаемую Activity, но и Task, в котором она запущена? Больше власти никогда не повредит, давай разбираться.
Что должно произойти при нажатии на иконку приложения в Launcher, если Task с таким taskAffinity уже существует в системе? «Да все просто, мы же говорили об этом выше, AMS должен будет запустить экземпляр Activity и поместить на верхушку стека выбранного Task», — скажешь ты. А вот и нет, из-за бага в Android, который немного нарушает логику работу AMS, поведение будет несколько иным.
Подмена приложения при указании только taskAffinity
Как и в предыдущих случаях, на устройстве в Background запущен таск с taskAffinity приложения, которое мы хотим подменить. При этом больше ничего дополнительно указывать не нужно, AMS все сделает за нас.
В этом случае при нажатии на иконку подменяемого приложения AMS просто выведет на Foreground Task с указанным taskAffinity. То есть Activity подменяемого приложения вообще не будет запущена. Для пользователя опять все абсолютно прозрачно: нажал на приложение, оно запустилось, выглядит привычно. Но теперь мы полностью контролируем всё — и Task, и Activity. Повторный запуск опять отправит пользователя во вредоносное приложение.
Включаем социальную инженерию
В Android есть возможность давать пользователю самому выбрать приложение, которое будет выполнять ту или иную функцию. Выглядит это как всплывающий список иконок приложений с названиями и реализуется при помощи неявных интентов. Попробуем использовать это в своих целях. У этого подхода есть особенность: нам нужно будет заставить пользователя выбрать наше приложение.
Для разнообразия будем атаковать функцию просмотра PDF. Для успешной реализации, а вернее для большего правдоподобия наше вредоносное приложение может действительно иметь возможность просмотра PDF. Реализуем это в отдельной экспортируемой Activity, которая на вид будет соответствовать стилю атакуемого приложения. Название и значок тоже сделаем почти идентичными. В общем, попробуем убедить пользователя, что в приложении есть такая функция, просто реализована она немного непривычным способом.
Подмена с использованием неявного Intent
Пользователь работает с приложением, выбирает PDF, собирается его открыть. Если выбор приложения для просмотра сделан с помощью неявного интента, пользователю будут предложены на выбор программы, которые могут обрабатывать файлы такого типа. Среди них-то и будет прятаться малварь, иконка которой ну очень похожа на иконку того приложения, которое он сейчас использует. Название тоже не должно вызывать подозрений.
Отлично, мы заставили пользователя выбрать наше приложение. AMS запускает вредоносную Activity и кладет на верхушку стека атакуемого приложения. После работы с документом пользователь нажимает на кнопку Back, чтобы вернуться обратно в приложение, но мы не даем ему это сделать. Переопределим метод onBackPressed() , который отвечает за обработку нажатия на Back. Перепишем его таким образом, чтобы перенаправить пользователя во вредоносное приложение и вывести его экран на Foreground. Готово, ловушка защелкнулась!
Защищаемся от удаления
Теперь нужно как-то закрепиться в системе. Первое, что приходит в голову, — это применить тот же самый принцип, чтобы защитить малварь от удаления. Ведь когда мы заходим в настройки Android или на экран удаления приложений, мы просто запускаем отдельные системные приложения со своим taskAffinity, которые ничем не отличаются от остальных, разве что иногда выполняются с большими привилегиями. Сказано — сделано, приступаем!
Защита от удаления
По старой памяти запускаем в Background Task с taskAffinity приложения настроек. В одном случае из-за дефекта с недокументированным поведением AMS приложение настроек просто не запустится. Такой вариант совершенно не интересен — рано или поздно поведение AMS придет в норму. Рассмотрим лучше случай, когда сервис работает как положено.
Итак, все работает как и должно, а в Background ждет своего часа условно вредоносный Task. Запускаем приложение настроек. AMS запускает Activity, находит наш Task и кладет его на верхушку стека. Теперь настройки живут в таске, который мы контролируем. Пользователь переходит по экранам, заглядывает в удаление приложений, видит там зловреда и нажимает на кнопку «Удалить».
После нажатия Android показывает диалоговое окно, которое предлагает подтвердить намерение удалить приложение. Это диалоговое окно не что иное, как очередная Activity, которую мы можем перекрыть своей, как только она появится внутри нашего таска. Делаем похожий экран с неактивной кнопкой «Удалить». При этом, как уже делали ранее, переписываем метод onBackPressed() таким образом, что при нажатии на Back снова запускаем Mal-Activity 1 в Background, используя флаг FLAG\_CLEAR\_TASK , чтобы очистить содержимое таска. И мы снова возвращаемся к изначальному состоянию.
Некоторые продвинутые пользователи могут попробовать удалить нехорошее приложение через Android Device Bridge (ADB). Но для того, чтобы удалось подключить устройство к компьютеру, необходимо включить опцию «Отладка по USB». Включение этой опции тоже находится в настройках. Дальнейшее развитие событий очевидно.
Лайфхаки
Автозапуск
Когда пользователь сам запускает вредоносное приложение — это удача для атакующего. Но что, если оно сможет запускаться самостоятельно? Для этого в приложении можно объявить BroadcastReceiver , который система будет запускать при загрузке. Например, пишем в AndroidManifest.xml :
Можно привязаться и к другим событиям, например изменению состояния подключения к интернету, получению SMS. Правда, в современных версиях Android для работы автозапуска приложения требуется, чтобы пользователь хотя бы раз запустил его вручную.
FLAG_ACTIVITY_CLEAR_TASK
Как ранее упоминалось, флаг FLAG\_ACTIVITY\_NEW\_TASK желательно использовать совместно с FLAG\_ACTIVITY\_CLEAR_TASK для того, чтобы очищать содержимое стека Task запускаемой Activity. Но этот же флаг может использоваться злоумышленником, чтобы гарантированно «занять» Task с целевым taskAffinity .
Это может быть полезно в случае, если целевое приложение уже запускалось и злоумышленнику требуется заменить содержимое его Task на свое. Например, при автозапуске после получения SMS.
dumpsys
Чтобы получить список запущенных в системе тасков, содержимое их бэкстека и информацию о его Activity, можно воспользоваться следующей командой:
Она выдаст вот такую структуру данных AMS:
Для наглядности приведена только часть информации. Из вывода видно, что на момент запуска в Foreground находится Task c taskAffinity=com.android.vending (Play Маркет) и realActivity=ru.mobsec.calcapp.CTFMobileBank.malware/ru.mobsec.calcapp.MainActivity . Суди сам, к чему это может привести пользователя.
Немного статистики
Авторы первоначального доклада собрали внушительную статистику, проанализировав большое количество приложений на предмет уязвимости к атакам подобного рода. Мы немного дополнили эту статистику.
Тип уязвимости
Процент уязвимых приложений
Подмена приложений из Launcher
100%
Использование неявных интентов
93,9%
Использование FLAG_ACTIVITY_NEW_TASK
65,5%
Использование режима запуска singleTask
14,2%
Сейчас перед такими атаками уязвимы все версии Android начиная с 3.x. Уязвимость никак не зависит от производителя устройства. Подмена приложения из Launcher при помощи указания taskAffinity не работает только в CyanogenMod. Очевидно, код запуска приложений в нем сильно изменен по сравнению с официальным вариантом. Тем не менее остальные способы работают.
Как защититься?
Рассмотрим основные способы борьбы с подобным вариантом атаки на приложения. Проблема связана со стандартным Android API, поэтому единственная возможная защита — это поменьше использовать уязвимые методы.
С осторожностью использовать FLAG\_ACTIVITY\_NEW_TASK , лучше вообще не делать этого без необходимости. Если же все-таки без него обойтись не получится, использовать его вместе с флагом FLAG\_ACTIVITY\_CLEAR\_TASK . Перед созданием Activity он очистит Task, к которому она будет привязана, обнулит его содержимое и сделает твою Activity корневой (нижней в стеке).
Не указывать режим запуска singleTask для Activity приложения. Если есть необходимость запустить в отдельном таске, то использовать рекомендацию из пункта 1.
Не указывать для Activity атрибут allowTaskReparenting , чтобы предотвратить перемещение Activity на стек вредоносного таска.
Использовать явные интенты для вызова сторонних приложений. Либо использовать неявные интенты с применением белого списка приложений, разрешенных к запуску. Как вариант, можно проверять такие приложения по цифровой подписи.
К сожалению, полноценного решения, позволяющего полностью защититься от атак подобного рода, не существует. Есть несколько идей, как потенциально можно предотвратить возможность атаки. Это создание сервиса, который бы отслеживал наличие в системе Task с taskAffinity защищаемого приложения. Когда такой таск будет найден, можно сверить цифровую подпись породившего его приложения и в случае несоответствия выдавать предупреждение или не запускать приложение. В рамках такого сервиса еще можно реализовать проверку таска, в котором создается Activity приложения.
Выводы?
Два года. Два года, Карл! Думается, что проблема до сих пор не решена потому, что уязвимость эта скорее архитектурная. Такие возможности управления задачами призваны помочь разработчикам и создать единое пространство, в котором работает приложение. Разумеется, никакие объяснения не будут достаточны для нас, хакеров, программистов, да и просто пользователей — ведь мы должны знать, как себя обезопасить. Если не себя, то хотя бы системные приложения!
Если программа устанавливает себе taskAffinity приложения настроек или любого другого системного приложения, то это явно нестандартное поведение.
В качестве временной меры разработчикам могли бы дать возможность запрещать другим приложениям производить какие-либо манипуляции со своим Task. Например, пусть это будет новый атрибут в манифесте приложения, который бы определял, может ли другая программа иметь тот же taskAffinity . Если значение выставлено в false, то система будет игнорировать попытки вредоносных приложений пересадить Activity на свой Task или перекрыть ее при помощи allowTaskReparenting .
Хочется верить, что в ближайшем будущем мы увидим исправление и официальные рекомендации по защите от подмены приложений таким способом. Пока что нам остается только с осторожностью использовать механизм многозадачности или писать костыли в виде сервисов, мониторящих состояние системы.