• Android开发之《制作自己的su文件》


    目录结构  ─ hello
      ├── jni
        ├── Android.mk

        └── hello.c

     编译步骤:

    # cd hello  
    # export NDK_PROJECT_PATH=`pwd`  
    # ndk-build  
    # adb push libs/armeabi/helloworld  /data  
    # adb shell  
    # cd  /data  
    # ls -l   
    # ./helloworld
     Hello World! 

    Android.mk

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_CFLAGS += -pie -fPIE

    LOCAL_LDFLAGS += -pie -fPIE

    LOCAL_MODULE := sur

    LOCAL_SRC_FILES := su.c

    # LOCAL_STATIC_LIBRARIES :=

    #     liblog

    #     libc

    LOCAL_LDLIBS :=

    -llog

    -lc

    LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)

    LOCAL_MODULE_TAGS := eng debug

    LOCAL_FORCE_STATIC_EXECUTABLE := true

    include $(BUILD_EXECUTABLE)

    su.c  (删除权限检查部分)

    /*
    **
    ** Copyright 2008, The Android Open Source Project
    **
    ** Licensed under the Apache License, Version 2.0 (the "License"); 
    ** you may not use this file except in compliance with the License. 
    ** You may obtain a copy of the License at 
    **
    **     http://www.apache.org/licenses/LICENSE-2.0 
    **
    ** Unless required by applicable law or agreed to in writing, software 
    ** distributed under the License is distributed on an "AS IS" BASIS, 
    ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    ** See the License for the specific language governing permissions and 
    ** limitations under the License.
    */
    
    #define LOG_TAG "su"
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <errno.h>
    
    #include <unistd.h>
    #include <time.h>
    
    //#include <pwd.h>
    
    //#include <private/android_filesystem_config.h>
    
    /*
     * SU can be given a specific command to exec. UID _must_ be
     * specified for this (ie argc => 3).
     *
     * Usage:
     * su 1000
     * su 1000 ls -l
     */
    int main(int argc, char **argv)
    {
        //struct passwd *pw;
        int uid, gid; //myuid;
    
        uid = 0;
        gid = 0;
    
        /*
        if(argc < 2) {
            uid = gid = 0;
        } else {
            pw = getpwnam(argv[1]);
    
            if(pw == 0) {
                uid = gid = atoi(argv[1]);
            } else {
                uid = pw->pw_uid;
                gid = pw->pw_gid;
            }
        }
    
        //Until we have something better, only root and the shell can use su. 
    
        myuid = getuid();
        if (myuid != AID_ROOT && myuid != AID_SHELL) {
            fprintf(stderr,"su: uid %d not allowed to su
    ", myuid);
            return 1;
        }*/
        
        if(setgid(gid) || setuid(uid)) {
            fprintf(stderr,"su: permission denied
    ");
            return 1;
        }
    
        /* User specified command for exec. */
        if (argc == 3 ) {
            if (execlp(argv[2], argv[2], NULL) < 0) {
                fprintf(stderr, "su: exec failed for %s Error:%s
    ", argv[2],
                        strerror(errno));
                return -errno;
            }
        } else if (argc > 3) {
            /* Copy the rest of the args from main. */
            char *exec_args[argc - 1];
            memset(exec_args, 0, sizeof(exec_args));
            memcpy(exec_args, &argv[2], sizeof(exec_args));
            if (execvp(argv[2], exec_args) < 0) {
                fprintf(stderr, "su: exec failed for %s Error:%s
    ", argv[2],
                        strerror(errno));
                return -errno;
            }
        }
    
        /* Default exec shell. */
        execlp("/system/bin/sh", "sh", NULL);
    
        fprintf(stderr, "su: exec failed
    ");
        return 1;
    }

    代码中使用su

    Process process = Runtime.getRuntime().exec("su");
    DataOutputStream os = new DataOutputStream(process.getOutputStream());
    os.writeBytes("mount -oremount,rw  " + "/system
    ");
    os.writeBytes("busybox cp " + zlsuPath + " /system/bin/" + Constants.ROOT_SU + "
    ");
    os.writeBytes("busybox chown 0:0 /system/bin/" + Constants.ROOT_SU + "
    ");
    os.writeBytes("chmod 4755 /system/bin/" + Constants.ROOT_SU + "
    ");
    os.writeBytes("exit
    ");
    os.flush();
    直接使用chmod出错,很多版本的chmod不支持a+s
    # chmod a+s su
    Bad mode
    
    使用busybox
    # busybox chmod a+s su

    查找挂载位置(mmcblk0p10-->system)
    # df

      Filesystem Size Used Free Blksize
      /dev 1006.3M 40.0K 1006.3M 4096
      /sys/fs/cgroup 1006.3M 0.0K 1006.3M 4096
      /mnt/asec 1006.3M 0.0K 1006.3M 4096
      /mnt/obb 1006.3M 0.0K 1006.3M 4096
      /system 1.5G 421.6M 1.1G 4096
      /cache 122.0M 144.0K 121.8M 4096
      /metadata 11.7M 40.0K 11.7M 4096
      /data 991.9M 591.2M 400.7M 4096
      /mnt/usb_storage 1006.3M 0.0K 1006.3M 4096
      /mnt/internal_sd 11.7G 22.2M 11.7G 8192
      /mnt/secure/asec 11.7G 22.2M 11.7G 8192

      # cat /proc/partitions

      major minor #blocks name

      254 0 520912 zram0
      179 0 15267840 mmcblk0
      179 1 4096 mmcblk0p1
      179 2 4096 mmcblk0p2
      179 3 16384 mmcblk0p3
      179 4 16384 mmcblk0p4
      179 5 32768 mmcblk0p5
      179 6 32768 mmcblk0p6
      179 7 53248 mmcblk0p7
      179 8 131072 mmcblk0p8
      179 9 4096 mmcblk0p9
      179 10 1572864 mmcblk0p10
      179 11 16384 mmcblk0p11
      179 12 4096 mmcblk0p12
      179 13 1048576 mmcblk0p13
      179 14 65536 mmcblk0p14
      179 15 12257280 mmcblk0p15

    adb shell mount -o rw,remount /system  
    adb push su /system/xbin/su  
    adb shell chmod 06755 /system  
    adb shell chmod 06755 /system/xbin/su

    最后已失败告终!!

    Android目前的ROOT的基本原理,是通过系统漏洞获取ROOT SHELL权限,然后往手机里面push 最核心的两个文件,su可执行文件和superUSer.apk。 后者用于管理对应用的授权,而前者则真正用来提升权限至ROOT。 当APK需要进行高权限操作时,使用Shell方式进行: su xxxxx 即可,此时(假设用户授权了,通过superUser.apk)xxxx的命令就会以ROOT用户权限方式执行。之所以push到手机中的su可以提升权限,其核心原理是su是Set-UID-Root的。具体原理分析,可参见本博客的 关于ROOT原理的文档,说明的非常详细了。

    但是,在Android4.3中,从如下的open Source Code :dalvik_system_Zygote.cpp-》forkAndSpecializeCommon:

    extern int gMallocLeakZygoteChild;
        gMallocLeakZygoteChild = 1;
    
        /* keep caps across UID change, unless we're staying root */
        if (uid != 0) {
            err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
    
            if (err < 0) {
                ALOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
                dvmAbort();
            }
        }
    
        for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
            err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
            if (err < 0) {
                if (errno == EINVAL) {
                    ALOGW("PR_CAPBSET_DROP %d failed: %s. "
                                  "Please make sure your kernel is compiled with "
                                  "file capabilities support enabled.",
                          i, strerror(errno));
                } else {
                    ALOGE("PR_CAPBSET_DROP %d failed: %s.", i, strerror(errno));
                    dvmAbort();
                }
            }
        }

    注意红色斜体的代码,这是4.3新加入的。新加入的这些代码,会导致set-uid-root不再起作用,也就是,原先的ROOT方案中的su+superUser.apk的模式不再工作了!!黑客们需要重新考虑新的ROOT方案了!360,腾讯等等一系列使用了ROOT权限的应用需要等待新的ROOT方案然后基于新的ROOT方案来调整提升权限的方式了,SU不再起作用了。

    这里简单说明一下原因,详细的请参见Linux的Capacity机制。  

    Android中每个APK的进程是Zygote Fork出来的,默认Fork出来的进程的Real UID和EUID都是继承自Zygote,也就是ROOT,然后,Zygote会对子进程做一些特殊处理,上面的红色斜体代码的作用是,在新Fork的APK进程中Drop掉所有的BoundSet Capacity,原本Zygote的BoundSet Capacity是全1,然后在APK的子进程中主动的Drop掉所有的这些Capacity,接着会再调用setUID/SetGID将APK进程的UID/GID从ROOT修改为App安装时分配的ID(权限退化)。 

    这样,你会看到,APK所在的进程的UID/GID退化成非ROOT了,原本还能通过su来提升权限。但是,4.3里面连所有的BoundsetCapacity也全部Drop掉了,里面包含的SETUID的capacity也Drop了,这样就导致,在APK所在的进程以及任意其子进程中,都无法修改UID了,即便通过set-UID-Root方式也无法修改了。

  • 相关阅读:
    谁说AI看不懂视频?
    为什么说容器的崛起预示着云原生时代到来?
    小熊派开发实践丨漫谈LiteOS之传感器移植
    华为云如何赋能无人车飞驰?从这群AI热血少年谈起
    趣味科普丨一文读懂云服务器的那些事儿
    【API进阶之路】研发需求突增3倍,测试团队集体闹离职
    这个应用魔方厉害了,让软件开发者效率提升10倍
    数据安全无小事:揭秘华为云GaussDB(openGauss)全密态数据库
    数据湖探索DLI新功能:基于openLooKeng的交互式分析
    基本数据类型与表达式5 零基础入门学习Delphi06
  • 原文地址:https://www.cnblogs.com/alanfang/p/6951939.html
Copyright © 2020-2023  润新知