Android Native 之 adbd进程分析

发布于:2025-06-04 ⋅ 阅读:(28) ⋅ 点赞:(0)

 

目录

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 entries
    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, 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的在值为0
        if (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。


网站公告

今日签到

点亮在社区的每一天
去签到