1. 程式人生 > >Android全局可調試(ro.debuggable = 1)的一種另類改法

Android全局可調試(ro.debuggable = 1)的一種另類改法

cal size kill -9 detach root img 地址 poke service

網上流傳比較多的,是重打包boot.img。讀aosp的init進程源碼,發現通過patch init進程也可以實現相同目的。

首先看一下init進程對ro只讀屬性的檢查:

/* property_service.c */
int property_set(const char *name, const char *value)
{
...
    pi = (prop_info*) __system_property_find(name);

    if(pi != 0) {
        /* ro.* properties may NEVER be modified once set */
        if(!strncmp(name, "ro.", 3)) return -1;  /* 如果是只讀屬性,不允許set,返回-1 */

        __system_property_update(pi, value, valuelen);
    } 
...

從上面代碼看出,如果將“ro.”改為“\0”即空字符串,即可繞過property_set對可讀屬性的檢查。

同時為了防止誤修改,我們查看init進程是否還有其它使用“ro.”字符串的地方,只找到一處,位於check_perms函數中:

/*
 * Checks permissions for setting system properties.
 * Returns 1 if uid allowed, 0 otherwise.
 */
static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
{
    int i;
    unsigned int app_id;

    if(!strncmp(name, "ro.", 3))
        name +=3;

    if (uid == 0)
        return check_mac_perms(name, sctx);
...

分析init進程的匯編代碼,發現property_set函數地址位於check_perms函數之前,因此只要修改搜索到的第一處內存即可。

使用ptrace實現,代碼如下:

kiiim@ubuntu:~/Android_prj/patch_init_process$ cat 1.c 
#include <stdio.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <memory.h>
#include <string.h>

int main(int argc, char **argv) {
        int rc;
        unsigned long maps, mape, addr, test, fake;
        FILE *fp;
        char line[512];
        char *buffer, *ro;

        fp = fopen("/proc/1/maps", "r");
        if (!fp) {
                perror("fopen");
                return 1;
        }
        memset(line, 0, sizeof(line));
        fgets(line, sizeof(line), fp);
        fclose(fp);
        rc = sscanf(line, "%08x-%08x", &maps, &mape);
        if (rc < 2) {
                perror("sscanf");
                return 1;
        }
        buffer = (char *) malloc(mape - maps);
        if (!buffer) {
                perror("malloc");
                return 1;
        }
        rc = ptrace(PTRACE_ATTACH, 1, 0, 0);
        if (rc < 0) {
                perror("ptrace");
                return rc;
        }
        for (addr = maps; addr < mape; addr += 4) {
                test = ptrace(PTRACE_PEEKTEXT, 1, (void *) addr, 0);
                *((unsigned long *)(buffer + addr - maps)) = test;
        }

        ro = memmem(buffer, mape - maps, "ro.", 3);
        if (ro) {
                printf("Patching init.\n");
                fake = 0;
                rc = ptrace(PTRACE_POKETEXT, 1, (void *)(maps + ro - buffer), &fake);
                if (rc < 0) {
                        perror("ptrace");
                }
        }
        free(buffer);
        rc = ptrace(PTRACE_DETACH, 1, 0, 0);

        return rc;
}

編譯並在Nexus 5中運行:

$ arm-linux-androideabi-gcc 1.c -o patch_init

運行後kill掉zygote進程:

root@hammerhead:/data/local/tmp # ps |grep zygote
ps |grep zygote
root      18887 1     860616 56352 ffffffff 400e26d8 S zygote
root@hammerhead:/data/local/tmp # kill -9 18887

zygote進程結束後,會自動被init進程拉起。待zygote重啟後,執行:


root@hammerhead:/data/local/tmp # setprop ro.debuggable 1 setprop ro.debuggable 1 root@hammerhead:/data/local/tmp # getprop ro.debuggable getprop ro.debuggable 1

以上,ro.debuggable屬性已經被修改。只要手機不重啟,此修改一直生效,手機重啟後需重新patch。

Android全局可調試(ro.debuggable = 1)的一種另類改法