一 为什么要进行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 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

【转】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. element-ui 上传图片或视频时,先回显在上传

    <el-upload class="upload-demo" ref="vidos" :action="URL+'/api/post/file' ...

  2. idea git提交代码步骤(转载)

    参考一: https://blog.csdn.net/u013452337/article/details/79956604

  3. Mysql 游标初识

    MySql 游标初识 认识 游标(cursor), 按字面意思可理解为, 游动的标识, 或者叫做"光标", 这样更容易理解. 就好比现有一张表存储了n行记录, 然后我想每次取出一行 ...

  4. 什么是OSI参考模型?

    一.OSI参考模型 1.OSI的来源 OSI(Open System Interconnect),即开放式系统互联. 一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模 ...

  5. 小型SSM项目出现Failed to load ApplicationContext错误的解决方法(个人向)

    使用单元测试的时候,出现了Failed to load ApplicationContext错误,在添加了一个新的Mapper.xml文件才出现的,在保证其他配置文件没有出错的情况下,检查mapper ...

  6. python的email、smtplib、poplib模块收发邮件

    一封电子邮件的旅程是: MUA:Mail User Agent--邮件用户代理.(即类似Outlook的电子邮件软件) MTA:Mail Transfer Agent--邮件传输代理,就是那些Emai ...

  7. 第一个python&selenium自动化测试实战项目

    说明:本项目采用流程控制思想,未引用unittest&pytest等单元测试框架 一.项目介绍 目的 测试某官方网站登录功能模块可以正常使用 用例 1.输入格式正确的用户名和正确的密码,验证是 ...

  8. 借助xxl-sso实现SSO

    前言 市场上一下主流的SSO技术搭配方案: SpringSecurity + OAuth2 SpringSecurity + CAS 功能较弱,对前后端分离的项目支持不是很好 Shiro + CAS ...

  9. score indicator

    The strongest scorer applet is the strongest scorer specially designed for the players. No longer wo ...

  10. Ice Igloos Gym - 101480I (暴力技巧)

    Problem I: Ice Igloos \[ Time Limit: 10 s \quad Memory Limit: 512 MiB \] 题意 给出\(n\)个圆,给出每个圆的坐标\(x\). ...