Root Detection — mecanism de protecție a aplicațiilor Android împotriva rulării pe dispozitive cu privilegii de superutilizator. Aplicațiile bancare, de plată și corporative blochează sau limitează funcționalitatea pe dispozitivele rootate, deoarece accesul root elimină restricțiile sandbox-ului Android și deschide posibilitatea interceptării traficului, citirii memoriei proceselor și substituirii datelor. Conform OWASP Mobile Top 10 (2024), absența Root Detection se încadrează în categoria M8 (Security Decisions via Untrusted Inputs). Root Detection se bazează pe o combinație de verificări statice ale sistemului de fișiere și analiză dinamică a comportamentului în runtime.
Principalele
Root Detection — mecanism software care determină prezența accesului root pe un dispozitiv Android. Accesul root oferă control complet asupra sistemului de operare, permițând aplicațiilor și scripturilor să execute comenzi cu UID 0. Pe un dispozitiv rootat, izolarea aplicațiilor (Android Sandbox) se pierde, făcând posibilă interceptarea intrărilor de la tastatură, citirea bazelor de date SQLite ale altor aplicații, injectarea de cod în procese și substituirea certificatelor SSL în depozitul de încredere.
Pentru aplicațiile financiare și corporative, rularea pe un dispozitiv rootat reprezintă un risc inacceptabil: atacatorul obține acces la tokenuri, chei de sesiune și date personale. Autoritățile de reglementare, inclusiv PCI Security Standards Council, solicită aplicațiilor de plată detectarea și reacția la accesul root. Ca răspuns, dezvoltatorii Android integrează Root Detection ca parte a strategiei de protecție proactivă.
Există două abordări de detectare: statică, care analizează sistemul de fișiere și pachetele instalate, și dinamică, care efectuează verificări în runtime. Abordarea combinată este considerată cea mai fiabilă, deoarece acoperă diferiți vectori de ocolire. Conform cercetării NowSecure (2025), 76% dintre aplicațiile bancare din top 100 Google Play conțin o formă sau alta de Root Detection.
Metodele statice se execută la pornirea aplicației și verifică semnele accesului root lăsate de instrumentele de rootare în sistemul de fișiere. Aceste metode nu necesită executarea de comenzi privilegiate și funcționează în contextul unei aplicații obișnuite.
Principalul semn al accesului root — prezența fișierului executabil su în căile standard: /system/bin/su, /system/xbin/su, /sbin/su, /su/bin/su. Aplicația verifică existența fișierului prin File.exists() sau implementarea nativă access() din libc. Suplimentar, se poate încerca executarea su --version sau su -c id și verificarea codului de ieșire.
Aplicații tipice pentru gestionarea accesului root: Superuser, SuperSU, Magisk Manager, KingRoot. Prezența lor se verifică prin PackageManager.getPackageInfo() sau citirea directorului /data/app/. Pachete de verificat: com.topjohnwu.magisk, eu.chainfire.supersu, com.noshufou.android.su, com.thirdparty.superuser, com.koushikdutta.superuser, com.zacharee1.systemuituner.
Android stochează informații despre starea sistemului în proprietăți de sistem accesibile prin System.getProperty și Build.TAGS. Dacă valoarea Build.TAGS conține test-keys în loc de release-keys — aceasta indică un firmware personalizat, adesea cu acces root. Suplimentar, se verifică ro.build.tags, ro.debuggable și ro.secure prin citirea /system/build.prop.
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) {
// pachetul nu a fost găsit
}
}
return false;
}
}
Metodele dinamice se execută în timpul funcționării aplicației și analizează mediul de execuție. Spre deosebire de cele statice, pot detecta rootarea ascunsă prin Magisk Hide sau Zygisk, deoarece verifică comportamentul sistemului, nu doar structura fișierelor.
La acces root, unele partiții de sistem sunt montate cu flagul rw (read-write) în loc de ro (read-only). Aplicația citește /proc/mounts și verifică dacă /system este montat ca ro. Dacă /system este montat ca rw — acesta este un semn de sistem modificat. Suplimentar, se verifică prezența montării /su prin Magisk.
Android Safe Mode dezactivează aplicațiile terțe, inclusiv managerii de root. O implementare corectă a Root Detection poate verifica dacă dispozitivul funcționează în modul sigur. Dacă aplicația detectează că managerii de root nu sunt vizibili, dar binarul su există — acesta este un semn de Magisk Hide.
Încercarea de a executa su -c id prin ProcessBuilder sau Runtime.exec — un test direct al accesului root. Cu toate acestea, Magisk poate intercepta această apelare. O opțiune mai fiabilă — verificarea prin cod nativ: deschiderea /proc/1/limits sau /proc/self/maps și analiza UID-ului proceselor în execuție. Dacă aplicația poate obține UID 0 sau poate citi fișiere accesibile doar root — dispozitivul este compromis.
public boolean checkRootDynamically() {
// Verificarea flagurilor de compilare
String buildTags = Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// Verificarea montării /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) {
// eroare la citirea montării
}
return false;
}
Root Detection implementat în Java este ușor de ocolit prin module Xposed sau Frida, care interceptează metodele Java și substituie valorile returnate. Implementarea nativă în C++ prin JNI este semnificativ mai rezistentă: instrumentele de analiză dinamică care funcționează la nivel Java nu văd apelurile native libc, cum ar fi stat, access, popen și dlopen.
#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;
}
Verificarea nativă nu folosește Java API, ceea ce o face invizibilă pentru instrumentele de ocolire care funcționează la nivel Dalvik/ART. Pentru protecție suplimentară, se recomandă stocarea constantelor (lista de căi) nu în secțiunea read-only, ci calcularea lor prin funcții simple reversibile. Apelul stat din libc se adresează direct nucleului Linux, ocolind wrapper-ele Java, și nu poate fi interceptat prin Xposed.
Dezvoltatorii de securitate trebuie să înțeleagă metodele existente de ocolire pentru a construi un sistem de detectare rezistent. Fiecare metodă de ocolire necesită o contra-măsură la nivelul corespunzător.
Magisk — cel mai popular instrument de rootare pe Android 9–14. Magisk Hide ascunde prezența su din /proc și substituie rezultatele verificării căilor. Magisk funcționează la nivel de nucleu și interceptează stat() și access() înainte ca aplicația să le vadă. Contra-măsură: verificarea prezenței Magisk însuși prin existența /sbin/.magisk sau verificarea prin citirea propriilor maps — Magisk își încorporează biblioteca în fiecare proces.
Frida — instrument de instrumentație dinamică care poate intercepta funcții native prin Ptrace sau Dobby. Frida înlocuiește valoarea returnată a oricărei verificări, substituind rezultatul stat cu ENOENT. Contra-măsură: verificarea integrității funcțiilor native prin calcularea sumei de control a instrucțiunilor în memorie și detectarea Frida prin analiza /proc/self/maps pentru prezența frida-agent.so sau frida-helper.
Root Detection implementat în Java este eliminat în 2–3 minute: APK este despachetat prin apktool, în codul smali se modifică valoarea returnată a metodei la false, APK este reasamblat și semnat. Contra-măsură: mutarea logicii critice în cod nativ și verificarea semnăturii digitale a aplicației în runtime prin Signature API sau compararea hash-ului APK cu etalonul pe server.
Root Detection eficient se bazează pe o arhitectură multistrat. Nicio metodă individuală nu asigură un nivel suficient de protecție. Combinația de verificări statice și dinamice, cod nativ și verificare pe server oferă o rezistență maximă.
Nu vă bazați doar pe verificarea client-side. Trimiteți pe server rezultatele Root Detection împreună cu un token de sesiune unic. Serverul ia decizia de blocare sau limitare a funcționalității. Acest lucru previne atacurile la nivel API, unde aplicația client poate fi modificată, iar serverul rămâne partea de încredere.
Codul Root Detection trebuie ofuscat. Dacă atacatorul vede în jadx o succesiune clară de verificări a căilor su — ocolirea va dura minute. Utilizați ProGuard sau DexGuard pentru a complica fluxul de control și a cripta șirurile de caractere. Ofuscarea crește timpul de analiză a codului de securitate de la câteva minute la câteva ore.
Lista căilor, pachetelor și indicatorilor verificați trebuie actualizată cu fiecare versiune a aplicației. Noi instrumente de rootare și ocolire apar lunar. O listă statică neschimbată timp de un an nu detectează metodele moderne. Se recomandă încărcarea semnăturilor actuale de pe server la pornirea aplicației înainte de efectuarea verificărilor.
Întrebări frecvente
Root Detection protejează împotriva rulării aplicației pe un dispozitiv unde sandbox-ul Android este dezactivat. Pe un dispozitiv rootat, orice aplicație poate citi datele altor aplicații. Aplicațiile bancare și de plată sunt obligate să blocheze funcționarea pe dispozitive rootate conform cerințelor PCI DSS și recomandărilor OWASP Mobile Security.
Magisk Hide utilizează mecanismul de montare a spațiilor de nume (mount namespace). Pentru fiecare proces specificat în lista de excepții, Magisk creează un namespace izolat, unde binarul su este invizibil. Apelurile de sistem stat, access și open în acest namespace nu văd fișierele Magisk. Magisk poate fi detectat prin verificarea prezenței /proc/self/maps și căutarea dump-ului magisk.
Da, dacă aplicația nu verifică integritatea propriului cod. Prin Frida se poate intercepta metoda Java de verificare și forța returnarea false. Contra-măsură — implementarea nativă a logicii critice în C++ și verificarea integrității prin hash-ul fișierului DEX. Fără ofuscare, orice Root Detection în Java este ocolit în 5–10 minute.
SafetyNet (învechit) și Play Integrity API — sunt verificări server de la Google care confirmă integritatea dispozitivului. Acestea includ verificarea bootloader-ului, a semnăturii de sistem și a statusului root. Play Integrity API — înlocuitorul recomandat pentru SafetyNet, oferind trei niveluri: BASIC, DEVICE și STRONG. Root Detection pe client completează atestarea pe server.
Instalați aplicația pe un dispozitiv real rootat (de exemplu, Pixel cu Magisk). Verificați dacă blocarea se activează. Apoi încercați să ascundeți root-ul prin Magisk Hide pentru aplicația dvs. și repetați testul. Pentru o verificare aprofundată, utilizați Frida pentru a intercepta metodele țintă și asigurați-vă că protecția nativă nu poate fi ocolită.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și