0x00 前言

这篇文章是讲移动安全中如何检测ROOT设备的,对于开发人员来说,这篇文章可以让你知道如何去检测;对于安全人员来说,知己知彼方能百战百胜。

0x01 Android系统的沙箱

众所周知Android系统是基于Linux内核的,而Linux系统是多用户的,那么问题来了——Android系统为什么不是多用户的?Android系统是为了智能手机而生的,而智能手机作为私人设备,自然不需要支持多物理用户使用了。

android多用户开发切换问题 android 多用户原理_移动安全

 至于Linux的多用户机制则被用到了APP隔离上,即沙箱中。每一个APP应用在Android系统安装的时候就会分配到一个UID,通过它对APP进行隔离,这样不同的APP就会在不同的沙箱中运行,再默认情况下不同的APP之间不能互相访问以及读写文件,这样就实现了互不干扰。

这个UID一般在10000-99999之间,可以在/data/system/packages.xml文件中查看,比如我们要查看包名为com.sy.h5demo的APP,可以看到UID是10176。

android多用户开发切换问题 android 多用户原理_安全_02

进入/data/data/com.sy.h5demo目录下,可以看到文件属性标识的用户名都是u0_a176,与UID相关联。

android多用户开发切换问题 android 多用户原理_android_03

 当APP要运行的时候,系统会给它创建一个进程,这个进程也是以这个UID来标识的,我们查看h5demo这个APP,果然如此。

android多用户开发切换问题 android 多用户原理_安全_04

说到这里,你可能会疑问那APP之间如何进行交互?

这是个好问题,系统其实早就考虑到了。我们可以通过配置AndroidManifest.xml文件来实现用户ID的共享,进行共享的APP其签名必须一致。所有的Android应用程序都是需要用证书进行签名的,这个签名私钥由开发者自己保存。这个私钥很重要,需要妥善保管,有的开发者直接将私钥当做资源也打包在APP当中,这也真是心大!

看到这里,通过沙箱机制,Android系统似乎挺安全的?的确如此,不过要加一个前提条件,排除root用户。root这个超级玩家在Linux系统拥有最高权限,它可以无视沙箱机制,超越任何用户和用户组来对文件、目录进行读、写、删除。

为了手机的安全,绝对不要轻易刷机!一个恶意的APP如果获得Root权限,那将是灾难性的!所以在资金交易等敏感场景,APP检测设备是否已经Root就显得非常有必要了。

0x02 APP检测Root原理

通常我们获取root权限,就是通过su命令,它是Linux下切换用户的命令,不带参数就是切换到root用户。

android多用户开发切换问题 android 多用户原理_android_05

 所以我们可以通过检测这个命令是否存在来判断系统是否已经Root。

1.检测是否存在可执行文件su

// 检测是否存在可执行文件su
public static boolean checkSuFile() {
    final String filePaths[] = {"/system/bin/", "/system/xbin/", "/system/sbin/", "/sbin/", "/vendor/bin/", "/su/bin/"};
    for (int i = 0;i <filePaths.length;i++){
        File f = new File(filePaths[i]+"su");
        if (f != null && f.exists()){
            Log.i(LOG_TAG, "SuFile is exists: " + filePaths[i]);
            return true;
        }
    }
    return false;
}

2.执行which命令查看是否存在su

//执行which命令查看是否存在su
public static boolean checkSuWhich() {
    String[] cmd = new String[]{"/system/xbin/which", "su"};
    ArrayList<String> result = executeCommand(cmd);
    if (result != null) {
        Log.i(LOG_TAG, "SuWhich is exists:" + result.toString());
        return true;
    } else {
        return false;
    }
}

3. 检测环境变量PATH上是否存在su

//检测环境变量PATH上是否存在su
public static boolean checkSuPath() {
    String[] paths = System.getenv("PATH").split(":");
    for (String path:paths){
        if (new File(path,"su").exists()){
            return true;
        }
    }
    return false;
}

以上三种检测方法就是最常用的三种,那我到底用哪种呢?当然是全要啊!

检测效果如下:

android多用户开发切换问题 android 多用户原理_android_06

一旦我们检测到设备已经Root,可直接结束进程。

 在以上三种方式存在的情况下,我们还可以添加其他的方式来加强检测,如:检测流行的ROOT工具是否存在等;对了查看系统是否为测试版(test-keys)这种方式是无效的,而且有的厂商发布的就是test-keys。

android多用户开发切换问题 android 多用户原理_android多用户开发切换问题_07

0x03 End

但是很遗憾的说,恶意用户通过Hook、反编译等技术可以轻松绕过以上检测,这就是说Root检测只是很小的一步,要做好移动安全,我们还有很长的路需要走!