Root Detection — en mekanism som skyddar Android-appar från att köras på enheter med superanvändarbehörighet. Bank-, betal- och företagsappar blockerar eller begränsar funktionaliteten på rotade enheter, eftersom root-åtkomst tar bort begränsningarna i Android-sandlådan och öppnar möjligheten att avlyssna trafik, läsa processminne och förfalska data. Enligt OWASP Mobile Top 10 (2024) tillhör avsaknaden av Root Detection kategori M8 (Security Decisions via Untrusted Inputs). Root Detection bygger på en kombination av statiska kontroller av filsystemet och dynamisk analys av runtime-beteende.
Huvudpunkter
Root Detection — en programvarumekanism som avgör förekomsten av root-åtkomst på en Android-enhet. Root-åtkomst ger fullständig kontroll över operativsystemet, vilket gör att appar och skript kan köra kommandon med UID 0. På en rotad enhet går isoleringen av appar (Android Sandbox) förlorad, vilket gör det möjligt att avlyssna tangentbordsinmatning, läsa SQLite-databaser från andra appar, injicera kod i processer och förfalska SSL-certifikat i det betrodda lagret.
För finansiella och företagsappar utgör drift på en rotad enhet en oacceptabel risk: angriparen får tillgång till token, sessionsnycklar och personuppgifter. Reglerande myndigheter, inklusive PCI Security Standards Council, kräver att betalappar upptäcker och reagerar på root-åtkomst. Som svar på detta integrerar Android-utvecklare Root Detection som en del av en proaktiv skyddsstrategi.
Det finns två tillvägagångssätt för detektion: statisk, som analyserar filsystemet och installerade paket, och dynamisk, som utför kontroller i runtime. Det kombinerade tillvägagångssättet anses vara mest tillförlitligt eftersom det täcker olika kringgåendvektorer. Enligt forskning från NowSecure (2025) innehåller 76% av bankapparna i topp 100 på Google Play någon form av Root Detection.
Statiska metoder körs vid appstart och kontrollerar tecken på root-åtkomst som lämnats av rootverktyg i filsystemet. Dessa metoder kräver inte exekvering av privilegierade kommandon och fungerar i en vanlig apps kontext.
Huvudtecknet på root-åtkomst — förekomsten av den körbara filen su på standardvägar: /system/bin/su, /system/xbin/su, /sbin/su, /su/bin/su. Appen kontrollerar filens existens via File.exists() eller en native implementering av access() från libc. Dessutom kan man försöka köra su --version eller su -c id och kontrollera utgångskoden.
Typiska appar för hantering av root-åtkomst: Superuser, SuperSU, Magisk Manager, KingRoot. Deras förekomst kontrolleras via PackageManager.getPackageInfo() eller läsning av katalogen /data/app/. Paket att kontrollera: com.topjohnwu.magisk, eu.chainfire.supersu, com.noshufou.android.su, com.thirdparty.superuser, com.koushikdutta.superuser, com.zacharee1.systemuituner.
Android lagrar information om systemets tillstånd i systemegenskaper som är tillgängliga via System.getProperty och Build.TAGS. Om värdet på Build.TAGS innehåller test-keys istället för release-keys — indikerar detta anpassad firmware, ofta med root-åtkomst. Dessutom kontrolleras ro.build.tags, ro.debuggable och ro.secure genom att läsa /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) {
// paketet hittades inte
}
}
return false;
}
}
Dynamiska metoder utförs under appens drift och analyserar exekveringsmiljön. Till skillnad från statiska metoder kan de upptäcka root som göms via Magisk Hide eller Zygisk, eftersom de kontrollerar systemets beteende, inte bara filstrukturen.
Vid root-åtkomst monteras vissa systempartitionerna med flaggan rw (read-write) istället för ro (read-only). Appen läser /proc/mounts och kontrollerar om /system är monterat som ro. Om /system är monterat som rw — är detta ett tecken på ett modifierat system. Dessutom kontrolleras förekomsten av montering av /su via Magisk.
Android Safe Mode inaktiverar tredjepartsappar, inklusive root-hanterare. En korrekt implementering av Root Detection kan kontrollera om enheten fungerar i säkert läge. Om appen upptäcker att root-hanterare inte är synliga, men su-binären finns — är detta ett tecken på Magisk Hide.
Försök att köra su -c id via ProcessBuilder eller Runtime.exec — ett direkt test av root-åtkomst. Magisk kan dock fånga upp detta anrop. Ett mer tillförlitligt alternativ — kontroll via native kod: öppna /proc/1/limits eller /proc/self/maps och analysera UID för aktiva processer. Om appen kan få UID 0 eller läsa filer som endast är tillgängliga för root — är enheten komprometterad.
public boolean checkRootDynamically() {
// Kontroll av kompileringsflaggor
String buildTags = Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// Kontroll av montering av /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) {
// fel vid läsning av mount
}
return false;
}
Root Detection implementerad i Java kringgås enkelt via Xposed-moduler eller Frida, som fångar upp Java-metoder och förfalskar returvärden. Native implementation i C++ via JNI är betydligt mer motståndskraftig: dynamiska analysverktyg som arbetar på Java-nivå ser inte de nativen libc-anropen som stat, access, popen och 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;
}
Native kontroll använder inte Java API, vilket gör den osynlig för kringgåendeverktyg som arbetar på Dalvik/ART-nivå. För extra skydd rekommenderas att lagra konstanter (väglista) inte i read-only-sektionen, utan att beräkna dem via enkla reversibla funktioner. Stat-anropet från libc vänder sig direkt till Linux-kärnan, förbi Java-wrapper och kan inte fångas upp via Xposed.
Säkerhetsutvecklare måste förstå befintliga kringgåendemetoder för att bygga ett motståndskraftigt detektionssystem. Varje kringgåendemetod kräver en motåtgärd på lämplig nivå.
Magisk — det mest populära rootverktyget på Android 9–14. Magisk Hide döljer förekomsten av su från /proc och förfalskar resultaten av vägkontroller. Magisk arbetar på kärnnivå och fångar upp stat() och access() innan appen ser dem. Motåtgärd: kontroll av förekomsten av själva Magisk via /sbin/.magisk eller kontroll via läsning av egna maps — Magisk bäddar in sitt bibliotek i varje process.
Frida — ett dynamiskt instrumenteringsverktyg som kan fånga upp nativen funktioner via Ptrace eller Dobby. Frida ersätter returvärdet för varje kontroll och förfalskar resultatet av stat till ENOENT. Motåtgärd: kontroll av integriteten hos nativen funktioner genom beräkning av kontrollsumma för instruktioner i minnet och detektering av Frida via analys av /proc/self/maps för förekomst av frida-agent.so eller frida-helper.
Root Detection implementerad i Java tas bort på 2–3 minuter: APK packas upp via apktool, i smali-koden ändras metodens returvärde till false, APK återmonteras och signeras. Motåtgärd: flytta kritisk logik till native kod och kontrollera appens digitala signatur i runtime via Signature API eller jämför APK-hash med referensen på servern.
Effektiv Root Detection bygger på en flerskiktad arkitektur. Ingen enskild metod ger tillräckligt skydd. Kombinationen av statiska och dynamiska kontroller, native kod och serververifiering ger maximal motståndskraft.
Förlita dig inte enbart på kontroll på klientsidan. Skicka resultaten från Root Detection tillsammans med en engångssessionstoken till servern. Servern fattar beslut om blockering eller begränsning av funktionalitet. Detta förhindrar attacker på API-nivå, där klientappen kan modifieras men servern förblir den betrodda parten.
Root Detection-koden måste obfuskeras. Om angriparen ser i jadx en tydlig sekvens av su-vägkontroller — tar kringgående minuter. Använd ProGuard eller DexGuard för att förvirra kontrollflödet och kryptera strängar. Obfuskering ökar analystiden för säkerhetskoden från några minuter till flera timmar.
Listan över kontrollerade vägar, paket och indikatorer måste uppdateras med varje app-release. Nya root- och kringgåendeverktyg dyker upp månatligen. En statisk lista som inte ändrats på ett år upptäcker inte moderna metoder. Det rekommenderas att ladda aktuella signaturer från servern vid appstart innan kontroller utförs.
Vanliga frågor
Root Detection skyddar mot att appen körs på en enhet där Android-sandlådan är avaktiverad. På en rotad enhet kan vilken app som helst läsa data från andra appar. Bankappar och betalappar är skyldiga att blockera drift på rotade enheter enligt PCI DSS-kraven och OWASP Mobile Security-rekommendationerna.
Magisk Hide använder mekanismen för monteringsnamnrymd (mount namespace). För varje process som anges i undantagslistan skapar Magisk en isolerad namnrymd där su-binären är osynlig. Systemanropen stat, access och open i denna namnrymd ser inte Magisk-filer. Magisk kan upptäckas genom att kontrollera förekomsten av /proc/self/maps och söka efter magisk-dump.
Ja, om appen inte kontrollerar integriteten hos sin egen kod. Via Frida kan Java-kontrollmetoden fångas upp och tvingas returnera false. Motåtgärd — native implementering av kritisk logik i C++ och integritetskontroll via hash av DEX-filen. Utan obfuskering kringgås varje Root Detection i Java på 5–10 minuter.
SafetyNet (föråldrat) och Play Integrity API — detta är serverkontroller från Google som bekräftar enhetens integritet. De inkluderar kontroll av bootloader, systemsignatur och root-status. Play Integrity API — den rekommenderade ersättningen för SafetyNet, som ger tre nivåer: BASIC, DEVICE och STRONG. Root Detection på klientsidan kompletterar serverattestation.
Installera appen på en verklig rotad enhet (t.ex. Pixel med Magisk). Kontrollera om blockeringen aktiveras. Försök sedan dölja root via Magisk Hide för din app och upprepa testet. För djupgående kontroll, använd Frida för att fånga upp målinriktade metoder och säkerställ att det nativen skyddet inte kan kringgås.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också