• 有时候我们写 Android APP,需要让它获取 ROOT 权限,那么如何让 APP 去向系统申请呢?下面提供一个方法,前提是系统是已经 ROOT 权限了,能够执行能 su 命令。如果不能,可以参考上一篇: 获取Android系统的...

    有时候我们写 Android APP,需要让它获取 ROOT 权限,那么如何让 APP 去向系统申请呢?下面提供一个方法,前提是系统是已经 ROOT 权限了,能够执行能 su 命令。如果不能,可以参考上一篇: 获取Android系统的ROOT权限 。

    1. 首先编写一个 SystemManager 类。

    01 package net.nowamagic.magicapp_v17;
    02  
    03 import java.io.DataOutputStream;
    04  
    05 import android.app.Activity;
    06 import android.util.Log;
    07  
    08 public class SystemManager extends Activity {
    09      
    10     /**
    11      * 应用程序运行命令获取 Root权限,设备必须已破解(获得ROOT权限)
    12      * @param command 命令:String apkRoot="chmod 777 "+getPackageCodePath(); RootCommand(apkRoot);
    13      * @return 应用程序是/否获取Root权限
    14      */
    15     public static boolean RootCommand(String command)
    16     {
    17         Process process = null;
    18         DataOutputStream os = null;
    19         try
    20         {
    21             process = Runtime.getRuntime().exec("su");
    22             os = new DataOutputStream(process.getOutputStream());
    23             os.writeBytes(command + "\n");
    24             os.writeBytes("exit\n");
    25             os.flush();
    26             process.waitFor();
    27         catch (Exception e)
    28         {
    29             Log.d("*** DEBUG ***""ROOT REE" + e.getMessage());
    30             return false;
    31         finally
    32         {
    33             try
    34             {
    35                 if (os != null)
    36                 {
    37                     os.close();
    38                 }
    39                 process.destroy();
    40             catch (Exception e)
    41             {
    42             }
    43         }
    44         Log.d("*** DEBUG ***""Root SUC ");
    45         return true;
    46     }
    47      
    48 }

    2. 然后在 MainActivity 中加入这么两句:

    01 public class MainActivity extends Activity
    02 {
    03     public void onCreate(Bundle savedInstanceState)
    04     {
    05         super.onCreate(savedInstanceState);
    06         setContentView(R.layout.main);
    07         String apkRoot="chmod 777 "+getPackageCodePath();
    08         SystemManager.RootCommand(apkRoot);
    09     }
    10 }

    运行 APP,即可向系统申请 ROOT 权限了。


    http://www.nowamagic.net/academy/detail/50282009
    展开全文
  • Android root-tools

    2016-09-18 12:33:52
    Android root-tools

    root-tools

    项目地址:root-tools
    • RootTools·Neo 正式发布啦~
    • RootTools 是一款专注于给 root 后的用户提供方便的软件。主要提供:

      • 应用冻结 不删除系统内的应用,而是将其冻结,在需要时可以解冻,但是别乱来哦,冻错了会无法开机,只能双清;
      • 自动化组件管理 一个应用内往往包含大量的『四大组件』并且持续耗电,这个功能可以帮助禁用组件,但是最大程度上不影响应用的正常使用;
      • 深度清理系统运行久了,总会有各种各样的缓存,特别是 ART 缓存很难清理,留着会造成一些奇怪的问题,清理 ART 事不宜迟。
    • 同时也针对目前海量用户的 MIUI 系统进行相应的优化:

      • 去除系统广告 不知从何时起,MIUI 充斥着广告,这个功能将最大限度的帮助清理掉广告,以及各种带广告的闪屏页;
      • 半个图标 MIUI8 通知栏的四个半图标实在丑得难以致信,好在我们可以把它改为五个,并且双页模式下现在拥有四列;
      • root 25 秒等待 又一个反人类设计,说好的为发烧而生呢,只能用一些黑科技来去掉这该死的 25 秒了,是谁说的时间就是金钱。
    • 为了实现如去除广告等功能,必须借助 xposed 框架,以实现对目标方法的 Hook 和修改。因此要求用户的手机已安装 xposed 框架,请特别注意 MIUI 需要专用的 xposed,请自行搜索。


    • 本软件遵守 GPLv2 协议, 并坚持免费和开源, 保持更新。不接受代理、转卖等各种商业行为, 也不要求捐赠, 完全将软件的使用权利交给用户。
    • 您甚至可以下载并修改这份源码, 在 GPLv2 允许的条件下自行发布版本。

    • 编译软件

      • 系统必备 jdk8 和 gradle 2.14.1

        $ git clone https://github.com/rarnu/root-tools
        $ cd root-tools
        $ gradle build
        
      • 如果您还需要自行编译 JNI 部分,可以自行下载 CodeTyphon,并编译其 Cross Elements 以适应 Android 跨平台编译(目前仅支持 Linux 环境,不需要额外安装 NDK)。源码中已提供编译脚本

        $ cd native
        $ ./build.sh
        
      • 此时即可以得到工作于 arm, mips, x86 三个平台的 libcmd.so

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

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

    那么root了会有什么风险呢,为什么不root就没有风险,又怎么来检查手机是否root了?

    我们先来了解下Android安全机制:

    Android安全架构是基于Linux多用户机制的访问控制。应用程序在默认的情况下不可以执行其他应用程序,包括读或写用户的私有数据(如联系人数据或email数据),读或写另一个应用程序的文件。
    一个应用程序的进程就是一个安全的沙盒(在受限的安全环境中运行应用程序,在沙盒中的所有改动对操作系统不会造成任何危害)。它不能干扰其它应用程序,除非显式地声明了“permissions”,以便它能够获取基本沙盒所不具备的额外的能力。
    每一个Android应用程序都会在安装时就分配一个独有的Linux用户ID,这就为它建立了一个沙盒,使其不能与其他应用程序进行接触。这个用户ID会在安装时分配给它,并在该设备上一直保持同一个数值。
    所有的Android应用程序必须用证书进行签名认证,而这个证书的私钥是由开发者保有的。该证书可以用以识别应用程序的作者。签名影响安全性的最重要的方式是通过决定谁可以进入基于签名的permisssions,以及谁可以share 用户IDs。通过这样的机制,在不考虑root用户的情况下,每个应用都是相互隔离的,实现了一定的安全。

    为什么要把root排除在外,才能说应用的隔离是安全的呢?

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

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

    接下来了解下root的方式

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

    root检测的方法

    下面介绍下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命令来实现的,所以可以检查这个命令是否存在。
    有三个方法来测试su是否存在:
    1)检测在常用目录下是否存在su

        public static boolean checkRootPathSU()
        {
            File f=null;
            final String kSuSearchPaths[]={"/system/bin/","/system/xbin/","/system/sbin/","/sbin/","/vendor/bin/"};
            try{
                for(int i=0;i<kSuSearchPaths.length;i++)
                {
                    f=new File(kSuSearchPaths[i]+"su");
                    if(f!=null&&f.exists())
                    {
                        Log.i(LOG_TAG,"find su in : "+kSuSearchPaths[i]);
                        return true;
                    }
                }
            }catch(Exception e)
            {
                e.printStackTrace();
            }
            return false;
        }

    这个方法是检测常用目录,那么就有可能漏过不常用的目录。
    所以就有了第二个方法,直接使用shell下的命令来查找。

    2)使用which命令查看是否存在su
    which是linux下的一个命令,可以在系统PATH变量指定的路径中搜索某个系统命令的位置并且返回第一个搜索结果。
    这里,我们就用它来查找su。

        public static boolean checkRootWhichSU() {
            String[] strCmd = new String[] {"/system/xbin/which","su"};
            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;
            }
        }

    其中调用了一个函数 executeCommand(),是执行linux下的shell命令。具体实现如下:

        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;
        }

    然而,这个方法也存在一个缺陷,就是需要系统中存在which这个命令。我在测试过程中,就遇到有的Android系统中没有这个命令,所以,这也不是一个完全有保障的方法,倒是可以和上一个方法(在常用路径下查找)进行组合,能提升成功率。
    这种查找命令的方式,还有一种缺陷,就是可能系统中存在su,但是已经失效的情况。例如,我曾经root过,后来又取消了,就可能出现这种情况:有su这个文件,但是当前设备不是root的。

    3)执行su,看能否获取到root权限
    由于上面两种查找方法都存在可能查不到的情况,以及有su文件与设备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;
            }
        }

    上面的代码,调用了两个函数:writeFile()写文件,readFile()读文件,下面是具体实现:

    //写文件
        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;
            }
        }
    

    这里说句题外话,我最初是想使用shell命令来写文件:

    echo "test_ok" > /data/su_test

    可是使用executeCommand()来调用执行这个命令,结果连文件都没有创建出来。在多次失败后才想到:应该是这个shell命令涉及到了重定向(例如本例中,将本来应该屏幕输出的信息转而写入文件中),才导致的失败。这个重定向应该是需要写代码获取数据流来自己实现。不过,既然要写代码使用数据流,那么我可以更简单的直接写文件,就没有去尝试用代码来实现重定向了。

    小结:

    由于每种方法各有其特色与缺陷,所以我最终将这些方法加起来了。注意,检查su的3种方法,不必都使用上,可以选第一二种查找的方法,或者选第三种执行的方法。
    组合调用的代码如下:

        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;
        }

    参考:

    http://blog.csdn.net/quanshui540/article/details/48242459
    https://blog.netspi.com/android-root-detection-techniques/
    http://blog.csdn.net/hudashi/article/details/8091543
    http://blog.csdn.net/jia635/article/details/38514101
    http://bobao.360.cn/learning/detail/144.html

    展开全文
  • 一 为什么要进行root检测? 出于安全原因,我们的应用程序不建议在已经root的设备上运行...在系统中,每个文件、目录和进程,都归属于某一个用户,没有用户许可其它普通用户是无法操作的,但对root除外。 root用户...

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

    ​​​​

    展开全文
  • 本文介绍了android中获取root权限的方法以及原理,让大家对android玩家中常说的“越狱”有一个更深层次的认识。   二、 Root的介绍 1.  Root 的目的 可以让我们拥有掌控手机系统的权限,比如删除一些system/app...

    一、 概述

    本文介绍了android中获取root权限的方法以及原理,让大家对android玩家中常说的“越狱”有一个更深层次的认识。

     

    二、 Root的介绍

    1.       Root 的目的

    可以让我们拥有掌控手机系统的权限,比如删除一些system/app下面的无用软件,更换开关机铃声和动画,拦截状态栏弹出的广告等。

    2.       Root的原理介绍

    谷歌的android系统管理员用户就叫做root,该帐户拥有整个系统至高无上的权利,它可以访问和修改你手机几乎所有的文件,只有root才具备最高级别的管理权限。我们root手机的过程也就是获得手机最高使用权限的过程。同时为了防止不良软件也取得root用户的权限,当我们在root的过程中,还会给系统装一个程序,用来作为运行提示,由用户来决定,是否给予最高权限。这个程序的名字叫做Superuser.apk。当某些程序执行su指令想取得系统最高权限的时候,Superuser就会自动启动,拦截该动作并作出询问,当用户认为该程序可以安全使用的时候,那么我们就选择允许,否则,可以禁止该程序继续取得最高权限。Root的过程其实就是把su文件放到/system/bin/ Superuser.apk 放到system/app下面,还需要设置/system/bin/su可以让任意用户可运行,有set uidset gid的权限。即要在android机器上运行命令:adb shell chmod 4755 /system/bin/su。而通常,厂商是不会允许我们随便这么去做的,我们就需要利用操作系统的各种漏洞,来完成这个过程。

    特别说明:我们烧机中的Eng版本并没有Root权限

    3.       Root的方法

    Root的原理我们了解到,root过程分三步:

    a.        adb push su /system/bin
    
    b.        adb push SuperUser.apk /system/app
    
    c.       adb shell chmod 4755 /system/bin/su

    若系统是eng版的,做到以上三步,那么我们Root就大功告成,但实际是不行的。为什么呢?原因有三:

    1user版的/system路径是只读权限,不能简单写入

    2 chmod需要Root权才能运行(死循环了)

    3、有些系统在启动时会自动将su4755权限设成755,甚至直接删除su

    那么针对这种情况,我们怎么办呢?非常简单:烧一个eng版本的boot.img就行了

    可以用展讯的烧录工具,或者用fastboot模式从sd卡烧一个boot.img文件即可

    至此,我们Root就成功了,可以用R.E(Root Explorer)在根目录创建和删除文件。

     

    三、 深入理解Root机制

    其流程是:

    1.       Su 被用户调用
    
    2.       Su 创建了一个socket监听
    
    3.       Su 向Superuser发送了一个广播,说是有一个程序要请求root
    
    4.       Su 等待socket 数据接收。有超时处理。
    
    5.       Superuser 界面收到广播后,弹出一个对话框,询问用户
    
    6.       Superuser 向传来的数据中的socket写回用户应答结果。
    
    7.       Su 根据socket得到的结果处理应该不应该继续执行
    
    8.       完成提权管理 

    superuser.apk这个程序是root成功后,专门用来管理root权限使用的,防止被恶意程序滥用。

    源码地址: http://superuser.googlecode.com/svn/trunk

    我们有两点疑问:

    1.  superuser是怎么知道谁想用root权限? 

    2.  superuser是如何把用户的选择告诉su程序的?

    superusersu程序是如何通讯的,他们俩位于不通的时空,一个在java虚拟中,一个在linux的真实进程中。

    superuser共有两个activity: SuperuserActivity SuperuserRequestActivity,其中SuperuserActivity主要是用来管理白名单的,就是记住哪个程序已经被允许使用root权限了,省的每次用时都问用户。

    SuperuserRequestActivity 就是用来询问用户目前有个程序想使用root权限,是否允许,是否一直允许,即放入白名单。

    这个白名单比较关键,是一个sqlite数据库文件,位置:

    /data/data/com.koushikdutta.superuser/databases/superuser.sqlite

    上文说过,root的本质就是往 /system/bin/下放一个su文件,不检查调用者权限的su文件。普通程序可以调用该su来运行root权限的命令。superuser.apk中就自带了一个这样的su程序。一开始superuser会检测/system/bin/su是否存在:

    File su = new File("/system/bin/su");
    
    // 检测su文件是否存在,如果不存在则直接返回
    
    if (!su.exists())  {
    
    Toast toast = Toast.makeText(this, "Unable to find /system/bin/su.", Toast.LENGTH_LONG);
    
    toast.show();
    
    return;
    
    } 
    
    //如果大小一样,则认为su文件正确,直接返回了事。
    
    if (su.length() == suStream.available()) 
    
    {
    
      suStream.close(); 
    
      return;   //
    
    } 
    
     
    
    // 如果检测到/system/bin/su文件存在,但是不对头,则把自带的su先写到"/data/data/com.koushikdutta.superuser/su"
    
    //再写到/system/bin/su。
    
    byte[] bytes = new byte[suStream.available()];
    
    DataInputStream dis = new DataInputStream(suStream);
    
    dis.readFully(bytes);
    
    FileOutputStream suOutStream = new FileOutputStream("/data/data/com.koushikdutta.superuser/su");
    
       suOutStream.write(bytes);
    
       suOutStream.close();
    
       
    
       Process process = Runtime.getRuntime().exec("su");
    
       DataOutputStream os = new DataOutputStream(process.getOutputStream());
    
       os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n");
    
       os.writeBytes("busybox cp /data/data/com.koushikdutta.superuser/su /system/bin/su\n");
    
       os.writeBytes("busybox chown 0:0 /system/bin/su\n");
    
       os.writeBytes("chmod 4755 /system/bin/su\n");
    
       os.writeBytes("exit\n");
    
       os.flush();
    

    有进程使用root权限,superuser是怎么知道的呢,关键是句:

    sprintf(sysCmd, "am start -a android.intent.action.MAIN
    
                                        -n com.koushikdutta.superuser/com.koushikdutta.superuser.SuperuserRequestActivity
    
                                     --ei uid %d --ei pid %d > /dev/null", g_puid, ppid);
    
      if (system(sysCmd))
    
       return executionFailure("am.");

       原理是am命令,am的用法:

     

     usage: am [subcommand] [options]
    
        start an Activity: am start [-D] [-W] <INTENT>
    
            -D: enable debugging
    
            -W: wait for launch to complete
    
        start a Service: am startservice <INTENT>
    
        send a broadcast Intent: am broadcast <INTENT>
    
        start an Instrumentation: am instrument [flags] <COMPONENT>
    
            -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)
    
            -e <NAME> <VALUE>: set argument <NAME> to <VALUE>
    
            -p <FILE>: write profiling data to <FILE>
    
            -w: wait for instrumentation to finish before returning
    
        start profiling: am profile <PROCESS> start <FILE>
    
        stop profiling: am profile <PROCESS> stop
    
     
    
        <INTENT> specifications include these flags:
    
            [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
    
            [-c <CATEGORY> [-c <CATEGORY>] ...]
    
            [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
    
            [--esn <EXTRA_KEY> ...]
    
            [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
    
            [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
    
            [-n <COMPONENT>] [-f <FLAGS>]
    
            [--grant-read-uri-permission] [--grant-write-uri-permission]
    
            [--debug-log-resolution]
    
            [--activity-brought-to-front] [--activity-clear-top]
    
            [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
    
            [--activity-launched-from-history] [--activity-multiple-task]
    
            [--activity-no-animation] [--activity-no-history]
    
            [--activity-no-user-action] [--activity-previous-is-top]
    
            [--activity-reorder-to-front] [--activity-reset-task-if-needed]
    
            [--activity-single-top]
    
            [--receiver-registered-only] [--receiver-replace-pending]
    
            [<URI>]<span style="font-family:Calibri;font-size:14px;"> </span>

    还有个疑点,就是su怎么知道用户是允许root权限还是反对呢?原来是上面提到的白名单起来作用,superuser把用户的选择放入:

    /data/data/com.koushikdutta.superuser/databases/superuser.sqlite   数据库中,然后su进程再去读该数据库来判断是否允许。

    static int checkWhitelist()
    
    {
    
     sqlite3 *db;
    
     int rc = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, NULL);
    
     if (!rc)
    
     {
    
      char *errorMessage;
    
      char query[1024];
    
      sprintf(query, "select * from whitelist where _id=%d limit 1;", g_puid);
    
      struct whitelistCallInfo callInfo;
    
      callInfo.count = 0;
    
      callInfo.db = db;
    
      rc = sqlite3_exec(db, query, whitelistCallback, &callInfo, &errorMessage);
    
      if (rc != SQLITE_OK)
    
      {
    
       sqlite3_close(db);
    
       return 0;
    
      }
    
      sqlite3_close(db);
    
      return callInfo.count;
    
     }
    
     sqlite3_close(db);
    
     return 0;
    
    } 

    四、 资源文件的获取

    从上文的源码地址获取源代码,替换系统的system/extras/su/下面的su.cAndroid.mk文件,使用编译命令 ./mk td28 u adr system/extras/su/编译成功后会生成out/target/product/hsdroid/system/xbin/su文件,而Superuser.apk就是普通的apk文件,都在源码地址里面可以下载,下载后倒入到eclipse即可直接运行。

     

    五、 总结

    在阅读完本文后,可以站在专业的角度了解root的真正原理,以及有用户有需求时我们可以帮助其快速的解决问题。


    转载请标明出处:http://blog.csdn.net/chaihuasong/article/details/8463212

    展开全文
  • 或者说替换掉系统中的su程序,因为系统中的默认su程序需要验证实际用户权限,只有root和 shell用户才有权运行系统默认的su程序,其他用户运行都会返回错误。而破解后的su将不检查实际用户权限,这样普通的用户也将...
  • 第1章 Root的基本原理Android的内核就是Linux,所以Android获取root其实和Linux获取root权限是一回事儿。你想在Linux下获取root权限的时候就是执行sudo或者su,接下来系统会提示你输入root用户的密码,密码正确就...
  • 制作Android Root Ramdisk

    2011-03-31 10:42:00
    制作Android Root Ramdisk 概 述 制作AndroidRoot Ramdisk,供linux挂载并运行 目 录 1. Android Root Ramdisk介绍... 3 2. Android Root Ramdisk的开发环境... 3 3. 制作Android Root Ramdisk.. 4 4. 使用Android...
  • Android ROOT、System权限、设备管理器的一些笔记。以后还会一些内容作补充,希望大神指教。
  • Android Root

    2020-05-03 13:00:37
    Root 通过内核漏洞获取最高权限(superuser) root用户:linux的root用户相当于window的administrator管理员用户,控制操作系统的一切权限 操作系统=系统内核+文件系统 linux系统= android系统 = linux内核+ ...
  • android手机Root全过程

    2019-04-09 17:36:20
    现在的android手机想要获取root的最高权限都是非常麻烦的,当然这样也能让手机相对更安全,但是最近公司一个项目其中的部分功能需要获取手机的root权限,所以这里就做一个root过程的记录。 以红米6为例,说一下root...
  • Android 操作系统 获取Root权限 原理解析
  • Android权限说明 Android系统是运行在Linux内核上的,Android与Linux分别有自己的一套严格的安全及权限机制, Android系统权限相关的内容, (一)linux文件系统上的权限 -rwxr-x--x system system 4156 2012-...
  • ROOT方法适用于RK3288/RK3399 的Android 32/64位系统。 可以root的前提是: 板子本身具有root权限,即可以在adb下执行su切换到root账户,并且可以挂载/system分区为读写模式,一般RK3288开发板都是这种模式,即...
  • Android Root原理初探

    2015-06-11 10:45:43
    RootLinux:Root == Windows:AdminstratorAndroid是Linux系统吗?操作系统 = 系统内核 + 文件系统 Linux发行版:Linux内核 + 文件系统(ext3/4) Android:Linux内核 + 文件系统(ext3/4) Android 没有本地窗口...
  • Accessing Root from the Magic/Sapphire Terminal Emulator Now that you have followed Magic Rooting to root your HTC Magic/Sapphire, you will notice that it is not possible to gain a root from an ...
  • Android的静默安装似乎是一个很有趣很诱人的东西,但是,用普通做法,如果手机没有root权限的话,似乎很难实现静默安装,因为Android并不提供显示的Intent调用,一般是通过以下方式安装apk: Intent intent = new ...
  • 关闭Android root权限

    2012-01-09 15:30:29
     系统在出厂时,将 root/default.prop  ro.secure=1  则将设备设置为不能被rooted, adb shell进去后看到的是 $ ----- 提示符;同时接串口显示也没有提示符。   因此 破解Android设备的方法则是先把改属性...
  • 手把手教你root Android系统因为从事的是智能家居相关行业,用的系统也是android系统,在某些场景下可能需要拿到系统的root权限。下面就手把手教大家去拿到app的root权限和adb的root权限,比如一般手机在出厂的时候...
  • androidroot权限

    2014-10-15 17:45:22
    本文将从几个方面,由浅至深地讲述ROOT到底是什么东西? 一. ROOT权限简单介绍 二.为什么需要ROOT 三. ADBD的ROOT权限 四.深入源代码 ROOT权限简介: ROOT权限是Linux内核中的最高权限,如果你的身份是ROOT,...
1 2 3 4 5 ... 20
收藏数 144,083
精华内容 57,633