打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
云中漫步 ? Android应用程序获得root权限

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系统安全。

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

你可以通过RSS 2.0 来跟踪本文的所有评论。 你可以对本文发表评论,或者对本文进行评分,或者从你的网站 引用 本文。

相关文章

COMMENTS

52 条评论

  1. bevis

    2011-01-20 14:51:20

    谢谢simon,每次定期的来你这里看看,总会学到很多知识。前几天就刚好遇到你说的这个问题,今天来这里看了一下,问题看来可以解决了,呵呵,谢谢!

    [回复]

    Simon_fu 回复:

    欢迎你多来关注Simon,也欢迎你对Simon的文章多提宝贵意见!大家共同进步!

    [回复]

  2. flye03

    2011-01-21 16:12:07

    后来我更改service 为
    service mtest /system/bin/logwrapper /system/etc/a.sh
    后程序就能正确运行了,不知道是什么原因。总体上是通过了,感谢simon的分享。

    [回复]

  3. tang

    2011-02-24 13:44:13

    Simon,你真棒

    [回复]

    Simon_fu 回复:

    欢迎大家多指正!
    共同进步~!

    [回复]

  4. gqdy365

    2011-02-24 18:11:04

    我有个问题想请教一下楼主,我在做fm模块时遇到了一个权限问题,驱动层生成的文件节点在dev目录下面,上层打开它时说没有权限,我通过串口修改权限后是可以打开的,我网上查了一下,有人说是在init.rc里面做初始化修改,可以指点一下吗?

    [回复]

    Simon_fu 回复:

    确实可以在init.rc中做,init.rc提供了chown和chmod命令,你可以参考system/core/init/readme.txt文件,里面对init.rc的命令进行了详细的描述,网上也有人已经翻译成了中文。

    [回复]

    gqdy365 回复:

    谢谢你,支持你的博客!

    [回复]

  5. billyc

    2011-03-10 03:06:19

    Thank you for this great article. The only one article talk about get app root access in an unrooted Android device.

    Great Job! and thank you again.

    [回复]

  6. 匿名

    2011-03-14 11:08:10

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

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

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

    不等于没说么,如何是Android系统开发人员的话,难道他就没有root权限么? 没有Root权限,他还叫系统开发人员么?

    最核心的问题是,大家都想知道,一般的应用程序如何能够请求到root权限,我目前system权限已经有了,就是没有root权限,因为我不是系统开发人员。

    [回复]

    Simon_fu 回复:

    你不能修改init.rc呢?
    如果能修改就可以了~!
    Android系统设计目标就是不把root暴露给应用程序的,需要root权限的操作都已经封装成Service了,当然我的实现也是这样的。
    如果你已经获得了system权限,那么你可以调用系统中定义的各种service,由各种service来执行需要root权限的操作。如果你要的操作没有对应的service,那么这就是你的系统提供商不想暴露给你。你唯一能做的就是破解它,来获得root权限了。
    Android系统开发人员有root权限,但是他们要把需要root权限的操作暴露给上层的应用程序也是需要考虑的一个方面。也是Android系统安全的一个考虑的方面。

    [回复]

  7. 匿名

    2011-03-20 12:36:49

    simon您好!
    您提到“实现一个虚拟设备,这个设备帮助Android应用程序执行root权限的命令”

    我现在已经写了一个相应驱动,但不知道android app如何跟底层的linux驱动通信,一直找不到头绪,能指导下我吗?
    万分感谢

    [回复]

    Simon_fu 回复:

    实现一个字符设备驱动,然后app打开这个设备驱动文件,然后向里面写入需要执行的命令,由驱动程序代理执行相应的命令。

    [回复]

    匿名 回复:

    谢谢您!
    祝博主天天开心!

    [回复]

  8. 匿名

    2011-04-07 17:09:36

    simon您好!
    看了您的博客,收益很大,想问问您两个问题
    1,您说的使用虚拟字符驱动的方法,在方法里怎样调用eth0让它开启,设置ip等呀,可以提供些函数嘛?
    2,使用服务的方法,怎样把参数传进去呀?运用一个脚本是ok的。
    希望指导下,万分感谢

    [回复]

    Simon_fu 回复:

    首先,实现字符设备的方法,我是这样做的,就和打开普通文件一样打开虚拟字符设备,然后把需要执行的命令一次性写入该设备文件,设备驱动就开始代理执行这些命令;你可以向做驱动的同事请教这个问题。
    其次:服务的方法,脚本应该也是可以处理参数的,当然你也可以通过C/C++编写一个程序来完成服务也是一样的。你可以查阅一下脚本的实现,另外init服务也是可以加参数的,请参考Android init readme.

    [回复]

    匿名 回复:

    很谢谢您的及时回复
    驱动也是我自己写的,现在问题就在于设备怎样去执行那些命令,驱动中没有system函数的调用,ifc_up也用不了,如何把ifconfig这个文件加入的话好像就麻烦了点,您说的“设备驱动就开始代理执行这些命令”是怎样代理的,能指点下嘛,非常感谢

    [回复]

    Simon_fu 回复:

    请参考一下这个帖子:
    http://www.unixresources.net/linux/clf/linuxK/archive/00/00/57/83/578302.html
    另外,虚拟设备方案不是Android平台下面常规方案,主要涉及到安全性;只有万不得已的时候再用。优先选用init服务的方案会比较好。

    [回复]

    匿名 回复:

    谢谢您如此热心。
    现在就是在考虑init服务写的那个socket如何能从用户手中获得参数,而不是在init中配置参数。
    非常感谢您的回答,祝您工作顺利,身体健康

    [回复]

  9. byfrancis

    2011-04-13 10:23:08

    Simon您好,看了你的博文感觉受益匪浅,按照我的理解,文中的方法好像没有不能让用户“一键获取root的权限”,或者是让应用程序自动获取root权限。我知道网上有个应用程序Z4root,可以让用户一键获取root权限,但我不知道是怎么实现的。如果是我对您的方法没有理解,或者是您有一键获取root权限的方法,能指点一下吗?不胜感激!

    [回复]

    Simon_fu 回复:

    这个就是传说中root破解,我没有研究过这种破解方式,没有发言权。不好意思!

    [回复]

    byfrancis 回复:

    非常感谢,期待您后续的android博文

    [回复]

  10. chaos

    2011-04-15 08:03:01

    simon牛,问你一个比较傻的问题啊

    像RE之类的文件甚至能有重新把根目录挂载为RW的权限

    这种权限也是通过这种方法实现的吗

    还是说已经root的手机应用程序即可以通过

    process = Runtime.getRuntime().exec(“su”);

    这种语句来获取root权限??

    [回复]

    Simon_fu 回复:

    我在网上看到很多人都是这样获得root权限的,但是这必须要是rooted过的手机,否则没戏!所以这种方法不通用。rooted手机本身也是利用了系统漏洞,如果那一天把漏洞堵上,也就没戏了!

    [回复]

    chaos 回复:

    谢谢simon牛

    我看了下android 那些terminal模拟器的代码,自己编译了,发现他们在没有root权限的机器上是没有办法执行su的,也看了下superuser的代码,它的思路是修改机器上的su程序,替换成自己编译的su程序,大致明白了通过process = Runtime.getRuntime().exec(“su”);怎么获取root权限的。

    ps:

    有一个小问题,我看了你上文提到的请参考《Android Permission》。里面我尝试着对init.rc文件进行修改,但是每次修改后重启机器init.rc文件都恢复成为修改前的状态了,请问你有修改过该文件吗?

    [回复]

    Simon_fu 回复:

    因为你的根分区是是只读的,试试adb remount行不行?

    [回复]

    chaos 回复:

    对 我是root权限 mount -o rw,remount -t rootfs /

    [回复]

    匿名 回复:

    init.rc 不是在ramdisk裡面嗎?ramdisk運行在內存裡面,
    每次重開機當然會恢復之前的狀態。

    [回复]

    chaos 回复:

    谢谢了 那init.rc未启动时具体在rom的什么文件里面呢?

    是不是在启动之后再映射到内存内吗

    如果要修改是不是得修改rom然后重新刷机才可以成功??

    [回复]

    Simon_fu 回复:

    呵呵!我只是研究了这个技术,刷机这种事儿我可没干过!
    这个帮不了你啊!
    你可以到刷机网站上面请教这个问题。

    [回复]

    chaos 回复:

    那在为映射到内存之前init.rc对应哪个文件呢?

    是否修改init.rc必须先修改rom

    然后重新刷机才能生效??

    [回复]

  11. pcsuite

    2011-04-16 12:15:53

    楼主,你好,我看了你很多篇文章,写的都很好,而且对我的帮助也很大,在此表示感谢。

    [回复]

  12. dxz

    2011-04-22 18:18:20

    你好,我要是想用我的应用在system目录下创建一个文件,用你说的那方法好像不可行吧。能不能给个思路。谢谢

    [回复]

    Simon_fu 回复:

    你遇到什么问题了吗?
    我觉得是可以做到的!因为已经有root权限了,在系统中创建文件没有理由不成功的。
    system分区是只读的,你可能需要remount一下吧。

    [回复]

    dxz 回复:

    您好,我是初学者,您说的那个服务该怎么写呢 ?我还是没明白那服务是怎么回事?为什么掉声明一个服务就可以应用就可以获取root权限呢 ?还是应用只能调用声明的那个服务里的方法?

    [回复]

  13. chaos

    2011-04-24 01:34:49

    simon牛

    最近我打算详细阅读以下android框架的源代码

    ActivityManagerService.java

    对ActivityManagerService的大致流程有所了解了

    但是对于细节很难看懂

    能不能介绍一下你阅读android源码的技巧吗

    或者在国外有没有对android相关源码剖析的文章或blog吗?

    尤其是对ActivityManagerService.java部分的??

    非常感谢

    [回复]

    Simon_fu 回复:

    说实话,上万行的代码我也不看!
    只是说自己需要的时候,顺藤摸瓜摸到这里而已!
    另外既然是service,熟悉了Android service对你理解它也很有帮助。

    [回复]

  14. chaos

    2011-04-24 19:20:04

    simon牛,请教一个问题

    请问一下能不能指点一下阅读android框架源代码的技巧啊

    比如我最近在阅读ActivityManagerService.java 光这一个模块就一万多行的代码

    大体知道是一个什么它流程 但细节深究实在是很乱啊 看不出头绪

    或者外国有没有相关剖析android源代码的blog或文章吗??

    [回复]

  15. aplikacje na telefon

    2011-04-30 08:58:52

    The most comprehensive and very well thought out write up I have found on this subject on the net. Keep on writing, I will keep on coming by to read your new content. This is my fourth time coming by your blog.

    [回复]

  16. soros

    2011-05-25 10:04:59

    谢谢楼主共享,不知道楼主是否研究过Runtime.exec() 方法执行shell 指令呢? 这样是不是也能够获取到root 执行权限呢? 我正在使用这种方法,但是却不能够正常执行shell 脚本。

    [回复]

    Simon_fu 回复:

    可以肯定的告诉你,绝对不可能拥有root权限。因为只有在java层才能调用Runtime.exec(),这样的进程不可能是root权限的进程,最高是system权限。

    [回复]

  17. abc

    2011-05-28 13:57:52

    理解错,谢谢,问题已经解决了

    [回复]

  18. abc

    2011-06-03 09:55:44

    解决了,是线程并发问题。

    [回复]

  19. 匿名

    2011-07-10 16:35:53

    simon_fu;你好,我想请问一下,我要通过jni方式去操作/dev目录下的设备文件,我看您的博文说只要获得system权限就可以操作设备了,但是我获得了system权限还是不能访问设备文件,请问访问设备文件ap必须要具备root权限吗?

    [回复]

    Simon_fu 回复:

    这个就要看你的设备驱动要求的权限了!
    有的设备驱动必须要root才可以!
    需要驱动哦你工程师商议!

    [回复]

  20. lufengdie

    2011-08-01 15:01:21

    “首先定义一个执行mount的脚本,我把它位于/system/etc/mount_nfs.sh”

    这一步不能操作啊。

    请教楼主、

    [回复]

    Simon_fu 回复:

    说明你没有设备的root权限,或者你没有remount system分区。

    [回复]

  21. 匿名

    2011-08-19 22:34:30

    你好simon,我最近遇到一个问题,我的apk要执行一些需要root权限的命令.看了你介绍的这种方法(第一种),可是这种方法怎么取得命令执行的输出呢?

    [回复]

    Simon_fu 回复:

    把命令行重定向到文件,然后执行结束之后,读取文件内容。

    [回复]

  22. vincent.yan

    2011-08-23 19:40:10

    simon牛,看了你的几篇文章,收益匪浅
    但是我现在遇到类似问题,希望能给予指导。

    首先我要实现的是一个android应用,但是我想要获取到root权限。(不是Android系统开发人员),这个情况该怎么做?是否用第二种方法可以实现

    或者你有什么好方法让应用在非root权限下,去抓屏呢?

    [回复]

    Simon_fu 回复:

    抓屏?
    我觉得应该是要用到framebuffer吧!
    没有root权限我觉得难!
    不好意思!

    [回复]

  23. Simon_fu

    2011-09-14 13:59:41

    研究一下init的帮助文档,里面解释了init service参数传递问题。

    [回复]

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android: 启动init.rc 中service的权限问题
Android系统root破解原理分析(续)
iMX6 Android系统下常见问题解决思路
android init.rc中启动的service 默认是disable的,后续如何启动此服务
Linux下让Oracle服务自动启动与停止 (2009-01-04 16:30:28)
Linux中如何将脚本做成系统服务开机自启动
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服