• Android全局可调试(ro.debuggable = 1)的一种另类改法


    网上流传比较多的,是重打包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.”改为“”即空字符串,即可绕过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.
    ");
                    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。

  • 相关阅读:
    javascript 读取内联之外的样式(style、currentStyle、getComputedStyle区别介绍) (转载)
    JS笔记2 --定义对象
    JS笔记1
    Chrome 中的 JavaScript 断点设置和调试技巧 (转载)
    屏蔽移动端浏览器的长按事件
    移除IOS下按钮的原生样式
    HTML5中的Range对象的研究(转载)
    js中的 window.location、document.location、document.URL 对像的区别(转载)
    html中插入flash代码详解(转载)
    关于获取各种浏览器可见窗口大小(转载)
  • 原文地址:https://www.cnblogs.com/gm-201705/p/9863930.html
Copyright © 2020-2023  润新知