这几天听朋友说 GG 可以在不加载驱动的情况下设置内存读写断点,类似 PC 上 ce 的 "查看谁访问了该内存" 功能。网上也查了下资料,发现其实不难.
简单来说,就是先注册一个异常处理函数,然后把内存属性设置为无法访问 (PROT_NONE), 然后当程序读取或改写这段内存后会触发异常,在异常处理函数里获取到 pc 寄存器的值后恢复内存属性即可.
1. 注册异常处理函数
1 2 3 4 5
| struct sigaction act ; memset(&act ,0 ,sizeof(act)); act.sa_sigaction = &handler ; act.sa_flags =SA_SIGINFO |SA_RESETHAND|SA_NODEFER; sigaction(SIGSEGV,&act ,NULL);
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| void handler (int sig ,siginfo_t *siginfo , void * context){ if (siginfo->si_addr==&i){ ucontext_t ctx=(*(ucontext_t*)context); LOGD("pc = 0x%llx \n",ctx.uc_mcontext.pc); } int pageSize = getpagesize(); unsigned long addr= reinterpret_cast<unsigned long>(&start); unsigned long mem = addr & (~(pageSize - 1)); LOGD("mprotect:%d",mprotect(reinterpret_cast<void *>(mem), pageSize, PROT_READ|PROT_WRITE)); return; }
|
2. 设置要读取的内存的属性,注意这个内存必须按页对齐。这里以读取 i 为例
1 2 3 4 5 6
| int pageSize = getpagesize(); unsigned long addr= reinterpret_cast<unsigned long>(&i); start = addr & (~(pageSize - 1)); LOGD("start:%p ",start); LOGD("pageSize:%p ",pageSize); LOGD("mprotect:%d",mprotect(reinterpret_cast<void *>(start), pageSize, PROT_NONE));
|
效果如下: