首页
社区
课程
招聘
[原创]android ro.debuggable属性调试修改(mprop逆向)
发表于: 2018-8-6 22:05 28518

[原创]android ro.debuggable属性调试修改(mprop逆向)

2018-8-6 22:05
28518

android ro属性调试修改(mprop逆向)

     大家都知道如果需要调试android 的程序,以下两个条件满足一个就行。第一是apk的配置文件内的AndroidManifest.xml的 android:debuggable=”true”,第二就是/default.prop中ro.debuggable=1。两种方式第一种通常是解包添加属性再打包,随着加壳软件以及apk校验等,容易出现安装包异常。第二种由于一般的手机发布时ro.debuggable一般是0 也就是不允许调试,通过修改rom的办法在手机上比较麻烦,需要刷机等等,模拟器上一般是vmdk的虚拟机,也没法修改rom。这样我们就无法调试应用了,比如使用DDMS时,只能看到手机,看不到进程信息。



        后来发现有人提供了一个软件叫做mprop,但是只有二进制的文件arm架构的,没有源码,一个问题是在有些手机上测试是无效的,第二个问题是在X86模拟器上调试就不可能了。所以尝试一下逆向mprop并且解决这个调试问题。

         打开mprop发现主要是附加了1号进程也就是init进程。通过对/dev/__properties__属性段执行修改来修改对应的数值。




针对于android4.4版本的x86模拟器。

我们进入源码中看看为何在init进程这里修改就可以了。在

system/core/init/property_service.c

system/core/init/init.c

Main执行时

property_init->init_property_area-> __system_property_area_init函数(位于bionic/libc/bionic/system_properties.c)->map_prop_area_rw  fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444)

打开了/dev/__properties__

随后调用property_load_boot_defaults加载了default.prop调用load_properties 通过property_set(key, value);将对应的键值设置好。

在 property_set 函数中 ro.开头的函数只能设置一次。否则就返回失败。所以我们后续调用setprop就是无效的。否则将调用__system_property_update执行更新。因此我们可以模拟__system_property_find 得到prop_info结构

__system_property_update prop_info结构中的数据

(bionic/libc/bionic/system_properties.c)实现。

关键就是 这个结构。name中是ro.debuggable value中是0

因此我们只要在 /dev/__properties__ 段中找到 对应的name然后向上移动PROP_VALUE_MAX(android4.4中是96)个字节。修改value为对应的值即可。我们dump可以看出来.

剩下就是编码 主要是通过ptrace进入init然后修改memory具体可以下代码

后续的操作如下

编译modprop


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 4
支持
分享
最新回复 (15)
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
https://security.tencent.com/index.php/opensource/detail/17  这个更方便
2018-8-7 08:27
2
雪    币: 129
活跃值: (407)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
感谢大佬分享详细步骤。
2018-8-7 09:11
0
雪    币: 2743
活跃值: (1049)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
感谢大佬分享细节!
2018-8-7 09:30
0
雪    币: 1392
活跃值: (5177)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
5
iwang王大军 https://security.tencent.com/index.php/opensource/detail/17 这个更方便[em_1]
有部分加壳的没法用。
2018-8-7 09:31
0
雪    币: 144
活跃值: (335)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
大佬现在搞安卓去了啊
2018-8-8 09:02
0
雪    币: 442
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mprop有源码啊,就不能先搜下吗

https://github.com/search?utf8=%E2%9C%93&q=mprop&type=
2018-8-10 15:29
0
雪    币: 442
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mprop有源码啊,就不能先搜下吗

https://github.com/search?utf8=%E2%9C%93&q=mprop&type=
2018-8-10 15:29
0
雪    币: 1392
活跃值: (5177)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
9
ucantseeme mprop有源码啊,就不能先搜下吗 https://github.com/search?utf8=%E2%9C%93&q=mprop&type=
那要麻烦你把源码找出来,那里面都是BIN文件。
2018-8-10 17:26
0
雪    币: 6266
活跃值: (1276)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
大佬,mprop作者在帖子下面的回复中发出了源码
/**
 * Copyright (C) 2018 netsniffer
 * mprop v1.0, 2017/01/19
 * https://bbs.pediy.com/thread-215311.htm
 */
 
#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;
}
2018-12-16 22:51
0
雪    币: 18
活跃值: (951)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢大佬分享
2019-10-31 09:38
0
雪    币: 159
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
这种方法重启就失效了吧。 用制作好的boot.img 刷一下也可以。
2019-11-12 15:46
0
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
iwang王大军 https://security.tencent.com/index.php/opensource/detail/17 这个更方便[em_1]
试了,这个方法有效。
2020-2-8 16:29
0
雪    币: 190
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
测试了note2 安卓4.3,没效果
getprop ro.debuggable 返回0
2020-4-17 21:54
0
雪    币: 4128
活跃值: (869)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
15
nox android7没效果
2020-10-7 19:10
0
游客
登录 | 注册 方可回帖
返回
//