Tentukan apakah berjalan pada perangkat yang di-rooting

292

Aplikasi saya memiliki fungsionalitas tertentu yang hanya akan berfungsi pada perangkat di mana root tersedia. Daripada memiliki fitur ini gagal ketika digunakan (dan kemudian menunjukkan pesan kesalahan yang sesuai kepada pengguna), saya lebih suka kemampuan untuk memeriksa diam-diam apakah root tersedia terlebih dahulu, dan jika tidak, sembunyikan opsi masing-masing di tempat pertama. .

Apakah ada cara untuk melakukan ini?

miracle2k
sumber
11
Tidak ada cara yang dapat diandalkan untuk melakukannya; jawaban di bawah memeriksa karakteristik umum tetapi perangkat yang diberikan mungkin tidak di-rooting secara umum. Jika memeriksa root menjadi lazim, solusi root mungkin akan mulai berupaya menyembunyikan diri. Karena mereka dapat memodifikasi perilaku sistem operasi, mereka memiliki banyak pilihan untuk melakukannya.
Chris Stratton
Mungkin lebih baik untuk menunjukkan bahwa fungsi tersebut tidak tersedia karena kurangnya kapabilitas root yang memberikan lebih banyak informasi kepada pengguna daripada menyembunyikan kemampuan aplikasi Anda menambah ambiguitas pada pengalaman keseluruhan.
nick fox
Apakah jawaban di bawah ini berfungsi untuk Root Tanpa Sistem ?
Piyush Kukadiya

Jawaban:

260

Ini adalah kelas yang akan memeriksa Root salah satu dari tiga cara.

/** @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();
        }
    }
}
Kevin Parker
sumber
8
Jika dua pertanyaan menjamin jawaban yang sama, maka 99% dari waktu itu adalah duplikat, jadi tandai sebagai dupes alih-alih memposting jawaban yang sama pada keduanya. Terima kasih.
Kev
2
Mungkin memang begitu, namun saya hanya memberi tahu Anda bahwa jawaban duplikat yang tepat ditandai oleh komunitas. Anda harus menyesuaikan jawaban Anda dan mengatasi kekhasan masalah OP. Salin dan tempel jawaban beresiko menarik downvotes.
Kev
9
-1, metode ini tidak dapat digunakan, karena beberapa ponsel menyertakan subiner sementara tidak di-root.
neevek
12
Hanya ingin memberi tahu Anda, aplikasi Fox Digital Copy (Beta) menggunakan kode Anda hampir kata demi kata, termasuk kelas Root dan ExecShell, serta metode checkRootMethod1 / 2/3. Merasa sangat lucu.
Matt Joseph
8
Saya bisa menuntut mereka seperti Fox menggugat orang lain yang tak terhitung jumlahnya?
Kevin Parker
58

Jika Anda sudah menggunakan Fabric / Firebase Crashlytics, Anda dapat menelepon

CommonUtils.isRooted(context)

Ini adalah implementasi metode itu saat ini:

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();
        }
    }
}
kingston
sumber
Jawaban terbaik yang pernah ada. Silakan gunakan ini di perpustakaan mana pun, ada banyak false positive yang berjalan di perangkat Cina.
Pedro Paulo Amorim
Apakah ada false positive dalam metode ini?
Ehsan Mashhadi
Saya menguji ini pada nexus 5 dengan download.chainfire.eu/363/CF-Root/CF-Auto-Root/… , ini tidak akurat.
Jeffrey Liu
54

Pustaka RootTools menawarkan metode sederhana untuk memeriksa root:

RootTools.isRootAvailable()

Referensi

Intrikasi
sumber
10
isRootAvailable () hanya memeriksa keberadaan su di path dan beberapa direktori hard-coded lainnya. Saya pernah mendengar bahwa beberapa alat unrooting akan meninggalkan su di sana, jadi ini akan memberikan hasil positif palsu.
Bob Whiteman
13
RootTools.isAccessGiven () tidak hanya akan memeriksa root, tetapi juga meminta izin root; jadi perangkat yang tidak di-root akan selalu kembali false dengan metode ini.
aggregate1166877
2
@ agreate1166877, Anda benar, tetapi itu tidak cukup baik, bagaimana jika saya tidak memerlukan izin root ketika saya bertanya? Saya hanya ingin tahu apakah sudah di-root, tapi saya tidak perlu izin root saat ini.
neevek
4
isAccessGiven () mengembalikan false ketika pengguna menolak izin meskipun perangkat itu sudah di-rooting.
subair_a
Ini adalah satu-satunya jawaban yang saya anggap layak untuk dipilih. Lihat jawaban saya di bawah ini jika Anda ingin sesuatu yang mirip dengan hanya menyalin tempel, atau ingin lebih detail
rsimp
52

Dalam aplikasi saya, saya memeriksa apakah perangkat di-rooting atau tidak dengan menjalankan perintah "su". Tetapi hari ini saya telah menghapus bagian dari kode saya ini. Mengapa?

Karena aplikasi saya menjadi pembunuh memori. Bagaimana? Biarkan saya menceritakan kisah saya kepada Anda.

Ada beberapa keluhan bahwa aplikasi saya memperlambat perangkat (Tentu saja saya pikir itu tidak benar). Saya mencoba mencari tahu mengapa. Jadi saya menggunakan MAT untuk mendapatkan timbunan dan analisis, dan semuanya tampak sempurna. Tetapi setelah meluncurkan ulang aplikasi saya berkali-kali saya menyadari bahwa perangkat semakin lambat dan menghentikan aplikasi saya tidak membuatnya lebih cepat (kecuali saya me-restart perangkat). Saya menganalisis file dump lagi saat perangkat sangat lambat. Tapi semuanya masih sempurna untuk file dump. Kemudian saya melakukan apa yang harus dilakukan pada awalnya. Saya mendaftar proses.

$ adb shell ps

Surprize; ada banyak proses untuk aplikasi saya (dengan tag proses aplikasi saya di manifes). Beberapa dari mereka adalah zombie, beberapa dari mereka tidak.

Dengan contoh aplikasi yang memiliki Kegiatan tunggal dan menjalankan perintah "su" saja, saya menyadari bahwa proses zombie sedang dibuat pada setiap peluncuran aplikasi. Awalnya zombie ini mengalokasikan 0KB tetapi dari sesuatu yang terjadi dan proses zombie memegang hampir KB yang sama dengan proses utama aplikasi saya dan mereka menjadi proses standar.

Ada laporan bug untuk masalah yang sama pada bugs.sun.com: http://bugs.sun.com/view_bug.do?bug_id=6474073 ini menjelaskan jika perintah tidak ditemukan, zombie akan dibuat dengan metode exec () . Tetapi saya masih tidak mengerti mengapa dan bagaimana mereka bisa menjadi proses standar dan memiliki KB yang signifikan. (Ini tidak terjadi setiap saat)

Anda dapat mencoba jika ingin dengan contoh kode di bawah ini;

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

Metode eksekusi perintah sederhana;

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

Untuk menyimpulkan; Saya tidak punya saran bagi Anda untuk menentukan apakah perangkat di-rooting atau tidak. Tetapi jika saya jadi Anda, saya tidak akan menggunakan Runtime.getRuntime (). Exec ().

Ngomong-ngomong; RootTools.isRootAvailable () menyebabkan masalah yang sama.

Devrim
sumber
5
Itu sangat mengkhawatirkan. Saya memiliki kelas deteksi perangkat berakar yang melakukan hal yang sama - setelah membaca ini saya mengkonfirmasi apa yang dirinci di atas. Proses zombie sesekali ditinggalkan, perlambatan perangkat, dll ...
AWT
1
Saya mengkonfirmasi masalah dengan RootTools 3.4 pada android 2.3.6 GT-S5830i. Sebagian besar zombie mendapat alokasi memori dan masalahnya sistematis. Saya perlu me-restart perangkat setelah 3-4 tes. Saya merekomendasikan untuk menyimpan hasil tes ke preferensi bersama.
Kristus
2
Google sekarang merekomendasikan untuk menggunakan ProcessBuilder () dan perintah mulai ().
EntangledLoops
1
@NickS Menarik, tetapi perintah apa yang Anda luncurkan? Saya tidak memiliki masalah yang sama di sini mengeluarkan perintah pada banyak ponsel Android dari tingkat API yang berbeda dari 9-23.
EntangledLoops
1
@EntangledLoops. Terima kasih. Saya meluncurkan biner saya sendiri dan berinteraksi dengannya melalui stdin / stdout. Saya memeriksa lagi bagaimana saya menghentikannya dan menemukan bahwa saya melewatkan Process.destroy () dalam salah satu kasus. Jadi, tidak ada zombie.
Nick S
36

Banyak jawaban yang tercantum di sini memiliki masalah bawaan:

  • Memeriksa kunci tes berkorelasi dengan akses root tetapi tidak selalu menjamin itu
  • Direktori "PATH" harus diturunkan dari variabel lingkungan "PATH" yang sebenarnya alih-alih menjadi kode keras
  • Keberadaan "su" yang dapat dieksekusi tidak selalu berarti perangkat telah di-root
  • Eksekusi "yang" dapat diinstal atau tidak, dan Anda harus membiarkan sistem menyelesaikan jalurnya jika memungkinkan
  • Hanya karena aplikasi SuperUser diinstal pada perangkat tidak berarti perangkat memiliki akses root

The RootTools perpustakaan dari Stericson tampaknya akan memeriksa akar yang lebih sah. Ini juga memiliki banyak alat dan utilitas tambahan jadi saya sangat merekomendasikannya. Namun, tidak ada penjelasan tentang cara khusus memeriksa root, dan mungkin sedikit lebih berat daripada yang dibutuhkan sebagian besar aplikasi.

Saya telah membuat beberapa metode utilitas yang secara longgar didasarkan pada pustaka RootTools. Jika Anda hanya ingin memeriksa apakah executable "su" ada di perangkat, Anda dapat menggunakan metode berikut:

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

Metode ini hanya loop melalui direktori yang tercantum dalam variabel lingkungan "PATH" dan memeriksa apakah ada file "su" di salah satu dari mereka.

Untuk benar-benar memeriksa akses root, perintah "su" harus benar-benar dijalankan. Jika aplikasi seperti SuperUser diinstal, maka pada titik ini mungkin meminta akses root, atau jika sudah diberikan / ditolak bersulang mungkin ditampilkan yang menunjukkan apakah akses diberikan / ditolak. Perintah yang baik untuk dijalankan adalah "id" sehingga Anda dapat memverifikasi bahwa id pengguna sebenarnya 0 (root).

Berikut adalah contoh metode untuk menentukan apakah akses root telah diberikan:

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

Sangat penting untuk benar-benar menguji menjalankan perintah "su" karena beberapa emulator memiliki "su" yang dapat dieksekusi yang sudah diinstal, tetapi hanya mengizinkan pengguna tertentu untuk mengaksesnya seperti adb shell.

Penting juga untuk memeriksa keberadaan executable "su" sebelum mencoba menjalankannya, karena android telah dikenal tidak membuang proses yang mencoba menjalankan perintah yang hilang dengan benar. Proses hantu ini dapat menjalankan konsumsi memori dari waktu ke waktu.

rsimp
sumber
Metode isRootAvailable () berfungsi dengan baik, terima kasih. Saya merekomendasikan tidak menjalankan ini pada utas utama namun untuk menghindari ANR, seperti panggilan dari AsyncTask
Thunderstick
1
Saya pikir perbedaan antara keinginan untuk memastikan root tidak tersedia dan ingin memastikannya. Jika Anda ingin memastikan perangkat tidak di-root, cek yang disarankan baik. Anda akan mendapatkan hasil positif palsu tetapi tidak apa-apa ketika tidak menjalankan kode Anda pada perangkat yang dikompromikan adalah perhatian utama Anda.
Jeffrey Blattman
1
@ DAC84 Saya tidak yakin saya mengerti pertanyaan Anda. Jika Anda menjalankan isRootGiven dan menolak aplikasi rooting Anda maka itu akan kembali salah. Bukankah itu yang terjadi? Jika Anda ingin menghindari peringatan, Anda bisa menggunakan isRootAvailable yang juga bisa dinamai doesSUExist. Anda juga dapat mencoba mengonfigurasi aplikasi root Anda untuk membagikan root secara gratis dan tidak mengelolanya.
rsimp
1
@BeeingJk tidak tidak terlalu, meskipun itu benar-benar yang paling Anda dapat memeriksa tanpa menjalankan su yang merupakan ujian nyata. Anda perlu memeriksa su di PATH sebelum mencoba menjalankannya. Namun sebenarnya mengeksekusi su sering menghasilkan pesan roti panggang atau interaksi dengan aplikasi pengelolaan root yang mungkin bukan yang Anda inginkan. Untuk logika Anda sendiri, Anda mungkin menganggap keberadaan su cukup. Ini masih dapat memberikan positif palsu di beberapa emulator yang mungkin berisi su executable tetapi akses kuncian untuk itu.
rsimp
1
@BeeingJk isRootAvailable mungkin semua yang Anda butuhkan, tapi intinya saya mencoba untuk membuat nama seperti itu atau bahkan doesSUExist memberikan semantik yang lebih baik daripada nama metode seperti isDeviceRooted yang tidak terlalu benar. Jika Anda benar-benar perlu memverifikasi akses root penuh sebelum melanjutkan, Anda perlu mencoba menjalankan perintah dengan su seperti yang dikodekan di isRootGiven
rsimp
35

Perbarui 2017

Anda dapat melakukannya sekarang dengan Google Safetynet API . SafetyNet API menyediakan API Pengesahan yang membantu Anda menilai keamanan dan kompatibilitas lingkungan Android tempat aplikasi Anda berjalan.

Pengesahan ini dapat membantu untuk menentukan apakah perangkat tertentu telah dirusak atau dimodifikasi.

API Pengesahan mengembalikan respons JWS seperti ini

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

Mengurai respons ini dapat membantu Anda menentukan apakah perangkat di-rooting atau tidak

Perangkat yang di-root tampaknya menyebabkan ctsProfileMatch = false.

Anda dapat melakukannya di sisi klien tetapi disarankan untuk mengurai respon di sisi server. Arsitektur server klien dasar dengan API jaring pengaman akan terlihat seperti ini: -

masukkan deskripsi gambar di sini

Hitesh Sahu
sumber
3
Informasi yang sangat baik, dan dalam konteks yang berbeda saya percaya ini akan menjadi jawaban yang benar. Sayangnya pertanyaan OPs bukan tentang mempertahankan aplikasinya dari lingkungan yang tidak aman, tetapi mendeteksi root untuk mengaktifkan fitur hanya root di appnya. Untuk tujuan OPs, proses ini tampaknya terlalu rumit.
rsimp
31

Pemeriksaan root di tingkat Java bukanlah solusi yang aman. Jika aplikasi Anda memiliki Masalah Keamanan untuk dijalankan pada perangkat yang di-rooting, silakan gunakan solusi ini.

Jawaban Kevin berfungsi kecuali telepon juga memiliki aplikasi seperti RootCloak. Aplikasi semacam itu memiliki Handle over Java API setelah ponsel di-rooting dan mereka mengejek API ini untuk mengembalikan ponsel tidak di-rooting.

Saya telah menulis kode tingkat asli berdasarkan jawaban Kevin, ia berfungsi bahkan dengan RootCloak! Juga tidak menyebabkan masalah kebocoran memori.

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

}

Dalam kode Java Anda, Anda perlu membuat kelas RootUtils wrapper untuk membuat panggilan asli

    public boolean checkRooted() {

       if( rootUtils.checkRootAccessMethod3()  == 0 || rootUtils.checkRootAccessMethod1()  == 0 || rootUtils.checkRootAccessMethod2()  == 0 )
           return true;
      return false;
     }
Alok Kulkarni
sumber
1
Saya pikir deteksi root terbagi dalam dua kategori, mengaktifkan fitur-fitur yang tergantung pada root dan kemudian langkah-langkah berbasis keamanan untuk mencoba mengurangi masalah keamanan dengan ponsel yang di-root. Untuk fitur yang tergantung pada root, saya menemukan jawaban Kevin sangat buruk. Dalam konteks jawaban ini, metode ini lebih masuk akal. Meskipun saya akan menulis ulang metode 2 untuk tidak menggunakan yang dan sebaliknya beralih pada variabel lingkungan PATH untuk mencari "su". "Yang" tidak dijamin berada di telepon.
rsimp
dapatkah Anda memberikan contoh cara menggunakan kode c ini di java?
mrid
@mrid Harap periksa cara melakukan panggilan JNI dari Java di Android.
Alok Kulkarni
Metode ini mencegah byepass deteksi root menggunakan aplikasi RootCloak. Adakah teknik byepass root yang diketahui yang gagal dalam metode ini?
Nidhin
20

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

Jika Anda tidak ingin menggunakan file jar cukup gunakan kode:

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 akan mencoba menemukan folder su:

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

Contoh:

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

} else {
   textView.setText("Device Unrooted");
}
noobProgrammer
sumber
Terima kasih! Saya menggunakan ini sebagai checkRootMethod4()dengan Jawaban Kevin .
Sheharyar
1
Jangan pernah menambahkan == trueke boolean, itu tidak menambah apa pun dan tidak terlihat bagus.
minipif
2
@smoothBlue Kenapa begitu? Ini tidak menghasilkan Proses apa pun seperti solusi DevrimTuncer.
FD_
1
Gagasan yang lebih baik adalah beralih ke PATH, daripada mengkodekan direktori PATH yang khas
rsimp
1
Gunakan, if (isRooted())periksa alih-alih secara eksplisit menulis true. Lebih baik mengikuti pola penulisan kode
blueware
13

Alih-alih menggunakan isRootAvailable () Anda dapat menggunakan isAccessGiven (). Langsung dari wiki RootTools :

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

RootTools.isAccessGiven () tidak hanya memeriksa apakah perangkat di-rooting, ia juga memanggil su untuk aplikasi Anda, meminta izin, dan mengembalikan true jika aplikasi Anda berhasil memberikan izin root. Ini dapat digunakan sebagai pemeriksaan pertama di aplikasi Anda untuk memastikan bahwa Anda akan diberikan akses saat Anda membutuhkannya.

Referensi

saulobrito
sumber
tetapi pengguna harus memberikan akses root, kan? jadi jika tujuan saya adalah menghentikan aplikasi saya dari berjalan jika perangkat di-root maka opsi saya benar-benar terbatas
Nasz Njoka Sr.
11

Beberapa build yang dimodifikasi digunakan untuk mengatur properti sistem ro.modversion untuk tujuan ini. Hal-hal tampaknya telah pindah; build saya dari TheDude beberapa bulan lalu memiliki ini:

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]

Emulator dari 1,5 SDK di sisi lain, menjalankan gambar 1,5, juga memiliki root, mungkin mirip dengan Android Dev Phone 1 (yang mungkin ingin Anda izinkan) dan memiliki ini:

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]

Sedangkan untuk ritel build, saya tidak punya satu untuk dikerjakan, tetapi berbagai pencarian di bawah site:xda-developers.cominformatif. Ini adalah G1 di Belanda , Anda bisa lihat yang ro.build.tagstidak memilikinya test-keys, dan saya pikir itu mungkin properti paling andal untuk digunakan.

Chris Boyle
sumber
Itu terlihat menarik, tetapi: Walaupun emulator (dan ADP) memungkinkan root, itu tidak mengizinkan aplikasi untuk menggunakannya, yaitu: $ su app_29 $ su su: uid 10029 tidak diizinkan untuk su
miracle2k
Ah, saya kira mereka tidak akan ... Anda bisa menggabungkannya dengan cek untuk ro.build.host (tidak) berakhir di google.com lalu, jika mereka satu-satunya yang memiliki kunci-uji tetapi memblokir su tanpa tanya pengguna. Tergantung apa host build untuk perangkat yang lebih baru, hal-hal yang bukan ponsel ... tidak mudah.
Chris Boyle
11

RootBeer adalah root memeriksa perpustakaan Android oleh Scott dan Matthew. Ini menggunakan berbagai pemeriksaan untuk menunjukkan apakah perangkat di-rooting atau tidak.

Cek Java

  • CheckRootManagementApps

  • PeriksaPotensialBahaya Aplikasi

  • PeriksaRootCloakingApps

  • CheckTestKeys

  • checkForDangerousProps

  • periksaForBusyBoxBinary

  • periksaForSuBinary

  • checkSuExists

  • checkForRWSystem

Cek asli

Kami memanggil pemeriksa root asli kami untuk menjalankan beberapa cek itu sendiri. Pemeriksaan bawaan biasanya lebih sulit untuk ditutup, sehingga beberapa aplikasi jubah root hanya memblokir pemuatan perpustakaan asli yang berisi kata-kata kunci tertentu.

  • periksaForSuBinary
Pengembang Android
sumber
8

Saya sarankan menggunakan kode asli untuk deteksi root. Ini adalah contoh lengkapnya .

masukkan deskripsi gambar di sini

Pembungkus JAWA :

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

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

konstanta:

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

deteksi root dari kode asli:

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;
}
Dima Kozhevin
sumber
4
Alat luar biasa, Dima. Terima kasih banyak. Bahkan menangkap bunga magis.
ahli
Ini adalah real deal.
Vahid Amiri
@klutch ada tautan ke contoh kerja (github) di baris pertama posting saya
Dima Kozhevin
7

Ini kode saya berdasarkan beberapa jawaban di sini:

 /**
   * 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;
  }
Peceps
sumber
7

Lebih jauh ke jawaban @Kevins, saya baru saja menemukan saat menggunakan sistemnya, bahwa Nexus 7.1 kembali falseuntuk ketiga metode - Tidak ada whichperintah, tidak test-keysdan SuperSUtidak diinstal pada/system/app .

Saya menambahkan ini:

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

Ini sedikit kurang berguna dalam beberapa situasi (jika Anda memerlukan jaminan akses root) karena SuperSU sepenuhnya dapat diinstal pada perangkat yang tidak memiliki akses SU.

Namun, karena SuperSU mungkin diinstal dan berfungsi tetapi tidak dalam /system/appdirektori, kasing tambahan ini akan membasmi (haha) kasing kasing tersebut .

Graeme
sumber
Ini bukan jawaban yang baik karena Anda memiliki paket root lain yang dapat diinstal pada perangkat Anda. Hard coding paket aplikasi lain akan menjadi keras karena Anda tidak dapat mengharapkan dan daftar semuanya
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);
        }
Kvant
sumber
4

Dua ide tambahan, jika Anda ingin memeriksa apakah suatu perangkat mampu melakukan root dari aplikasi Anda:

  1. Periksa keberadaan biner 'su': jalankan "su mana" dari Runtime.getRuntime().exec()
  2. Cari SuperUser.apk di /system/app/Superuser.apklokasi
Proyek Wali
sumber
3

Menggunakan C ++ dengan ndk adalah pendekatan terbaik untuk mendeteksi root bahkan jika pengguna menggunakan aplikasi yang menyembunyikan root-nya seperti RootCloak. Saya menguji kode ini dengan RootCloak dan saya dapat mendeteksi root bahkan jika pengguna mencoba menyembunyikannya. Jadi file cpp Anda ingin:

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

Dan Anda akan memanggil fungsi dari kode java Anda sebagai berikut

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();
}
Sami Kanafani
sumber
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
ESSPEE
sumber
1

Ada Safety Net Attestation API dari layanan Google play yang dengannya kami dapat menilai perangkat dan menentukan apakah perangkat itu di-rooting / dirusak.

Silakan buka jawaban saya untuk berurusan dengan perangkat yang di-rooting:
https://stackoverflow.com/a/58304556/3908895

Kalpesh Wadekar
sumber
1

Lupakan semua yang mendeteksi aplikasi root dan binary su. Periksa proses daemon root. Ini dapat dilakukan dari terminal dan Anda dapat menjalankan perintah terminal dalam suatu aplikasi. Coba satu garis ini.

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

Anda tidak perlu izin root untuk mencapai ini juga.

5p0ng3b0b
sumber
0

Memang itu adalah pertanyaan yang menarik dan sejauh ini tidak ada yang pantas mendapatkan penghargaan. Saya menggunakan kode berikut:

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

Kode ini tentu bukan antipeluru, karena jaringan tidak tersedia sehingga Anda mendapatkan pengecualian. Jika metode ini mengembalikan true maka 99% Anda bisa yakin, jika tidak hanya 50% yang tidak. Izin jaringan juga dapat merusak solusinya.

Singagirl
sumber
Saya menguji ini dan tidak mengembalikan true dengan perangkat saya yang di-rooting.
tricknology
Sangat menarik untuk melihat pengecualian seperti apa yang Anda dapatkan. Anda mungkin mendapatkan pengecualian port yang sudah terikat, namun jika Anda tidak dapat membuat port server dalam kisaran di bawah 1024, itu akan mengurangi nilai rooting, karena Anda masih memiliki batasan tertentu.
Singagirl
-1

Menggunakan perpustakaan saya di rootbox , itu cukup mudah. Periksa kode yang diperlukan di bawah ini:

    //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.");
VPZ
sumber