一 为什么要进行root检测?

出于安全原因,我们的应用程序不建议在已经root的设备上运行,所以需要检测是否设备已经root,以提示用户若继续使用会存在风险。

二 root了会有什么风险?

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

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

三 不root为什么就安全了呢?

Android安全架构是基于Linux多用户机制的访问控制。应用程序在默认的情况下不可以执行其他应用程序,包括读或写用户的私有数据(如联系人数据或email数据),读或写另一个应用程序的文件。

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

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

四 root的方式有哪些?

通常可以分为2种,不完全Root和完全Root

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

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

五 检测Android设备是否root有哪些方法?

1、查看系统是否是测试版

我们可以查看发布的系统版本,是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,可能大家对这个标识也不是特别注意吧。所以具体是否使用,还要多考虑考虑呢。也许能解决问题,也许会给自己带来些麻烦。

2、检查是否存在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;}

3、检查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吧。

4、执行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;}}

5、访问/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;}}

六、具体如何使用?

只需调用以下代码即可

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 buildTagsif (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 sureturn 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;}}
}

​​​​

Android root检测方法总结相关推荐

  1. Android root检测方法小结

    出于安全原因,我们的应用程序不建议在已经root的设备上运行,所以需要检测是否设备已经root,以提示用户若继续使用会存在风险. 那么root了会有什么风险呢,为什么不root就没有风险,又怎么来检查 ...

  2. Android设备Root检测方法

    app发布后,一些root用户可能会修改我们应用的一些信息,如传感器获得的数据,那么这些用户的数据就不再具有参考价值,应该被单独列出, 以方便数据的分析,所以就有了本文. 下面是检测Android设备 ...

  3. android 绕过root检测,公主连结怎么绕过root检测 绕过root检测方法一览

    公主连结刷初始怎么绕过root检测呢?很多小伙伴想刷初始可是经常被root检测,有没有什么办法才能绕过检测呢? 实机可以用magisk自带的hide功能,xposed框架可以选择rootcloak,A ...

  4. android内存检测方法,Android_Android系统检测程序内存占用各种方法,1.检查系统总内存 复制代码 - phpStudy...

    Android系统检测程序内存占用各种方法 1.检查系统总内存 liuhx@uc ~ $ adb shell cat /proc/meminfo MemTotal:         840868 kB ...

  5. android+root+新方法,安卓手机最新Root通用教程

    直接运行superSu Root失败 直接运行superSu等Root工具在很多手机上都会Root失败,关键在于没有相关权限,那么怎么才能在这些手机上获取Root权限呢? 开发者选项 首先打开开发者选 ...

  6. android判断软件是否已root权限,Android应用开发Android 判断手机是否有root权限方法...

    本文将带你了解Android应用开发Android 判断手机是否有root权限方法,希望本文对大家学Android有所帮助. root权限是安卓最高的操作权限,俗称superuser,简称su,一般来 ...

  7. android 隐私泄露 路径,一种Android应用隐私泄露漏洞检测方法与流程

    本发明涉及Android查漏的技术领域,尤其涉及到一种Android应用隐私泄露漏洞检测方法. 背景技术: 在目前的Android隐私泄露漏洞检测方法中,静态污点分析是最常用且最有效的方法.首先对an ...

  8. android获取录音读写权限设置,Android编程检测手机录音权限是否打开的方法

    本文实例讲述了Android编程检测手机录音权限是否打开的方法.分享给大家供大家参考,具体如下: 6.0之前的权限检测只是检测到是否在清单文件中注册 Boolean flag = (PackageMa ...

  9. Android隐私合规检测方法

    背景: 公司的APP被工信部通报:1.在用户确认隐私权限以前会获取用户的mac地址.2.在app内频繁的获取定位,超过了场景所必须的频次. 排查过程 收到通报我们一脸懵,我们排查业务代码中没有获取ma ...

最新文章

  1. JavaScript的编译模式
  2. 用偷梁换柱法清除腾讯QQ迷你首页的方法
  3. List 的add()与addAll()的区别
  4. 3. std::string::size_type
  5. 快速排序的性能和名字一样优秀
  6. CF903G-Yet Another Maxflow Problem【线段树,最大流】
  7. 利用POI 技术动态替换word模板内容
  8. 网游服务器通信架构设计
  9. Santander Customer Transaction Prediction(2)
  10. mysql1232_Mysql执行流程
  11. 3 EDA技术实用教程 【基础知识1】
  12. LCD 12864B V2.0的使用
  13. Java 前后端分离部署方式
  14. Adding Powers
  15. windows 强制关闭程序并强制删除文件
  16. Android 状态栏常规操作(状态栏显示,状态栏颜色,沉浸式状态栏)
  17. java 生僻字 问号_csv导出姓名生僻字变问号
  18. 网络与信息安全实验总结(报文监听与分析,漏洞扫描,逆向工程,安全产品)
  19. 无线路由器的基础配置(一)
  20. 黑客教父龚蔚:是谁打开了潘多拉的魔盒

热门文章

  1. location 拦截所有_超强广告拦截软件,简直手机必备App,太太太太太太太太太好用了!...
  2. linux查看IO情况
  3. maya 中切换当前渲染器的方法和设置
  4. codevs 1227 方格取数2
  5. ruby rails + grape + sidekiq 项目实践
  6. 2020604 Java基础复习
  7. 云计算机服务英文翻译,基于云的服务,Cloud Based Service,音标,读音,翻译,英文例句,英语词典...
  8. 计算机管理员考核指标库,仓库管理员绩效考核指标.docx
  9. CODESYS 赛搏机器智能MIC7001总线控制器+松下A6BE总线驱动器
  10. python Dataframe 根据某一列的值来删除多行