Javascript required
Skip to content Skip to sidebar Skip to footer

How to Install Android Marshmallow on Rooted Device

I suggest using native code for root detection. Here is a full working example.

enter image description here

JAVA wrapper:

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

constants:

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

root detections from native code:

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

How to Install Android Marshmallow on Rooted Device

Source: https://stackoverflow.com/questions/1101380/determine-if-running-on-a-rooted-device