Köklü bir cihazda çalışıp çalışmadığını belirleme


292

Uygulamamın yalnızca root'un bulunduğu bir cihazda çalışacak belirli bir işlevi var. Bu özelliğin kullanıldığında başarısız olması (ve daha sonra kullanıcıya uygun bir hata mesajı göstermesi) yerine, önce kökün kullanılabilir olup olmadığını sessizce kontrol etmeyi ve değilse, ilgili seçenekleri ilk etapta gizlemeyi tercih ederim. .

Bunu yapmanın bir yolu var mı?


11
Bunu yapmanın güvenilir bir yolu yoktur; aşağıdaki cevaplar ortak özellikleri kontrol eder, ancak belirli bir cihaz ortak bir şekilde köklenmemiş olabilir. Kök kontrolü yaygınlaşırsa, kök çözümleri muhtemelen kendilerini gizleme çabasına girecektir. İşletim sistemi davranışını değiştirebildikleri için bunu yapmak için birçok seçenek vardır.
Chris Stratton

Uygulamanın genel deneyime belirsizlik ekleyerek yeteneklerini gizlemek yerine kullanıcıya daha fazla bilgi sağlayan kök yeteneğinin olmaması nedeniyle işlevin kullanılabilir olmadığını belirtmek daha iyi olabilir.
nick fox

Aşağıdaki cevaplar Sistemsiz Kök için işe yarıyor mu?
Piyush Kukadiya

Yanıtlar:


260

İşte Root'un üç yolundan birini kontrol edecek bir sınıf.

/** @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
İki soru aynı cevapları garanti ediyorsa, zaman kopyalarının% 99'udır, bu nedenle her ikisinde de aynı cevabı göndermek yerine dupes olarak işaretleyin. Teşekkürler.
Kev

2
Öyle olabilir, ancak size tam yinelenen cevapların topluluk tarafından işaretlendiğini bildiriyorum . Yanıtlarınızı uyarlamalı ve OP sorununun özelliklerini ele almalısınız. Kopyalama ve yapıştırma cevapları downvotes çekmek için risk altındadır.
Kev

9
-1, bu yöntem geçerli değildir, çünkü bazı telefonlar suköklü olmasa da ikili içerir .
neevek

12
Sadece size bildirmek istedim, Fox Digital Copy (Beta) uygulaması, Root ve ExecShell sınıfları ve checkRootMethod1 / 2/3 yöntemleri de dahil olmak üzere kodunuzu neredeyse kelimesi kelimesine kullanır. Son derece eğlenceli buldum.
Matt Joseph

8
Onlara Fox'un sayısız başkasına dava açmış gibi dava açabilir miyim?
Kevin Parker

59

Zaten Fabric / Firebase Crashlytics kullanıyorsanız arayabilirsiniz

CommonUtils.isRooted(context)

Bu yöntemin şu anki uygulamasıdır:

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

En iyi cevap. Lütfen bunu herhangi bir kütüphane üzerinde kullanın, Çin cihazlarında çok sayıda yanlış pozitif çalışma var.
Pedro Paulo Amorim

Bu yöntemde yanlış pozitif var mı?
Ehsan Mashhadi

Bunu nexus 5'te download.chainfire.eu/363/CF-Root/CF-Auto-Root/… ile test ettim , bu doğru değil.
Jeffrey Liu

54

RootTools kütüphanesi kökü kontrol etmek için basit yöntemler sunar:

RootTools.isRootAvailable()

Referans


10
isRootAvailable () sadece yoldaki su ve diğer sabit kodlu dizinlerin varlığını kontrol eder. Bazı köklenmemiş araçların orada su bırakacağını duydum, bu da yanlış bir pozitif verecek.
Bob Whiteman

13
RootTools.isAccessGiven () sadece root kontrolü yapmakla kalmayacak, aynı zamanda root izni isteyecektir; böylece köklenmemiş bir cihaz bu yöntemle her zaman false değerini döndürür.
aggregate1166877

2
@ aggregate1166877, haklısın, ama yeterince iyi değil, sorduğumda root iznine ihtiyacım yoksa ne olacak? Sadece köklü olup olmadığını bilmek istiyorum, ama şu anda kök iznine ihtiyacım yok.
neevek

4
isAccessGiven (), cihaz köklü olmasına rağmen kullanıcı izni reddettiğinde false değerini döndürür.
subair_a

Oylamaya değer bulduğum tek cevap bu. Sadece kopyala yapıştırmaya benzer bir şey istiyorsanız veya daha fazla ayrıntı istiyorsanız, aşağıdaki cevabımı kontrol edin
rsimp

52

Uygulamamda "su" komutunu kullanarak cihazın köklü olup olmadığını kontrol ediyordum. Ama bugün kodumun bu kısmını kaldırdım. Neden?

Çünkü uygulamam bir bellek katili oldu. Nasıl? Sana hikayemi anlatayım.

Uygulamamın cihazları yavaşlattığına dair bazı şikayetler vardı (Tabii ki bunun doğru olamayacağını düşündüm). Nedenini anlamaya çalıştım. Bu yüzden MAT'ı yığın yığınları almak ve analiz etmek için kullandım ve her şey mükemmel görünüyordu. Ancak uygulamamı birçok kez yeniden başlattıktan sonra cihazın gerçekten yavaşladığını fark ettim ve uygulamamı durdurmak daha hızlı yapmadı (cihazı yeniden başlatmadıkça). Cihaz çok yavaşken döküm dosyalarını tekrar analiz ettim. Ancak her şey döküm dosyası için mükemmeldi. Sonra ilk başta yapılması gerekeni yaptım. İşlemleri listeledim.

$ adb shell ps

surprize; uygulamam için birçok işlem vardı (uygulamamın işlem etiketi manifestodayken). Bazıları zombi, bazıları değil.

Tek bir Aktiviteye sahip ve sadece "su" komutunu uygulayan örnek bir uygulama ile uygulamanın her lansmanında bir zombi sürecinin yaratıldığını fark ettim. İlk başta bu zombiler 0KB ayırır, ancak bir şey olur ve zombi süreçleri uygulamamın ana süreci ile neredeyse aynı KB'leri tutuyor ve standart süreçler haline geliyorlar.

Bugs.sun.com'da aynı sorun için bir hata raporu var: http://bugs.sun.com/view_bug.do?bug_id=6474073 Bu komut bulunmazsa exec () yöntemiyle zombiler oluşturulacak . Ama yine de neden ve nasıl standart süreçler haline gelebildiklerini ve önemli KB'leri tutabileceklerini anlamıyorum. (Bu her zaman olmuyor)

Aşağıdaki kod örneği ile isterseniz deneyebilirsiniz;

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

Basit komut yürütme yöntemi;

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) {
            }
        }
    }
}

Sonuç olarak; Cihazın köklü olup olmadığını belirlemeniz için tavsiyem yok. Ama ben olsaydım Runtime.getRuntime (). Exec () kullanmazdım.

Bu arada; RootTools.isRootAvailable () aynı soruna neden olur.


5
Bu çok endişe verici. Aynı şeyi yapan köklü bir cihaz algılama sınıfım vardı - bunu okuduktan sonra yukarıda ayrıntılı olarak ne aegean doğruladı. Ara sıra zombi süreçleri geride bırakılıyor, cihaz yavaşlıyor, vb ...
AWT

1
GT-S5830i android 2.3.6'da RootTools 3.4 ile ilgili sorunu onaylıyorum. Zombi çoğu bellek ayırdı ve sorun sistematik. 3-4 testinden sonra cihazı yeniden başlatmam gerekiyor. Test sonucunu paylaşılan tercihe kaydetmenizi tavsiye ederim.
Mesih

2
Google artık ProcessBuilder () ve start () komutunun kullanılmasını önermektedir .
EntangledLoops

1
@NickS İlginç, ama hangi komutu başlattınız? Burada 9 - 23 arasında farklı API düzeylerine sahip çok sayıda Android telefonunda komutlar vermekle aynı sorunum yok
EntangledLoops

1
@EntangledLoops. Teşekkür ederim. Ben kendi ikili başlatmak ve stdin / stdout üzerinden onunla etkileşim. Nasıl durdurduğumu tekrar kontrol ettim ve bir durumda Process.destroy () yöntemini kaçırdığımı öğrendim. Yani, zombiler yok.
Nick S

37

Burada listelenen cevapların çoğunun doğal sorunları vardır:

  • Test anahtarlarını kontrol etmek kök erişimi ile ilişkilidir, ancak mutlaka garanti vermez
  • "PATH" dizinleri sabit kodlanmak yerine gerçek "PATH" ortam değişkeninden türetilmelidir
  • "Su" yürütülebilir dosyasının varlığı, cihazın köklü olduğu anlamına gelmez
  • "Hangi" yürütülebilir dosya yüklenebilir veya yüklenmeyebilir ve sistemin mümkünse yolunu çözmesine izin vermelisiniz
  • SuperUser uygulaması cihaza yüklendiğinde, cihazın henüz root erişimi olduğu anlamına gelmez

RootTools Stericson gelen kütüphane daha meşru root kontrol gibi görünüyor. Ayrıca çok fazla araç ve yardımcı programları vardır, bu yüzden kesinlikle tavsiye ederim. Bununla birlikte, özellikle kökleri nasıl kontrol ettiğine dair bir açıklama yoktur ve çoğu uygulamanın gerçekten ihtiyaç duyduğundan biraz daha ağır olabilir.

RootTools kütüphanesine dayanan birkaç yardımcı yöntem yaptım. Cihazda "su" yürütülebilir dosyasının olup olmadığını kontrol etmek istiyorsanız, aşağıdaki yöntemi kullanabilirsiniz:

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

Bu yöntem basitçe "PATH" ortam değişkeninde listelenen dizinler arasında dolaşır ve bunlardan birinde "su" dosyasının olup olmadığını kontrol eder.

Kök erişimini gerçekten kontrol etmek için "su" komutunun gerçekten çalıştırılması gerekir. SuperUser gibi bir uygulama yüklüyse, bu noktada root erişimi isteyebilir veya zaten verilmişse / reddedilmişse, erişimin verilip verilmediğini / reddedildiğini gösteren bir tost gösterilebilir. Çalıştırmak için iyi bir komut "id" dir, böylece kullanıcı kimliğinin aslında 0 (root) olduğunu doğrulayabilirsiniz.

Kök erişim izni verilip verilmediğini belirlemek için örnek bir yöntem:

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

Bazı emülatörlerde önceden yüklenmiş "su" yürütülebilir dosyası bulunduğundan "su" komutunu çalıştırmayı test etmek önemlidir, ancak yalnızca belirli kullanıcıların adb kabuğu gibi erişmesine izin verir.

Ayrıca, çalıştırmaya çalışmadan önce "su" yürütülebilir dosyasının varlığını kontrol etmek de önemlidir, çünkü android eksik komutları çalıştırmaya çalışan işlemleri düzgün bir şekilde atmadığı bilinmektedir. Bu hayalet süreçleri zaman içinde bellek tüketimini azaltabilir.


İsRootAvailable () yöntemi harika çalışıyor, teşekkür ederim. Ancak bir AsyncTask
Thunderstick

1
Bence, kökün mevcut olmamasını istemek ve olmasını sağlamak istemek arasındaki fark. Bir cihazın köklü olmadığından emin olmak istiyorsanız, önerilen kontroller iyidir. Yanlış pozitifler alacaksınız, ancak kodunuzu güvenliği ihlal edilmiş bir cihazda çalıştırmadığınız zaman sorun değil.
Jeffrey Blattman

1
@ DAC84 Sorunuzu anladığımdan emin değilim. İsRootGiven komutunu çalıştırırsanız ve kök uygulamanızda reddederseniz, false döndürmelidir. Olan bu değil mi? Uyarıyı önlemek istiyorsanız, isSoxxA olarak da adlandırılabilen isRootAvailable'ı kullanabilirsiniz. Kök uygulamanızı kökten özgürce vermek ve yönetmemek için yapılandırmayı da deneyebilirsiniz.
rsimp

1
@BeeingJk hayır gerçekten değil, ancak gerçek test olan su çalıştırmadan kontrol edebileceğiniz en çok şey bu. Yine de yürütmeye çalışmadan önce PATH'de su için kontrol etmeniz gerekir. Ancak aslında su'nun çalıştırılması genellikle bir tost mesajına veya istediğiniz bir şey olmayabilir bir kök yönetim uygulamasıyla etkileşime neden olur. Kendi mantığınız için sadece su varlığını yeterli bulabilirsiniz. Bu yine de bazı emülatörlerde su yürütülebilir ama kilitlemeli erişim içerebilecek yanlış pozitifler verebilir.
rsimp

1
@BeeingJk isRootAvailable muhtemelen ihtiyacınız olan tek şeydir, ancak yapmaya çalıştığım nokta, böyle bir adın veya doesSUExist'in, isDeviceRooted gibi bir yöntem adından daha doğru anlamsızlık sağlamasıdır. Devam etmeden önce tam kök erişimini doğrulamanız gerekiyorsa, isRootGiven kodlu gibi su ile bir komut çalıştırmayı denemelisiniz
rsimp

35

2017 Güncellemesi

Şimdi bunu Google Safetynet API'sı ile yapabilirsiniz . SafetyNet API, uygulamalarınızın çalıştığı Android ortamlarının güvenliğini ve uyumluluğunu değerlendirmenize yardımcı olan Onay API'sı sağlar.

Bu tasdik, belirli bir cihazın kurcalanıp değiştirilmediğini veya başka bir şekilde değiştirilip değiştirilmediğini belirlemeye yardımcı olabilir.

Tasdik API'sı aşağıdaki gibi bir JWS yanıtı döndürür

{
  "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,
}

Bu yanıtı ayrıştırmak, cihazın köklü olup olmadığını belirlemenize yardımcı olabilir

Köklü aygıtlar ctsProfileMatch = false'a neden oluyor gibi görünüyor.

İstemci tarafında yapabilirsiniz, ancak sunucu tarafında yanıt ayrıştırma önerilir. Güvenlik ağı API'sine sahip temel bir istemci sunucusu mimarisi şöyle görünecektir:

resim açıklamasını buraya girin


3
Mükemmel bilgi ve farklı bir bağlamda bunun doğru cevap olacağına inanıyorum. Ne yazık ki OPs sorusu, uygulamasını güvenli olmayan ortamlardan korumakla ilgili değil, uygulamasında yalnızca kök özellikleri etkinleştirmek için kökleri algılamakla ilgilidir. OP'lerin amaçladığı amaç için bu süreç aşırı karmaşık görünüyor.
rsimp

31

Java düzeyinde kök kontrolü güvenli bir çözüm değildir. Uygulamanızın Köklü bir cihazda çalıştırılacak Güvenlik Endişeleri varsa, lütfen bu çözümü kullanın.

Telefonun RootCloak gibi bir uygulaması yoksa Kevin'in cevabı işe yarar. Telefon köklendikten sonra bu tür uygulamaların Java API'ları üzerinde bir Kulpu vardır ve telefonu döndürmek için bu API'ları alay ederler.

Kevin'in cevabına göre yerel seviye kodu yazdım, RootCloak ile bile çalışıyor! Ayrıca bellek sızıntısı sorunlarına neden olmaz.

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

}

Java kodunuzda, yerel aramalar yapmak için RootUtils sarmalayıcı sınıfı oluşturmanız gerekir

    public boolean checkRooted() {

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

1
Kök algılamanın iki kategoriye ayrıldığını ve köklü telefonların güvenlik sorunlarını azaltmaya çalışmak için köke bağlı özelliklerin ve daha sonra güvenlik tabanlı önlemlerin alındığını düşünüyorum. Kök bağımlı özellikler için Kevin'in cevabının oldukça zayıf olduğunu düşünüyorum. Bu cevap bağlamında bu yöntemler daha anlamlı. Her ne kadar ben kullanmak için yöntem 2 yeniden yazmak ve bunun yerine "su" aramak için PATH ortam değişkeni üzerinde yineleme. "hangisinin" telefonda olduğu garanti edilmez.
rsimp

java'da bu c kodunun nasıl kullanılacağına ilişkin bir örnek verebilir misiniz?
17'de

@mrid Lütfen Android'de Java'dan JNI çağrılarının nasıl yapılacağını kontrol edin.
Alok Kulkarni

Bu yöntem, RootCloak uygulamasını kullanarak kök algılama byepassını önler. Bu yöntemde başarısız olan bilinen bir kök byepass tekniği var mı?
Nidhin

20

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

Jar dosyasını kullanmak istemiyorsanız sadece kodu kullanın:

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

Program su klasörünü bulmaya çalışacaktır:

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

Misal:

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

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

Teşekkürler! Bunu Kevin's AnswercheckRootMethod4() ile kullanıyorum .
2015'te Sheharyar

1
Asla == truebir boole eklemeyin , hiçbir şey eklemez ve iyi görünmez.
minipif

2
@smoothBlue Neden olsun ki? DevrimTuncer'in çözümü olduğu gibi herhangi bir Süreç üretmemektedir.
FD_

1
Daha iyi bir fikir, tipik PATH dizinlerini sabit kodlamak yerine
PATH'yi

1
Kullanın, if (isRooted())açıkça doğru yazmak yerine denetleyin. Kod yazma kalıplarını takip etmek daha iyi
blueware

13

İsRootAvailable () kullanmak yerine isAccessGiven () kullanabilirsiniz. Doğrudan RootTools wiki'sinden :

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

RootTools.isAccessGiven () yalnızca bir cihazın köklü olup olmadığını kontrol etmekle kalmaz, aynı zamanda uygulamanız için su çağırır, izin ister ve uygulamanıza kök izinleri başarıyla verildiyse true değerini döndürür. Bu, ihtiyaç duyduğunuzda size erişim verileceğinden emin olmak için uygulamanızdaki ilk kontrol olarak kullanılabilir.

Referans


ama kullanıcı root erişimi vermek zorunda değil mi? bu yüzden amacım cihaz köklü ise uygulamamın çalışmasını durdurmak olsaydı seçeneklerim gerçekten sınırlı
Nasz Njoka Sr.

11

Bu amaçla sistem özelliğini ayarlamak için kullanılan bazı değiştirilmiş derlemeler ro.modversion. Her şey yolunda gidiyor gibi görünüyor; TheDude'dan birkaç ay önce yaptığım yapıda şunlar var:

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]

Öte yandan 1.5 SDK'dan gelen emülatör, 1.5 görüntüyü çalıştırıyor, ayrıca kökü var, muhtemelen Android Dev Phone 1'e (muhtemelen izin vermek istediğiniz) benziyor ve buna sahip:

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]

Perakende yapılara gelince, elimde bir tane yok, ancak altında çeşitli aramalar site:xda-developers.combilgilendirici. İşte Hollanda'da bir G1, bununro.build.tags olmadığını görebilirsiniz test-keysve bence bu muhtemelen en güvenilir özelliktir.


Bu ilginç görünüyor, ancak: Emülatör (ve ADP) kendi başına root'a izin verirken, uygulamaların bunu kullanmasına izin vermezler, yani: $ su app_29 $ su su: uid 10029 su için izin verilmiyor
miracle2k

Ah, sanırım ... google.com ile biten ro.build.host (değil) için bir çekle birleştirebilirsin, eğer test anahtarları olan ancak su olmadan bloke ettiler kullanıcıya soruyor. Yapılandırma ana makinesinin yeni cihazlar için ne olduğuna, telefon olmayan şeylere bağlı ... kolay değil.
Chris Boyle

11

RootBeer , Scott ve Matthew tarafından kök kontrolü yapan bir Android kütüphanesidir. Cihazın köklü olup olmadığını belirtmek için çeşitli kontroller kullanır.

Java kontrolleri

  • CheckRootManagementApps

  • CheckPotentiallyDangerousAppss

  • CheckRootCloakingApps

  • CheckTestKeys

  • checkForDangerousProps

  • checkForBusyBoxBinary

  • checkForSuBinary

  • checkSuExists

  • checkForRWSystem

Yerel kontroller

Kendi kontrollerini yapmak için yerel kök denetleyicimizi çağırıyoruz. Yerel denetimlerin gizlenmesi genellikle daha zordur, bu nedenle bazı kök pelerin uygulamaları, belirli anahtar sözcükleri içeren yerel kitaplıkların yüklenmesini engeller.

  • checkForSuBinary

8

Kök tespiti için yerel kod kullanmanızı öneririm. İşte tam bir çalışma örneği .

resim açıklamasını buraya girin

JAVA sarıcı :

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

JNI sarmalayıcısı (native-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();
}

sabitler:

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

yerel koddan kök saptamaları:

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
Harika bir araç, Dima. Çok teşekkürler. Magisk'i bile yakalar.
uzman

Gerçek anlaşma bu.
Vahid Amiri

@klutch yazımın ilk satırında çalışma örneği (github) bağlantısı var
Dima Kozhevin

7

Kodum burada bazı cevaplara dayanmaktadır:

 /**
   * 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

Onun sistemini kullanırken Ayrıca @Kevins cevaba Geçenlerde Nexus 7.1 dönüyordu ki buldum falseher üç yöntemleri için - Hayır whichkomutu, hayır test-keysve SuperSUyüklü değildi/system/app .

Bunu ekledim:

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

Bu biraz daha azSuperSU'nun SU erişimi olmayan cihazlara yüklenmesi tamamen mümkün olduğundan, bu bazı durumlarda ( kök erişimine ihtiyacınız varsa) kullanışlıdır.

O olması mümkündür Ancak, SuperSu ve çalışma ama yüklü değil de /system/appdizine, bu ekstra durum irade kökü (haha) Bu gibi durumlarda dışarı.


Cihazınıza kurulabilecek diğer kök paketleriniz olduğu için bu iyi bir yanıt değildir. Diğer uygulama paketlerini zor kodlama, beklemediğiniz ve hepsini listelemediğiniz için sert olacaktır
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

Bir cihazın uygulamanızdan root yeteneğine sahip olup olmadığını kontrol etmek istiyorsanız iki ek fikir:

  1. 'Su' ikili dosyasının var olup olmadığını kontrol edin: Runtime.getRuntime().exec()
  2. İçinde SuperUser.apk arayın /system/app/Superuser.apkkonumu

3

Kullanıcı kökünü gizleyen RootCloak gibi uygulamaları kullanıyor olsa bile ndk ile C ++ kullanmak en iyi yöntemdir. RootCloak ile bu kodu test ettim ve kullanıcı gizlemeye çalışıyor olsa bile kök saptamayı başardım. Yani cpp dosyanız:

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

Ve java kodunuzdaki işlevi aşağıdaki gibi çağıracaksınız

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

Kök uygulamaları ve su ikili dosyalarını tespit eden tüm bunları unutun. Kök daemon sürecini kontrol edin. Bu terminalden yapılabilir ve bir uygulama içinde terminal komutlarını çalıştırabilirsiniz. Bu tek astarı deneyin.

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

Bunu başarmak için root iznine de ihtiyacınız yok.


0

Gerçekten ilginç bir soru ve şimdiye kadar hiç kimse ödülü hak etmedi. Aşağıdaki kodu kullanıyorum:

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

Kod kesinlikle kurşun geçirmez değildir, çünkü ağ kullanılamayabilir, bu nedenle bir istisna elde edersiniz. Bu yöntem true değerini döndürürse% 99'dan emin olabilirsiniz, aksi takdirde yalnızca% 50'si emin olmaz. Ağ oluşturma izni de çözümü bozabilir.


Bunu test ettim ve köklü cihazımla doğru dönmüyor.
tricknology

Ne tür bir istisna aldığınızı görmek ilginç. Bağlantı noktası zaten bağlı bir istisna alabilirsiniz, ancak 1024'ün altında aralıkta sunucu bağlantı noktası oluşturamazsanız, yine de belirli sınırlamalarınız olduğu için köklenme değerini azaltır.
Singagirl

-1

Kütüphanemi rootbox'ta kullanmak oldukça kolay. Aşağıdaki gerekli kodu kontrol edin:

    //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.");
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.