程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Adb分析及獲取root權限

Adb分析及獲取root權限

編輯:C++入門知識

Adb的全稱為Android Debug Bridge,起到通過PC對Android系統的調試橋的作用,是一個多用途的工具,它能夠執行多種命令,還能提供一個shell。這兒簡單介紹一下Adb的代碼結構,並在某些情況下我們可以獲取root權限。

Adb的代碼在system/core/adb裡,它的入口函數很直接了當:

[cpp]
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  

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()函數,這裡主要是負責解析參數並執行相應的命令,注意這兒在執行命令之前還有一個啟動本地服務的動作:

[cpp]
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; 

    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的初始化:

[cpp]
#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 

#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. 組織命令格式,

[cpp]
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; 
    } 

    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機制)。

[java]
fdevent_loop(); 

fdevent_loop();
其中我們對運行級別比較感興趣,一般情況下我們的adb都是運行在shell用戶下,而事實上,adb.c中的代碼都是以root權限運行的,以完成部分初始化工作,直到執行了下面的代碼:
[cpp]
if (should_drop_privileges()) { 
    ...... 
        if (setgid(AID_SHELL) != 0) { 
            exit(1);                        //這兒曾經是個漏洞,沒有檢查返回值,可以被某些惡意軟件利用來破解root權限  
        } 
        if (setuid(AID_SHELL) != 0) { 
            exit(1); 
        } 

if (should_drop_privileges()) {
    ......
        if (setgid(AID_SHELL) != 0) {
            exit(1);                        //這兒曾經是個漏洞,沒有檢查返回值,可以被某些惡意軟件利用來破解root權限
        }
        if (setuid(AID_SHELL) != 0) {
            exit(1);
        }
它被強行將為shell用戶,失去了root權限,那麼它在什麼情況下才被降級呢?我們看到是因為should_drop_privileges()函數,代碼如下:
[cpp]
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 */  

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下執行:[plain] view plaincopyprint?setprop service.adb.root 1 

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命令:


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

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,我們可以添加一個密碼參數,使得該命令只有加上正確的密碼才能執行。
[cpp]
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); 
    } 

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);
    }
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved