Root Detection nelle app mobili — metodi di rilevamento e principio di funzionamento

Autore: IT Sectr Pubblicato: 2026-04-03 Tempo di lettura: 9 min

Root Detection è un meccanismo di sicurezza che protegge le applicazioni Android dall'esecuzione su dispositivi con privilegi di superutente. Le applicazioni bancarie, di pagamento e aziendali bloccano o limitano le funzionalità sui dispositivi rootati, perché l'accesso root rimuove le restrizioni della sandbox Android e apre la possibilità di intercettare il traffico, leggere la memoria dei processi e manomettere i dati. Secondo OWASP Mobile Top 10 (2024), l'assenza di Root Detection rientra nella categoria M8 (Security Decisions via Untrusted Inputs). Root Detection si basa su una combinazione di controlli statici del file system e analisi dinamica del comportamento a runtime.

Punti chiave

  • Root Detection — verifica di un dispositivo Android per l'accesso root per proteggere l'applicazione dall'esecuzione in un ambiente compromesso
  • Metodi statici controllano il file system per la presenza di binari su, applicazioni Superuser e modifiche alle partizioni di sistema
  • Metodi dinamici analizzano il runtime: verifica di Build.TAGS, tentativo di apertura di /proc/self/maps con processi privilegiati
  • Implementazione nativa in C/C++ tramite JNI fornisce resistenza all'elusione tramite Xposed e Frida a livello Java
  • Sicurezza Root Detection richiede offuscamento continuo e verifica lato server per prevenire la manomissione dei risultati

Cos'è Root Detection?

Root Detection è un meccanismo software che rileva la presenza di accesso root su un dispositivo Android. L'accesso root fornisce il controllo completo sul sistema operativo, consentendo ad applicazioni e script di eseguire comandi con UID 0. Su un dispositivo rootato, l'isolamento delle applicazioni (Android Sandbox) viene perso, rendendo possibile intercettare l'input della tastiera, leggere i database SQLite di altre applicazioni, iniettare codice nei processi e sostituire i certificati SSL nell'archivio fidato.

Per le applicazioni finanziarie e aziendali, operare su un dispositivo rootato presenta un rischio inaccettabile: un aggressore ottiene accesso a token, chiavi di sessione e dati personali. Gli enti regolatori, incluso il PCI Security Standards Council, richiedono che le applicazioni di pagamento rilevino e rispondano all'accesso root. In risposta, gli sviluppatori Android integrano Root Detection come parte di una strategia di protezione proattiva.

Esistono due approcci al rilevamento: statico, che analizza il file system e i pacchetti installati, e dinamico, che esegue controlli a runtime. L'approccio combinato è considerato il più affidabile, poiché copre diversi vettori di elusione. Secondo uno studio di NowSecure (2025), il 76% delle applicazioni bancarie nella top 100 di Google Play contiene qualche forma di Root Detection.

Metodi statici di rilevamento root

I metodi statici vengono eseguiti all'avvio dell'applicazione e verificano i segni di accesso root lasciati dagli strumenti di rooting nel file system. Questi metodi non richiedono l'esecuzione di comandi privilegiati e funzionano nel contesto di un'applicazione normale.

Verifica dell'esistenza del binario su

Il principale indicatore di accesso root è la presenza del file eseguibile su nei percorsi standard: /system/bin/su, /system/xbin/su, /sbin/su, /su/bin/su. L'applicazione verifica l'esistenza del file tramite File.exists() o un'implementazione nativa di access() da libc. Inoltre, si può tentare di eseguire su --version o su -c id e verificare il codice di uscita.

Ricerca di gestori root

Applicazioni tipiche per gestire l'accesso root: Superuser, SuperSU, Magisk Manager, KingRoot. La loro presenza viene verificata tramite PackageManager.getPackageInfo() o leggendo la directory /data/app/. Pacchetti da verificare: com.topjohnwu.magisk, eu.chainfire.supersu, com.noshufou.android.su, com.thirdparty.superuser, com.koushikdutta.superuser, com.zacharee1.systemuituner.

Verifica delle proprietà di sistema

Android memorizza le informazioni sullo stato del sistema nelle proprietà di sistema, accessibili tramite System.getProperty e Build.TAGS. Se Build.TAGS contiene test-keys invece di release-keys, questo indica un firmware personalizzato, spesso con accesso root. Inoltre, ro.build.tags, ro.debuggable e ro.secure vengono verificati leggendo /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;
    }
}

Metodi dinamici di verifica

I metodi dinamici vengono eseguiti durante il funzionamento dell'applicazione e analizzano l'ambiente di esecuzione. A differenza dei metodi statici, possono rilevare il rooting nascosto tramite Magisk Hide o Zygisk, poiché verificano il comportamento del sistema e non solo la struttura dei file.

Verifica dei punti di montaggio

Con l'accesso root, alcune partizioni di sistema vengono montate con il flag rw (lettura-scrittura) invece di ro (sola lettura). L'applicazione legge /proc/mounts e verifica che /system sia montato come ro. Se /system è montato come rw, questo indica un sistema modificato. Inoltre, viene verificata la presenza del montaggio di /su tramite Magisk.

Test della modalità provvisoria

La modalità provvisoria di Android disabilita le applicazioni di terze parti, inclusi i gestori root. Un'implementazione corretta di Root Detection può verificare se il dispositivo è in esecuzione in modalità provvisoria. Se l'applicazione rileva che i gestori root non sono visibili ma il binario su esiste, questo è un indicatore di Magisk Hide.

Verifica dell'esecuzione di comandi

Tentare di eseguire su -c id tramite ProcessBuilder o Runtime.exec è un test diretto dell'accesso root. Tuttavia, Magisk può intercettare questa chiamata. Un approccio più affidabile è la verifica tramite codice nativo: aprire /proc/1/limits o /proc/self/maps e analizzare l'UID dei processi in esecuzione. Se l'applicazione può ottenere UID 0 o leggere file accessibili solo a root, il dispositivo è compromesso.

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;
}

Implementazione nativa di Root Detection in C++

Root Detection implementato in Java viene facilmente aggirato tramite moduli Xposed o Frida, che intercettano i metodi Java e sostituiscono i valori di ritorno. L'implementazione nativa in C++ tramite JNI è significativamente più resistente: gli strumenti di analisi dinamica che operano a livello Java non vedono le chiamate native libc come stat, access, popen e 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;
}

La verifica nativa non utilizza l'API Java, rendendola invisibile agli strumenti di elusione che operano a livello Dalvik/ART. Per una protezione aggiuntiva, si consiglia di non memorizzare le costanti (elenco dei percorsi) in una sezione di sola lettura, ma di calcolarle tramite semplici funzioni reversibili. La chiamata stat da libc accede direttamente al kernel Linux, bypassando i wrapper Java, e non può essere intercettata tramite Xposed.

Metodi di elusione di Root Detection

Gli sviluppatori di protezione devono comprendere i metodi di elusione esistenti per costruire un sistema di rilevamento robusto. Ogni metodo di elusione richiede una contromisura al livello appropriato.

Elusione tramite Magisk Hide e Zygisk

Magisk è lo strumento di rooting più popolare su Android 9–14. Magisk Hide nasconde la presenza di su da /proc e falsifica i risultati della verifica dei percorsi. Magisk opera a livello di kernel e intercetta stat() e access() prima che l'applicazione li veda. Contromisura: verificare la presenza di Magisk stesso tramite l'esistenza di /sbin/.magisk o verificare tramite la lettura delle proprie mappe dell'applicazione — Magisk inietta la sua libreria in ogni processo.

Elusione tramite Frida

Frida è uno strumento di strumentazione dinamica che può intercettare funzioni native tramite Ptrace o Dobby. Frida sostituisce il valore di ritorno di qualsiasi verifica, falsificando il risultato di stat in ENOENT. Contromisura: verificare l'integrità delle funzioni native calcolando un checksum delle istruzioni in memoria e rilevare Frida tramite l'analisi di /proc/self/maps per la presenza di frida-agent.so o frida-helper.

Elusione tramite patch dell'APK

Root Detection implementato in Java viene rimosso in 2–3 minuti: l'APK viene decompilato tramite apktool, il valore di ritorno del metodo viene modificato in false nel codice smali, l'APK viene ricostruito e firmato. Contromisura: trasferire la logica critica nel codice nativo e verificare la firma digitale dell'applicazione in fase di runtime tramite l'API di Signature o confrontare l'hash dell'APK con un riferimento sul server.

Raccomandazioni per una protezione affidabile

Un Root Detection efficace si basa su un'architettura multilivello. Nessun singolo metodo fornisce una protezione sufficiente da solo. La combinazione di controlli statici e dinamici, codice nativo e verifica lato server offre la massima resistenza.

Verifica lato server

Non affidarsi esclusivamente alla verifica lato client. Inviare i risultati di Root Detection al server insieme a un token di sessione monouso. Il server decide se bloccare o limitare le funzionalità. Questo previene gli attacchi a livello API, dove l'applicazione client può essere modificata mentre il server rimane una parte fidata.

Offuscamento del codice

Il codice di Root Detection deve essere offuscato. Se un aggressore vede una sequenza chiara di controlli dei percorsi su in jadx, l'elusione richiederà minuti. Utilizzare ProGuard o DexGuard per offuscare il flusso di controllo e crittografare le stringhe. L'offuscamento aumenta il tempo di analisi del codice di protezione da minuti a ore.

Aggiornamento regolare delle firme

L'elenco dei percorsi, dei pacchetti e degli indicatori controllati deve essere aggiornato con ogni versione dell'applicazione. Nuovi strumenti di rooting e elusione appaiono mensilmente. Un elenco statico che non è cambiato in un anno non rileverà i metodi moderni. Si consiglia di caricare le firme attuali dal server all'avvio dell'applicazione prima di eseguire i controlli.

Domande frequenti

Perché le applicazioni hanno bisogno di Root Detection?

Root Detection protegge dall'esecuzione di un'applicazione su un dispositivo in cui la sandbox Android è disabilitata. Su un dispositivo rootato, qualsiasi applicazione può leggere i dati di altre applicazioni. Le applicazioni bancarie e di pagamento sono obbligate a bloccare il funzionamento su dispositivi rootati secondo i requisiti PCI DSS e le raccomandazioni OWASP Mobile Security.

Come funziona Magisk Hide?

Magisk Hide utilizza un meccanismo di namespace di montaggio (mount namespace). Per ogni processo nell'elenco di esclusione, Magisk crea un namespace isolato in cui il binario su è invisibile. Le chiamate di sistema stat, access e open in questo namespace non vedono i file di Magisk. Magisk può essere rilevato verificando la presenza di /proc/self/maps e cercando dump magisk.

Root Detection può essere aggirato senza root?

Sì, se l'applicazione non verifica l'integrità del suo codice. Tramite Frida, è possibile intercettare il metodo Java di verifica e forzarlo a restituire false. La contromisura è un'implementazione nativa della logica critica in C++ e la verifica dell'integrità tramite hash del file DEX. Senza offuscamento, qualsiasi Root Detection in Java viene aggirato in 5–10 minuti.

Cosa sono SafetyNet e attestazione?

SafetyNet (obsoleto) e Play Integrity API sono controlli lato server di Google che confermano l'integrità del dispositivo. Includono la verifica del bootloader, della firma di sistema e dello stato root. Play Integrity API è il sostituto raccomandato per SafetyNet, che fornisce tre livelli: BASIC, DEVICE e STRONG. Root Detection lato client integra l'attestazione lato server.

Come testare Root Detection nella propria applicazione?

Installare l'applicazione su un dispositivo rootato reale (ad esempio, un Pixel con Magisk). Verificare se il blocco si attiva. Quindi provare a nascondere il root tramite Magisk Hide per la propria applicazione e riavviare il test. Per un test approfondito, utilizzare Frida per intercettare i metodi target e assicurarsi che la protezione nativa non possa essere aggirata.

Riepilogo

  • Root Detection è un componente di sicurezza obbligatorio per le applicazioni Android bancarie, di pagamento e aziendali, che opera su una combinazione di controlli statici e dinamici
  • Metodi statici includono la ricerca del binario su nei percorsi standard, la verifica dei gestori root installati e l'analisi delle proprietà di sistema Build.TAGS
  • Metodi dinamici analizzano il montaggio di /system in modalità rw, verificano l'integrità di /proc/mounts ed eseguono test di comandi privilegiati
  • Implementazione nativa in C++ tramite JNI rende i controlli invisibili a Xposed e Frida che operano a livello Java, richiedendo elusione tramite Dobby o Ptrace
  • Magisk Hide è lo strumento principale per aggirare Root Detection tramite mount namespace, rilevabile attraverso l'analisi di /proc/self/maps per le librerie magisk
  • Architettura raccomandata: controlli nativi + offuscamento del codice + verifica dei risultati lato server + aggiornamento regolare delle firme
  • Play Integrity API di Google integra Root Detection lato client con attestazione del dispositivo lato server, fornendo una protezione completa

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche