首页
社区
课程
招聘
[原创]adb 源码分析
2023-3-9 09:52 6073

[原创]adb 源码分析

2023-3-9 09:52
6073

本文讲述了Android adb调试功能的架构,以及手机端adbd的启动过程。本文分析adb源码是基于Android 13!

adb框架

Android Adb 一共分为三个部分:adb、adb server、adbd。

  1. ADB 客户端:ADB 客户端是一个命令行工具,通常位于计算机上,并与 Android 设备进行通信。它可以向设备发送命令以执行特定的操作,例如启动应用程序或从设备中复制文件等。
  2. ADB 服务器:ADB 服务器是一个后台进程,运行在 Android 设备上,并接收来自客户端的命令。它可以执行诸如在设备上运行 shell 命令或启动应用程序等操作,并向客户端返回响应。
  3. ADB 守护进程:ADB 守护进程是一个在 Android 设备启动时启动的后台进程,它的作用是监听 USB 设备连接和断开的事件,并启动或停止 ADB 服务器。当设备通过 USB 连接到计算机时,ADB 客户端可以连接到 ADB 服务器并与设备进行通信。

根据他们运行的地方不同,可以分为pc端和手机端两部分。

 

源码路径:/packages/modules/adb/daemon/main.cpp。

adbd启动流程

启动过程中,init 进程会检查一个名为 "ro.debuggable" 的系统属性来确定是否需要启动 adbd。如果这个属性被设置为 1,则 adbd 将会被启动。在启动后,adbd 会监听来自 ADB 客户端的连接请求,从而可以接收来自客户端的命令并执行相应的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
on property:ro.debuggable=1
  start console
 
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
  class core
  socket adbd stream 660 system system
  disabled
  seclabel u:r:adbd:s0
 
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
  start adbd

adbd的启动代码在/packages/modules/adb/daemon/main.cpp中,其中main函数调用了adbd_main完成启动过程。adbd是一个linux程序,通过tcp或者usb与PC端的adb server通信,调用logcat shell等等程序实现各种调试功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
int adbd_main(int server_port) {
    umask(0);
 
    signal(SIGPIPE, SIG_IGN);
 
    #if defined(__BIONIC__)
    auto fdsan_level = android_fdsan_get_error_level();
    if (fdsan_level == ANDROID_FDSAN_ERROR_LEVEL_DISABLED) {
        android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
    }
    #endif
 
    init_transport_registration();
 
    // We need to call this even if auth isn't enabled because the file
    // descriptor will always be open.
    adbd_cloexec_auth_socket();
 
    #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 = android::base::GetBoolProperty("ro.adb.secure.recovery", true);
        #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
 
    // Our external storage path may be different than apps, since
    // we aren't able to bind mount after dropping root.
    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
    if (adb_external_storage != nullptr) {
        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
    } else {
        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
            " unchanged.\n");
    }
 
    #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
 
    // 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()) {
        std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
        if (prop_port.empty()) {
            prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
        }
 
        #if !defined(__ANDROID__)
        if (prop_port.empty() && getenv("ADBD_PORT")) {
            prop_port = getenv("ADBD_PORT");
        }
        #endif
 
        int port;
        if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
            D("using tcp port=%d", port);
            // Listen on TCP and VSOCK port specified by service.adb.tcp.port property.
            addrs.push_back(android::base::StringPrintf("tcp:%d", port));
        addrs.push_back(android::base::StringPrintf("vsock:%d", port));
        setup_adb(addrs);
    } else if (!is_usb) {
        // Listen on default port.
        addrs.push_back(
        android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
        addrs.push_back(
        android::base::StringPrintf("vsock:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
        setup_adb(addrs);
    }
    } else {
        addrs = android::base::Split(prop_addr, ",");
        setup_adb(addrs);
    }
 
        LOG(INFO) << "adbd started";
 
        D("adbd_main(): pre init_jdwp()");
        init_jdwp();
        D("adbd_main(): post init_jdwp()");
 
        D("Event loop starting");
        fdevent_loop();
 
        return 0;
    }

adbd权限

adbd启动过程中的权限处理,在adbd_main函数中调用了drop_privileges进行降权处理。因为由init启动的进程启动,所以同样拥有和init一样的root权限。root权限过高,如果编译模式不是调试版本,就要进行降权处理。如果当ro_debuggable && adb_root为true时,可以不用降权,维持root权限。简而言之就是当ro.debuggable为1且ro.secure为0的时候不用降权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
static bool should_drop_privileges() {
    // The properties that affect `adb root` and `adb unroot` are ro.secure and
    // ro.debuggable. In this context the names don't make the expected behavior
    // particularly obvious.
    //
    // ro.debuggable:
    //   Allowed to become root, but not necessarily the default. Set to 1 on
    //   eng and userdebug builds.
    //
    // ro.secure:
    //   Drop privileges by default. Set to 1 on userdebug and user builds.
    bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
    bool ro_debuggable = __android_log_is_debuggable();
 
    // Drop privileges if ro.secure is set...
    bool drop = ro_secure;
 
    // ... except "adb root" lets you keep privileges in a debuggable build.
    std::string prop = android::base::GetProperty("service.adb.root", "");
    bool adb_root = (prop == "1");
    bool adb_unroot = (prop == "0");
    if (ro_debuggable && adb_root) {
        drop = false;
    }
    // ... and "adb unroot" lets you explicitly drop privileges.
    if (adb_unroot) {
        drop = true;
    }
 
    return drop;
}
 
// 省略代码段
// *********
 
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()) {  
        const bool should_drop_caps = !__android_log_is_debuggable();
 
        if (should_drop_caps) {
            minijail_use_caps(jail.get(), CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
        }
 
        minijail_change_gid(jail.get(), AID_SHELL);
        minijail_change_uid(jail.get(), AID_SHELL);
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());
 
        // Whenever ambient capabilities are being used, minijail cannot
        // simultaneously drop the bounding capability set to just
        // CAP_SETUID|CAP_SETGID while clearing the inheritable, effective,
        // and permitted sets. So we need to do that in two steps.
        using ScopedCaps =
            std::unique_ptr<std::remove_pointer<cap_t>::type, std::function<void(cap_t)>>;
        ScopedCaps caps(cap_get_proc(), &cap_free);
        if (cap_clear_flag(caps.get(), CAP_INHERITABLE) == -1) {
            PLOG(FATAL) << "cap_clear_flag(INHERITABLE) failed";
        }
        if (cap_clear_flag(caps.get(), CAP_EFFECTIVE) == -1) {
            PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
        }
        if (cap_clear_flag(caps.get(), CAP_PERMITTED) == -1) {
            PLOG(FATAL) << "cap_clear_flag(PEMITTED) failed";
        }
        if (cap_set_proc(caps.get()) != 0) {
            PLOG(FATAL) << "cap_set_proc() failed";
        }
 
        D("Local port disabled");
    } else {
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());
 
        if (root_seclabel != nullptr) {
            if (selinux_android_setcon(root_seclabel) < 0) {
                LOG(FATAL) << "Could not set SELinux context";
            }
        }
    }
}

如果要编译user版本,可以把ro.secure=1改为ro.secure=0不进项降权处理以root用户运行。ro.adb.secure=1改为0不进行adb授权弹框。但是这种方式容易被检测出来:通过获取ro.secure/ro.adb.secure是否为0来判断手机是否为root。
我们来看下降权函数,我们将此函数直接返回false,是不是就不用考虑ro.secure/ro.adb.secure的值了呢。当我们 adb shell 自动以root 身份运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static bool should_drop_privileges() {
    // The properties that affect `adb root` and `adb unroot` are ro.secure and
    // ro.debuggable. In this context the names don't make the expected behavior
    // particularly obvious.
    //
    // ro.debuggable:
    //   Allowed to become root, but not necessarily the default. Set to 1 on
    //   eng and userdebug builds.
    //
    // ro.secure:
    //   Drop privileges by default. Set to 1 on userdebug and user builds.
    bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
    bool ro_debuggable = __android_log_is_debuggable();
 
    // Drop privileges if ro.secure is set...
    bool drop = ro_secure;
 
    // ... except "adb root" lets you keep privileges in a debuggable build.
    std::string prop = android::base::GetProperty("service.adb.root", "");
    bool adb_root = (prop == "1");
    bool adb_unroot = (prop == "0");
    if (ro_debuggable && adb_root) {
        drop = false;
    }
    // ... and "adb unroot" lets you explicitly drop privileges.
    if (adb_unroot) {
        drop = true;
    }
 
    return drop;
}

我们再来看下adb授权:
代码的第一行检查宏ANDROID是否已定义。
第二行检查ro.boot.verifiedbootstate属性是否设置为“orange”。如果是,则将device_unlocked设置为true。该属性用于确定设备是否处于锁定或解锁状态。
第三行检查device_unlocked是否为true或android_log_is_debuggable()是否为true。如果是,则将auth_required设置为false,表示不需要进行adb授权。
如果设备未解锁且
android_log_is_debuggable()的返回值为false,则继续执行第四行到第八行的代码。这段代码会检查是否在recovery下运行,并根据ro.adb.secure.recovery属性的值来确定是否需要进行身份验证。如果不是在恢复模式下运行,则将auth_required设置为true,表示需要进行adb授权。

1
2
3
4
5
6
7
8
9
10
11
12
#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 = android::base::GetBoolProperty("ro.adb.secure.recovery", true);
#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

那么我们来修改一下:这样是不是无论设备在什么状态都不需要授权了。

1
2
3
4
5
6
7
8
9
10
11
12
13
#if defined(__ANDROID__)
  //  bool device_unlocked = android::base::GetProperty("ro.boot.verifiedbootstate", "") == "orange";
    // if (device_unlocked || __android_log_is_debuggable()) {
    if (1==1) {
#if defined(__ANDROID_RECOVERY__)
        auth_required = android::base::GetBoolProperty("ro.adb.secure.recovery", true);
#else
        // If we're on userdebug/eng or the device is unlocked, permit no-authentication.
        // auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
        auth_required = false;
#endif
    }
#endif


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞4
打赏
分享
最新回复 (3)
雪    币: 414
活跃值: (934)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Andy_877594 2023-3-9 09:53
2
0
前排学习
雪    币: 167
活跃值: (851)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
BestToYou 2023-3-9 10:06
3
0
get了
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Static. 2023-3-9 10:23
4
0
学习
游客
登录 | 注册 方可回帖
返回