一 为什么要进行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”,代表此系统是正式版。 
在代码中的检测方法如下:

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

若是非官方发布版,很可能是完全root的版本,存在使用风险。 
可是在实际情况下,我遇到过某些厂家的正式发布版本,也是test-keys,可能大家对这个标识也不是特别注意吧。所以具体是否使用,还要多考虑考虑呢。也许能解决问题,也许会给自己带来些麻烦。

2、检查是否存在Superuser.apk

Superuser.apk是一个被广泛使用的用来root安卓设备的软件,所以可以检查这个app是否存在。 
检测方法如下:

  1. public static boolean checkSuperuserApk() {
  2. try {
  3. File file = new File("/system/app/Superuser.apk");
  4. if (file.exists()) {
  5. Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
  6. return true;
  7. }
  8. } catch (Exception e) {
  9. }
  10. return false;
  11. }

3、检查su命令

su是Linux下切换用户的命令,在使用时不带参数,就是切换到超级用户。通常我们获取root权限,就是使用su命令来实现的,所以可以检查这个命令是否存在。这样,系统就会在PATH路径中搜索su,如果找到,就会执行,执行成功后,就是获取到真正的超级权限了。

  1. public static synchronized boolean checkGetRootAuth() {
  2. Process process = null;
  3. DataOutputStream os = null;
  4. try {
  5. Log.i(LOG_TAG, "to exec su");
  6. process = Runtime.getRuntime().exec("su");
  7. os = new DataOutputStream(process.getOutputStream());
  8. os.writeBytes("exit\n");
  9. os.flush();
  10. int exitValue = process.waitFor();
  11. Log.i(LOG_TAG, "exitValue=" + exitValue);
  12. if (exitValue == 0) {
  13. return true;
  14. } else {
  15. return false;
  16. }
  17. } catch (Exception e) {
  18. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  19. + e.getMessage());
  20. return false;
  21. } finally {
  22. try {
  23. if (os != null) {
  24. os.close();
  25. }
  26. process.destroy();
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }

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

4、执行busybox

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

  1. public static synchronized boolean checkBusybox() {
  2. try {
  3. Log.i(LOG_TAG, "to exec busybox df");
  4. String[] strCmd = new String[]{"busybox", "df"};
  5. ArrayList<String> execResult = executeCommand(strCmd);
  6. if (execResult != null) {
  7. Log.i(LOG_TAG, "execResult=" + execResult.toString());
  8. return true;
  9. } else {
  10. Log.i(LOG_TAG, "execResult=null");
  11. return false;
  12. }
  13. } catch (Exception e) {
  14. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  15. + e.getMessage());
  16. return false;
  17. }
  18. }

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

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

  1. public static synchronized boolean checkAccessRootData() {
  2. try {
  3. Log.i(LOG_TAG, "to write /data");
  4. String fileContent = "test_ok";
  5. Boolean writeFlag = writeFile("/data/su_test", fileContent);
  6. if (writeFlag) {
  7. Log.i(LOG_TAG, "write ok");
  8. } else {
  9. Log.i(LOG_TAG, "write failed");
  10. }
  11.  
  12. Log.i(LOG_TAG, "to read /data");
  13. String strRead = readFile("/data/su_test");
  14. Log.i(LOG_TAG, "strRead=" + strRead);
  15. if (fileContent.equals(strRead)) {
  16. return true;
  17. } else {
  18. return false;
  19. }
  20. } catch (Exception e) {
  21. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  22. + e.getMessage());
  23. return false;
  24. }
  25. }

六、具体如何使用?
只需调用以下代码即可

  1. CheckRoot.isDeviceRooted()

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

  1. import android.util.Log;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.BufferedWriter;
  5. import java.io.ByteArrayOutputStream;
  6. import java.io.DataOutputStream;
  7. import java.io.File;
  8. import java.io.FileInputStream;
  9. import java.io.FileOutputStream;
  10. import java.io.InputStreamReader;
  11. import java.io.OutputStreamWriter;
  12. import java.util.ArrayList;
  13.  
  14. public class CheckRoot {
  15. private static String LOG_TAG = CheckRoot.class.getName();
  16.  
  17. public static boolean isDeviceRooted() {
  18. if (checkDeviceDebuggable()) {
  19. return true;
  20. }//check buildTags
  21. if (checkSuperuserApk()) {
  22. return true;
  23. }//Superuser.apk
  24. //if (checkRootPathSU()){return true;}//find su in some path
  25. //if (checkRootWhichSU()){return true;}//find su use 'which'
  26. if (checkBusybox()) {
  27. return true;
  28. }//find su use 'which'
  29. if (checkAccessRootData()) {
  30. return true;
  31. }//find su use 'which'
  32. if (checkGetRootAuth()) {
  33. return true;
  34. }//exec su
  35.  
  36. return false;
  37. }
  38.  
  39. public static boolean checkDeviceDebuggable() {
  40. String buildTags = android.os.Build.TAGS;
  41. if (buildTags != null && buildTags.contains("test-keys")) {
  42. Log.i(LOG_TAG, "buildTags=" + buildTags);
  43. return true;
  44. }
  45. return false;
  46. }
  47.  
  48. public static boolean checkSuperuserApk() {
  49. try {
  50. File file = new File("/system/app/Superuser.apk");
  51. if (file.exists()) {
  52. Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
  53. return true;
  54. }
  55. } catch (Exception e) {
  56. }
  57. return false;
  58. }
  59.  
  60. public static synchronized boolean checkGetRootAuth() {
  61. Process process = null;
  62. DataOutputStream os = null;
  63. try {
  64. Log.i(LOG_TAG, "to exec su");
  65. process = Runtime.getRuntime().exec("su");
  66. os = new DataOutputStream(process.getOutputStream());
  67. os.writeBytes("exit\n");
  68. os.flush();
  69. int exitValue = process.waitFor();
  70. Log.i(LOG_TAG, "exitValue=" + exitValue);
  71. if (exitValue == 0) {
  72. return true;
  73. } else {
  74. return false;
  75. }
  76. } catch (Exception e) {
  77. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  78. + e.getMessage());
  79. return false;
  80. } finally {
  81. try {
  82. if (os != null) {
  83. os.close();
  84. }
  85. process.destroy();
  86. } catch (Exception e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. }
  91.  
  92. public static synchronized boolean checkBusybox() {
  93. try {
  94. Log.i(LOG_TAG, "to exec busybox df");
  95. String[] strCmd = new String[]{"busybox", "df"};
  96. ArrayList<String> execResult = executeCommand(strCmd);
  97. if (execResult != null) {
  98. Log.i(LOG_TAG, "execResult=" + execResult.toString());
  99. return true;
  100. } else {
  101. Log.i(LOG_TAG, "execResult=null");
  102. return false;
  103. }
  104. } catch (Exception e) {
  105. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  106. + e.getMessage());
  107. return false;
  108. }
  109. }
  110.  
  111. public static ArrayList<String> executeCommand(String[] shellCmd) {
  112. String line = null;
  113. ArrayList<String> fullResponse = new ArrayList<String>();
  114. Process localProcess = null;
  115. try {
  116. Log.i(LOG_TAG, "to shell exec which for find su :");
  117. localProcess = Runtime.getRuntime().exec(shellCmd);
  118. } catch (Exception e) {
  119. return null;
  120. }
  121. BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
  122. BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
  123. try {
  124. while ((line = in.readLine()) != null) {
  125. Log.i(LOG_TAG, "–> Line received: " + line);
  126. fullResponse.add(line);
  127. }
  128. } catch (Exception e) {
  129. e.printStackTrace();
  130. }
  131. Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
  132. return fullResponse;
  133. }
  134.  
  135. public static synchronized boolean checkAccessRootData() {
  136. try {
  137. Log.i(LOG_TAG, "to write /data");
  138. String fileContent = "test_ok";
  139. Boolean writeFlag = writeFile("/data/su_test", fileContent);
  140. if (writeFlag) {
  141. Log.i(LOG_TAG, "write ok");
  142. } else {
  143. Log.i(LOG_TAG, "write failed");
  144. }
  145.  
  146. Log.i(LOG_TAG, "to read /data");
  147. String strRead = readFile("/data/su_test");
  148. Log.i(LOG_TAG, "strRead=" + strRead);
  149. if (fileContent.equals(strRead)) {
  150. return true;
  151. } else {
  152. return false;
  153. }
  154. } catch (Exception e) {
  155. Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  156. + e.getMessage());
  157. return false;
  158. }
  159. }
  160.  
  161. //写文件
  162. public static Boolean writeFile(String fileName, String message) {
  163. try {
  164. FileOutputStream fout = new FileOutputStream(fileName);
  165. byte[] bytes = message.getBytes();
  166. fout.write(bytes);
  167. fout.close();
  168. return true;
  169. } catch (Exception e) {
  170. e.printStackTrace();
  171. return false;
  172. }
  173. }
  174.  
  175. //读文件
  176. public static String readFile(String fileName) {
  177. File file = new File(fileName);
  178. try {
  179. FileInputStream fis = new FileInputStream(file);
  180. byte[] bytes = new byte[1024];
  181. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  182. int len;
  183. while ((len = fis.read(bytes)) > 0) {
  184. bos.write(bytes, 0, len);
  185. }
  186. String result = new String(bos.toByteArray());
  187. Log.i(LOG_TAG, result);
  188. return result;
  189. } catch (Exception e) {
  190. e.printStackTrace();
  191. return null;
  192. }
  193. }
  194. }

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

【转】Android root检测方法总结的更多相关文章

  1. Android root检测方法小结

    转载目的,之前主要应用这里的原理解决了,手机被某个APP检测为root过的手机的问题,记录后续可能参考. 出于安全原因,我们的应用程序不建议在已经root的设备上运行,所以需要检测是否设备已经root ...

  2. Android手机安全软件的恶意程序检测靠谱吗--LBE安全大师、腾讯手机管家、360手机卫士恶意软件检测方法研究

    转载请注明出处,谢谢. Android系统开放,各大论坛活跃,应用程序分发渠道广泛,这也就为恶意软件的传播提供了良好的环境.好在手机上安装了安全软件,是否能有效的检测出恶意软件呢?下边针对LBE安全大 ...

  3. Android Root原理

    概述:通过阅读本文可以深刻理解Android系统中获得Root权限的方法和原理.本文会详细介绍Root的目的,原理和代码层次的具体实现方法. Android Root介绍: 1. Root目的 手机获 ...

  4. 【转】Root检测与反检测

    0x00背景需要在手机上构建一个环境对root过的设备进行伪装,让设备里面的应用将该设备当成未root的设备.10x01 Root检测手段1.检查已安装的APK包:SuperSU应用程序或者一键roo ...

  5. Android抓包方法(二)之Tcpdump命令+Wireshark

    Android抓包方法(二) 之Tcpdump命令+Wireshark 前言 做前端测试,基本要求会抓包,会分析请求数据包,查看接口是否调用正确,数据返回是否正确,问题产生是定位根本原因等.学会抓包分 ...

  6. 使用新版Android Studio检测内存泄露和性能

    内存泄露,是Android开发者最头疼的事.可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴.  怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的 ...

  7. Android DDMS检测内存泄露

    Android DDMS检测内存泄露 DDMS是Android开发包中自带工具,可以测试app性能,用于发现内存问题. 1.环境搭建 参考之前发的Android测试环境搭建相关文章,这里不再复述: 2 ...

  8. Android性能检测--traceview工具各个参数的意思

    Android性能检测 traceview的使用方法 1. 把android-sdk-windows\tools路径加到Path当中 2. 编写测试代码: package com.wwj.tracev ...

  9. Android模拟器检测常用方法

    在Android开发过程中,防作弊一直是老生常谈的问题,而模拟器的检测往往是防作弊中的重要一环,接下来有关于模拟器的检测方法,和大家进行一个简单的分享. 1.传统的检测方法. 传统的检测方法主要是对模 ...

随机推荐

  1. 网址URL分解

    http://www.joymood.cn:8080/test.php?user=admin&pwd=admin#login 1.location.href:得到整个如上的完整url 2.lo ...

  2. Python 序列、列表(List)、元组(Tuple)

    序列 序列是Python中最基本的数据结构,包括字符串.列表.元组. 序列,顾名思义,是有序的,序列都有索引,都能进行索引.切片(截取).加(连接).乘(倍增).检查成员的操作. 因为序列有序,可通过 ...

  3. git 检索

    图形化客户端:sourcetree下载: https://www.sourcetreeapp.com/安装: 由于种种不可描述的原因,无法注册账号且无法登陆所以需要绕过登陆绕过登陆: 去到 C:\Us ...

  4. 使用nginx 做kbmmw REST 服务的负载均衡

    我们一般在云上部署REST服务.既想利用kbmmw 的方便性,又想保证系统的安全性,同时 想通过负载均衡保证服务器的健壮性.下面我们使用ubuntu+nginx 来实现以下kbmmw rest 服务器 ...

  5. fiddler模拟弱网测试

    1.首先设置手机代理 设置手机代理到本机ip,端口号8888(Fiddler默认设置): 手机访问http://ip:port安装Fiddler证书 2.修改fiddler配置 勾选上后,已经开始限速 ...

  6. Mysql 单表查询-排序-分页-group by初识

    Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...

  7. 【Spring Cloud】Spring Cloud之Zipkin server搭建以及HTTP收集,分布式服务跟踪(2)

    一.搭建步骤 1)新建Spring Boot项目,引入pom坐标 <parent> <groupId>org.springframework.boot</groupId& ...

  8. 树莓派无显示屏连接wifi

    在烧好Raspbian系统的TF卡boot分区新建 wpa_supplicant.conf 文件,内容如下(修改自己的WIFI名和密码,key_mgmt根据路由器配置),保存后启动树莓派即可自动连接W ...

  9. JavaWeb项目前后端分离

    前戏   前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以中间加一个nodejs)有效的进行解耦, 并且前后端分离会为以后的大型分布式架构.弹性计算架构.微 ...

  10. Ubuntu不能使用passwd的--stdin的解决办法

    转载请注明来源https://www.cnblogs.com/sogeisetsu/p/11397648.html Ubuntu不能使用passwd的--stdin的解决办法 可以使用chpasswd ...