Android su权限管理与分析
发布日期:2021-09-27 14:12:37 浏览次数:10 分类:技术文章

本文共 7736 字,大约阅读时间需要 25 分钟。

由于Android底层是Linux内核,故了解了Linux的权限管理后就可以知道ROOT的原理,具体可以访问《Android系统权限和root权限》一文,而一般的Androd下的su命令只支持在ROOT用户和SHELL用户下才有权限让程序以root用户身份运行,其实看完Android源码下的system/extras/su/su.c代码即可清楚,而我们绕过了其中的当前运行用户判断来让所有的用户都可以将以自己身份运行的程序尝试去设置以root用户身份运行,即运行su命令不需判断运行程序的当前用户的uid,直接可以设置相应的uid和gid,而我们所做的只是修改su.c文件,把如下代码屏蔽即可。        myuid = getuid();    if (myuid != AID_ROOT && myuid != AID_SHELL) {        fprintf(stderr,"su: uid %d not allowed to su\n", myuid);        return 1;    }
使用android 手机很多情况下需要root权限,关于root权限获取的原理可以参考以下文章:1、云中漫步博客:  Android系统root破解原理分析     http://my.unix-center.net/~Simon_fu/?p=10692、云中漫步 ? Android系统root破解原理分析(续) http://my.unix-center.net/~Simon_fu/?p=11003、zergRush - 随想专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/tomken_zhang/article/details/68662604、zergRush (补充) - 随想专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/tomken_zhang/article/details/68701045、结合init源码剖析android root提权漏洞(CVE-2010-E... http://bbs.pediy.com/showthread.php?t=1397386、Android提权代码zergRush分析 | i, Claud http://blog.claudxiao.net/2011/10/zergrush.........原理是利用了android的两个提权漏洞: CVE-2010-EASY 和 ZergRush。 我把大概原理简单说说:1, CVE-2010-EASY : linux的内核的模块化程度很高,很多功能模块是需要到时候再加载,在 android中由init进程来管理这些的。但是这个init进程不会检测发给它的指令的来源,不管是内核发送的,还是用户发送的,它都执行不误,会顺从的去加载或卸载一些模块,而加载的模块都是以root身份运行的。因此你可以给它准备一个精心制作的功能模块(ko文件),然后触发相应的加载条件,比如热拔插、开关wifi等等, 该功能模块运行后,会生成 /data/local/tmp/rootshell    一个带s位的shell。2,ZergRush原理: 具有root权限的vold进程使用了libsysutils.so库,该库有个函数存在栈溢出,因此可以root权限执行输入的shellcode。印象中好像还有个提权漏洞,原理大概是: 某root权限的进程在干完一些事情后会自动降权到普通权限,但是如果普通权限的进程数满了,它就降权不成功,接着它就堂而皇之的以root权限运行了,好像是adbd进程。扯了半天还没扯到superuser.apk,这个程序是root成功后,专门用来管理root权限使用的,防止被恶意程序滥用。我一直很好奇他是怎么做到这一点的,         源码地址:http://superuser.googlecode.com/svn/trunk这个源码有点老,不过感觉原理和最新的superuser应该是差不多的。带着两个问题我们来分析源码:1、superuser是怎么知道谁想用root权限?  2、superuser是如何把用户的选择告诉su程序的那? 即superuser和su程序是如何通讯的,他们俩位于不通的时空,一个在java虚拟机中,一个在linux的真实进程中。共有两个active: SuperuserActivity 和 SuperuserRequestActivity ,呵呵比较简单。其中SuperuserActivity 主要是用来管理白名单的,就是记住哪个程序已经被允许使用root权限了,省的每次用时都问用户。SuperuserRequestActivity 就是用来询问用户目前有个程序想使用root权限,是否允许,是否一直允许,即放入白名单。这个白名单比较关键,是一个sqlite数据库文件,位置:/data/data/com.koushikdutta.superuser/databases/superuser.sqlite看完一开始我列的文章,就能明白root的本质就是往 /system/bin/ 下放一个带s位的,不检查调用者权限的su文件。普通程序可以调用该su来运行root权限的命令。superuser.apk中就自带了一个这样的su程序。一开始superuser会检测/system/bin/su是否存在,是否是老子自个放进去的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文件的完整性,比较大小,太省事了吧   //如果大小一样,则认为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();上面提到的su肯定是动过手脚的, 我 最纳闷的就是有进程使用root权限,superuser是怎么知道的,看完su 的代码明白了,关键是句:  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] 
-D: enable debugging -W: wait for launch to complete start a Service: am startservice
send a broadcast Intent: am broadcast
start an Instrumentation: am instrument [flags]
-r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT) -e
: set argument
to
-p
: write profiling data to
-w: wait for instrumentation to finish before returning start profiling: am profile
start
stop profiling: am profile
stop
specifications include these flags: [-a
] [-d
] [-t
] [-c
[-c
] ...] [-e|--es
...] [--esn
...] [--ez
...] [-e|--ei
...] [-n
] [-f
] [--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] [
]还有个疑点,就是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;}至此分析结束,回头看看,原来如此,又想起初中老师的一句话:会者不难,难者不会。 其实原理都不难,只要用心。

 

Android的应用程序入口肯定是java程序。应用程序的启动者是由系统临时根据Androidmanifest.xml中定义的权限而创建的临时用户。而不像linux那样是使用登陆者的身份启动,从而使得进程具有登陆者的所有权限。这也是android的安全机制之一。   新的权限机制也带来新的问题,android给应用程序的权限是按功能来分,java虽然可以访问文件系统。但由于应用程序本身是临时用户启动,这个临时用户权限十分有限。因此诞生了
<越狱 root机器>
这样的产物。其实root机器不是真正能让你的应用程序具有root权限。它原理就跟linux下的像sudo这样的命令。在系统的bin目录下放个su程序并属主是root并有suid权限。则通过su执行的命令都具有root权限。Su的源代码网上也有,有兴趣的同学去google下。当然使用临时用户权限想把su拷贝的/system/bin目录并改属性并不是一件容易的事情。这里用到2个工具跟2个命令。工具就是busybox。不熟悉的同学可以去网上google下。这个太有名了我就不多说了。 把busybox拷贝到你有权限访问的目录然后给他赋予4755权限,你就可以用它做很多事了。 当然busybox只能不能提升权限,真正提升权限的是ratc这个程序,这个程序中一键root包里面可以找到,作用是rooting在adb的shell。网上介绍Ratc的文章不多,它是rage against the cage 的缩写。是真正的提升权限的破解程序。虽然我没看过源代码,但估计是利用adb源代码部分内容来实现的,原理估计跟模拟器使用adb shell登陆可以获得root shell差不多。(因为它运行需要adb连接才会成功)。使用busybox前先运行ratc,这样运行busybox的UID将是0,也就是root。首先把system目录改成可读性的:busybox mount -o remount,rw /system,当然你还不能改下面的文件,因为system下文件的所有者都不是你。但你可以偷梁换柱把system下的目录给换掉。使用命令Busybox mount -t tmpfs none /system/xbin,呵呵这下xbin目录你随便写了。将su跟busybox弄过去cp /data/data/xxx/su /system/xbin。然后赋权限chmod 4755 /system/xbin/su。然后使目录生效busybox --install -s /system/xbin,别忘善后busybox mount -o remount,ro /system去掉system可写。 这样只是临时的,只能用su跟busybox能执行一些原来系统没有权限执行的命令而已。当系统重启后/system/xbin又变为原来的文件。真正要改系统的话需要自己写内核代码(相当于windows的驱动程序)。内核文件拥有所有权限。使用busybox命令insmod /data/data/xxx/xxx.ko装载内核文件,你想干嘛就可以干嘛了。 当然我们不是搞破解的没必要去改别人的机器,我们只是想让自己应用程序具有root权限而已。所以临时的su就可以了。我们用c++写一个可执行文件。使用socket可以跟java的程序通讯。然后将需要使用root权限才能执行的代码放在c++程序里,然后java程序中创建新的su进程,将c++程序带全路径作为参数1。启动后就可以通过socket调用c++函数去执行你想干的事了。 最后程序执行完了别忘了善后busybox umount /system/xbin。最后说说要注意的事情,如果机器已经root过的话就不需要做这些事情了,但root过的机器都有装有个权限管理的程序。会弹出对话框。但这个程序管理能力有限,如果不想让他弹出的话。也许可以通过改su文件名来解决。有兴趣的同学不妨试试。

 

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/4091902.html

转载地址:https://blog.csdn.net/FLY_THINK2012/article/details/101840937 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android模拟按键——源码环境下开发应用程序 ---编译jar(android可执行程序)
下一篇:VMware 虚拟机中添加新硬盘的方法

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月18日 11时10分18秒