开发你自己的su


layout: post
title: 开发你自己的su
categories: Android
description: 开发你自己的su
keywords: android
url: https://lichao890427.github.io/ https://github.com/lichao890427/


开发你自己的su

背景

  市面上常见的Android Root工具,原理就是利用系统漏洞将su文件下载到可执行目录。这样第三方进程可以执行su提升子进程的权限(记住Root提权不是提升当前进程权限,而是给子进程提权)。比如在app中读取文件可以用命令,su -c cat /data/data/com.example/xxx,当前app进程并未提权,而是cat子进程提权,所以读取到了其他App-com.example的文件。
  上面介绍了Root原理,那么很多Root工具除了su,还会有对应的授权管理app存在,它们记录一个白名单,决定哪个app拥有权限,一般有3种权限:允许/询问/拒绝。询问的时候,第三方app调用su后,su会和授权管理app通信,导致系统弹窗询问用户是否允许。这个在有时候是很讨厌的,那么怎么去除这个弹窗呢,这就必须我们自己编译一个su,并设置SUID位。SUID位确保su执行的子进程以Root权限运行
  这里介绍的是绝对可行的root方式,对于android模拟器,无论x86 x64 ,无论4.0 5.0 6.0都适用。真机的话5.0和6.0,root成功率比较低,因此不适合在上面做root方面的测试,这时只能考虑虚拟机,因为虚拟机adb有root权限,利用adb root权限便可以提升su权限。网上盛传的方法是http://androidsu.com/superuser https://www.0xaa55.com/forum.php ... tid=1648&extra=
需要superuser.apk,我分析了该网站的su,发现除了传统su的流程(setuid setgid)外,还加入了和superuser.apk通信的这一步。superuser.apk用于单个app权限设置。遗憾的是该作者并没完成mips架构,和5.0以上的su适配
  默认的su,是只允许root权限和shell权限来执行的,因此一般的app并不能使用,因此这也是我们修改的重点,同时还要给su加上必要的环境变量,我这种方式,去除了权限判断部分,因此减少了某些情况下由于这部分带来的root权限未成功获取的bug。这里提供一种方式,可以支持全平台

代码

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>

#define AID_ROOT             0  /* traditional unix root user */
#define AID_SYSTEM        1000  /* system server */
#define AID_SHELL         2000  /* adb and debug shell user */
#define AID_NOBODY        9999
#define AID_APP          10000  /* first app user */
#define AID_USER        100000  /* offset for uid ranges for each user */


void pwtoid(const char* tok, uid_t* uid, gid_t* gid) {
    struct passwd* pw = getpwnam(tok);
    if (pw)
    {
        if (uid) *uid = pw->pw_uid;
        if (gid) *gid = pw->pw_gid;
    }
    else
    {
        char* end;
        errno = 0;
        uid_t tmpid = strtoul(tok, &end, 10);
        if (errno != 0 || end == tok)
                printf("invalid uid/gid '%s'", tok);
        if (uid) *uid = tmpid;
        if (gid) *gid = tmpid;
    }
}

void extract_uidgids(const char* uidgids, uid_t* uid, gid_t* gid, gid_t* gids, int* gids_count) {
    char *clobberablegids;
    char *nexttok;
    char *tok;
    int gids_found;

    if (!uidgids || !*uidgids)
    {
        *gid = *uid = 0;
        *gids_count = 0;
        return;
    }

    clobberablegids = strdup(uidgids);
    strcpy(clobberablegids, uidgids);
    nexttok = clobberablegids;
    tok = strsep(&nexttok, ",");
    pwtoid(tok, uid, gid);
    tok = strsep(&nexttok, ",");
    if (!tok)
    {
        /* gid is already set above */
        *gids_count = 0;
        free(clobberablegids);
        return;
    }
    pwtoid(tok, NULL, gid);
    gids_found = 0;
    while ((gids_found < *gids_count) && (tok = strsep(&nexttok, ",")))
    {
        pwtoid(tok, NULL, gids);
        gids_found++;
        gids++;
    }
    if (nexttok && gids_found == *gids_count)
    {
        fprintf(stderr, "too many group ids\n");
    }
    *gids_count = gids_found;
    free(clobberablegids);
}

int main(int argc, char** argv)
{
    uid_t current_uid = getuid();

    // Handle -h and --help.
    ++argv;
    if (*argv && (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0))
    {
        fprintf(stderr,
                "usage: su [UID[,GID[,GID2]...]] [COMMAND [ARG...]]\n"
                "\n"
                "Switch to WHO (default 'root') and run the given command (default sh).\n"
                "\n"
                "where WHO is a comma-separated list of user, group,\n"
                "and supplementary groups in that order.\n"
                "\n");
        return 0;
    }

    uid_t uid = 0;
    gid_t gid = 0;

    if (*argv)
    {
        gid_t gids[10];
        int gids_count = sizeof(gids)/sizeof(gids[0]);
        extract_uidgids(*argv, &uid, &gid, gids, &gids_count);
        if (gids_count) {
            if (setgroups(gids_count, gids))
            {
                printf("setgroups failed");
            }
        }
        ++argv;
    }

    if (setgid(gid))
            printf("setgid failed");
    if (setuid(uid))
            printf("setuid failed");

    //设置环境变量
    setenv("PATH", "/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin", 1);
    setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 1);
    setenv("ANDROID_BOOTLOGO", "1", 1);
    setenv("ANDROID_ROOT", "/system", 1);
    setenv("ANDROID_DATA", "/data", 1);
    setenv("ANDROID_ASSETS", "/system/app", 1);
    setenv("EXTERNAL_STORAGE", "/sdcard", 1);
    setenv("ASEC_MOUNTPOINT", "/mnt/asec", 1);
    setenv("LOOP_MOUNTPOINT", "/mnt/obb", 1);
    char* exec_args[argc + 1];
    size_t i = 0;
    for (; *argv != NULL; ++i)
    {
      exec_args[i] = *argv++;
    }

    if (i == 0) exec_args[i++] = "/system/bin/sh";
    exec_args[i] = NULL;

    execvp(exec_args[0], exec_args);
    printf("failed to exec %s", exec_args[0]);
}

相关代码我的github上也有

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容