博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
应用获取root权限分析及总结
阅读量:6418 次
发布时间:2019-06-23

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

ROM授权root权限,主要技术点在哪里?如何实现?带着这些问题,边实验边分析,并将过程和犯的错误记录如下。

1、rom支持root授权,需要包含su

简单点说,就是rom中支持su指令;必须包含su可执行程序,对应的代码/system/su目录下代码; 编译生成su程序后,再将其push到/system/xbin目录下;

注意:此时需要修改该文件的执行权限, chmod 755 su

 

2、应用程序如何获取root权限?

关键点在于下面这句,通过执行su产生一个具有root权限的进程:

Process p = Runtime.getRuntime().exec("su"); 其中,Runtime.getRuntime().exec可以直接调用底层linux的程序或脚本;

1 // 执行命令并且输出结果  2     public static String execRootCmd(String cmd) {  3         String result = "";  4         DataOutputStream dos = null;  5         DataInputStream dis = null;  6           7         try {  8             Process p = Runtime.getRuntime().exec("su");// 经过Root处理的android系统即有su命令  9             dos = new DataOutputStream(p.getOutputStream()); 10             dis = new DataInputStream(p.getInputStream()); 11  12             dos.writeBytes(cmd + "\n"); 13             dos.flush(); 14             dos.writeBytes("exit\n"); 15             dos.flush(); 16             String line = null; 17             while ((line = dis.readLine()) != null) { 18                 Log.d("result = ", line); 19                 result += line; 20             } 21             p.waitFor(); 22         } catch (Exception e) { 23             e.printStackTrace(); 24         } finally { 25             if (dos != null) { 26                 try { 27                     dos.close(); 28                 } catch (IOException e) { 29                     e.printStackTrace(); 30                 } 31             } 32             if (dis != null) { 33                 try { 34                     dis.close(); 35                 } catch (IOException e) { 36                     e.printStackTrace(); 37                 } 38             } 39         } 40         Log.d(TAG, "execRootCmd cmd = " + cmd + ", result = " + result); 41         return result; 42 }

 

3、去掉su程序中的用户uid判断

执行包含execRootCmd("echo test")代码的apk应用后,result无返回; 检查su的代码发现在其main()函数中:

if (su_from.uid == AID_ROOT || su_from.uid == AID_SHELL)
allow(shell, orig_umask);
即只有root或shell用户可以执行,去掉此处的限制;再次运行,发现result = test 有回复了。

 

4、setresuid为什么失败?

 

这样就成功了吗? 执行execRootCmd("id"), 日志如下:

DEBUG/rtc_test(5732): execRootCmd cmd = id, result = uid=10081(app_81) gid=10081(app_81) groups=1015(sdcard_rw)
显然用户uid没有切换到root。
分析su中的代码,allow()中调用了
setresgid(to->uid, to->uid, to->uid);
setresuid(to->uid, to->uid, to->uid);
Setresuid设置真实的、有效的和保存过的uid, 要想切换到root用户,那么su必须是已root用户运行的进程。

 

5、liunx文件权限中的S位

R,W,X是基本权限 S、T是特殊权限;

r(Read,读取):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目 录的权限。
w(Write,写入):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。
x(eXecute,执行):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。
s或S(SUID,Set UID):可执行的文件搭配这个权限,便能得到特权,任意存取该文件的所有者能使用的全部系统资源。请注意具备SUID权限的文件,黑客经常利用这种权限,以SUID配上root帐号拥有者,无声无息地在系统中开扇后门,供日后进出使用。
T或T(Sticky):/tmp和、/var/tmp目录供所有用户暂时存取文件,亦即每位用户皆拥有完整的权限进入该目录,去浏览、删除和移动文件。
调用“chmod 6755 su”修改su文件的属性,让su的执行者具有root权限。

修改之后,再次运行execRootCmd("id"),日志如下:

DEBUG/rtc_test(3686): execRootCmd cmd = id, result = uid=0(root) gid=0(root) groups=1015(sdcard_rw)
显然,切换成功了。

 

6、深入一下:Linux根据文件的s位设置uid,代码在哪里实现的?

 先看一下创建进程的过程,先fork子进程,再exec加载新进程;

fork时和父进程一样,不可能在这里设置uid;那比较有可能在exec阶段了。

早期的linux版本,在 exec.c文件中do_execve函数:
int do_execve(unsigned long * eip,long tmp,char * filename,
char ** argv, char ** envp) {
......
// 根据其属性(对应i 节点的uid 和gid),看本进程是否有权执行它
//如果设置了S_ISUID,则进程具有节点的uid
i = inode->i_mode;
e_uid = (i & S_ISUID) ? inode->i_uid : current->euid;
e_gid = (i & S_ISGID) ? inode->i_gid : current->egid;

 ......

// 重新设置进程的用户id 和组id

current->euid = e_uid;
current->egid = e_gid;

 新版本的linux代码中也有类似的实现:

do_execve ---> do_execve_common() ---> prepare_binprm()

7、linux为什么要有这种切换uid的功能?

A、最常用的需求是修改密码,在Linux系统中每个普通用户都可以更改自己的密码,这是合理的设置。问题是:用户的信息保存在文件/etc/passwd中,用户的密码保存在文件/etc/shadow中,也就是说用户更改自己密码时是修改了/etc/shadow文件中的加密密码,这个时候就需要用到S位了;

B、另外,就是比较常用的网络指令。

8、回头看下第三步的修改(去掉su程序中的uid判断)是否必要?

既然设置S位后,新进程以文件所有者(root)的权限在运行,那么是否可以去掉第三步的修改?

在main()函数中,还原第三步修改,发现无法执行"echo test";在su中加log信息
LOGD("su.c main() from.uid = %d, euid = %d, to.uid = %d.", su_from.uid, geteuid(), su_to.uid);
打印日志如下:
DEBUG/su(3642): su.c main() from.uid = 10081, euid = 0, to.uid = 0.

 linux系统中每个进程都有2个ID,分别为用户ID(uid)和有效用户ID(euid),UID一般表示进程的创建者(属于哪个用户创建),而EUID表示进程对于文件和资源的访问权限(具备等同于哪个用户的权限)。C语言中,可以通过函数getuid()和geteuid()来获得进程的两个ID值。

在exec中修改的只是euid,uid还是应用的uid。

9、Superuser超级用户权限授权程序介绍

解压其升级包Superuser-3.2-arm-signed.zip,主要包含su和Superuser.apk及一些升级辅助文件;su和我们编译的差不多,apk提供了一些供用户操作的界面;当有用户调用su指令时,即通知到Superuser.apk,对用户的行为进行管理。当用户允许之后,下次就不再提醒。

 

 

转载于:https://www.cnblogs.com/nick-zhang/p/3733870.html

你可能感兴趣的文章
Swift 中 Substrings 与 String
查看>>
作为一个开源软件的作者是一种什么样的感受?
查看>>
基于vue-cli3 SSR 程序实现热更新功能
查看>>
性能优化篇 - css typed OM(css typed object model)
查看>>
看图轻松理解数据结构与算法系列(Radix树)
查看>>
写在专栏前-Java那些事儿
查看>>
亿万级访问量下的前端同构直出实践
查看>>
SpringSession系列-分布式 session 实现方案及 SpringSession 功能分析
查看>>
Sybase数据库安全
查看>>
令牌的故事(CVE-2015-0002)
查看>>
数据结构——二叉树的存储结构
查看>>
HTTP状态码简明宝典
查看>>
Java 基础 - 对java多态的理解
查看>>
iOS开发笔记(五):UIScrollView实现原理
查看>>
HTTPie 官方文档中文翻译版
查看>>
Bulk 异常引发的 Elasticsearch 内存泄漏
查看>>
Java 8 Stream
查看>>
Android6 0新应用权限管理机制详解
查看>>
leetCode 6 ZigZag Conversion
查看>>
作为一位Java架构师需要点亮的那些技能树
查看>>