निर्धारित करें कि क्या रूट किए गए डिवाइस पर चल रहा है


292

मेरे ऐप में कार्यक्षमता का एक निश्चित टुकड़ा है जो केवल एक डिवाइस पर काम करेगा जहां रूट उपलब्ध है। इस सुविधा के विफल होने के बजाय जब इसका उपयोग किया जाता है (और फिर उपयोगकर्ता को एक उपयुक्त त्रुटि संदेश दिखाते हैं), मैं चुपचाप यह देखने की क्षमता पसंद करूंगा कि क्या रूट पहले उपलब्ध है, और यदि नहीं, तो संबंधित विकल्पों को पहले स्थान पर छिपाएं। ।

क्या इसे करने का कोई तरीका है?


11
ऐसा करने का कोई विश्वसनीय तरीका नहीं है; नीचे दिए गए उत्तर सामान्य विशेषताओं की जांच करते हैं लेकिन किसी दिए गए उपकरण को सामान्य तरीके से निहित नहीं किया जा सकता है। यदि जड़ की जाँच प्रचलित हो जाती है, तो जड़ समाधान संभवत: स्वयं को छिपाने के प्रयास में जाने लगेंगे। चूंकि वे ऑपरेटिंग सिस्टम व्यवहार को संशोधित कर सकते हैं, इसलिए उनके पास ऐसा करने के लिए बहुत सारे विकल्प हैं।
क्रिस स्ट्रैटन

यह इंगित करना बेहतर हो सकता है कि फ़ंक्शन आपके ऐप की क्षमताओं को छिपाने के बजाय उपयोगकर्ता को अधिक जानकारी प्रदान करने की जड़ क्षमता की कमी के कारण उपलब्ध नहीं है, समग्र अनुभव में अस्पष्टता जोड़ रहा है।
निक फॉक्स

क्या नीचे दिए गए जवाब सिस्टमलेस रूट के लिए काम करते हैं ?
पियूष कुकड़िया

जवाबों:


260

यहां एक वर्ग है जो रूट के तीन तरीकों में से एक की जांच करेगा।

/** @author Kevin Kowalewski */
public class RootUtil {
    public static boolean isDeviceRooted() {
        return checkRootMethod1() || checkRootMethod2() || checkRootMethod3();
    }

    private static boolean checkRootMethod1() {
        String buildTags = android.os.Build.TAGS;
        return buildTags != null && buildTags.contains("test-keys");
    }

    private static boolean checkRootMethod2() {
        String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
                "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};
        for (String path : paths) {
            if (new File(path).exists()) return true;
        }
        return false;
    }

    private static boolean checkRootMethod3() {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            if (in.readLine() != null) return true;
            return false;
        } catch (Throwable t) {
            return false;
        } finally {
            if (process != null) process.destroy();
        }
    }
}

8
यदि एक दो प्रश्न समान उत्तर देते हैं, तो वे समय का 99% डुप्लिकेट हैं, इसलिए दोनों पर एक ही उत्तर पोस्ट करने के बजाय झंडे के रूप में ध्वज। धन्यवाद।
केव

2
ऐसा हो सकता है, हालांकि मैं आपको सिर्फ यह बता रहा हूं कि सटीक डुप्लिकेट उत्तर समुदाय द्वारा चिह्नित किए गए हैं। आपको अपने उत्तरों को दर्ज़ करना चाहिए और ओपी की समस्या की बारीकियों पर ध्यान देना चाहिए। कॉपी और पेस्ट उत्तर डाउनवोट्स को आकर्षित करने से खतरे में हैं।
केव

9
-1, यह विधि व्यवहार्य नहीं है, क्योंकि कुछ फोन में suबाइनरी शामिल होती है जबकि रूट नहीं होती है।
नीवेक

12
बस आपको यह बता देना चाहता था कि फॉक्स डिजिटल कॉपी (बीटा) ऐप आपके कोड को लगभग वर्बेटिम का उपयोग करता है, जिसमें रूट और एक्सशेल क्लासेस, साथ ही चेकरूटमेथोड 1/2/3 विधियाँ शामिल हैं। यह अत्यधिक मनोरंजक पाया।
मैट जोसफ

8
मैं उन पर मुकदमा कर सकता हूं जैसे फॉक्स ने अनगिनत दूसरों पर मुकदमा दायर किया?
केविन पार्कर

58

यदि आप पहले से ही फैब्रिक / फायरबेस क्रेशलीटिक्स का उपयोग कर रहे हैं, तो आप कॉल कर सकते हैं

CommonUtils.isRooted(context)

यह उस पद्धति का वर्तमान कार्यान्वयन है:

public static boolean isRooted(Context context) {
    boolean isEmulator = isEmulator(context);
    String buildTags = Build.TAGS;
    if(!isEmulator && buildTags != null && buildTags.contains("test-keys")) {
        return true;
    } else {
        File file = new File("/system/app/Superuser.apk");
        if(file.exists()) {
            return true;
        } else {
            file = new File("/system/xbin/su");
            return !isEmulator && file.exists();
        }
    }
}

सबसे अच्छा जवाब कभी। कृपया इसे किसी भी पुस्तकालय में उपयोग करें, चीनी उपकरणों पर बहुत सारे सकारात्मक चल रहे हैं।
पेड्रो पाउलो अमोरिम

क्या इस विधि में कोई गलत सकारात्मक है?
एहसान मशहदी

मैंने इसे nexus 5 पर download.chainfire.eu/363/CF-Root/CF-Auto-Root/… के साथ परीक्षण किया , यह सटीक नहीं है।
जेफरी लियू

54

रूटटूल लाइब्रेरी रूट की जाँच करने के लिए सरल तरीके प्रदान करती है:

RootTools.isRootAvailable()

संदर्भ


10
isRootAvailable () सिर्फ रास्ते में सु के अस्तित्व और कुछ अन्य हार्ड-कोडित निर्देशिकाओं के लिए जाँच करता है। मैंने सुना है कि कुछ unrooting उपकरण वहाँ su छोड़ देंगे, तो यह एक झूठी सकारात्मक देगा।
बॉब व्हाइटमैन

13
RootTools.isAccessGiven () न केवल रूट की जांच करेगा, बल्कि रूट अनुमति का भी अनुरोध करेगा; तो एक अनियंत्रित डिवाइस हमेशा इस विधि के साथ गलत वापस आएगा।
समुच्चय

2
@ कुल 1166877, आप सही हैं, लेकिन यह पर्याप्त नहीं है, क्या होगा अगर मुझे पूछने पर रूट अनुमति की आवश्यकता नहीं है? मैं सिर्फ यह जानना चाहता हूं कि क्या यह निहित है, लेकिन मुझे इस समय रूट अनुमति की आवश्यकता नहीं है।
नीवेक

4
isAccessGiven () झूठा वापस आता है जब उपयोगकर्ता डिवाइस को रूट किया गया था तब भी अनुमति से इनकार करता है।
उपैर_आय

यह एकमात्र जवाब है जो मुझे वोट देने लायक लगता है। नीचे दिए गए मेरे जवाब की जाँच करें यदि आप चाहते हैं कि बस कॉपी पेस्ट के समान कुछ है, या कुछ और विवरण चाहेंगे
rsimp

52

मेरे आवेदन में मैं यह जांच रहा था कि क्या डिवाइस निहित है या "सु" कमांड को निष्पादित करके नहीं। लेकिन आज मैंने अपने कोड के इस हिस्से को हटा दिया है। क्यों?

क्योंकि मेरा आवेदन एक स्मृति हत्यारा बन गया। कैसे? मैं आपको अपनी कहानी बताता हूं।

कुछ शिकायतें थीं कि मेरा आवेदन उपकरणों को धीमा कर रहा था (निश्चित रूप से मुझे लगा था कि यह सच नहीं हो सकता है)। मैंने यह जानने की कोशिश की कि क्यों। इसलिए मैंने MAT का उपयोग ढेर डंप करने और विश्लेषण करने के लिए किया, और सब कुछ सही लग रहा था। लेकिन कई बार अपने ऐप को रिलॉन्च करने के बाद मुझे महसूस हुआ कि डिवाइस वास्तव में धीमा हो रहा है और मेरे एप्लिकेशन को रोकने से यह तेज़ नहीं हुआ (जब तक कि मैं पुनः आरंभ नहीं करता)। मैंने डंप फ़ाइलों का फिर से विश्लेषण किया, जबकि डिवाइस बहुत धीमा है। लेकिन डंप फ़ाइल के लिए अभी भी सब कुछ सही था। फिर मैंने वही किया जो पहले किया जाना चाहिए। मैंने प्रक्रियाओं को सूचीबद्ध किया।

$ adb shell ps

सरप्राइज़; मेरे आवेदन के लिए कई प्रक्रियाएँ थीं (प्रकट में मेरे आवेदन की प्रक्रिया टैग के साथ)। उनमें से कुछ ज़ोंबी थे उनमें से कुछ नहीं।

एक नमूना अनुप्रयोग के साथ, जिसमें एक ही गतिविधि है और सिर्फ "सु" कमांड को निष्पादित करता है, मैंने महसूस किया कि आवेदन के हर लॉन्च पर एक ज़ोंबी प्रक्रिया बनाई जा रही है। सबसे पहले ये लाश 0KB आवंटित करते हैं, लेकिन कुछ होता है और ज़ोंबी प्रक्रिया मेरे आवेदन की मुख्य प्रक्रिया के रूप में लगभग एक ही KB पकड़ रहे हैं और वे standart प्रक्रिया बन गए।

Bugs.sun.com पर इसी मुद्दे के लिए एक बग रिपोर्ट है: http://bugs.sun.com/view_bug.do?bug_id=6474073 यह बताती है कि क्या कमांड नहीं मिली लाश को निष्पादन () विधि से बनाया जा रहा है । लेकिन मुझे अभी तक समझ नहीं आया है कि वे क्यों और कैसे बड़ी हो सकती हैं और महत्वपूर्ण केबी पकड़ लेते हैं। (यह हर समय नहीं हो रहा है)

यदि आप नीचे दिए गए कोड नमूने के साथ चाहते हैं तो आप कोशिश कर सकते हैं;

String commandToExecute = "su";
executeShellCommand(commandToExecute);

सरल कमांड निष्पादन विधि;

private boolean executeShellCommand(String command){
    Process process = null;            
    try{
        process = Runtime.getRuntime().exec(command);
        return true;
    } catch (Exception e) {
        return false;
    } finally{
        if(process != null){
            try{
                process.destroy();
            }catch (Exception e) {
            }
        }
    }
}

सारांश में; मुझे यह निर्धारित करने के लिए आपके पास कोई सलाह नहीं है कि डिवाइस निहित है या नहीं। लेकिन अगर मैं तुम होते तो मैं Runtime.getRuntime () (exec।) का उपयोग नहीं करता।

वैसे; RootTools.isRootAvailable () एक ही समस्या का कारण बनता है।


5
यह बहुत चिंताजनक है। मेरे पास एक रूटेड डिवाइस डिटेक्शन क्लास था जिसने वही काम किया - इसे पढ़ने के बाद मैंने पुष्टि की कि ऊपर क्या ईजियन है। सामयिक ज़ोंबी प्रक्रियाओं को पीछे छोड़ा जा रहा है, डिवाइस मंदी आदि ...
AWT

1
मैं GT-S5830i एंड्रॉइड 2.3.6 पर रूटटूल 3.4 के साथ समस्या की पुष्टि करता हूं। अधिकांश ज़ोंबी को आवंटित स्मृति मिली और समस्या व्यवस्थित है। मुझे 3-4 परीक्षण के बाद डिवाइस को पुनरारंभ करने की आवश्यकता है। मैं साझा वरीयता के लिए परीक्षा परिणाम को बचाने की सलाह देता हूं।
मसीह

2
Google अब ProcessBuilder () और प्रारंभ () कमांड का उपयोग करने की अनुशंसा करता है
EntangledLoops

1
@ निक्स दिलचस्प है, लेकिन आपने क्या कमांड लॉन्च किया? मेरे पास एक ही मुद्दा नहीं है यहां 9 - 23 से अलग-अलग एपीआई स्तर के कई एंड्रॉइड फोन पर कमांड जारी किए जा रहे हैं।
एंटैंगल्डलॉप्स

1
@EntangledLoops। धन्यवाद। मैं अपना खुद का बाइनरी लॉन्च करता हूं और स्टड / स्टडआउट के माध्यम से इसके साथ बातचीत करता हूं। मैंने फिर से जाँच की कि मैं इसे कैसे रोकूं और मुझे पता चला कि मैंने एक मामले में Process.destroy () को याद किया। तो, कोई लाश नहीं।
निक

37

यहाँ सूचीबद्ध उत्तरों में से कई में अंतर्निहित मुद्दे हैं:

  • परीक्षण-कुंजियों के लिए जाँच को रूट एक्सेस के साथ सहसंबद्ध किया जाता है लेकिन जरूरी नहीं कि इसकी गारंटी हो
  • "PATH" निर्देशिका को हार्ड कोडित होने के बजाय वास्तविक "PATH" पर्यावरण चर से लिया जाना चाहिए
  • "सु" निष्पादन योग्य के अस्तित्व का मतलब यह नहीं है कि डिवाइस को रूट किया गया है
  • "कौन सा" निष्पादन योग्य स्थापित हो सकता है या नहीं हो सकता है, और यदि संभव हो तो आपको सिस्टम को अपना रास्ता हल करने देना चाहिए
  • सिर्फ इसलिए कि डिवाइस पर सुपरयूजर ऐप इंस्टॉल है इसका मतलब यह नहीं है कि डिवाइस की रूट एक्सेस अभी तक नहीं है

RootTools Stericson से पुस्तकालय अधिक वैध तरीके से रूट के लिए जाँच कर रहा है। इसमें बहुत सारे अतिरिक्त उपकरण और उपयोगिताओं हैं इसलिए मैं इसकी अत्यधिक अनुशंसा करता हूं। हालांकि, इसका कोई स्पष्टीकरण नहीं है कि यह विशेष रूप से रूट के लिए कैसे जांचता है, और यह वास्तव में ज़रूरत वाले अधिकांश ऐप की तुलना में थोड़ा भारी हो सकता है।

मैंने कुछ उपयोगिता विधियाँ बनाई हैं जो रूटटूल लाइब्रेरी पर आधारित हैं। यदि आप बस यह जांचना चाहते हैं कि क्या "सु" निष्पादन योग्य डिवाइस पर है तो आप निम्न विधि का उपयोग कर सकते हैं:

public static boolean isRootAvailable(){
    for(String pathDir : System.getenv("PATH").split(":")){
        if(new File(pathDir, "su").exists()) {
            return true;
        }
    }
    return false;
}

यह विधि केवल "पथ" पर्यावरण चर में सूचीबद्ध निर्देशिकाओं के माध्यम से लूप करती है और जांचती है कि उनमें से एक में "सु" फ़ाइल मौजूद है या नहीं।

वास्तव में रूट एक्सेस की जांच के लिए "सु" कमांड को वास्तव में चलाया जाना चाहिए। यदि SuperUser जैसा कोई ऐप इंस्टॉल किया गया है, तो इस बिंदु पर यह रूट एक्सेस के लिए कह सकता है, या यदि इसकी पहले से ही अनुमति / इनकार कर दिया गया है, तो यह इंगित करते हुए दिखाया जा सकता है कि एक्सेस दी गई / अस्वीकृत थी। चलाने के लिए एक अच्छा आदेश "आईडी" है ताकि आप यह सत्यापित कर सकें कि उपयोगकर्ता आईडी वास्तव में 0 (रूट) है।

रूट एक्सेस प्रदान किया गया है या नहीं यह निर्धारित करने के लिए यहां एक नमूना विधि दी गई है:

public static boolean isRootGiven(){
    if (isRootAvailable()) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[]{"su", "-c", "id"});
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String output = in.readLine();
            if (output != null && output.toLowerCase().contains("uid=0"))
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null)
                process.destroy();
        }
    }

    return false;
}

यह वास्तव में "सु" कमांड चलाने के लिए महत्वपूर्ण है क्योंकि कुछ एमुलेटर में "सु" निष्पादन योग्य पूर्व-स्थापित है, लेकिन केवल कुछ उपयोगकर्ताओं को इसे अदब शेल की तरह एक्सेस करने की अनुमति है।

एंड्रॉइड को चलाने के लिए प्रयास करने से पहले "सु" निष्पादन योग्य के अस्तित्व की जांच करना भी महत्वपूर्ण है, क्योंकि एंड्रॉइड को उन प्रक्रियाओं का ठीक से निपटान नहीं करने के लिए जाना जाता है जो लापता कमांड चलाने की कोशिश करते हैं। ये भूत प्रक्रियाएं समय के साथ मेमोरी खपत को बढ़ा सकती हैं।


IsRootAvailable () विधि महान काम करती है, धन्यवाद। मैं फिर भी इस तरह के एक AsyncTask से फोन के रूप में एक ANR से बचने के लिए, मुख्य थ्रेड पर इस से नहीं चल रहा की सलाह देते हैं
Thunderstick

1
मुझे लगता है कि यह सुनिश्चित करना चाहते हैं कि रूट उपलब्ध नहीं है और यह सुनिश्चित करना चाहते हैं के बीच का अंतर है। यदि आप यह सुनिश्चित करना चाहते हैं कि डिवाइस जड़ नहीं है, तो सुझाए गए चेक अच्छे हैं। आपको झूठी सकारात्मकता मिलेगी लेकिन यह ठीक है जब एक समझौता डिवाइस पर अपना कोड नहीं चलाया जा रहा है तो यह आपकी मुख्य चिंता है।
जेफरी बट्टमैन

1
@ DAC84 मुझे यकीन नहीं है कि मैं आपके सवाल को समझ सकता हूँ। यदि आप isRootGiven चलाते हैं और अपने रूटिंग एप्लिकेशन से इनकार करते हैं तो इसे गलत लौटना चाहिए। क्या यह नहीं हो रहा है? यदि आप उस अलर्ट से बचना चाहते हैं जो आप केवल isRootAvailable का उपयोग कर सकते हैं जिसका नाम doSUExist भी हो सकता है। आप स्वतंत्र रूप से रूट देने और इसे प्रबंधित न करने के लिए अपने रूट एप्लिकेशन को कॉन्फ़िगर करने का भी प्रयास कर सकते हैं।
rsimp

1
@BeeingJk वास्तव में नहीं है, हालांकि यह वास्तव में सबसे अधिक है जो आप बिना सु चलाने के लिए देख सकते हैं जो असली परीक्षा है। हालांकि इसे निष्पादित करने की कोशिश करने से पहले आपको PATH में su की जांच करनी होगी। हालांकि वास्तव में र को निष्पादित करने से अक्सर एक टोस्ट संदेश या रूट प्रबंधन ऐप के साथ एक इंटरैक्शन होता है जो आप नहीं चाहते हैं। अपने स्वयं के तर्क के लिए आप पर्याप्त रूप से मात्र अस्तित्व को नष्ट कर सकते हैं। यह अभी भी कुछ एमुलेटरों में गलत पॉज़िटिव दे सकता है जिसमें एक su निष्पादन योग्य लेकिन लॉकडाउन एक्सेस हो सकता है।
rsimp

1
@BeeingJk isRootAvailable शायद आप सभी की जरूरत है, लेकिन मैं जो बनाने की कोशिश कर रहा हूं, वह यह है कि ऐसा नाम या यहां तक ​​कि doSUExist isDeviceRooted जैसे विधि नाम से बेहतर शब्दार्थ प्रदान करता है जो कि काफी सही है। यदि आपको वास्तव में आगे बढ़ने से पहले पूर्ण रूट एक्सेस को सत्यापित करने की आवश्यकता है, तो आपको su के साथ कमांड चलाने की कोशिश करने की आवश्यकता है जैसे कि isRootGiven में कोडित
rsimp

35

अपडेट 2017

अब आप इसे Google Safetynet API के साथ कर सकते हैं । सेफ्टीनेट एपीआई अटेस्टेशन एपीआई प्रदान करता है जो आपको एंड्रॉइड वातावरण की सुरक्षा और संगतता का आकलन करने में मदद करता है जिसमें आपके ऐप चलते हैं।

यह सत्यापन यह निर्धारित करने में मदद कर सकता है कि किसी विशेष उपकरण के साथ छेड़छाड़ की गई है या नहीं या फिर संशोधित की गई है।

सत्यापन एपीआई इस तरह एक JWS प्रतिक्रिया देता है

{
  "nonce": "R2Rra24fVm5xa2Mg",
  "timestampMs": 9860437986543,
  "apkPackageName": "com.package.name.of.requesting.app",
  "apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
                                  certificate used to sign requesting app"],
  "apkDigestSha256": "base64 encoded, SHA-256 hash of the app's APK",
  "ctsProfileMatch": true,
  "basicIntegrity": true,
}

इस प्रतिक्रिया को पार्स करने से आपको यह निर्धारित करने में मदद मिल सकती है कि डिवाइस निहित है या नहीं

रूट किए गए डिवाइस ctsProfileMatch = false का कारण बनते हैं।

आप इसे क्लाइंट की तरफ से कर सकते हैं, लेकिन सर्वर की ओर से पार्सिंग प्रतिक्रिया की सिफारिश की जाती है। एक मूल ग्राहक सर्वर आर्काइव के साथ सुरक्षा नेट एपीआई इस तरह दिखेगा: -

यहां छवि विवरण दर्ज करें


3
उत्कृष्ट जानकारी, और एक अलग संदर्भ में मेरा मानना ​​है कि यह सही उत्तर होगा। दुर्भाग्य से ओपी का सवाल असुरक्षित वातावरण से अपने ऐप का बचाव करने के बारे में नहीं है, लेकिन अपने ऐप में रूट-ओनली सुविधाओं को सक्षम करने के लिए रूट का पता लगाना है। ओपी इच्छित उद्देश्य के लिए यह प्रक्रिया अत्यधिक जटिल लगती है।
rsimp

31

जावा स्तर पर रूट चेक एक सुरक्षित समाधान नहीं है। यदि आपके ऐप में रूटेड डिवाइस पर चलने के लिए सुरक्षा चिंताएं हैं, तो कृपया इस समाधान का उपयोग करें।

केविन का जवाब तब तक काम करता है जब तक फोन में RootCloak जैसा कोई ऐप न हो। इस तरह के ऐप में एक बार फोन रूट होने के बाद जावा एपीआई पर एक हैंडल होता है और फोन वापस करने के लिए वे इन एपीआई का मजाक उड़ाते हैं।

मैंने केविन के उत्तर के आधार पर एक देशी स्तर का कोड लिखा है, यह रूट-क्लोक के साथ भी काम करता है! इसके अलावा यह किसी भी स्मृति रिसाव मुद्दों का कारण नहीं है।

#include <string.h>
#include <jni.h>
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include "android_log.h"
#include <errno.h>
#include <unistd.h>
#include <sys/system_properties.h>

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod1(
        JNIEnv* env, jobject thiz) {


    //Access function checks whether a particular file can be accessed
    int result = access("/system/app/Superuser.apk",F_OK);

    ANDROID_LOGV( "File Access Result %d\n", result);

    int len;
    char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
    len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
    if(strcmp(build_tags,"test-keys") == 0){
        ANDROID_LOGV( "Device has test keys\n", build_tags);
        result = 0;
    }
    ANDROID_LOGV( "File Access Result %s\n", build_tags);
    return result;

}

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod2(
        JNIEnv* env, jobject thiz) {
    //which command is enabled only after Busy box is installed on a rooted device
    //Outpput of which command is the path to su file. On a non rooted device , we will get a null/ empty path
    //char* cmd = const_cast<char *>"which su";
    FILE* pipe = popen("which su", "r");
    if (!pipe) return -1;
    char buffer[128];
    std::string resultCmd = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            resultCmd += buffer;
    }
    pclose(pipe);

    const char *cstr = resultCmd.c_str();
    int result = -1;
    if(cstr == NULL || (strlen(cstr) == 0)){
        ANDROID_LOGV( "Result of Which command is Null");
    }else{
        result = 0;
        ANDROID_LOGV( "Result of Which command %s\n", cstr);
        }
    return result;

}

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod3(
        JNIEnv* env, jobject thiz) {


    int len;
    char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
    int result = -1;
    len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
    if(len >0 && strstr(build_tags,"test-keys") != NULL){
        ANDROID_LOGV( "Device has test keys\n", build_tags);
        result = 0;
    }

    return result;

}

अपने जावा कोड में, आपको देशी कॉल करने के लिए रैपर क्लास RootUtils बनाने की आवश्यकता है

    public boolean checkRooted() {

       if( rootUtils.checkRootAccessMethod3()  == 0 || rootUtils.checkRootAccessMethod1()  == 0 || rootUtils.checkRootAccessMethod2()  == 0 )
           return true;
      return false;
     }

1
मुझे लगता है कि रूट का पता लगाना दो श्रेणियों में आता है, रूट डिपेंडेंट फीचर्स को सक्षम करना और फिर रूट किए गए फोन के साथ सुरक्षा समस्याओं को कम करने के लिए सुरक्षा आधारित उपाय। रूट पर निर्भर सुविधाओं के लिए मुझे केविन का जवाब काफी घटिया लगता है। इस उत्तर के संदर्भ में ये विधियाँ अधिक समझ में आती हैं। यद्यपि मैं विधि 2 को फिर से लिखूंगा जिसका उपयोग न करने के लिए और "su" की खोज करने के लिए PATH पर्यावरण चर पर पुनरावृति करना होगा। "जो" फोन पर होने की गारंटी नहीं है।
rsimp

क्या आप जावा में इस c कोड का उपयोग करने का एक उदाहरण प्रदान कर सकते हैं?
मृग

@mrid कृपया Android पर जावा से जेएनआई कॉल करने का तरीका देखें।
आलोक कुलकर्णी

यह विधि रूट डिटेक्शन को रूटकैप एप्लिकेशन का उपयोग करके बायपास को रोकती है। क्या कोई ज्ञात रूट बायपास तकनीक है जो इन विधि को विफल करती है?
निधिन

20

http://code.google.com/p/roottools/

यदि आप जार फ़ाइल का उपयोग नहीं करना चाहते हैं तो कोड का उपयोग करें:

public static boolean findBinary(String binaryName) {
        boolean found = false;
        if (!found) {
            String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
                    "/data/local/xbin/", "/data/local/bin/",
                    "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
            for (String where : places) {
                if (new File(where + binaryName).exists()) {
                    found = true;

                    break;
                }
            }
        }
        return found;
    }

प्रोग्राम su फ़ोल्डर खोजने की कोशिश करेगा:

private static boolean isRooted() {
        return findBinary("su");
    }

उदाहरण:

if (isRooted()) {
   textView.setText("Device Rooted");

} else {
   textView.setText("Device Unrooted");
}

धन्यवाद! मैं केविन के उत्तर केcheckRootMethod4() साथ इसका उपयोग कर रहा हूं ।
शेहर

1
== trueबूलियन में कभी न जोड़ें , यह कुछ भी नहीं जोड़ता है और अच्छा नहीं दिखता है।
मिनीपिफ

2
@smoothBlue यह क्यों होगा? यह किसी भी प्रक्रिया को जन्म नहीं दे रहा है क्योंकि DevrimTuncer का समाधान है।
FD_

1
एक बेहतर विचार है कि PATH पर कड़ी मेहनत करना, विशेष PATH निर्देशिकाओं को कोडित करने के बजाय
rsimp

1
उपयोग करें, if (isRooted())स्पष्ट रूप से सही लिखने के बजाय जांचें। इसके बेहतर पालन करने के लिए कोड लिखने पैटर्न
blueware

13

इसके बजाय isRootAvailable () का उपयोग करने के बजाय आप isAccessGiven () का उपयोग कर सकते हैं। रूटटूल विकि से प्रत्यक्ष :

if (RootTools.isAccessGiven()) {
    // your app has been granted root access
}

RootTools.isAccessGiven () न केवल यह जांचता है कि कोई डिवाइस रूट किया गया है, यह आपके ऐप के लिए su भी कहता है, अनुमति देता है, और यदि आपका ऐप सफलतापूर्वक रूट अनुमतियाँ दी गई है तो यह सच है। यह आपके ऐप में पहली जाँच के रूप में इस्तेमाल किया जा सकता है ताकि यह सुनिश्चित किया जा सके कि आपको ज़रूरत पड़ने पर पहुँच प्रदान की जाएगी।

संदर्भ


लेकिन उपयोगकर्ता को रूट एक्सेस सही देना होगा? इसलिए यदि मेरा उद्देश्य मेरे ऐप को चलाने से रोकना है यदि डिवाइस निहित है तो मेरे विकल्प वास्तव में सीमित हैं
Nasz Njoka Sr.

11

कुछ संशोधित बिल्ड इस उद्देश्य के लिए सिस्टम प्रॉपर्टी सेट करने के लिए उपयोग किया जाता है ro.modversion। लगता है चीजें आगे बढ़ गई हैं; कुछ महीने पहले TheDude से मेरा निर्माण यह है:

cmb@apollo:~$ adb -d shell getprop |grep build
[ro.build.id]: [CUPCAKE]
[ro.build.display.id]: [htc_dream-eng 1.5 CUPCAKE eng.TheDudeAbides.20090427.235325 test-keys]
[ro.build.version.incremental]: [eng.TheDude.2009027.235325]
[ro.build.version.sdk]: [3]
[ro.build.version.release]: [1.5]
[ro.build.date]: [Mon Apr 20 01:42:32 CDT 2009]
[ro.build.date.utc]: [1240209752]
[ro.build.type]: [eng]
[ro.build.user]: [TheDude]
[ro.build.host]: [ender]
[ro.build.tags]: [test-keys]
[ro.build.product]: [dream]
[ro.build.description]: [kila-user 1.1 PLAT-RC33 126986 ota-rel-keys,release-keys]
[ro.build.fingerprint]: [tmobile/kila/dream/trout:1.1/PLAT-RC33/126986:user/ota-rel-keys,release-keys]
[ro.build.changelist]: [17615# end build properties]

दूसरी ओर 1.5 एसडीके से एमुलेटर, 1.5 छवि चल रहा है, जिसमें रूट भी है, संभवतः एंड्रॉइड देव फोन 1 (जो आप संभवतः अनुमति देना चाहते हैं) के समान है और यह है:

cmb@apollo:~$ adb -e shell getprop |grep build
[ro.build.id]: [CUPCAKE]
[ro.build.display.id]: [sdk-eng 1.5 CUPCAKE 148875 test-keys]
[ro.build.version.incremental]: [148875]
[ro.build.version.sdk]: [3]
[ro.build.version.release]: [1.5]
[ro.build.date]: [Thu May 14 18:09:10 PDT 2009]
[ro.build.date.utc]: [1242349750]
[ro.build.type]: [eng]
[ro.build.user]: [android-build]
[ro.build.host]: [undroid16.mtv.corp.google.com]
[ro.build.tags]: [test-keys]
[ro.build.product]: [generic]
[ro.build.description]: [sdk-eng 1.5 CUPCAKE 148875 test-keys]
[ro.build.fingerprint]: [generic/sdk/generic/:1.5/CUPCAKE/148875:eng/test-keys]

खुदरा विक्रेताओं के लिए, मेरे पास एक हाथ नहीं है, लेकिन विभिन्न खोजों के तहत site:xda-developers.comजानकारीपूर्ण हैं। यहाँ नीदरलैंड में एक G1 है , आप देख सकते हैं कि ro.build.tagsऐसा नहीं है test-keys, और मुझे लगता है कि शायद उपयोग करने के लिए सबसे विश्वसनीय संपत्ति है।


यह दिलचस्प लग रहा है, लेकिन: जबकि एमुलेटर (और ADP) रूट प्रति se की अनुमति देते हैं, वे अनुप्रयोगों को इसका उपयोग करने की अनुमति नहीं देते हैं, अर्थात: $ su app_29 $ su su: uid 10029 su
miracle2k के

आह, मुझे लगता है कि वे ऐसा नहीं करेंगे ... आप इसे google.com में समाप्त होने वाले ro.build.host (नहीं) के लिए एक चेक के साथ जोड़ सकते हैं, अगर वे केवल वही हैं जिनके पास परीक्षण-कुंजी हैं, लेकिन बिना su उपयोगकर्ता पूछ रहा है। निर्भर करता है कि बिल्ड होस्ट नए उपकरणों के लिए है, जो चीजें फोन नहीं हैं ... आसान नहीं है।
क्रिस बॉयल

11

RootBeer स्कॉट और मैथ्यू द्वारा एक एंड्रॉइड लाइब्रेरी की जड़ की जाँच है। यह इंगित करने के लिए विभिन्न जांचों का उपयोग करता है कि डिवाइस निहित है या नहीं।

जावा जाँच

  • CheckRootManagementApps

  • CheckPotentiallyDangerousAppss

  • CheckRootCloakingApps

  • CheckTestKeys

  • checkForDangerousProps

  • checkForBusyBoxBinary

  • checkForSuBinary

  • checkSuExists

  • checkForRWSystem

देशी जाँच

हम अपने मूल रूट चेकर के माध्यम से कॉल करते हैं यह कुछ स्वयं की जांच चलाने के लिए है। नेटिव चेक आमतौर पर क्लोक करने के लिए कठिन होते हैं, इसलिए कुछ रूट क्लोक ऐप केवल मूल पुस्तकालयों के लोडिंग को अवरुद्ध करते हैं जिनमें कुछ प्रमुख शब्द होते हैं।

  • checkForSuBinary

8

मैं मूल पता लगाने के लिए मूल कोड का उपयोग करने का सुझाव देता हूं। यहाँ एक पूर्ण कार्य उदाहरण है

यहां छवि विवरण दर्ज करें

जावा आवरण :

package com.kozhevin.rootchecks.util;


import android.support.annotation.NonNull;

import com.kozhevin.rootchecks.BuildConfig;

public class MeatGrinder {
    private final static String LIB_NAME = "native-lib";
    private static boolean isLoaded;
    private static boolean isUnderTest = false;

    private MeatGrinder() {

    }

    public boolean isLibraryLoaded() {
        if (isLoaded) {
            return true;
        }
        try {
            if(isUnderTest) {
                throw new UnsatisfiedLinkError("under test");
            }
            System.loadLibrary(LIB_NAME);
            isLoaded = true;
        } catch (UnsatisfiedLinkError e) {
            if (BuildConfig.DEBUG) {
                e.printStackTrace();
            }
        }
        return isLoaded;
    }

    public native boolean isDetectedDevKeys();

    public native boolean isDetectedTestKeys();

    public native boolean isNotFoundReleaseKeys();

    public native boolean isFoundDangerousProps();

    public native boolean isPermissiveSelinux();

    public native boolean isSuExists();

    public native boolean isAccessedSuperuserApk();

    public native boolean isFoundSuBinary();

    public native boolean isFoundBusyboxBinary();

    public native boolean isFoundXposed();

    public native boolean isFoundResetprop();

    public native boolean isFoundWrongPathPermission();

    public native boolean isFoundHooks();

    @NonNull
    public static MeatGrinder getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private static class InstanceHolder {
        private static final MeatGrinder INSTANCE = new MeatGrinder();
    }
}

जेएनआई आवरण (मूल- lib.c) :

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isDetectedTestKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isDetectedTestKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isDetectedDevKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isDetectedDevKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isNotFoundReleaseKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isNotFoundReleaseKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundDangerousProps(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundDangerousProps();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isPermissiveSelinux(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isPermissiveSelinux();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isSuExists(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isSuExists();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isAccessedSuperuserApk(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isAccessedSuperuserApk();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundSuBinary(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundSuBinary();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundBusyboxBinary(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundBusyboxBinary();
}


JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundXposed(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundXposed();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundResetprop(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundResetprop();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundWrongPathPermission(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundWrongPathPermission();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundHooks(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundHooks();
}

स्थिरांक:

// Comma-separated tags describing the build, like= "unsigned,debug".
const char *const ANDROID_OS_BUILD_TAGS = "ro.build.tags";

// A string that uniquely identifies this build. 'BRAND/PRODUCT/DEVICE:RELEASE/ID/VERSION.INCREMENTAL:TYPE/TAGS'.
const char *const ANDROID_OS_BUILD_FINGERPRINT = "ro.build.fingerprint";

const char *const ANDROID_OS_SECURE = "ro.secure";

const char *const ANDROID_OS_DEBUGGABLE = "ro.debuggable";
const char *const ANDROID_OS_SYS_INITD = "sys.initd";
const char *const ANDROID_OS_BUILD_SELINUX = "ro.build.selinux";
//see https://android.googlesource.com/platform/system/core/+/master/adb/services.cpp#86
const char *const SERVICE_ADB_ROOT = "service.adb.root";

const char * const MG_SU_PATH[] = {
        "/data/local/",
        "/data/local/bin/",
        "/data/local/xbin/",
        "/sbin/",
        "/system/bin/",
        "/system/bin/.ext/",
        "/system/bin/failsafe/",
        "/system/sd/xbin/",
        "/su/xbin/",
        "/su/bin/",
        "/magisk/.core/bin/",
        "/system/usr/we-need-root/",
        "/system/xbin/",
        0
};

const char * const MG_EXPOSED_FILES[] = {
        "/system/lib/libxposed_art.so",
        "/system/lib64/libxposed_art.so",
        "/system/xposed.prop",
        "/cache/recovery/xposed.zip",
        "/system/framework/XposedBridge.jar",
        "/system/bin/app_process64_xposed",
        "/system/bin/app_process32_xposed",
        "/magisk/xposed/system/lib/libsigchain.so",
        "/magisk/xposed/system/lib/libart.so",
        "/magisk/xposed/system/lib/libart-disassembler.so",
        "/magisk/xposed/system/lib/libart-compiler.so",
        "/system/bin/app_process32_orig",
        "/system/bin/app_process64_orig",
        0
};

const char * const MG_READ_ONLY_PATH[] = {
        "/system",
        "/system/bin",
        "/system/sbin",
        "/system/xbin",
        "/vendor/bin",
        "/sbin",
        "/etc",
        0
};

देशी कोड से रूट डिटेल:

struct mntent *getMntent(FILE *fp, struct mntent *e, char *buf, int buf_len) {

    while (fgets(buf, buf_len, fp) != NULL) {
        // Entries look like "/dev/block/vda /system ext4 ro,seclabel,relatime,data=ordered 0 0".
        // That is: mnt_fsname mnt_dir mnt_type mnt_opts mnt_freq mnt_passno.
        int fsname0, fsname1, dir0, dir1, type0, type1, opts0, opts1;
        if (sscanf(buf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
                   &fsname0, &fsname1, &dir0, &dir1, &type0, &type1, &opts0, &opts1,
                   &e->mnt_freq, &e->mnt_passno) == 2) {
            e->mnt_fsname = &buf[fsname0];
            buf[fsname1] = '\0';
            e->mnt_dir = &buf[dir0];
            buf[dir1] = '\0';
            e->mnt_type = &buf[type0];
            buf[type1] = '\0';
            e->mnt_opts = &buf[opts0];
            buf[opts1] = '\0';
            return e;
        }
    }
    return NULL;
}


bool isPresentMntOpt(const struct mntent *pMnt, const char *pOpt) {
    char *token = pMnt->mnt_opts;
    const char *end = pMnt->mnt_opts + strlen(pMnt->mnt_opts);
    const size_t optLen = strlen(pOpt);
    while (token != NULL) {
        const char *tokenEnd = token + optLen;
        if (tokenEnd > end) break;
        if (memcmp(token, pOpt, optLen) == 0 &&
            (*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) {
            return true;
        }
        token = strchr(token, ',');
        if (token != NULL) {
            token++;
        }
    }
    return false;
}

static char *concat2str(const char *pString1, const char *pString2) {
    char *result;
    size_t lengthBuffer = 0;

    lengthBuffer = strlen(pString1) +
                   strlen(pString2) + 1;
    result = malloc(lengthBuffer);
    if (result == NULL) {
        GR_LOGW("malloc failed\n");
        return NULL;
    }
    memset(result, 0, lengthBuffer);
    strcpy(result, pString1);
    strcat(result, pString2);
    return result;
}

static bool
isBadPropertyState(const char *key, const char *badValue, bool isObligatoryProperty, bool isExact) {
    if (badValue == NULL) {
        GR_LOGE("badValue may not be NULL");
        return false;
    }
    if (key == NULL) {
        GR_LOGE("key may not be NULL");
        return false;
    }
    char value[PROP_VALUE_MAX + 1];
    int length = __system_property_get(key, value);
    bool result = false;
    /* A length 0 value indicates that the property is not defined */
    if (length > 0) {
        GR_LOGI("property:[%s]==[%s]", key, value);
        if (isExact) {
            if (strcmp(value, badValue) == 0) {
                GR_LOGW("bad value[%s] equals to [%s] in the property [%s]", value, badValue, key);
                result = true;
            }
        } else {
            if (strlen(value) >= strlen(badValue) && strstr(value, badValue) != NULL) {
                GR_LOGW("bad value[%s] found in [%s] in the property [%s]", value, badValue, key);
                result = true;
            }
        }
    } else {
        GR_LOGI("[%s] property not found", key);
        if (isObligatoryProperty) {
            result = true;
        }
    }
    return result;
}

bool isDetectedTestKeys() {
    const char *TEST_KEYS_VALUE = "test-keys";
    return isBadPropertyState(ANDROID_OS_BUILD_TAGS, TEST_KEYS_VALUE, true, false);
}

bool isDetectedDevKeys() {
    const char *DEV_KEYS_VALUE = "dev-keys";
    return isBadPropertyState(ANDROID_OS_BUILD_TAGS, DEV_KEYS_VALUE, true, false);
}

bool isNotFoundReleaseKeys() {
    const char *RELEASE_KEYS_VALUE = "release-keys";
    return !isBadPropertyState(ANDROID_OS_BUILD_TAGS, RELEASE_KEYS_VALUE, false, true);
}

bool isFoundWrongPathPermission() {

    bool result = false;
    FILE *file = fopen("/proc/mounts", "r");
    char mntent_strings[BUFSIZ];
    if (file == NULL) {
        GR_LOGE("setmntent");
        return result;
    }

    struct mntent ent = {0};
    while (NULL != getMntent(file, &ent, mntent_strings, sizeof(mntent_strings))) {
        for (size_t i = 0; MG_READ_ONLY_PATH[i]; i++) {
            if (strcmp((&ent)->mnt_dir, MG_READ_ONLY_PATH[i]) == 0 &&
                isPresentMntOpt(&ent, "rw")) {
                GR_LOGI("%s %s %s %s\n", (&ent)->mnt_fsname, (&ent)->mnt_dir, (&ent)->mnt_opts,
                        (&ent)->mnt_type);
                result = true;
                break;
            }
        }
        memset(&ent, 0, sizeof(ent));
    }
    fclose(file);
    return result;
}


bool isFoundDangerousProps() {
    const char *BAD_DEBUGGABLE_VALUE = "1";
    const char *BAD_SECURE_VALUE = "0";
    const char *BAD_SYS_INITD_VALUE = "1";
    const char *BAD_SERVICE_ADB_ROOT_VALUE = "1";

    bool result = isBadPropertyState(ANDROID_OS_DEBUGGABLE, BAD_DEBUGGABLE_VALUE, true, true) ||
                  isBadPropertyState(SERVICE_ADB_ROOT, BAD_SERVICE_ADB_ROOT_VALUE, false, true) ||
                  isBadPropertyState(ANDROID_OS_SECURE, BAD_SECURE_VALUE, true, true) ||
                  isBadPropertyState(ANDROID_OS_SYS_INITD, BAD_SYS_INITD_VALUE, false, true);

    return result;
}

bool isPermissiveSelinux() {
    const char *BAD_VALUE = "0";
    return isBadPropertyState(ANDROID_OS_BUILD_SELINUX, BAD_VALUE, false, false);
}

bool isSuExists() {
    char buf[BUFSIZ];
    char *str = NULL;
    char *temp = NULL;
    size_t size = 1;  // start with size of 1 to make room for null terminator
    size_t strlength;

    FILE *pipe = popen("which su", "r");
    if (pipe == NULL) {
        GR_LOGI("pipe is null");
        return false;
    }

    while (fgets(buf, sizeof(buf), pipe) != NULL) {
        strlength = strlen(buf);
        temp = realloc(str, size + strlength);  // allocate room for the buf that gets appended
        if (temp == NULL) {
            // allocation error
            GR_LOGE("Error (re)allocating memory");
            pclose(pipe);
            if (str != NULL) {
                free(str);
            }
            return false;
        } else {
            str = temp;
        }
        strcpy(str + size - 1, buf);
        size += strlength;
    }
    pclose(pipe);
    GR_LOGW("A size of the result from pipe is [%zu], result:\n [%s] ", size, str);
    if (str != NULL) {
        free(str);
    }
    return size > 1 ? true : false;
}

static bool isAccessedFile(const char *path) {
    int result = access(path, F_OK);
    GR_LOGV("[%s] has been accessed with result: [%d]", path, result);
    return result == 0 ? true : false;
}

static bool isFoundBinaryFromArray(const char *const *array, const char *binary) {
    for (size_t i = 0; array[i]; ++i) {
        char *checkedPath = concat2str(array[i], binary);
        if (checkedPath == NULL) { // malloc failed
            return false;
        }
        bool result = isAccessedFile(checkedPath);
        free(checkedPath);
        if (result) {
            return result;
        }
    }
    return false;
}

bool isAccessedSuperuserApk() {
    return isAccessedFile("/system/app/Superuser.apk");
}

bool isFoundResetprop() {
    return isAccessedFile("/data/magisk/resetprop");
}

bool isFoundSuBinary() {
    return isFoundBinaryFromArray(MG_SU_PATH, "su");
}

bool isFoundBusyboxBinary() {
    return isFoundBinaryFromArray(MG_SU_PATH, "busybox");
}

bool isFoundXposed() {
    for (size_t i = 0; MG_EXPOSED_FILES[i]; ++i) {
        bool result = isAccessedFile(MG_EXPOSED_FILES[i]);
        if (result) {
            return result;
        }
    }
    return false;
}

bool isFoundHooks() {
    bool result = false;
    pid_t pid = getpid();
    char maps_file_name[512];
    sprintf(maps_file_name, "/proc/%d/maps", pid);
    GR_LOGI("try to open [%s]", maps_file_name);
    const size_t line_size = BUFSIZ;
    char *line = malloc(line_size);
    if (line == NULL) {
        return result;
    }
    FILE *fp = fopen(maps_file_name, "r");
    if (fp == NULL) {
        free(line);
        return result;
    }
    memset(line, 0, line_size);
    const char *substrate = "com.saurik.substrate";
    const char *xposed = "XposedBridge.jar";
    while (fgets(line, line_size, fp) != NULL) {
        const size_t real_line_size = strlen(line);
        if ((real_line_size >= strlen(substrate) && strstr(line, substrate) != NULL) ||
            (real_line_size >= strlen(xposed) && strstr(line, xposed) != NULL)) {
            GR_LOGI("found in [%s]: [%s]", maps_file_name, line);
            result = true;
            break;
        }
    }
    free(line);
    fclose(fp);
    return result;
}

4
बहुत बढ़िया उपकरण, दिमा। बहुत बहुत धन्यवाद। यहां तक ​​कि यह मैजिक पकड़ता है।
विशेषज्ञ

यह एक वास्तविक डील है।
वाहिद अमीरी

@ कच्छ मेरी पोस्ट की पहली पंक्ति में काम करने के उदाहरण (github) का लिंक है
Dima Kozhevin

7

यहाँ कुछ उत्तरों के आधार पर मेरा कोड दिया गया है:

 /**
   * Checks if the phone is rooted.
   * 
   * @return <code>true</code> if the phone is rooted, <code>false</code>
   * otherwise.
   */
  public static boolean isPhoneRooted() {

    // get from build info
    String buildTags = android.os.Build.TAGS;
    if (buildTags != null && buildTags.contains("test-keys")) {
      return true;
    }

    // check if /system/app/Superuser.apk is present
    try {
      File file = new File("/system/app/Superuser.apk");
      if (file.exists()) {
        return true;
      }
    } catch (Throwable e1) {
      // ignore
    }

    return false;
  }

7

@Kevins उत्तर के आगे, मैंने हाल ही में उनके सिस्टम का उपयोग करते हुए पाया है, कि नेक्सस 7.1 falseसभी तीन तरीकों के लिए लौट रहा था - कोई whichआदेश, नहीं test-keysऔर SuperSUमें स्थापित नहीं था/system/app

मैंने इसे जोड़ा:

public static boolean checkRootMethod4(Context context) {
    return isPackageInstalled("eu.chainfire.supersu", context);     
}

private static boolean isPackageInstalled(String packagename, Context context) {
    PackageManager pm = context.getPackageManager();
    try {
        pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
        return true;
    } catch (NameNotFoundException e) {
        return false;
    }
}

यह थोड़ा कम है कुछ स्थितियों में उपयोगी है (यदि आपको रूट एक्सेस की गारंटी है) तो सुपरसु के लिए उन डिवाइसों पर स्थापित करना पूरी तरह संभव है जिनमें एसयू एक्सेस नहीं है।

हालाँकि, चूंकि सुपरएसयू को स्थापित करना और काम करना संभव है, लेकिन निर्देशिका में नहीं है /system/app, इसलिए यह अतिरिक्त मामला ऐसे मामलों को जड़ (हाहा) कर देगा।


यह एक अच्छा जवाब नहीं है क्योंकि आपके पास अन्य रूट पैकेज हैं जो आपके डिवाइस पर इंस्टॉल किए जा सकते हैं। हार्ड अन्य एप्लिकेशन संकुल कोडिंग कठोर होगा जैसा कि आप उम्मीद करते हैं और उन सभी की सूची नहीं कर सकते हैं
blueware

5
    public static boolean isRootAvailable(){
            Process p = null;
            try{
               p = Runtime.getRuntime().exec(new String[] {"su"});
               writeCommandToConsole(p,"exit 0");
               int result = p.waitFor();
               if(result != 0)
                   throw new Exception("Root check result with exit command " + result);
               return true;
            } catch (IOException e) {
                Log.e(LOG_TAG, "Su executable is not available ", e);
            } catch (Exception e) {
                Log.e(LOG_TAG, "Root is unavailable ", e);
            }finally {
                if(p != null)
                    p.destroy();
            }
            return false;
        }
 private static String writeCommandToConsole(Process proc, String command, boolean ignoreError) throws Exception{
            byte[] tmpArray = new byte[1024];
            proc.getOutputStream().write((command + "\n").getBytes());
            proc.getOutputStream().flush();
            int bytesRead = 0;
            if(proc.getErrorStream().available() > 0){
                if((bytesRead = proc.getErrorStream().read(tmpArray)) > 1){
                    Log.e(LOG_TAG,new String(tmpArray,0,bytesRead));
                    if(!ignoreError)
                        throw new Exception(new String(tmpArray,0,bytesRead));
                }
            }
            if(proc.getInputStream().available() > 0){
                bytesRead = proc.getInputStream().read(tmpArray);
                Log.i(LOG_TAG, new String(tmpArray,0,bytesRead));
            }
            return new String(tmpArray);
        }

4

दो अतिरिक्त विचार, यदि आप जांचना चाहते हैं कि क्या कोई डिवाइस आपके ऐप से रूट करने में सक्षम है:

  1. 'सु' बाइनरी के मौजूदा की जाँच करें: "सु" से "रन" करें Runtime.getRuntime().exec()
  2. /system/app/Superuser.apkस्थान में SuperUser.apk की तलाश करें

3

रूट के साथ C ++ का उपयोग करना रूट का पता लगाने के लिए सबसे अच्छा तरीका है, भले ही उपयोगकर्ता उन एप्लिकेशन का उपयोग कर रहा हो जो रूटकॉल जैसे अपने रूट को छिपाते हैं। मैंने रूट कोड के साथ इस कोड का परीक्षण किया और मैं रूट का पता लगाने में सक्षम था, भले ही उपयोगकर्ता इसे छिपाने की कोशिश कर रहा हो। तो आपकी cpp फाइल चाहेगी:

#include <jni.h>
#include <string>


/**
 *
 * function that checks for the su binary files and operates even if 
 * root cloak is installed
 * @return integer 1: device is rooted, 0: device is not 
 *rooted
*/
extern "C"
JNIEXPORT int JNICALL


Java_com_example_user_root_1native_rootFunction(JNIEnv *env,jobject thiz){
const char *paths[] ={"/system/app/Superuser.apk", "/sbin/su", "/system/bin/su",
                      "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
                      "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};

int counter =0;
while (counter<9){
    if(FILE *file = fopen(paths[counter],"r")){
        fclose(file);
        return 1;
    }
    counter++;
}
return 0;
}

और आप अपने जावा कोड से फ़ंक्शन को निम्नानुसार कॉल करेंगे

public class Root_detect {



   /**
    *
    * function that calls a native function to check if the device is 
    *rooted or not
    * @return boolean: true if the device is rooted, false if the 
    *device is not rooted
   */
   public boolean check_rooted(){

        int checker = rootFunction();

        if(checker==1){
           return true;
        }else {
           return false;
        }
   }
   static {
    System.loadLibrary("cpp-root-lib");//name of your cpp file
   }

   public native int rootFunction();
}

1
if [[ "`adb shell which su | grep -io "permission denied"`" != "permission denied" ]]; then
   echo "Yes. Rooted device."
 else
   echo "No. Device not rooted. Only limited tasks can be performed. Done."
    zenity --warning --title="Device Not Rooted" --text="The connected Android Device is <b>NOT ROOTED</b>. Only limited tasks can be performed." --no-wrap
fi

1

नहीं है सेफ्टी नेट सत्यापन एपीआई के लिए Google Play सेवाओं है जिसके द्वारा हम डिवाइस का आकलन करने और यह निर्धारित करता है, तो यह है निहित / छेड़छाड़ कर सकते हैं।

कृपया रूट किए गए उपकरणों से निपटने के लिए मेरे उत्तर पर जाएं :
https://stackoverflow.com/a/58304556/3908895


1

रूट ऐप्स और su binaries का पता लगाने वाले सभी को भूल जाओ। रूट डेमॉन प्रक्रिया के लिए जाँच करें। यह टर्मिनल से किया जा सकता है और आप एक ऐप के भीतर टर्मिनल कमांड चला सकते हैं। इस एक-लाइनर की कोशिश करें।

if [ ! -z "$(/system/bin/ps -A | grep -v grep | grep -c daemonsu)" ]; then echo "device is rooted"; else echo "device is not rooted"; fi

इसे प्राप्त करने के लिए आपको रूट अनुमति की आवश्यकता नहीं है।


0

वास्तव में यह दिलचस्प सवाल है और अब तक किसी ने पुरस्कार के हकदार नहीं हैं। मैं निम्नलिखित कोड का उपयोग करता हूं:

  boolean isRooted() {
      try {
                ServerSocket ss = new ServerSocket(81);
                ss.close();
                                    return true;
            } catch (Exception e) {
                // not sure
            }
    return false;
  }

कोड निश्चित रूप से बुलेटप्रूफ नहीं है, क्योंकि नेटवर्क उपलब्ध नहीं हो सकता है इसलिए आपको एक अपवाद मिलता है। अगर यह तरीका सही है तो 99% आप सुनिश्चित हो सकते हैं, अन्यथा सिर्फ 50%। नेटवर्किंग की अनुमति भी समाधान को खराब कर सकती है।


मैंने इसका परीक्षण किया और यह मेरे मूल डिवाइस के साथ सही नहीं है।
छल विज्ञान

यह देखना दिलचस्प है कि आपको किस तरह का अपवाद मिलता है। आपको पोर्ट पहले से ही अपवाद मिल सकता है, हालांकि यदि आप 1024 के तहत सीमा में सर्वर पोर्ट नहीं बना सकते हैं, तो इससे रूटिंग का मान घट जाता है, क्योंकि अभी भी आपकी कुछ सीमाएँ हैं।
० .:

-1

रूटबॉक्स में मेरे पुस्तकालय का उपयोग करना , यह बहुत आसान है। नीचे दिए गए आवश्यक कोड की जाँच करें:

    //Pass true to <Shell>.start(...) call to run as superuser
    Shell shell = null;
    try {
            shell = Shell.start(true);
    } catch (IOException exception) {
            exception.printStackTrace();
    }
    if (shell == null)
            // We failed to execute su binary
            return;
    if (shell.isRoot()) {
            // Verified running as uid 0 (root), can continue with commands
            ...
    } else
            throw Exception("Unable to gain root access. Make sure you pressed Allow/Grant in superuser prompt.");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.