Порт эксплойта CVE-2026-43499 ("GhostLock") на новое устройство, KernelSU и запуск рута в один тап
Русский · English version
На телефоне Realme GT 7T (RMX5085) с заблокированным загрузчиком получен полноценный root:
KernelSU, рабочий su, работающий интернет и запуск в один тап с телефона (приложение Anchor), без
компьютера и без разблокировки загрузчика.
Модели RMX5085 нет ни в одном публичном списке поддерживаемых устройств (в апстрим-эксплойте 13 устройств, в альтернативном проекте 4), поэтому потребовался порт: определить параметры ядра нашего устройства, исправить четыре калибровки, из-за которых эксплойт либо молча промахивался, либо ронял телефон в панику, и собрать свою сборку приложения для запуска в один тап.
Честное разделение работ: сам эксплойт написан не мной - это открытый проект JoinChang/ghostlock-oneplus. Моя часть: порт на новое устройство, отладка по паникам и логам ядра, сборка профиля устройства и упаковка маршрута "один тап". Все источники перечислены в CREDITS.md.
flowchart LR
subgraph DEV["Телефон (заблокированный загрузчик)"]
E["Эксплойт<br/>GhostLock"] -->|W1| S["SELinux<br/>разрешающий режим"]
E -->|W2| C["подмена cred<br/>uid 0"]
C --> K["KernelSU<br/>late-load модуля"]
K --> SU["su + менеджер<br/>ReSukiSU"]
end
A["Anchor<br/>(один тап)"] -.->|запускает| E
SU --> APP["root-приложения"]
Ядро устройства уязвимо (6.6.118, исправлено начиная с 6.6.140), поэтому эксплойт может записать немного данных в память ядра и получить root. Всё живёт только в оперативной памяти: после перезагрузки следов не остаётся, и рут запускается заново одним нажатием.
- Определён профиль устройства. Из собственного
boot.imgтелефона вытащены символы ядра (105 666 символов), проверены таблицы структур и вычислены все адреса, нужные эксплойту: адресinit_task,init_cred,selinux_enforcing, таблицыfopsдля ashmem и configfs, точка физической загрузки ядра. - Исправлены четыре независимые калибровки, каждая из которых полностью блокировала работу:
сдвиг слова ожидания futex для ветки 6.6 (-2 вместо 0 по умолчанию); физический базовый адрес
MT6899 (0x40000000, а не 0x80000000 и не кваликоммовский 0xa8000000 по умолчанию); жёстко
зашитые в исходник константы из чужой версии ядра (6.12), которые перекрывали таблицу runtime
(файл
target.hпереписан под наше ядро); скрипт, который убивал себя сигналом SIGHUP в середине работы и из-за этого не доходил до установки userspace-части KernelSU. - Разобран и решён вопрос с интернетом. Побочный эффект записи W1 портит соседние поля
selinux_state, из-за чего ядро перестаёт помечать сетевые пакеты и блокирует весь трафик, а перезагрузка политики отклоняется. Рабочее решение: оставлять SELinux в разрешающем режиме. - Собран маршрут "один тап". Официальный APK Anchor пересобран с нашим профилем устройства
(
rmx5085|RE6090L1,RMX5085|-2) и нашей сборкойlibanchor.so, подписан своим ключом. Теперь после перезагрузки достаточно открыть приложение и нажать Bootstrap. - Инструменты. Скрипты извлечения символов из ядра, генерации профиля устройства, сборки нативного модуля и перепаковки APK.
PHYS_OFFSETна MT6899 =0x40000000. Различается даже внутри MediaTek (MT6991 -0x80000000). Правильное значение ядро печатает само в заголовке паники (PHYS_OFFSET: 0x...) - это способ узнать его без root. Неверное значение даёт молчаливые промахи: запись уходит в постороннюю память.- Добавить файл
offsets.hдля нового устройства недостаточно. Часть адресов программа берёт из макроопределений, зашитых на этапе сборки, а не из таблицы времени выполнения: в дампе паники было видно, что поддельная страница содержит значения по умолчанию изtarget.h(6.12 и Qualcomm), а не наши. Для нового устройства нужно править и их. trap '' HUP TERMв начале генерируемого root-скрипта. При запуске черезadb shellскрипт получает SIGHUP и умирает после закрытия сессии - ровно после загрузки модуля KernelSU, до установки userspace-части. Отсюда и "рут есть, аsuнет".- После записи W1 интернет не работает, и перезагрузка политики SELinux отклоняется. Причина:
повреждённые соседние байты
selinux_state, включая флагdisable_policyloads. Лечение: оставлять SELinux в разрешающем режиме (setenforce 0), интернет и всё остальное при этом работают.
Дополнительно: libksud.so из ReSukiSU - это мультивызываемый бинарник, и копия файла с именем
su (не симлинк - симлинк агрессивно блокирует вендорский защитный модуль OPLUS) работает как
штатный su. Именно так завершилась userspace-часть KernelSU.
$ adb shell "/data/local/tmp/su -c id"
uid=0(root) gid=0(root) ... context=u:r:ksu:s0
$ adb shell getenforce
Permissive
$ adb shell ping -c 2 8.8.8.8
2 packets transmitted, 2 received, 0% packet loss
$ adb shell "su -c 'grep kernelsu /proc/modules'"
kernelsu 192512 1 - Live (O)
Плюс: /data/adb/ksu/bin/ заполнен установщиком ksud, разрешение для shell сохраняется в базе
менеджера между перезагрузками, root-приложения (проверка root, Stryker) получают права через диалог
ReSukiSU.
| Область | Чем работал |
|---|---|
| Ядро и эксплойт | C для aarch64, механизмы futex PI и планировщика Linux, структуры ядра 6.6, анализ дампов паник из pstore |
| Разбор образа ядра | Python, собственные скрипты извлечения символов (kallsyms), чтение таблиц указателей прямо из образа, сверка по дизассемблеру |
| SELinux | разрешающий режим, чтение avc-логов, разбор причины отказа перезагрузки политики |
| Root-стек | KernelSU, late-load модуля, ReSukiSU (менеджер), база разрешений .allowlist |
| Упаковка | перепаковка APK (zip-хирургия), NDK r30 для нативной библиотеки, подпись APK своим ключом |
| Инструменты | adb, logcat, pstore, Git Bash, команды телефона, скрипты на Python и Bash |
device/rmx5085/ профиль нашего устройства: таблица адресов и патч к апстрим-эксплойту
tools/ скрипты извлечения символов ядра, генерации профиля, сборки модуля Anchor
scripts/ перепаковка APK Anchor с нашим профилем
docs/ разбор уязвимости, отчёт о порте, находки для апстрима, вопросы безопасности
docs/img/ скриншоты
- Получить
boot.imgсвоей прошивки и извлечь символы ядра (tools/extract_boot.py,tools/extract_kallsyms.py). - Сгенерировать профиль устройства (
tools/gen_device_target.py) и сверить адреса по образу ядра и дизассемблеру. - Применить патч device/rmx5085/rmx5085-port.patch к апстрим-проекту эксплойта и собрать бинарник под aarch64.
- Установить менеджер ReSukiSU, запустить эксплойт (нормально: 1-5 попыток, паники возможны и
безвредны), затем разрешить
shellв менеджере. - Для запуска без компьютера: собрать
libanchor.so(tools/build_anchor_native.py), перепаковать официальный APK Anchor скриптомscripts/repack_anchor.py, установить и импортировать пару adb-ключей.
Подробности, включая все значения адресов, в docs/PORT.md.
- Root временный, по устройству самого телефона. Эксплойт ничего не пишет на диск, ядро при загрузке берётся из флеша нетронутым. Постоянный root на заблокированном загрузчике получить нельзя: это потребовало бы прошивки своего ядра, что и блокирует загрузчик.
- Не устанавливайте обновления системы. В ядре 6.6.140 уязвимость закрыта - одно обновление закроет окно навсегда.
- Паники ядра - это норма. Эксплойт работает по вероятности (у авторов 5/7 и 4/9 попаданий). Паника означает перезагрузку и ничего больше: данные и прошивка не страдают.
- Только своё устройство. Всё описанное проверялось на собственном телефоне.
- В репозитории нет чужих бинарников (ни эксплойта, ни APK, ни библиотек): только собственный код, профиль устройства, патч и документация. См. NOTICE.md.
Полный список с ссылками в CREDITS.md. Кратко: эксплойт и его README - JoinChang/ghostlock-oneplus; идея маршрута "один тап" - zenyxx-xd/RootMyVivo и Root-My-Device-Payloads; приложение для запуска - byemaxx/ghostlock-anchor; менеджер root - ReSukiSU на базе KernelSU.
Nixbones
Код и документация этого репозитория - MIT (см. LICENSE). Чужие проекты, упомянутые здесь, распространяются по своим лицензиям, их код в репозиторий не включён.