• 应用获取root权限分析及总结


    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 + "
    "); 
    13             dos.flush(); 
    14             dos.writeBytes("exit
    "); 
    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,对用户的行为进行管理。当用户允许之后,下次就不再提醒。

  • 相关阅读:
    mac 配置pycharm(2021.3版本) 和 clion(2019.3版本)
    深度学习神经网络backbone
    Windows获取CPU、内存和磁盘使用率脚本
    Unicode编码转换
    @ControllerAdvice全局数据预处理
    查看Linux系统内存、CPU、磁盘使用率和详细信息
    服务器nginx配置SSL证书后启动报错问题解决方案
    Inno Setup 寻找 AppId 的方法
    慢sql_查询条件加了函数导致索引失效
    k8s暂停一个pod
  • 原文地址:https://www.cnblogs.com/nick-zhang/p/3733870.html
Copyright © 2020-2023  润新知