【转】Android root检测方法总结

一 为何要进行root检测?
出于安全缘由,咱们的应用程序不建议在已经root的设备上运行,因此须要检测是否设备已经root,以提示用户若继续使用会存在风险。java

二 root了会有什么风险?
在Linux操做系统中,root的权限是最高的,也被称为超级权限的拥有者。 
在系统中,每一个文件、目录和进程,都归属于某一个用户,没有用户许可其它普通用户是没法操做的,但对root除外。android

root用户的特权性还表如今:root能够超越任何用户和用户组来对文件或目录进行读取、修改或删除(在系统正常的许可范围内);对可执行程序的执行、终止;对硬件设备的添加、建立和移除等;也能够对文件和目录进行属主和权限进行修改,以适合系统管理的须要(由于root是系统中权限最高的特权用户);root是超越任何用户和用户组的,基于用户ID的权限机制的沙盒是隔离不了它的。shell

三 不root为何就安全了呢?
Android安全架构是基于Linux多用户机制的访问控制。应用程序在默认的状况下不能够执行其余应用程序,包括读或写用户的私有数据(如联系人数据或email数据),读或写另外一个应用程序的文件。安全

一个应用程序的进程就是一个安全的沙盒(在受限的安全环境中运行应用程序,在沙盒中的全部改动对操做系统不会形成任何危害)。它不能干扰其它应用程序,除非显式地声明了“permissions”,以便它可以获取基本沙盒所不具有的额外的能力。 
每个Android应用程序都会在安装时就分配一个独有的Linux用户ID,这就为它创建了一个沙盒,使其不能与其余应用程序进行接触。这个用户ID会在安装时分配给它,并在该设备上一直保持同一个数值。架构

 全部的Android应用程序必须用证书进行签名认证,而这个证书的私钥是由开发者保有的。该证书能够用以识别应用程序的做者。签名影响安全性的最重要的方式是经过决定谁能够进入基于签名的permisssions,以及谁能够share 用户IDs。经过这样的机制,在不考虑root用户的状况下,每一个应用都是相互隔离的,实现了必定的安全。app

四 root的方式有哪些?
一般能够分为2种,不彻底Root和彻底Root 工具

目前获取Android root 权限经常使用方法是经过各类系统漏洞,替换或添加SU程序到设备,获取Root权限,而在获取root权限之后,会装一个程序用以提醒用户是否给予程序最高权限,能够必定程度上防止恶意软件,一般会使用Superuser或者 SuperSU ,这种方法一般叫作“不彻底Root”。测试

而 “彻底ROOT”是指,替换设备原有的ROM,以实现取消secure设置。ui

五 检测Android设备是否root有哪些方法?
一、查看系统是不是测试版spa

咱们能够查看发布的系统版本,是test-keys(测试版),仍是release-keys(正式版)。 
能够先在adb shell中运行下命令查看:

root@android:/ # cat /system/build.prop | grep ro.build.tags
ro.build.tags=release-keys
这个返回结果“release-keys”,表明此系统是正式版。 
在代码中的检测方法以下:

public static boolean checkDeviceDebuggable() {
        String buildTags = android.os.Build.TAGS;
        if (buildTags != null && buildTags.contains("test-keys")) {
            Log.i(LOG_TAG, "buildTags=" + buildTags);
            return true;
        }
        return false;
    }

 


如果非官方发布版,极可能是彻底root的版本,存在使用风险。 
但是在实际状况下,我遇到过某些厂家的正式发布版本,也是test-keys,可能你们对这个标识也不是特别注意吧。因此具体是否使用,还要多考虑考虑呢。也许能解决问题,也许会给本身带来些麻烦。

二、检查是否存在Superuser.apk

Superuser.apk是一个被普遍使用的用来root安卓设备的软件,因此能够检查这个app是否存在。 
检测方法以下:

public static boolean checkSuperuserApk() {
        try {
            File file = new File("/system/app/Superuser.apk");
            if (file.exists()) {
                Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
                return true;
            }
        } catch (Exception e) {
        }
        return false;
    }

 


三、检查su命令

su是Linux下切换用户的命令,在使用时不带参数,就是切换到超级用户。一般咱们获取root权限,就是使用su命令来实现的,因此能够检查这个命令是否存在。这样,系统就会在PATH路径中搜索su,若是找到,就会执行,执行成功后,就是获取到真正的超级权限了。 

public static synchronized boolean checkGetRootAuth() {
        Process process = null;
        DataOutputStream os = null;
        try {
            Log.i(LOG_TAG, "to exec su");
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("exit\n");
            os.flush();
            int exitValue = process.waitFor();
            Log.i(LOG_TAG, "exitValue=" + exitValue);
            if (exitValue == 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

 


这种检测su的方法,应该是最靠谱的,不过,也有个问题,就是在已经root的设备上,会弹出提示框,请求给app开启root权限。这个提示不太友好,可能用户会不喜欢。 
若是想安静的检测,能够用上两种方法的组合;若是须要尽可能安全的检测到,仍是执行su吧。

四、执行busybox

Android是基于Linux系统的,但是在终端Terminal中操做,会发现一些基本的命令都找不到。这是因为Android系统为了安全,将可能带来风险的命令都去掉了,最典型的,例如su,还有find、mount等。对于一个已经获取了超级权限的人来说,这是很不爽的事情,因此,便要想办法加上本身须要的命令了。一个个添加命令也麻烦,有一个很方便的方法,就是使用被称为“嵌入式Linux中的瑞士军刀”的Busybox。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令。 
因此若设备root了,极可能Busybox也被安装上了。这样咱们运行busybox测试也是一个好的检测方法。
 

public static synchronized boolean checkBusybox() {
        try {
            Log.i(LOG_TAG, "to exec busybox df");
            String[] strCmd = new String[]{"busybox", "df"};
            ArrayList<String> execResult = executeCommand(strCmd);
            if (execResult != null) {
                Log.i(LOG_TAG, "execResult=" + execResult.toString());
                return true;
            } else {
                Log.i(LOG_TAG, "execResult=null");
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }

 

五、访问/data目录,查看读写权限

在Android系统中,有些目录是普通用户不能访问的,例如 /data、/system、/etc 等。 
咱们就已/data为例,来进行读写访问。本着谨慎的态度,我是先写入一个文件,而后读出,查看内容是否匹配,若匹配,才认为系统已经root了。

public static synchronized boolean checkAccessRootData() {
        try {
            Log.i(LOG_TAG, "to write /data");
            String fileContent = "test_ok";
            Boolean writeFlag = writeFile("/data/su_test", fileContent);
            if (writeFlag) {
                Log.i(LOG_TAG, "write ok");
            } else {
                Log.i(LOG_TAG, "write failed");
            }
 
            Log.i(LOG_TAG, "to read /data");
            String strRead = readFile("/data/su_test");
            Log.i(LOG_TAG, "strRead=" + strRead);
            if (fileContent.equals(strRead)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }

 


6、具体如何使用?
只需调用如下代码便可

CheckRoot.isDeviceRooted()

 


其中CheckRoot.java的完整代码以下:

import android.util.Log;
 
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
 
public class CheckRoot {
    private static String LOG_TAG = CheckRoot.class.getName();
 
    public static boolean isDeviceRooted() {
        if (checkDeviceDebuggable()) {
            return true;
        }//check buildTags
        if (checkSuperuserApk()) {
            return true;
        }//Superuser.apk
        //if (checkRootPathSU()){return true;}//find su in some path
        //if (checkRootWhichSU()){return true;}//find su use 'which'
        if (checkBusybox()) {
            return true;
        }//find su use 'which'
        if (checkAccessRootData()) {
            return true;
        }//find su use 'which'
        if (checkGetRootAuth()) {
            return true;
        }//exec su
 
        return false;
    }
 
    public static boolean checkDeviceDebuggable() {
        String buildTags = android.os.Build.TAGS;
        if (buildTags != null && buildTags.contains("test-keys")) {
            Log.i(LOG_TAG, "buildTags=" + buildTags);
            return true;
        }
        return false;
    }
 
    public static boolean checkSuperuserApk() {
        try {
            File file = new File("/system/app/Superuser.apk");
            if (file.exists()) {
                Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
                return true;
            }
        } catch (Exception e) {
        }
        return false;
    }
 
    public static synchronized boolean checkGetRootAuth() {
        Process process = null;
        DataOutputStream os = null;
        try {
            Log.i(LOG_TAG, "to exec su");
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("exit\n");
            os.flush();
            int exitValue = process.waitFor();
            Log.i(LOG_TAG, "exitValue=" + exitValue);
            if (exitValue == 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 
    public static synchronized boolean checkBusybox() {
        try {
            Log.i(LOG_TAG, "to exec busybox df");
            String[] strCmd = new String[]{"busybox", "df"};
            ArrayList<String> execResult = executeCommand(strCmd);
            if (execResult != null) {
                Log.i(LOG_TAG, "execResult=" + execResult.toString());
                return true;
            } else {
                Log.i(LOG_TAG, "execResult=null");
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }
 
    public static ArrayList<String> executeCommand(String[] shellCmd) {
        String line = null;
        ArrayList<String> fullResponse = new ArrayList<String>();
        Process localProcess = null;
        try {
            Log.i(LOG_TAG, "to shell exec which for find su :");
            localProcess = Runtime.getRuntime().exec(shellCmd);
        } catch (Exception e) {
            return null;
        }
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
        BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
        try {
            while ((line = in.readLine()) != null) {
                Log.i(LOG_TAG, "–> Line received: " + line);
                fullResponse.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
        return fullResponse;
    }
 
    public static synchronized boolean checkAccessRootData() {
        try {
            Log.i(LOG_TAG, "to write /data");
            String fileContent = "test_ok";
            Boolean writeFlag = writeFile("/data/su_test", fileContent);
            if (writeFlag) {
                Log.i(LOG_TAG, "write ok");
            } else {
                Log.i(LOG_TAG, "write failed");
            }
 
            Log.i(LOG_TAG, "to read /data");
            String strRead = readFile("/data/su_test");
            Log.i(LOG_TAG, "strRead=" + strRead);
            if (fileContent.equals(strRead)) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
                    + e.getMessage());
            return false;
        }
    }
 
    //写文件
    public static Boolean writeFile(String fileName, String message) {
        try {
            FileOutputStream fout = new FileOutputStream(fileName);
            byte[] bytes = message.getBytes();
            fout.write(bytes);
            fout.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
 
    //读文件
    public static String readFile(String fileName) {
        File file = new File(fileName);
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] bytes = new byte[1024];
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len;
            while ((len = fis.read(bytes)) > 0) {
                bos.write(bytes, 0, len);
            }
            String result = new String(bos.toByteArray());
            Log.i(LOG_TAG, result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

​​​​from:https://blog.csdn.net/yonbor605/article/details/83748665

相关文章
相关标签/搜索