安卓ro屬性修改

1、使用

(1) 前提html

下載mprop文件點這裏。使用以前請確保如下幾點:linux

  • 兼容範圍爲Android 4.x-7.x。
  • adb shell 擁有root權限,或adb shell su之後能夠擁有root權限。且獲取的shell其selinux domain爲permissive domain。

如 u:r:su:s0或其餘能夠ptrace init進程且有設置ro.xx目標屬性selinux權限的domain。android

(2) 用法shell

adb shell getprop [key]用於查看手機自己的系統屬性。app

adb shell setprop [key] [value]用於設置手機自己的系統屬性。dom

  • adb push ./mprop /data/local/tmp/。推送文件到手機工具

  • adb shell su。切換到su模式ui

  • chmod 755 /data/local/tmp/mprop。賦予755權限debug

  • data/local/tmp/mprop。修改init進程中的默認邏輯,以後就能夠修改ro屬性rest

  • setprop ro.debuggable 1。設置任意ro屬性,這裏設置debuggable屬性

    改完以後用getprop ro.debuggable可查看debuggable的狀態(並非去default.prop文件中校驗)。

  • /data/local/tmp/mprop -r。恢復init進程中的默認邏輯,以後就沒法再修改ro屬性

  • exit。退出su模式

注意從新開機後debuggable會失效,還要從新運行修改。

2、思路

針對 安卓屬性系統(default.prop)的分析 請參考這裏這裏

直接ptrace init進程,對標紅的ro.屬性的判斷邏輯進行修改或跳過,這樣任意屬性就均可以設置。相關目標文件是該文件:system\core\init\property_service.c*

static int property_set** (const char* name, const char* value) {
    ...

    prop_info* pi = (prop_info*) __system_property_find(name);

    if(pi != 0) {
        /* ro.* properties may NEVER be modified once set */
        [COLOR="Red"]if(!strncmp(name, "ro.", 3)) return -1;[/COLOR]
 
        __system_property_update(pi, value, valuelen);
    } else {
        int rc = __system_property_add(name, namelen, value, valuelen);
        if (rc < 0) return rc;
    }
   ...
}

3、代碼

#include <unistd.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <memory.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/system_properties.h>

#define PROP_NAME_MAX   32
#define PROP_VALUE_MAX  92

static void dump_hex(const char *buf, int len) {
    const uint8_t *data = (const uint8_t *) buf;
    int i;
    char ascii_buf[17];

    ascii_buf[16] = '\0';

    for (i = 0; i < len; i++) {
        int val = data[i];
        int off = i % 16;

        if (off == 0) printf("%08x  ", i);
        printf("%02x ", val);
        ascii_buf[off] = isprint(val) ? val : '.';
        if (off == 15) printf(" %-16s\n", ascii_buf);
    }

    i %= 16;
    if (i) {
        ascii_buf[i] = '\0';
        while (i++ < 16) printf("   ");
        printf(" %-16s\n", ascii_buf);
    }
}

#define ORI_INST  0x2e6f72
#define HACK_INST 0x2e6f73

int main(int argc, char **argv) {
    FILE *fp;
    int m, rc;
    int patch_count;
    unsigned long maps, mape, addr, mlen;
    unsigned long real_val, real_vaddr;

    char perms[5];
    char line[512];
    char *buffer, *ro;
    char *name = NULL, *value = NULL;

    uint32_t tmp;
    uint32_t dest_inst = ORI_INST;
    uint32_t mod_inst = HACK_INST;

    int restore = 0, verbose = 0;

    for (m = 1; m < argc; m++) {
        if (argv[m] == NULL) continue;

        if (argv[m][0] != '-') break;

        if (argv[m][1] == 'r') {
            restore = 1;
            dest_inst = HACK_INST;
            mod_inst = ORI_INST;
        } else if (argv[m][1] == 'v') {
            verbose = 1;
        }
    }

    if (restore) {
        fprintf(stderr, "restore ...\n");
    } else {
        if (argc - m >= 2) {
            // fprintf(stderr, "Usage: %s [-r] [-v] [prop_name] [prop_value]\n"
            //                 "e.g.:  %s ro.debuggable 1\n", argv[0], argv[0]);
            name = argv[m];
            value = argv[m + 1];
        }

        fprintf(stderr, "start hacking ...\n");
    }

    fp = fopen("/proc/1/maps", "r");
    if (!fp) {
        perror("!! fopen ");
        return 1;
    }

    // 00008000-000cb000 r-xp 00000000 00:01 6999       /init
    memset(line, 0, sizeof(line));
    while (fgets(line, sizeof(line), fp)) {
        int main_exe = (strstr(line, "/init") != NULL) ? 1 : 0;
        if (main_exe) {
            rc = sscanf(line, "%lx-%lx %4s ", &maps, &mape, perms);
            if (rc < 3) {
                perror("!! sscanf ");
                return 1;
            }
            if (perms[0] == 'r' && perms[1] == '-' && perms[2] == 'x' && perms[3] == 'p') {
                break;
            }
        }
    }
    fclose(fp);

    fprintf(stderr, "target mapped area: 0x%lx-0x%lx\n", maps, mape);

    mlen = mape - maps;
    buffer = (char *) calloc(1, mlen + 16);
    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) {
        tmp = ptrace(PTRACE_PEEKTEXT, 1, (void *) addr, 0);
        *((uint32_t * )(buffer + addr - maps)) = tmp;
    }

    if (verbose) {
        dump_hex(buffer, mlen);
    }

    for (m = 0; m < mlen; ++m) {
        if (dest_inst == *(uint32_t * )(buffer + m)) { // 72 6F 2E 00  == ro.\0
            break;
        }
    }

    if (m >= mlen) {
        fprintf(stderr, ">> inject position not found, may be already patched!\n");
    } else {
        real_vaddr = maps + m;
        real_val = *(uint32_t * )(buffer + m);
        fprintf(stderr, ">> patching at: 0x%lx [0x%lx -> 0x%08x]\n", real_vaddr, real_val, mod_inst);

        tmp = mod_inst;
        rc = ptrace(PTRACE_POKETEXT, 1, (void *) real_vaddr, (void *) tmp);
        if (rc < 0) {
            perror("!! patching failed ");
        }

        tmp = ptrace(PTRACE_PEEKTEXT, 1, (void *) real_vaddr, 0);
        fprintf(stderr, ">> %s reread: [0x%lx] => 0x%08x\n", restore ? "restored!" : "patched!", real_vaddr, tmp);
    }

    free(buffer);
    rc = ptrace(PTRACE_DETACH, 1, 0, 0);

    if (!restore && (name && value && name[0] != 0)) {
        char propbuf[PROP_VALUE_MAX];
        fprintf(stderr, "-- setprop: [%s] = [%s]\n", name, value);
        __system_property_set(name, value);
        usleep(400000);
        __system_property_get(name, propbuf);
        fprintf(stderr, "++ getprop: [%s] = [%s]\n", name, propbuf);

    }
    return rc;
}

4、附加

想要很方便的對安卓源碼進行分析請看這裏


參考:看雪論壇用戶netsniffer的文章《修改ro屬性的小工具新版本

相關文章
相關標籤/搜索