Determine if running on a rooted device

后端 未结 24 2228
無奈伤痛
無奈伤痛 2020-11-22 06:43

My app has a certain piece of functionality that will only work on a device where root is available. Rather than having this feature fail when it is used (and then show an a

24条回答
  •  粉色の甜心
    2020-11-22 06:58

    Root check at Java level is not a safe solution. If your app has Security Concerns to run on a Rooted device , then please use this solution.

    Kevin's answer works unless the phone also has an app like RootCloak . Such apps have a Handle over Java APIs once phone is rooted and they mock these APIs to return phone is not rooted.

    I have written a native level code based on Kevin's answer , it works even with RootCloak ! Also it does not cause any memory leak issues.

    #include 
    #include 
    #include 
    #include 
    #include 
    #include "android_log.h"
    #include 
    #include 
    #include 
    
    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 .
        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"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 .
        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;
    
    }
    

    In your Java code , you need to create wrapper class RootUtils to make the native calls

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

提交回复
热议问题