Root Detection w aplikacjach mobilnych — istota, metody wykrywania i zasada działania

Autor: IT Sectr Opublikowano: 2026-04-03 Czas czytania: 9 min

Root Detection — mechanizm zabezpieczający aplikacje Android przed uruchomieniem na urządzeniach z uprawnieniami superużytkownika. Aplikacje bankowe, płatnicze i korporacyjne blokują lub ograniczają funkcjonalność na zrootowanych urządzeniach, ponieważ dostęp root usuwa ograniczenia piaskownicy Android i umożliwia przechwytywanie ruchu, odczytywanie pamięci procesów oraz podmianę danych. Według OWASP Mobile Top 10 (2024), brak Root Detection należy do kategorii M8 (Security Decisions via Untrusted Inputs). Root Detection opiera się na kombinacji statycznych sprawdzeń systemu plików i dynamicznej analizy zachowania w runtime.

Najważniejsze

  • Root Detection — sprawdzanie urządzenia Android na obecność dostępu root w celu ochrony aplikacji przed uruchomieniem w środowisku skompromitowanym
  • Metody statyczne sprawdzają system plików na obecność binarnych plików su, aplikacji Superuser oraz zmian w partycjach systemowych
  • Metody dynamiczne analizują runtime: sprawdzanie Build.TAGS, próba otwarcia /proc/self/maps z uprzywilejowanymi procesami
  • Implementacja natywna w C/C++ przez JNI zapewnia odporność na obejście przez Xposed i Frida na poziomie Java
  • Bezpieczeństwo Root Detection wymaga ciągłej obfuskacji i weryfikacji po stronie serwera w celu zapobieżenia podmianie wyników sprawdzania

Co to jest Root Detection?

Root Detection — programowy mechanizm określający obecność dostępu root na urządzeniu Android. Dostęp root zapewnia pełną kontrolę nad systemem operacyjnym, umożliwiając aplikacjom i skryptom wykonywanie poleceń z UID 0. Na zrootowanym urządzeniu tracona jest izolacja aplikacji (Android Sandbox), co umożliwia przechwytywanie wprowadzania z klawiatury, odczytywanie baz danych SQLite innych aplikacji, wstrzykiwanie kodu do procesów oraz podmianę certyfikatów SSL w zaufanym magazynie.

Dla aplikacji finansowych i korporacyjnych praca na zrootowanym urządzeniu stanowi niedopuszczalne ryzyko: włamywacz uzyskuje dostęp do tokenów, kluczy sesyjnych i danych osobowych. Organy regulacyjne, w tym PCI Security Standards Council, wymagają od aplikacji płatniczych wykrywania i reagowania na dostęp root. W odpowiedzi na to programiści Android wbudowują Root Detection jako część strategii proaktywnej ochrony.

Istnieją dwa podejścia do wykrywania: statyczne, analizujące system plików i zainstalowane pakiety, oraz dynamiczne, wykonujące sprawdzenia w runtime. Podejście kombinowane uważane jest za najbardziej niezawodne, ponieważ pokrywa różne wektory obejścia. Według badań NowSecure (2025), 76% aplikacji bankowych w top 100 Google Play zawiera jakąś formę Root Detection.

Statyczne metody wykrywania root

Metody statyczne wykonywane są przy starcie aplikacji i sprawdzają oznaki dostępu root pozostawiane przez narzędzia rootujące w systemie plików. Metody te nie wymagają wykonywania uprzywilejowanych poleceń i działają w kontekście zwykłej aplikacji.

Sprawdzanie istnienia binarnego pliku su

Główna oznaka dostępu root — obecność pliku wykonywalnego su w standardowych ścieżkach: /system/bin/su, /system/xbin/su, /sbin/su, /su/bin/su. Aplikacja sprawdza istnienie pliku przez File.exists() lub natywną implementację access() z libc. Dodatkowo można spróbować wykonać su --version lub su -c id i sprawdzić kod wyjścia.

Wyszukiwanie menedżerów root

Typowe aplikacje do zarządzania dostępem root: Superuser, SuperSU, Magisk Manager, KingRoot. Ich obecność sprawdzana jest przez PackageManager.getPackageInfo() lub odczyt katalogu /data/app/. Pakiety do sprawdzenia: com.topjohnwu.magisk, eu.chainfire.supersu, com.noshufou.android.su, com.thirdparty.superuser, com.koushikdutta.superuser, com.zacharee1.systemuituner.

Sprawdzanie właściwości systemowych

Android przechowuje informacje o stanie systemu we właściwościach systemowych dostępnych przez System.getProperty i Build.TAGS. Jeśli wartość Build.TAGS zawiera test-keys, a nie release-keys — wskazuje to na niestandardowe oprogramowanie układowe, często z dostępem root. Dodatkowo sprawdzane są ro.build.tags, ro.debuggable i ro.secure przez odczyt /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) {
                // nie znaleziono pakietu
            }
        }
        return false;
    }
}

Dynamiczne metody sprawdzania

Metody dynamiczne wykonywane są podczas działania aplikacji i analizują środowisko wykonawcze. W przeciwieństwie do statycznych, mogą wykryć rootowanie ukryte przez Magisk Hide lub Zygisk, ponieważ sprawdzają zachowanie systemu, a nie tylko strukturę plików.

Sprawdzanie punktów montowania

Przy dostępie root niektóre partycje systemowe są montowane z flagą rw (read-write) zamiast ro (read-only). Aplikacja czyści /proc/mounts i sprawdza, czy /system jest zamontowany jako ro. Jeśli /system jest zamontowany jako rw — to oznaka zmodyfikowanego systemu. Dodatkowo sprawdzana jest obecność montowania /su przez Magisk.

Test trybu bezpiecznego

Android Safe Mode wyłącza aplikacje innych firm, w tym menedżery root. Poprawna implementacja Root Detection może sprawdzić, czy urządzenie działa w trybie bezpiecznym. Jeśli aplikacja wykrywa, że menedżery root nie są widoczne, ale binarny plik su istnieje — to oznaka Magisk Hide.

Sprawdzanie wykonywania poleceń

Próba wykonania su -c id przez ProcessBuilder lub Runtime.exec — bezpośredni test dostępu root. Jednak Magisk może przechwycić to wywołanie. Bardziej niezawodną opcją jest sprawdzenie przez kod natywny: otwarcie /proc/1/limits lub /proc/self/maps i analiza UID uruchomionych procesów. Jeśli aplikacja może uzyskać UID 0 lub odczytać pliki dostępne tylko dla root — urządzenie jest skompromitowane.

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

    // Sprawdzanie montowania /system
    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) {
        // błąd odczytu montowania
    }

    return false;
}

Natywna implementacja Root Detection w C++

Root Detection zaimplementowany w Java jest łatwo omijany przez moduły Xposed lub Frida, które przechwytują metody Java i podmieniają zwracane wartości. Natywna implementacja w C++ przez JNI jest znacznie bardziej odporna: narzędzia dynamicznej analizy działające na poziomie Java nie widzą natywnych wywołań libc, takich jak stat, access, popen i 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;
}

Natywne sprawdzenie nie używa Java API, co czyni je niewidocznym dla narzędzi obejścia działających na poziomie Dalvik/ART. Dla dodatkowej ochrony zaleca się przechowywanie stałych (lista ścieżek) nie w sekcji read-only, ale obliczanie ich przez proste funkcje odwracalne. Wywołanie stat z libc bezpośrednio odwołuje się do jądra Linux, omijając opakowania Java, i nie można go przechwycić przez Xposed.

Metody obejścia Root Detection

Twórcom zabezpieczeń konieczne jest zrozumienie istniejących metod obejścia, aby zbudować odporny system wykrywania. Każda metoda obejścia wymaga środka zaradczego na odpowiednim poziomie.

Obejście przez Magisk Hide i Zygisk

Magisk — najpopularniejsze narzędzie rootowania na Android 9–14. Magisk Hide ukrywa obecność su z /proc i podmienia wyniki sprawdzania ścieżek. Magisk działa na poziomie jądra i przechwytuje stat() i access() zanim zobaczy je aplikacja. Środek zaradczy: sprawdzenie obecności samego Magisk przez obecność /sbin/.magisk lub sprawdzenie przez odczyt własnych map — Magisk wbudowuje swoją bibliotekę w każdy proces.

Obejście przez Frida

Frida — narzędzie dynamicznej instrumentacji, które może przechwytywać funkcje natywne przez Ptrace lub Dobby. Frida zastępuje wartość zwracaną każdego sprawdzenia, podmieniając wynik stat na ENOENT. Środek zaradczy: sprawdzenie integralności funkcji natywnych przez obliczanie sumy kontrolnej instrukcji w pamięci i wykrywanie Frida przez analizę /proc/self/maps na obecność frida-agent.so lub frida-helper.

Obejście przez patch APK

Root Detection zaimplementowany w Java jest usuwany w 2–3 minuty: APK jest rozpakowywane przez apktool, w kodzie smali poprawiana jest wartość zwracana metody na false, APK jest ponownie składane i podpisywane. Środek zaradczy: przeniesienie krytycznej logiki do kodu natywnego i sprawdzenie podpisu cyfrowego aplikacji w runtime przez Signature API lub porównanie hasha APK z wzorcem na serwerze.

Zalecenia dotyczące niezawodnej ochrony

Efektywny Root Detection opiera się na wielowarstwowej architekturze. Żadna metoda osobno nie zapewnia wystarczającego poziomu ochrony. Kombinacja sprawdzeń statycznych i dynamicznych, kodu natywnego i weryfikacji serwerowej daje maksymalną odporność.

Weryfikacja serwerowa

Nie polegaj wyłącznie na sprawdzeniu po stronie klienta. Wysyłaj na serwer wyniki Root Detection wraz z jednorazowym tokenem sesji. Serwer podejmuje decyzję o blokadzie lub ograniczeniu funkcjonalności. Zapobiega to atakom na poziomie API, gdzie aplikacja kliencka może być zmodyfikowana, a serwer pozostaje zaufaną stroną.

Obfuskacja kodu sprawdzania

Kod Root Detection powinien być zaciemniony. Jeśli atakujący widzi w jadx wyraźną sekwencję sprawdzeń ścieżek su — obejście zajmie minuty. Użyj ProGuard lub DexGuard do zaciemnienia przepływu sterowania i szyfrowania ciągów znaków. Obfuskacja zwiększa czas analizy kodu zabezpieczeń z kilku minut do kilku godzin.

Regularna aktualizacja sygnatur

Lista sprawdzanych ścieżek, pakietów i wskaźników powinna być aktualizowana z każdą wersją aplikacji. Nowe narzędzia rootowania i obejścia pojawiają się co miesiąc. Statyczna lista, niezmieniana od roku, nie wykrywa nowoczesnych metod. Zaleca się pobieranie aktualnych sygnatur z serwera przy starcie aplikacji przed wykonaniem sprawdzeń.

Często zadawane pytania

Po co aplikacjom Root Detection?

Root Detection chroni przed uruchomieniem aplikacji na urządzeniu, gdzie piaskownica Android jest wyłączona. Na zrootowanym urządzeniu każda aplikacja może czytać dane innych aplikacji. Aplikacje bankowe i płatnicze są obowiązane blokować działanie na zrootowanych urządzeniach zgodnie z wymaganiami PCI DSS i zaleceniami OWASP Mobile Security.

Jak działa Magisk Hide?

Magisk Hide wykorzystuje mechanizm montowania przestrzeni nazw (mount namespace). Dla każdego procesu wskazanego na liście wyjątków Magisk tworzy izolowaną przestrzeń nazw, gdzie binarny plik su jest niewidoczny. Wywołania systemowe stat, access i open w tej przestrzeni nazw nie widzą plików Magisk. Wykryć Magisk można przez sprawdzenie obecności /proc/self/maps i wyszukanie zrzutu magisk.

Czy można ominąć Root Detection bez roota?

Tak, jeśli aplikacja nie sprawdza integralności swojego kodu. Przez Frida można przechwycić metodę Java sprawdzenia i wymusić zwrócenie false. Środek zaradczy — natywna implementacja krytycznej logiki w C++ i sprawdzenie integralności przez hash pliku DEX. Bez obfuskacji każdy Root Detection w Java jest omijany w 5–10 minut.

Co to jest safety net i attestation?

SafetyNet (przestarzałe) i Play Integrity API — to serwerowe sprawdzenia od Google potwierdzające integralność urządzenia. Obejmują one sprawdzenie bootloadera, podpisu systemowego i statusu root. Play Integrity API — zalecany zamiennik SafetyNet, dający trzy poziomy: BASIC, DEVICE i STRONG. Root Detection po stronie klienta uzupełnia atestację serwerową.

Jak sprawdzić Root Detection w swojej aplikacji?

Zainstaluj aplikację na rzeczywistym zrootowanym urządzeniu (np. Pixel z Magisk). Sprawdź, czy blokada zadziałała. Następnie spróbuj ukryć root przez Magisk Hide dla swojej aplikacji i uruchom ponownie test. Do dogłębnego sprawdzenia użyj Frida do przechwycenia docelowych metod i upewnij się, że natywna ochrona nie daje się obejść.

Podsumowanie

  • Root Detection — obowiązkowy komponent bezpieczeństwa dla bankowych, płatniczych i korporacyjnych aplikacji Android, działający na kombinacji sprawdzeń statycznych i dynamicznych
  • Metody statyczne obejmują wyszukiwanie binarnego pliku su w standardowych ścieżkach, sprawdzanie zainstalowanych menedżerów root i analizę właściwości systemowych Build.TAGS
  • Metody dynamiczne analizują montowanie /system w trybie rw, sprawdzają integralność /proc/mounts i wykonują testy uruchamiania uprzywilejowanych poleceń
  • Implementacja natywna w C++ przez JNI czyni sprawdzenia niewidocznymi dla Xposed i Frida działających na poziomie Java i wymaga obejścia przez Dobby lub Ptrace
  • Magisk Hide — główne narzędzie obejścia Root Detection przez mount namespaces, wykrywane przez analizę /proc/self/maps na obecność bibliotek magisk
  • Zalecana architektura: sprawdzenia natywne + obfuskacja kodu + weryfikacja serwerowa wyników + regularna aktualizacja sygnatur
  • Play Integrity API od Google uzupełnia Root Detection po stronie klienta atestacją serwerową urządzenia, zapewniając kompleksową ochronę

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również