zoukankan      html  css  js  c++  java
  • Android应用程序获得root权限

    我在博文《Android程序的安全系统》中提到两种让root权限的办法。最近在网上发现很多朋友转载那篇文章,但是对那篇文章中提到的第一种方法怎样实现,不是很明白。本文将会以一个例子实现来演示怎样让一个Android应用程序获得root权限。

    问题

        我遇到的问题是我想在Java应用程序中动态mount一个NFS的系统,但是执行mount命令必须要要root权限才可以。一般情况下,在Android的Java层是不能获得root权限的。

    思路

       我在博文《Android程序的安全系统》中提到两种思路:

    1、实现一个init实现一个Service,来帮助Android应用程序执行root权限的命令。
    2、实现一个虚拟设备,这个设备帮助Android应用程序执行root权限的命令。

       本文将会选择第一种来解决Android应用程序mount NFS文件系统的问题。

    Init.rc Service

       在Android系统init.rc中定义很多Service,具体定义格式可以参考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定义的Service将会被Init进程创建,这样将可以获得root权限。

       现在问题是Android应用程序怎样启动让init进程知道我们想运行那个进程呢?答案是设置系统属性“ctl.start”,把 “ctl.start”设置为你要运行的Service,假设为“xxx”,Android系统将会帮你运行“ctl.start”系统属性中指定的 Service。那么运行结果init进程将会将会写入命名为“init.svc.+Service名称”的属性中,也就是“init.svc.xxx” 属性,应用程序可以参考查阅这个值来确定Service执行的情况。想更深入了解Android property系统可以参考博文《(翻译)Android属性系统》。

    Android property权限

        难道Android属性“ctl.start”是所有进程都可以设置的吗?那世界不就乱套了,谁都可以可以执行init.rc中Service了,查看 property_service.c中的源码,设置Android系统属性的函数为handle_property_set_fd:

       1: void handle_property_set_fd(int fd)
       2: {
       3:     ......
       4:     switch(msg.cmd) {
       5:     case PROP_MSG_SETPROP:
       6:         msg.name[PROP_NAME_MAX-1] = 0;
       7:         msg.value[PROP_VALUE_MAX-1] = 0;
       8:  
       9:         if(memcmp(msg.name,"ctl.",4) == 0) {
      10:             if (check_control_perms(msg.value, cr.uid, cr.gid)) {
      11:                 handle_control_message((char*) msg.name + 4, (char*) msg.value);
      12:             } else {
      13:                 ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
      14:                         msg.name + 4, msg.value, cr.uid, cr.pid);
      15:             }
      16:         }
      17:         ......
      18:     }
      19: }

        从源码中我们发现如果设置“ctl.”开头的Android系统property,将会调用check_control_perms函数来检查调用者的权限,其定义如下:

       1: static int check_control_perms(const char *name, int uid, int gid) {
       2:     int i;
       3:     if (uid == AID_SYSTEM || uid == AID_ROOT)
       4:         return 1;
       5:  
       6:     /* Search the ACL */
       7:     for (i = 0; control_perms[i].service; i++) {
       8:         if (strcmp(control_perms[i].service, name) == 0) {
       9:             if ((uid && control_perms[i].uid == uid) ||
      10:                 (gid && control_perms[i].gid == gid)) {
      11:                 return 1;
      12:             }
      13:         }
      14:     }
      15:     return 0;
      16: }

        我们发现root权限和system权限的应用程序将会授权修改“ctl.”开头的Android系统属性。否则将会检查control_perms全局变量中的定义权限和Service。

        如果想更深入的了解Android Init进程和Android Property的权限控制,请参考《Android Permission》。

    实例

        通过上面的介绍我们基本已经有思路了,下面以上面提出的mount nfs文件系统为例说明:

    1、首先定义一个执行mount的脚本,我把它位于/system/etc/mount_nfs.sh,定义如下:

       1: #!/system/bin/sh
       2:  
       3: /system/bin/busybox mount -o rw,nolock -t nfs 192.168.1.6:/nfs_srv /data/mnt

    不要忘了把它加上可执行权限。

    2、在init.rc中加入一个Service定义,定义如下:

       1: service mount_nfs /system/etc/mount_nfs.sh
       2:     oneshot
       3:     disabled

    3、让自己的应用程序获得system权限,博文《Android程序的安全系统》中提到了怎样获得system权限,请参考,这里就不赘述了。

    4、在自己应用程序中设置System系统属性“ctl.start”为“mount_nfs”,这样Android系统将会帮我们运行mount_nfs系统属性了。这里需要强调的是不能够调用System.getProperty, 这个函数只是修改JVM中的系统属性。而不能修改Android的系统属性。可以调用 android.os.SystemProperties(Android 2.1 Eclair系统可以调用这个API),如果你的Android版本不能调用这个类,只能通过JNI,调用C/C++层的API property_get和property_set函数了。如果想详细了解请参考(翻译)Android属性系统。代码如下:

       1: SystemProperties.set("ctl.start", "mount_nfs");

    5、最后在自己应用程序中,读取“init.svc.mount_nfs”Android系统Property,检查执行结果。代码如下:

       1: while(true)
       2: {
       3:     mount_rt = SystemProperties.get("init.svc.mount_nfs", "");
       4:     if(mount_rt != null && mount_rt.equals("stopped"))
       5:     {
       6:         return true;
       7:     }
       8:     
       9:     try
      10:     {
      11:         Thread.sleep(1000);
      12:     }catch(Exception ex){
      13:         Log.e(TAG, "Exception: " + ex.getMessage());
      14:     }
      15: }

        init进程维护一个service的队列,所以我们需要轮训来查询service的执行结果。

        通过上面的这些步骤,Android应用程序就能够调用init.rc中定义的Service了。这样你的Android应用程序也就获得了root权限。

    总结

       通过上文可以看出,在Android获得root权限还是需要一些前提的,比如:

    1、必须是Android系统开发人员,否则你无法修改init.rc等文件。 2、你的应用程序必须要获得system权限。

        这样可以防止root权限被应用程序无限制的使用,最终危及Android系统安全。

        希望本文对你能有所帮助,如果有错误之处敬请指正。

    原文

  • 相关阅读:
    HDU 2116 Has the sum exceeded
    HDU 1233 还是畅通工程
    HDU 1234 开门人和关门人
    HDU 1283 最简单的计算机
    HDU 2552 三足鼎立
    HDU 1202 The calculation of GPA
    HDU 1248 寒冰王座
    HDU 1863 畅通工程
    HDU 1879 继续畅通工程
    颜色对话框CColorDialog,字体对话框CFontDialog使用实例
  • 原文地址:https://www.cnblogs.com/xiaoxiaoboke/p/2349711.html
Copyright © 2011-2022 走看看