近期工作一直非常忙。居然慢慢地疏远了CSDN的博客,然而在工作中遇到问题,又会被多次的引导至CSDN,故笔者抽出时间也将自己学习的成果与大家分享在这里,希望能帮助到须要帮助的人。
本文将从几个方面,由浅至深地讲述ROOT究竟是什么东西?
一. ROOT权限简介
二.为什么须要ROOT
三. ADBD的ROOT权限
四.深入源码
ROOT权限简单介绍:
ROOT权限是Linux内核中的最高权限,假设你的身份是ROOT。那么你就具有了ROOT权限。
有了最高权限。你就能够为所欲为,换句话说,假设恶意程序获取到了ROOT权限,那么就能够肆意地破坏你的手机。获取的隐私...所以厂商一般在生产手机的时候,不会提供给用户ROOT权限。官方宣称是为了保护用户手机的安全。然后装了一堆开机自己主动启动。而用户这辈子也用不到也卸载不了垃圾软件(相信使用安卓的同学们都懂我的意思),而苹果所说的越狱,也就是获取ROOT权限。
为什么须要获取ROOT权限?
苹果用户获取ROOT权限。是为了能够免费安装各种软件。以及为了获取更加灵活的操作体验,苹果不会安装一堆恶心的软件;而安卓普通用户获取ROOT权限,最大的目的就是为了卸载这些恶心的自带软件,安卓极客用户则是为了各种折腾安卓手机,安卓开发者是为了得到日志文件,分析BUG。
ADBD的ROOT权限:
ADBD是什么?相信大家都看过。IT男把手机连上电脑,然后不知怎么的弹出一个黑乎乎的窗体,上面有一排排白色的英文字母,然后帅气的敲击着键盘(一般敲击 adb shell,然后进入手机),啪啪几下,能够帮你解决一些手机的问题。这个能够和手机交互的进程就是ADBD。
这就好比,你去朋友家玩,然后你朋友家比較高端,进大门之前有个可视对讲机。那么你首先通过对讲机呼叫朋友(敲击adb
shell),看看在不在家(手机是否对应adb shell这个命令)。假设朋友在家。那么就会通过对讲机为你开门(成功进入手机中)。提供这个服务的可视对讲机就相当于ADBD。
说白了,ADBD就是能够为你提供一种进入手机内部的服务通道。
那么为什么须要ADBD具有ROOT权限?这就涉及到还有一个与ROOT息息相关的东西——su。
我们开机之后,使用手机的身份就是一个普通用户(user),假设运行su,那么就能够直接切换到ROOT身份。就像仙剑奇侠传三里面的景天,是个凡人,法力有限,可是大家都知道。他的前世是飞蓬将军,法力高强。天界无人能敌,仅仅有魔界至尊重楼能够与他一较高下。当他们来到天庭的时候,玉帝施法,让景天直接切换成飞蓬将军,于是他就有了飞蓬将军的记忆和法力,与重楼重新大战。su就是这样一个奇妙的命令。
高通平台上,su的相关代码位于: LINUX/android/system/extras/su/su.c中
事实上我们所说的越狱或者ROOT。就是把su安装到手机里面 /system/bin文件夹下,并把它的权限设置为4755,那么某些程序须要ROOT权限的时候,就能够通过su切换到ROOT身份,然后去运行。因此一般被ROOT的手机都会安装一个“超级用户”这种应用,就是用于管理哪些软件能够切换到ROOT身份,哪些不能够。保证用户安全。这个想法是非常好非常天真。对于正规的软件,人家依照你的路子来,不正规的软件。你一个小小的超级用户的应用,岂能挡我获取ROOT,虐不死你。
那么为什么须要ADBD获取ROOT权限呢?经过上面的解说大家应该能猜到,假设ADBD有ROOT权限。就能够通过adb 工具。为所欲为。而又不留下痕迹(不安装su),能够删除自带垃圾软件,获取随意文件夹的文件。安全性较高。笔者就是通过这样的方式获取一些系统级别文件。
深入代码:
看了上面的文字,或许非常多人会有这种想法,原来ROOT一个手机这么简单?错!
一点也不简单。
首先:/system分区是仅仅读的文件系统,即你无法往system分区中写入不论什么东西,其次就算你侥幸把su安装到/system/bin下,你也没法改动它的权限为4755,再者,即使你侥幸把su的权限设为4755,你也逃只是有些手机的反root机制(即检測到有文件的权限为4755。就删除)。
首先我们来看看su的部分代码:
/* 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\n", myuid);
return 1;
}
这句话告诉我们。假设运行su的不是ROOT或者SHELL用户,那就直接退出。说明切换身份时候,你必须是这两个用户。还好我们用adb shell进入。是SHELL用户,好险啊。
if(argc < 2) {
uid = gid = 0;
} else {
int gids_count = sizeof(gids)/sizeof(gids[0]);
extract_uidgids(argv[1], &uid, &gid, gids, &gids_count);
if(gids_count) {
if(setgroups(gids_count, gids)) {
fprintf(stderr, "su: failed to set groups\n");
return 1;
}
}
}
推断运行su的时候,有没有其他參数,我们仅仅是运行su,即argc < 2成立。su也能够切换成其他用户(argc > 2,具体看su命令的使用),这时候。uid 和 gid 都被设置为0 。即ROOT用户的ID号和组号
if(setgid(gid) || setuid(uid)) {
fprintf(stderr,"su: permission denied\n");
return 1;
}
来了来了。就是它,这就是我们终于的目的,把我变身成飞蓬将军,假设一切顺利。你就能够变身成功了(切换ROOT成功)
/* Default exec shell. */
execlp("/system/bin/sh", "sh", NULL);
每次su之后,就会变成root#,然后就能够通过控制台继续敲命令,可是不同的是,你已经是ROOT了,权限已经非常大了。
Android系统启动的时候,ADBD是ROOT权限,仅仅是后来被降级了,推断是否降级的函数是should_drop_privileges()这个函数:
static int should_drop_privileges() {
#ifndef ALLOW_ADBD_ROOT
return 1;
#else /* ALLOW_ADBD_ROOT */
首先推断是否定义了ALLOW_ADBD_ROOT,假设系统都不同意你ROOT。就直接返回1,以下什么都不看了,就像找工作的时候,无论你多么厉害,假设你第一条要求都不符合,就直接把你pass了,说什么都没用,够狠的。
int secure = 0;
char value[PROPERTY_VALUE_MAX]; /* run adbd in secure mode if ro.secure is set and
** we are not in the emulator
*/
property_get("ro.kernel.qemu", value, "");
if (strcmp(value, "1") != 0) {
property_get("ro.secure", value, "1");
if (strcmp(value, "1") == 0) {
// don't run as root if ro.secure is set...
secure = 1;
以下就是获取系统的属性。推断是否打开ROOT权限,能够看到假设ro.kernel.qumu 这个属性被置为了。没关系再给你一次机会,推断ro.secure是否也是1。假设是。对不起你无法获得root权限。我要把secure置为1了(secure为1意味着要降级,后面会解说)。接着:
// ... except we allow running as root in userdebug builds if the
// service.adb.root property has been set by the "adb root" command
property_get("ro.debuggable", value, "");
if (strcmp(value, "1") == 0) {
property_get("service.adb.root", value, "");
if (strcmp(value, "1") == 0) {
secure = 0;
}
}
}
}
哈哈,又给了你一次机会,我再来推断ro.debuggable是不是1,假设不是。对不起,我必需要降级,否则再给你一次机会。推断service.adb.root这个属性的值,假设也是1,那么就不降级,一般在编译ROM版本号的时候,会同事编译两个版本号。一个是project版本号,是具有ROOT权限的ADBD。这样方便开发人员调试系统,还有一个就是我们用户用的版本号,叫user版本号,这个是没有ROOT权限的,能够看到,就是通过property_get一系列属性来推断是否降级。
return secure;
#endif /* ALLOW_ADBD_ROOT */
}
最后,返回secure就可以。能够看到最后决定是否降级的变量就是secure,全部假设有源码的话。仅仅有最后将secure赋值为0。无论什么版本号。最后都是ROOT权限。
if (should_drop_privileges()) {
drop_capabilities_bounding_set_if_needed(); gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET,
AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
AID_NET_BW_STATS };
if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
exit(1); /* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {<span style="white-space:pre"> </span>//以前的漏洞。被封住了
exit(1);
}
if (setuid(AID_SHELL) != 0) {<span style="white-space:pre"> </span>//以前的漏洞
exit(1);
} D("Local port disabled\n");
}
从这段代码能够看到。假设should_drop_privileges返回1,那么就能够降级了。降级函数为setgid(AID_SHELL)和setuid(AID_SHELL)。以前有黑客利用一些方法。使得setgid和setuid运行失败,即降级失败,以前的代码中是没有exit的,那么当setuid和setgid运行失败之后。就不会降级。
ROOT不是那么轻易的。如今有非常多已知的漏洞,可是都被*了,全部不是每一个root工具都能root成功的。要看它採用的是什么方法来ROOT。