Android Native 之 adbd进程分析

article/2025/7/19 22:22:37

 

目录

1、adbd守护进程

2、adbd权限降级

3、adbd命令解析

1)adb shell

2)adb root

3)adb reboot

4、案例

1)案例之实现不需要执行adb root命令自动具有root权限

2)案例之实现不需要RSA认证直接能够使用adb shell命令


adb源码的架构,其实在system/packages/modules/adb/中有注释,如下两个方向:

  • PC主机与adb设备的拓扑图

根据下面一段文字的介绍,android设备的adb主要靠守护进程adbd来实现,具体代码实现是在Daemon里面。

1、adbd守护进程

adbd作为android设备的守护进程,android.bp文件定义如下:

回到adbd主函数中调用adbd_main函数里面,源码如下:

//aosp/packages/modules/adb/daemon/main.cpp
int adbd_main(int server_port) {//...省略...//重点1:auth_required为true表示进行RSA校验,其默认值根据ro.adb.secure
#if defined(__ANDROID__)bool device_unlocked = android::base::GetProperty("ro.boot.verifiedbootstate", "") == "orange";if (device_unlocked || __android_log_is_debuggable()) {
#if defined(__ANDROID_RECOVERY__)auth_required = false;  // Bypass authorization when the device transitions to
#else// If we're on userdebug/eng or the device is unlocked, permit no-authentication.auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
#endif}
#endif//重点2:是否进行权限降级
#if defined(__ANDROID__)drop_privileges(server_port);
#endif
#if defined(__ANDROID__)// A thread gets spawned as a side-effect of initializing the watchdog, so it needs to happen after we drop privileges.watchdog::Initialize();
#endif//重点3:证书权限相关校验,如果auth_required为false其adb/daemon/auth.cpp直接返回不需要校验// adbd_auth_init will spawn a thread, so we need to defer it until after selinux transitions.adbd_auth_init();bool is_usb = false;
#if defined(__ANDROID__)if (access(USB_FFS_ADB_EP0, F_OK) == 0) {// Listen on USB.usb_init();is_usb = true;}
#endif// If one of these properties is set, also listen on that port.// If one of the properties isn't set and we couldn't listen on usb, listen on the default port.std::vector<std::string> addrs;std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", "");if (prop_addr.empty()) {//...省略...} else {addrs = android::base::Split(prop_addr, ",");setup_adb(addrs);}//重点3:关键日志,adbd启动,如果没有这行日志,说明adbd根本无法使用LOG(INFO) << "adbd started";D("adbd_main(): pre init_jdwp()");init_jdwp();D("adbd_main(): post init_jdwp()");D("Event loop starting");//重点4:进入fd事件轮询,即监听pc端发送过来的数据,最终传递在daemon_service_to_fd函数中进行解析fdevent_loop();return 0;
}

总结如上adbd守护进程主函数大致流程如下:

  • 设置auth_required状态,为true表示进行RSA校验,其默认值根据ro.adb.secure。重点,我们可以定制ro.adb.secure属性的值来实现不需要设备授权直接使用adb命令
  • 通过drop_privileges方法来实现权限降级
  • 通过setup_adb设置地址(串口号?),这里除了判断是usb链接还是wifi链接之外,还处理多台usb设备之间的关系
  • 进入fdevent_loop事件轮询,监听PC adb端发送过来的命令

2、adbd权限降级

前面已经介绍了drop_privileges来实现权限降级,那么什么是权限降级呢?这涉及到linux dac机制,在android_filesystem_config.h 文件中定义了大量的权限等级:

AID_XXX定义了android系统中基本能分解的所有用户组和权限(0-100000)。其中AID_ROOT等于0被作为最高用户组。咨询AI这其实就是Linux DAC的实现机制。

回到drop_privileges函数如下内容:

static void drop_privileges(int server_port) {ScopedMinijail jail(minijail_new());// Add extra groups:// AID_ADB to access the USB driver// AID_LOG to read system logs (adb logcat)// AID_INPUT to diagnose input issues (getevent)// AID_INET to diagnose network issues (ping)// AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)// AID_SDCARD_R to allow reading from the SD card// AID_SDCARD_RW to allow writing to the SD card// AID_NET_BW_STATS to read out qtaguid statistics// AID_READPROC for reading /proc entries across UID boundaries// AID_UHID for using 'hid' command to read/write to /dev/uhid// AID_EXT_DATA_RW for writing to /sdcard/Android/data (devices without sdcardfs)// AID_EXT_OBB_RW for writing to /sdcard/Android/obb (devices without sdcardfs)// AID_READTRACEFS for reading tracefs entriesgid_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, AID_READPROC,     AID_UHID,     AID_EXT_DATA_RW,AID_EXT_OBB_RW,   AID_READTRACEFS};minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);// Don't listen on a port (default 5037) if running in secure mode.// Don't run as root if running in secure mode.if (should_drop_privileges()) {//...省略...//核心代码:通过minijail_change_gid切换用户组ID为AID_SHELL,属于Linux DAC降低权限minijail_change_gid(jail.get(), AID_SHELL);minijail_change_uid(jail.get(), AID_SHELL);//核心代码:通过minijail_enter执行最终的沙箱隔离操作,属于Linux DAC机制// minijail_enter() will abort if any priv-dropping step fails.minijail_enter(jail.get());//...省略...D("Local port disabled");} else {//核心代码:通过minijail_enter执行最终的沙箱隔离操作,默认是ROOT?// minijail_enter() will abort if any priv-dropping step fails.minijail_enter(jail.get());//防错处理,如果变量root_seclabel设置的selinux安全上下文不是0,即不是root用户,强制属性service.adb.root的在值为0if (root_seclabel != nullptr) {if (selinux_android_setcon(root_seclabel) < 0) {// If we failed to become root, don't try again to avoid a// restart loop.android::base::SetProperty("service.adb.root", "0");LOG(FATAL) << "Could not set SELinux context";}}}
}

如上代码总结如下:

  • 通过should_drop_privileges来判断是否需要进行权限降级,返回true进行权限降级
  • 进行权限降级:切换用户组为AID_SHELL,来达到降级的目的
  • 不进行权限降级:没有地方去切换用户组等级,默认为root组?

接下来继续分析一下should_drop_privileges是如何来判断需要进行权限降级?

  • 所以最后的核心:最后通过下一小节可以了解到执行adb root之后就会设置属性service.adb.root为1;执行adb unroot之后就会设置属性service.adb.root为0,即adb root之后,adb终端重启并进入最高用户权限等级。

3、adbd命令解析

PC主机发送过来的adb xxx命令,最后由守护进程adb/daemon/services通过套接字或者fd的方式来接收adb相关命令,如下代码逻辑:

如上代码,解析几条重要的adb xxx命令之后,通过create_service_thread的方式去启动线程来执行对应的命令。

1)adb shell

daemon_service_to_fd方法解析为adb shell,直接调用ShellService来进行命令参数拼接

这里比较核心的方法StartSubprocess,在adb/daemon守护进程里面基本上通过它来创建子进程,然后用shell作为执行源。

2)adb root

我们执行adb root的时候,会执行如下函数,如果不是debug版本直接返回,如果是debug版本设置service.adb.root属性值为1.

3)adb reboot

adb reboot命令同上,但是这里区分一下,并没有使用终端shell方式,第二个参数为null,cmd直接定义为/system/bin/reboot,即后续直接创建子进程,以reboot文件作为执行源。

4、案例

1)案例之实现不需要执行adb root命令自动具有root权限

根据adbd权限降级和adb root命令执行可以了解如下逻辑:

  • 执行adb root之后:service.adb.root 为1,在drop_privileges中使用了root用户组
  • 执行adb unroot之后:service.adb.root 为0,在drop_privileges中使用了shell用户组

因此如果我们想绕过adb root命令,直接带有root用户组权限,那么可以强制函数should_drop_privileges返回false。如下案例:

2)案例之实现不需要RSA认证直接能够使用adb shell命令

安卓设备通过usb链接电脑之后,我们在开发者模式菜单开启usb调试之后,通常还无法直接通过adb shell链接设备。会弹出如下对话框进行授权

如果我们想跳过这个对话框的显示,那么可以根据adbd守护进程中讲解的,强制属性ro.adb.secure的值为false即可,在debug版本或者解锁版本中,此值如果没有设置默认当成false。


http://www.hkcw.cn/article/BnXcxJBqUT.shtml

相关文章

wireshark分析国标rtp ps流

1.将抓到的tcp或者udp视频流使用decode as 转为rtp包 2.电话->RTP->RTP播放器 选择Export 里面的Payload 就可以导出原始PS流

next.js 如何做中英文切换(详解)

最近开发的项目涉及到了 react, 因为之前没用过 next.js, 发现文档比较乱&#xff0c;所以也是花了点时间&#xff0c;这里做个记录。 前提依赖&#xff1a;App 文件夹路由 {"next": "14.2.22","react-i18next": "^15.5.1","i1…

SpringAI系列4: Tool Calling 工具调用 【感觉这版本有bug】

前言&#xff1a;在最近发布的 Spring AI 1.0.0.M6 版本中&#xff0c;其中一个重大变化是 Function Calling 被废弃&#xff0c;被 Tool Calling 取代。Tool Calling工具调用&#xff08;也称为函数调用&#xff09;是AI应用中的常见模式&#xff0c;允许模型通过一组API或工具…

SAR ADC 比较器噪声分析(二)

SAR ADC的比较器是非常重要的模块&#xff0c;需要仔细设计。主要考虑比较器的以下指标&#xff1a; 1)失调电压 2)输入共模范围 3)比较器精度 4)传输延时 5)噪声 6)功耗 这里主要讲一下动态比较器的noise。 动态比较器一般用于高速SAR ADC中&#xff0c;且精度不会超过12bit…

Haproxy搭建Web集群

目录 Haproxy概述 Haproxy调度算法 静态调度算法 动态调度算法 其他调度算法 案例环境 配置网站 配置Haproxy Haproxy日志 MySQL负载均衡调度模式 Nginx负载均衡算法 Haproxy概述 Haproxy是一款开源、高性能的负载均衡和代理服务器&#xff0c;支持TCP和HTTP协议&a…

中联教育 - 嵌入式BI助力财经数据分析服务

“借助Wyn商业智能软件嵌入式BI工具强大的嵌入式能力&#xff0c;我们实现了与已有的财经教育教学实训平台的深度融合&#xff0c;大幅提升了平台的数据分析服务能力。同时&#xff0c;产品简单易用的特性&#xff0c;也让我们的学员能够快速上手&#xff0c;进行财务报表的设计…

Qt实现csv文件按行读取的方式

Qt实现csv文件按行读取的方式 场景:我有一个保存数据的csv文件,文件内保存的是按照行保存的数据,每行数据是以逗号为分隔符分割的文本数据。如下图所示: 现在,我需要按行把这些数据读取出来。 一、使用QTextStream文本流的方式读取 #include <QFile>void readfil…

VMware Workstation虚拟系统设置双网口

一.设置windows11系统VMware Network Adapter VMnet1。 1.进入到网络和Internet -> 高级网络设置 2.找到VMware Network Adapter VMnet1&#xff0c;进入到“更多配置选项”并“编辑”。 3.进入到属性&#xff0c;双击“Interenet协议版本4&#xff08;TCP/IPv4&#xff…

CppCon 2014 学习:Lock-Free Programming

你这段文字讲的是“为什么要使用无锁&#xff08;Lock-Free&#xff09;代码”&#xff0c;我帮你总结并解释一下&#xff1a; 为什么选择无锁代码&#xff1f; 并发性和可扩展性&#xff08;Concurrency and scalability&#xff09; 无锁算法允许多个线程同时操作共享数据&a…

MFA多因素认证与TOTP算法核心解析(含Java案例)

目录 一、多因素认证(MFA)概述MFA基本概念MFA与2FA的区别MFA的重要性 二、TOTP算法原理TOTP基本概念时间变量T的计算TOTP生成过程TOTP验证过程 三、TOTP在MFA中的应用绑定流程认证流程TOTP的优势 四、TOTP的安全考虑哈希算法选择密钥管理防暴力破解时间同步通信安全 五、TOTP的…

openssl-aes-ctr使用openmp加速

openssl-aes-ctr使用openmp加速 openssl-aes-ctropenmp omp for openssl-aes-ctr 本文采用openssl-1.1.1w进行开发验证开发&#xff1b;因为aes-ctr加解密模式中&#xff0c;不依赖与上一个模块的加/解密的内容&#xff0c;所以对于aes-ctr加解密模式是比较适合进行并行加速的…

git查看commit属于那个tag

1. 快速确认commit原始分支及合入tag # git describe 213b4b3bbef2771f7a1b8166f6e6989442ca67c8 查看commit合入tag # git describe 213b4b3bbef2771f7a1b8166f6e6989442ca67c8 --all 查看commit原始分支 2.查看分支与master关系 # git show --all 0.5.67_0006 --stat 以缩…

怎么在window上打开ubuntu虚拟机?

怎么在window上打开ubuntu虚拟机&#xff1f; 1.先下载ubuntu镜像包并解压&#xff08;VM-ubuntu18-202304.7z&#xff09;,下载地址在本文档中有链接&#xff0c;自行查找。&#xff08;解压路径不要有中文&#xff09; 2.打开VMware软件&#xff0c;&#xff08;软件下载地址…

中国移动咪咕助力第五届全国人工智能大赛“AI+数智创新”专项赛道开展

第五届全国人工智能大赛由鹏城实验室主办&#xff0c;新一代人工智能产业技术创新战略联盟承办&#xff0c;华为、中国移动、鹏城实验室科教基金会等单位协办&#xff0c;广东省人工智能与机器人学会支持。 大赛发布“AI图像编码”、“AI增强视频质量评价”、“AI数智创新”三大…

第十三章 MQTT消息

系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…

国芯思辰| 16通道12位模数转换器SC1425高性价比SGM5200替代方案,专为数字电源优化

与传统的模拟电源相比&#xff0c;数字电源的主要区别是控制与通信部分。在复杂的多系统业务中&#xff0c;数字电源是通过软件编程来实现多方面的应用&#xff0c;数字电源广泛应用于在可控因素较多、实时反应速度更快、需要多个模拟系统电源管理的、复杂的高性能系统应用中。…

Java 大数据处理:使用 Hadoop 和 Spark 进行大规模数据处理

Java 大数据处理&#xff1a;使用 Hadoop 和 Spark 进行大规模数据处理 在当今数字化时代&#xff0c;数据呈现出爆炸式增长&#xff0c;如何高效地处理大规模数据成为企业面临的重要挑战。Java 作为一门广泛使用的编程语言&#xff0c;在大数据处理领域同样发挥着关键作用。本…

深度学习复习笔记

深度前馈神经网络 卷积神经网络 Advanced卷积神经网络 Lightweight CNN dwconv squeezenet 这边右侧的e3是3x3卷积吧 SENet 在通道维度压一下&#xff0c;强迫各维度混合学习&#xff0c;再还原 ShuffleNet Group Convolution在 AlexNet 中引入&#xff0c;用于将模型分布到…

Linux系统编程收尾(35)

文章目录 前言一、读写锁二、自旋锁总结 前言 大家好&#xff0c;这是我们Linux系统编程的最后一节课了&#xff01;   大家请再撑住一会儿~ 一、读写锁 提到读写锁&#xff0c;我们就不得不提到 读者写者模型 &#xff0c;跟 生产者消费者模型 不同的是&#xff0c;本模型的…

C文件操作1

一、为什么使用文件 如果没有文件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失 了&#xff0c;等再次运行程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进行持久化的保存&am…