android root and su

来源:互联网 发布:java html5 视频播放 编辑:程序博客网 时间:2024/06/05 09:39

在android用管理员权限执行指令很简单,就像这样

public static void sudo(String cmd) {    Process su;    DataOutputStream outputStream = null;    try {        su = Runtime.getRuntime().exec("su");        outputStream = new DataOutputStream(su.getOutputStream());        outputStream.writeBytes(cmd + "\n");        outputStream.flush();        outputStream.writeBytes("exit\n");        outputStream.flush();        su.waitFor();        su.getInputStream().close();        su.getErrorStream().close();    } catch (IOException | InterruptedException e) {        e.printStackTrace();    } finally {        Closer.closeSilently(outputStream);    }}

Runtime.exec 做了什么呢?

java.lang.ProcessManager

/** Executes a command in a child process. */static pid_t ExecuteProcess(JNIEnv* env, char** commands, char** environment,                            const char* workingDirectory, jobject inDescriptor,                            jobject outDescriptor, jobject errDescriptor,                            jboolean redirectErrorStream) {    //... ignore    pid_t childPid = fork();    //... ignore    // Execute process. By convention, the first argument in the arg array    // should be the command itself.    execvp(commands[0], commands);    //... ignore}

所以是fork出一个进程来执行su的指令,获得root权限是执行su指令之后的事情,su指令fork出一个子进程。

接着看su指令是怎么做的

可以参考 Superuser

在android_x86中的目录是:external/koush/Superuser/Superuser/jni/su/su.c

简单介绍下背景好了

android的权限机制其实就是linux权限那一套东西,所以root账号是有的root权限也是有的,不过root权限的uid和gid都是0,android系统在init的时候就是用 0 起的。su指令提供了一个方法,可以切换过去。换句话说,只要能把进程的uid和gid变为 0 那么就获得了ROOT权限。指令是不是叫su其实没关系。
在android_x86中,susuperuser 是配套使用的,具体细节如下:

static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {    char *arg0;    int argc, err;    umask(ctx->umask);    int send_to_app = 1;    // no need to log if called by root    if (ctx->from.uid == AID_ROOT)        send_to_app = 0;    // dumpstate (which logs to logcat/shell) will spam the crap out of the system with su calls    if (strcmp("/system/bin/dumpstate", ctx->from.bin) == 0)        send_to_app = 0;    if (send_to_app)        send_result(ctx, ALLOW);    char *binary;    argc = ctx->to.optind;    if (ctx->to.command) {        binary = ctx->to.shell;        ctx->to.argv[--argc] = ctx->to.command;        ctx->to.argv[--argc] = "-c";    }    else if (ctx->to.shell) {        binary = ctx->to.shell;    }    else {        if (ctx->to.argv[argc]) {            binary = ctx->to.argv[argc++];        }        else {            binary = DEFAULT_SHELL;        }    }    arg0 = strrchr (binary, '/');    arg0 = (arg0) ? arg0 + 1 : binary;    if (ctx->to.login) {        int s = strlen(arg0) + 2;        char *p = malloc(s);        if (!p)            exit(EXIT_FAILURE);        *p = '-';        strcpy(p + 1, arg0);        arg0 = p;    }    populate_environment(ctx);    set_identity(ctx->to.uid);#define PARG(arg)                                    \    (argc + (arg) < ctx->to.argc) ? " " : "",                    \    (argc + (arg) < ctx->to.argc) ? ctx->to.argv[argc + (arg)] : ""    LOGD("%u %s executing %u %s using binary %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s",            ctx->from.uid, ctx->from.bin,            ctx->to.uid, get_command(&ctx->to), binary,            arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5),            (ctx->to.optind + 6 < ctx->to.argc) ? " ..." : "");    ctx->to.argv[--argc] = arg0;    execvp(binary, ctx->to.argv + argc);    err = errno;    PLOGE("exec");    fprintf(stderr, "Cannot execute %s: %s\n", binary, strerror(err));    exit(EXIT_FAILURE);}

执行是

execvp(binary, ctx->to.argv + argc);

在app里面binary默认就是走的sh(/system/bin/su),也就是,所以就和执行Runtime.getRuntime().exec("sh") 的效果是一致的,除了权限的不同。

sh是怎么做的呢,原理应该是每次监听输入,fork一个进程去执行指令,apue中有提供了一个类似的例子

#include "apue.h"#include <sys/wait.h>intmain(int argc, char *argv[]){    char buf[MAXLINE];    pid_t pid;    int status;    printf("%% ");    while(fgets(buf,MAXLINE,stdin) != NULL){        if(buf[strlen(buf) - 1 ] == '\n')            buf[strlen(buf) - 1 ] = 0;        if((pid = fork()) <0){            err_sys("fork error");        }else if(pid == 0){            execlp(buf,buf,(char *)0);            err_ret("couldn't excute: %s",buf);            exit(127);        }        if((pid = waitpid(pid,&status,0))<0)            err_sys("wait pid error");        printf("%% ");    }    exit(0);}

系统是否被root的判断

有个rootTool,可以判断。简单点自己写的话,就查查

/system/bin/su 或者/system/xbin/su 存不存在

有看到一个的程序员写的一个

/system/xbin/which su

然后捕获抛出的异常,正常的手机下是没有xbin的 : (

原创粉丝点击