?
目錄
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。