Root Detection у мобільних додатках — методи виявлення та принцип роботи

Автор: IT Sectr Опубліковано: 2026-04-03 Час читання: 9 хв

Root Detection — механізм захисту Android-додатків від запуску на пристроях з отриманими привілеями суперкористувача. Банківські, платіжні та корпоративні додатки блокують або обмежують функціональність на рутованих пристроях, оскільки root-доступ знімає обмеження пісочниці Android і відкриває можливість перехоплення трафіку, читання пам'яті процесів і підміни даних. За даними OWASP Mobile Top 10 (2024), відсутність Root Detection належить до категорії M8 (Security Decisions via Untrusted Inputs). Root Detection будується на комбінації статичних перевірок файлової системи та динамічного аналізу runtime-поведінки.

Головне

  • Root Detection — перевірка Android-пристрою на наявність root-доступу для захисту додатка від запуску в скомпрометованому середовищі
  • Статичні методи перевіряють файлову систему на наявність su-бінарників, додатків Superuser та змін системних розділів
  • Динамічні методи аналізують runtime: перевірка Build.TAGS, спроба відкриття /proc/self/maps з привілейованими процесами
  • Нативна реалізація на C/C++ через JNI забезпечує стійкість до обходу через Xposed та Frida на рівні Java
  • Безпека Root Detection вимагає continuous obfuscation та server-side верифікації для запобігання підміні результатів перевірки

Що таке Root Detection?

Root Detection — програмний механізм, що визначає наявність root-доступу на Android-пристрої. Root-доступ надає повний контроль над операційною системою, дозволяючи додаткам і скриптам виконувати команди з UID 0. На рутованому пристрої втрачається ізоляція додатків (Android Sandbox), що робить можливим перехоплення введення з клавіатури, читання SQLite-баз даних інших додатків, ін'єкцію коду в процеси та підміну SSL-сертифікатів у довіреному сховищі.

Для фінансових і корпоративних додатків робота на рутованому пристрої становить неприйнятний ризик: зломщик отримує доступ до токенів, сесійних ключів і персональних даних. Регулятори, включаючи PCI Security Standards Council, вимагають від платіжних додатків виявлення та реакції на root-доступ. У відповідь на це Android-розробники вбудовують Root Detection як частину стратегії проактивного захисту.

Існує два підходи до виявлення: статичний, що аналізує файлову систему та встановлені пакети, і динамічний, що виконує перевірки в runtime. Комбінований підхід вважається найбільш надійним, оскільки покриває різні вектори обходу. За даними дослідження NowSecure (2025), 76% банківських додатків у топ-100 Google Play містять ту чи іншу форму Root Detection.

Статичні методи виявлення root

Статичні методи виконуються при старті додатка та перевіряють ознаки root-доступу, що залишаються інструментами рутингу у файловій системі. Ці методи не вимагають виконання привілейованих команд і працюють у контексті звичайного додатка.

Перевірка існування su-бінарника

Основна ознака root-доступу — наявність виконуваного файлу su в стандартних шляхах: /system/bin/su, /system/xbin/su, /sbin/su, /su/bin/su. Додаток перевіряє існування файлу через File.exists() або нативну реалізацію access() з libc. Додатково можна спробувати виконати su --version або su -c id і перевірити exit code.

Пошук root-менеджерів

Типові додатки для керування root-доступом: Superuser, SuperSU, Magisk Manager, KingRoot. Їх наявність перевіряється через PackageManager.getPackageInfo() або читання /data/app/ директорії. Пакети для перевірки: com.topjohnwu.magisk, eu.chainfire.supersu, com.noshufou.android.su, com.thirdparty.superuser, com.koushikdutta.superuser, com.zacharee1.systemuituner.

Перевірка системних властивостей

Android зберігає інформацію про стан системи в системних властивостях, доступних через System.getProperty та Build.TAGS. Якщо значення Build.TAGS містить test-keys, а не release-keys — це вказує на кастомну прошивку, часто з root-доступом. Додатково перевіряються ro.build.tags, ro.debuggable та ro.secure через читання /system/build.prop.

java
public class RootDetectionChecker {
    private static final String[] SU_PATHS = {
        "/system/bin/su",
        "/system/xbin/su",
        "/sbin/su",
        "/su/bin/su",
        "/system/sd/xbin/su"
    };

    public boolean checkRootByFiles() {
        for (String path : SU_PATHS) {
            if (new File(path).exists()) {
                return true;
            }
        }
        return false;
    }

    public boolean checkRootByPackages(Context ctx) {
        String[] packages = {
            "com.topjohnwu.magisk",
            "eu.chainfire.supersu",
            "com.noshufou.android.su",
            "com.koushikdutta.superuser"
        };
        for (String pkg : packages) {
            try {
                ctx.getPackageManager().getPackageInfo(pkg, 0);
                return true;
            } catch (PackageManager.NameNotFoundException e) {
                // package not found
            }
        }
        return false;
    }
}

Динамічні методи перевірки

Динамічні методи виконуються під час роботи додатка та аналізують середовище виконання. На відміну від статичних, вони можуть виявити рутинг, прихований через Magisk Hide або Zygisk, оскільки перевіряють поведінку системи, а не тільки файлову структуру.

Перевірка mount points

При root-доступі деякі системні розділи монтуються з прапорцем rw (read-write) замість ro (read-only). Додаток читає /proc/mounts і перевіряє, що /system змонтовано як ro. Якщо /system змонтовано як rw — це ознака модифікованої системи. Додатково перевіряється наявність монтування /su через Magisk.

Тест безпечного режиму

Android Safe Mode відключає сторонні додатки, включаючи root-менеджери. Коректна реалізація Root Detection може перевірити, чи працює пристрій у безпечному режимі. Якщо додаток виявляє, що root-менеджери не видимі, але su-бінарник існує — це ознака Magisk Hide.

Перевірка виконання команд

Спроба виконання su -c id через ProcessBuilder або Runtime.exec — прямий тест root-доступу. Однак Magisk може перехоплювати цей виклик. Більш надійний варіант — перевірка через нативний код: відкрити /proc/1/limits або /proc/self/maps і проаналізувати UID запущених процесів. Якщо додаток може отримати UID 0 або прочитати файли, доступні тільки root — пристрій скомпрометовано.

java
public boolean checkRootDynamically() {
    // Build flags check
    String buildTags = Build.TAGS;
    if (buildTags != null && buildTags.contains("test-keys")) {
        return true;
    }

    // Checking /system mount
    try {
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(new FileInputStream("/proc/mounts"))
        );
        String line;
        while ((line = reader.readLine()) != null) {
            if (line.contains("/system")
                && line.contains("rw")) {
                reader.close();
                return true;
            }
        }
        reader.close();
    } catch (IOException e) {
        // error reading mounts
    }

    return false;
}

Нативна реалізація Root Detection на C++

Root Detection, реалізований на Java, легко обходиться через Xposed-модулі або Frida, які перехоплюють Java-методи та підміняють значення, що повертаються. Нативна реалізація на C++ через JNI значно стійкіша: інструменти динамічного аналізу, що працюють на Java-рівні, не бачать нативних викликів libc, таких як stat, access, popen та dlopen.

cpp
#include <unistd.h>
#include <sys/stat.h>
#include <cstring>
#include <vector>

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_example_checker_RootCheck_nativeCheck(
    JNIEnv* env, jobject instance) {

    std::vector<const char*> paths = {
        "/system/bin/su",
        "/system/xbin/su",
        "/sbin/su",
        "/data/local/su"
    };

    struct stat st;
    for (const char* path : paths) {
        if (stat(path, &st) == 0) {
            return JNI_TRUE;
        }
    }
    return JNI_FALSE;
}

Нативна перевірка не використовує Java API, що робить її невидимою для інструментів обходу, що працюють на Dalvik/ART рівні. Для додаткового захисту рекомендується зберігати константи (список шляхів) не в read-only секції, а обчислювати їх через прості оборотні функції. Stat-виклик з libc безпосередньо звертається до ядра Linux, минаючи Java-обгортки, і його неможливо перехопити через Xposed.

Методи обходу Root Detection

Розробникам захисту необхідно розуміти існуючі методи обходу, щоб будувати стійку систему виявлення. Кожен метод обходу вимагає контр-заходу на відповідному рівні.

Обхід через Magisk Hide та Zygisk

Magisk — найпопулярніший інструмент рутингу на Android 9–14. Magisk Hide приховує наявність su з /proc та підміняє результати перевірки шляхів. Magisk працює на рівні ядра та перехоплює stat() і access() до того, як їх побачить додаток. Контр-захід: перевірка наявності самого Magisk через наявність /sbin/.magisk або перевірка через читання власних maps — Magisk вбудовує свою бібліотеку в кожен процес.

Обхід через Frida

Frida — інструмент динамічної інструментації, який може перехоплювати нативні функції через Ptrace або Dobby. Frida замінює return value будь-якої перевірки, підміняючи результат stat на ENOENT. Контр-захід: перевірка цілісності нативних функцій через підрахунок контрольної суми інструкцій у пам'яті та виявлення Frida через аналіз /proc/self/maps на наявність frida-agent.so або frida-helper.

Обхід через патч APK

Root Detection, реалізований у Java, видаляється за 2–3 хвилини: APK розпаковується через apktool, у smali-коді виправляється return-значення методу на false, APK перезбирається та підписується. Контр-захід: перенесення критичної логіки в нативний код та перевірка цифрового підпису додатка в runtime через Signature API або звірка хешу APK з еталоном на сервері.

Рекомендації щодо надійного захисту

Ефективний Root Detection будується на багатошаровій архітектурі. Жоден метод окремо не забезпечує достатнього рівня захисту. Комбінація статичних та динамічних перевірок, нативного коду та серверної верифікації дає максимальну стійкість.

Серверна верифікація

Не покладайтеся тільки на client-side перевірку. Надсилайте на сервер результати Root Detection разом з одноразовим токеном сесії. Сервер приймає рішення про блокування або обмеження функціональності. Це запобігає атакам на рівні API, де клієнтський додаток може бути модифікований, а сервер залишається довіреною стороною.

Обфускація коду перевірки

Код Root Detection має бути обфускований. Якщо зловмисник бачить у jadx чітку послідовність перевірок su-шляхів — обхід займе хвилини. Використовуйте ProGuard або DexGuard для заплутування потоку керування та шифрування рядків. Obfuscation підвищує час аналізу коду захисту з кількох хвилин до кількох годин.

Регулярне оновлення сигнатур

Список шляхів, пакетів та індикаторів, що перевіряються, має оновлюватися з кожним релізом додатка. Нові інструменти рутингу та обходу з'являються щомісяця. Статичний список, що не змінювався рік, не виявляє сучасні методи. Рекомендується завантажувати актуальні сигнатури з сервера при старті додатка перед виконанням перевірок.

Часті запитання

Навіщо додаткам Root Detection?

Root Detection захищає від запуску додатка на пристрої, де пісочниця Android вимкнена. На рутованому пристрої будь-який додаток може читати дані інших додатків. Банківські та платіжні додатки зобов'язані блокувати роботу на рутованих пристроях за вимогами PCI DSS та рекомендаціями OWASP Mobile Security.

Як працює Magisk Hide?

Magisk Hide використовує механізм монтування простору імен (mount namespace). Для кожного процесу, зазначеного у списку винятків, Magisk створює ізольований namespace, де su-бінарник невидимий. Системні виклики stat, access та open у цьому namespace не бачать файлів Magisk. Виявити Magisk можна через перевірку наявності /proc/self/maps та пошук magisk-дампу.

Чи можна обійти Root Detection без рута?

Так, якщо додаток не перевіряє цілісність свого коду. Через Frida можна перехопити Java-метод перевірки та примусово повернути false. Контр-захід — нативна реалізація критичної логіки на C++ та перевірка цілісності через хеш DEX-файлу. Без обфускації будь-який Root Detection на Java обходиться за 5–10 хвилин.

Що таке SafetyNet та атестація?

SafetyNet (застарілий) та Play Integrity API — це серверні перевірки від Google, що підтверджують цілісність пристрою. Вони включають перевірку bootloader, системного підпису та root-статусу. Play Integrity API — рекомендована заміна SafetyNet, що дає три рівні: BASIC, DEVICE та STRONG. Root Detection на клієнті доповнює серверну атестацію.

Як перевірити Root Detection у своєму додатку?

Встановіть додаток на реальний рутований пристрій (наприклад, Pixel з Magisk). Перевірте, чи спрацьовує блокування. Потім спробуйте приховати рут через Magisk Hide для вашого додатка та перезапустіть тест. Для поглибленої перевірки використовуйте Frida для перехоплення цільових методів та переконайтеся, що нативний захист не піддається обходу.

Підсумки

  • Root Detection — обов'язковий компонент безпеки для банківських, платіжних та корпоративних Android-додатків, що працює на комбінації статичних та динамічних перевірок
  • Статичні методи включають пошук su-бінарника в стандартних шляхах, перевірку встановлених root-менеджерів та аналіз системних властивостей Build.TAGS
  • Динамічні методи аналізують монтування /system у режимі rw, перевіряють цілісність /proc/mounts та виконують тести виконання привілейованих команд
  • Нативна реалізація на C++ через JNI робить перевірки невидимими для Xposed та Frida, що працюють на Java-рівні, і вимагає обходу через Dobby або Ptrace
  • Magisk Hide — основний інструмент обходу Root Detection через mount namespaces, виявляється через аналіз /proc/self/maps на наявність magisk-бібліотек
  • Рекомендована архітектура: нативні перевірки + обфускація коду + серверна верифікація результатів + регулярне оновлення сигнатур
  • Play Integrity API від Google доповнює client-side Root Detection серверною атестацією пристрою, забезпечуючи комплексний захист

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також