XDebuggable&mprop代码分析
0x01 背景
XDebuggable是一个xposed的插件用来 使android:debuggable="true"保证可调试状态
mprop修改default.prop中ro.debuggable=1保证可调试状态
0x02 XDebuggable核心代码
hook修改android/os/Process.java的start方法,并保证其第五个参数debugflags的值为1.
关键在于hook修改start函数的第五个参数,我们来看第五个参数是啥?
debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER值为1则开启调试模式 然后启动新的进程
0x03 mprop原理分析
1.提前关闭selinux
查看SELinux状态:
1、/usr/sbin/sestatus -v ##如果SELinux status参数为enabled即为开启状态
SELinux status: enabled
2、getenforce ##也可以用这个命令检查
关闭SELinux:
1、临时关闭(不用重启机器):
setenforce 0 ##设置SELinux 成为permissive模式
setenforce 1 设置SELinux 成为enforcing模式
2、修改配置文件需要重启机器:
修改/etc/selinux/config 文件
将SELINUX=enforcing改为SELINUX=disabled
重启机器即可
2.用法
adb shell suchmod 755 /data/local/tmp/mpropdata/local/tmp/mprop ro.debuggable 1/data/local/tmp/mprop -r
3.使用后
手机默认的prop属性如下:
root@cancro:/ # cat default.propcat default.prop## ADDITIONAL_DEFAULT_PROPERTIES#ro.adb.secure=0ro.secure=1security.perf_harden=1ro.allow.mock.location=0ro.debuggable=1ro.zygote=zygote32dalvik.vm.image-dex2oat-Xms=64mdalvik.vm.image-dex2oat-Xmx=64mdalvik.vm.dex2oat-Xms=64mdalvik.vm.dex2oat-Xmx=512mro.dalvik.vm.native.bridge=0debug.atrace.tags.enableflags=0persist.sys.strict_op_enable=falsepersist.sys.whitelist=/system/etc/whitelist_appops.xmlcamera2.portability.force_api=1persist.sys.timezone=Asia/Shanghai## BOOTIMAGE_BUILD_PROPERTIES#ro.bootimage.build.date=Wed Jun 14 02:20:41 CST 2017ro.bootimage.build.date.utc=1497378041ro.bootimage.build.fingerprint=Xiaomi/cancro/cancro:6.0.1/MMB29M/7.6.14:user/release-keyspersist.sys.usb.config=adb
原理:直接ptrace init进程,对标红的ro.属性的判断逻辑进行修改,跳过,这样任意属性就都可以设置了。
/** * Copyright (C) 2018 netsniffer * mprop v1.0, 2017/01/19 * https://bbs.pediy.com/thread-215311.htm */#include #include #include #include #include #include #include #include #include #include #include #include #include #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; }//输出每个参数printf("%s",argv[m]); } 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) {printf("%s","dump dex"); 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;}
利用__system_property_update
#include #include #include #include #include #include #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_#include #include struct prop_info;struct prop_area;extern int __system_property_area_init();extern int __system_property_get(const char *name, char *value);extern int __system_property_add(const char *name, unsigned int namelen, const char *value, unsigned int valuelen);extern const prop_info *__system_property_find(const char *name);extern prop_area *__system_property_area__;extern int __system_property_update(prop_info *pi, const char *value, unsigned int len);void usage() { printf("usage: mprop property_name property_value\n");}int main(int argc,char **argv){ sleep(30); printf("start....\n"); const int fd = open("/dev/__properties__", O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444); if (argc!=3) { usage(); return -1; } if (strlen(argv[1])+1>PROP_NAME_MAX) { printf("property name is to long\n"); return -1; } if (sizeof(argv[2])+1>PROP_VALUE_MAX) { printf("property value is to long\n"); return -1; } if (fd<0) { perror("open"); return -1; } struct stat fd_stat; if (fstat(fd, &fd_stat) <0) { perror("fstat"); return -1; } if (!S_ISREG(fd_stat.st_mode)) { printf("internal error\n"); return -1; } void *memory_area = mmap(NULL, fd_stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); __system_property_area__ = (prop_area *)memory_area; printf("mapd...\n"); char value[PROP_VALUE_MAX]; bool update = true; if(__system_property_get(argv[1],value)<=0) { update = false; printf("update falsei\n"); } if (update) { printf("old value : %s\n",value); prop_info *pinfo = const_cast(__system_property_find(argv[1])); if (!pinfo){ printf("internal error\n"); return -1; } if(__system_property_update(pinfo,argv[2],strlen(argv[2]))) { printf("update error\n"); return -1; } } else { printf("add value: name:%s value:%s\n",argv[1],argv[2]); if(__system_property_add(argv[1],strlen(argv[1]),argv[2],strlen(argv[2]))) { printf("update error\n"); return -1; } } printf("new value %s\n",argv[2]); return 0;}
参考:
android ro.debuggable属性调试修改(mprop逆向) https://bbs.pediy.com/thread-246081.htm
http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/java/android/os/Process.java#start
更多相关文章
- Android列表组件ListView使用详解之动态加载或修改列表数据
- G1定制攻略
- 安卓动画(Animation使用)
- Android(安卓)4.0 framework源码修改编译,模拟器运行不起来
- Android强制竖屏
- Android三种实现自定义ProgressBar的方式介绍
- Android之开源控件ViewFLow学习笔记【含下载地址】--(原创-201504
- android 数据持久化——I/O操作
- Android(安卓)8.0 高通代码预制apk可卸载,恢复出厂设置apk可恢复