Adb的全称为Android Debug Bridge,起到通过PC对Android系统的调试桥的作用,是一个多用途的工具,它能够执行多种命令,还能提供一个shell。这儿简单介绍一下Adb的代码结构,并在某些情况下我们可以获取root权限。

Adb的代码在system/core/adb里,它的入口函数很直接了当:

int main(int argc, char **argv)
{
#if ADB_HOST //代码被ADB_HOST宏分成两部分,一部分是宿主,即被ADB_HOST定义包括的部分,运行在Windows或Linux系统上。另一部分是目标,即Android系统上的deamon程序。
adb_sysdeps_init();
adb_trace_init();
D("Handling commandline()\n");
return adb_commandline(argc - 1, argv + 1);
#else
/* If adbd runs inside the emulator this will enable adb tracing via
* adb-debug qemud service in the emulator. */
adb_qemu_trace_init();
if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
adb_device_banner = "recovery";
recovery_mode = 1;
} start_device_log();
D("Handling main()\n");
return adb_main(0, DEFAULT_ADB_PORT);
#endif
}

先看宿主代码的路径,我们看到它进入了adb_commandline()函数,这里主要是负责解析参数并执行相应的命令,注意这儿在执行命令之前还有一个启动本地服务的动作:

    if (is_server) {
if (no_daemon || is_daemon) {
r = adb_main(is_daemon, server_port); //Linux平台
} else {
r = launch_server(server_port); //Windows平台
}
if(r) {
fprintf(stderr,"* could not start server *\n");
}
return r;
}

这儿会区分宿主平台是Linux还是Windows,他们的服务形态是不一样 的。我们可以使用adb start-server, adb kill-server这样的命令原因在此。

在本地服务启动前会有一些初始化工作,例如USB的初始化:

#if ADB_HOST
HOST = 1;
usb_vendors_init();
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
if(install_listener(local_name, "*smartsocket*", NULL)) {
exit(1);
}
#else

因为adb是通过USB 进行socket通信,以adb devices的命令执行过程分析如下:

1. 组织命令格式,

    if(!strcmp(argv[0], "devices")) {
char *tmp;
snprintf(buf, sizeof buf, "host:%s", argv[0]); //命令格式为:host:devices
tmp = adb_query(buf); //发送命令并返回命令执行结果
if(tmp) {
printf("List of devices attached \n");
printf("%s\n", tmp); //打印结果
return 0;
} else {
return 1;
}
}

2. 在adb_query()函数中调用adb_connect()函数发送socket数据,返回后再调用adb_close()关闭socket连接

下面再来分析目标机器即Android上的adbd守护进程,在刚才的入口函数中,它直接进入了adb_main()函数,并传入DEFAULT_ADB_PORT  5037作为默认端口。在adb_main()函数里进行了一系列初始化动作如,USB,端口监听,运行级别,权限设置等,最后进入到事件循环中等待连接(这儿使用epoll机制)。

fdevent_loop();

其中我们对运行级别比较感兴趣,一般情况下我们的adb都是运行在shell用户下,而事实上,adb.c中的代码都是以root权限运行的,以完成部分初始化工作,直到执行了下面的代码:

if (should_drop_privileges()) {
......
if (setgid(AID_SHELL) != 0) {
exit(1); //这儿曾经是个漏洞,没有检查返回值,可以被某些恶意软件利用来破解root权限
}
if (setuid(AID_SHELL) != 0) {
exit(1);
}

它被强行将为shell用户,失去了root权限,那么它在什么情况下才被降级呢?我们看到是因为should_drop_privileges()函数,代码如下:

static int should_drop_privileges() {
#ifndef ALLOW_ADBD_ROOT
return 1;
#else /* ALLOW_ADBD_ROOT */
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; // ... 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;
}
}
}
}
return secure;
#endif /* ALLOW_ADBD_ROOT */
}

首先考虑ALLOW_ADBD_ROOT宏,这是编译系统决定的,eng版本会打开该宏,其次我们看到变量secure初始值为0,但是在检查了一些属性之后,它变成了1,导致权限降级。而如果ro.debuggable激活,service.adb.root也为1的话,我们还是root权限。在userdebug版本中我们可以在shell下执行:

setprop service.adb.root 1

然后杀死并重启adbd守护进程,来提升root权限。

adb里面有个root命令,可以用来获取root权限。Android守护进程adbd启动时,会调用create_local_service_socket()创建socket套接字,

fd = service_to_fd(name);

在service_to_fd(name)函数里,有各种命令的处理方法,如root命令:

else if(!strncmp(name, "root:", 5)) {
//ret = create_service_thread(restart_root_service, NULL);
ret = create_service_thread(restart_root_service, (void *)(name + 5));
}

它在一个新线程里面执行restart_root_service()函数,原始的调用中参数为NULL,我们可以添加一个密码参数,使得该命令只有加上正确的密码才能执行。

void restart_root_service(int fd, void *cookie)
{
char buf[100];
char value[PROPERTY_VALUE_MAX]; if (getuid() == 0) { //本来就运行在root用户下
snprintf(buf, sizeof(buf), "adbd is already running as root\n");
writex(fd, buf, strlen(buf));
adb_close(fd);
} else {
property_get("ro.debuggable", value, "");
if (strcmp(value, "1") != 0) { //始终绕不过的一个只读属性
snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
writex(fd, buf, strlen(buf));
adb_close(fd);
return;
} property_set("service.adb.root", "1"); //恭喜你拥有root了
snprintf(buf, sizeof(buf), "restarting adbd as root\n");
writex(fd, buf, strlen(buf));
adb_close(fd); // quit, and init will restart us as root
sleep(1);
exit(1);
}
}

Adb分析及获取root权限的更多相关文章

  1. 获取root权限及破解原理分析

    2012-03-18 17:58:45|  分类: android |字号 订阅 如今Android系统的root破解基本上成为大家的必备技能!网上也有非常多中一键破解的软件,使root破解越来越ea ...

  2. ADB工具 获取ROOT权限及复制文件方法

    adb push d:\tm3_sqlit.db data/zouhao/tm3_sqlit.dbadb pull data/zouhao/tm3_sqlit.db d:\tm3_sqlit.db a ...

  3. Android获取Root权限之后的静默安装实现代码示例分析

    转:http://blog.csdn.net/jiankeufo/article/details/43795015 Adroid开发中,我们有时会遇到一些特殊功能的实现,有些功能并没有太高技术难度,但 ...

  4. android中获取root权限的方法以及原理(转)

    一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android 玩家中常说的“越狱”有一个更深层次的认识. 二. Root 的介绍 1. Root 的目的 可以让我们拥有 ...

  5. 一则利用内核漏洞获取root权限的案例【转】

    转自:https://blog.csdn.net/u014089131/article/details/73933649 目录(?)[-] 漏洞描述 漏洞的影响范围 漏洞曝光时间 漏洞产生的原因 漏洞 ...

  6. Android 获取ROOT权限原理解析

    一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android玩家中常说的“越狱”有一个更深层次的认识. 二. Root的介绍 1.       Root 的目的 可以让 ...

  7. Android 上SuperUser获取ROOT权限原理解析

    Android 上SuperUser获取ROOT权限原理解析 一. 概述 本文介绍了android中获取root权限的方法以及原理,让大家对android 玩家中常说的“越狱”有一个更深层次的认识. ...

  8. Android获取ROOT权限的通用方法

    背景 自从Android问世以后,给手机获取ROOT权限变成了玩机爱好者老生常谈的话题.拥有手机,却不能拥有操作手机的最高权限,这对于手机爱好者而言,这怎么可以忍?所以无论Android升到什么什么版 ...

  9. Android刷第三方Recovery &获取root权限

    一.基础环境 Make sure your computer has working adb and fastboot. Setup instructions can be found here. E ...

随机推荐

  1. pytho中pickle、json模块

    pickle & json 模块 json,用于字符串 和 python数据类型间进行转换 pickle,用于python特有的类型 和 python的数据类型间进行转换 json模块提供了四 ...

  2. Struts2 + MySQL 实现分页

    代码结构: package com.action; import java.util.List; import java.util.Map; import com.bean.Pager; import ...

  3. 第5天:Ansible-Playbook

    Ansible中的每个模块专注于某一方面的功能.虽然每个模块实现的功能都比较简单,但是,将各个模块结合起来就可以实现比较复杂的功能.在Ansible中,将各个模块组合起来的文件是一个YAML格式的配置 ...

  4. 【BZOJ 4572】【SCOI 2016】围棋

    http://www.lydsy.com/JudgeOnline/problem.php?id=4572 轮廓线DP:设\(f(i,j,S,x,y)\). \(S\)表示\((i,1)\)到\((i, ...

  5. [BZOJ4765]普通计算姬(分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1725  Solved: 376[Submit][Status][Discus ...

  6. ArrayList之扩容与迭代器

    1. 扩容 ArrayList扩容包括ensureCapacity(对外开放)和ensureCapacityInternal(内部隐式调用)两个接口: 1' 两者都调用ensureExplicitCa ...

  7. Scala 数据类型

    Scala 与 Java有着相同的数据类型,下表列出了 Scala 支持的数据类型: Byte8位有符号补码整数.数值区间为 -128 到 127 Short16位有符号补码整数.数值区间为 -327 ...

  8. linux命令查看开放哪些端口

    netstat -nupl (UDP类型的端口)netstat -ntpl (TCP类型的端口) a 表示所有 n表示不查询dns t表示tcp协议 u表示udp协议 p表示查询占用的程序 l表示查询 ...

  9. 封装log4cp p

    log4cpp 是参考 log4j 所写的 c++ 版本的写 log 的库.可以在这里下载   http://log4cpp.sourceforge.net/   我的使用方法是: 1,定义了一个 _ ...

  10. 十.spring-boot添加jsp支持

    1.创建maven web project: 2.在添加web依赖 3.配置application.properties支持jsp 4.添加一个controller类 5.加入jsp页面 6.启动类 ...