对于一些有 crc 检测,而且注册了 sigaction 的 app 来说,通过异常的方式来追踪检测流程属实是太困难了,不过硬件断点解决了这个难题.
代码来源 rwProcMem33.
本文仅说明使用方法.
设置驱动访问权限及 selinux
参考定制 SELinux 规则 允许 app 访问内核模块
首先加载模块,设置驱动权限
1 2
| insmod /data/local/tmp/hwBreakpointProc1.ko chmod 666 /dev/hwBreakpointProc1
|
接下来可以关闭 selinux 或设置 sepolicy
或者
1 2 3
| magiskpolicy --live "allow untrusted_app device chr_file { read write ioctl open getattr map }" magiskpolicy --live "attradd untrusted_app mlstrustedsubject"
|
app 连接驱动,设置断点
连接驱动
1 2 3 4 5 6
| int err = 0; if (!driver.ConnectDriver(err)) { LOGD("连接驱动失败\n"); return nullptr; }
|
获取当前进程内所有线程 id, 因为硬件断点是针对线程的
1 2 3 4 5 6 7
| std::vector<int> vTask; GetProcessTask(getpid(), vTask); if (vTask.size() == 0) { LOGD("获取当前进程task失败\n"); return nullptr; }
|
设置硬件断点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| for (int task : vTask) { uint64_t hProcess = driver.OpenProcess(task); if (!hProcess) { LOGD("调用驱动 OpenProcess 失败\n"); fflush(stdout); continue; }
uint64_t hwBpHandle = driver.AddProcessHwBp(hProcess, (uint64_t)address, HW_BREAKPOINT_LEN_4, HW_BREAKPOINT_R);
if (hwBpHandle) { vHwBpHandle.push_back(hwBpHandle); } driver.CloseHandle(hProcess); }
|
删除硬断,读取硬件断点信息
删除硬件断点
1 2 3 4 5 6 7 8 9
| LOGD("请等待2秒"); sleep(2);
for (uint64_t hwBpHandle : vHwBpHandle) { driver.DelProcessHwBp(hwBpHandle); }
|
读取硬件断点命中信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| for (uint64_t hwBpHandle : vHwBpHandle) { std::vector<USER_HIT_INFO> vHit; BOOL b = driver.ReadHwBpInfo(hwBpHandle, vHit);
for (USER_HIT_INFO userhInfo : vHit) { LOGD("==========================================================================\n"); LOGD("硬件断点命中地址:%p,命中次数:%zu\n", userhInfo.hit_addr, userhInfo.hit_count); for (int r = 0; r < 30; r += 5) { LOGD("\tX%-2d=%-12llx X%-2d=%-12llx X%-2d=%-12llx X%-2d=%-12llx X%-2d=%-12llx\n", r, userhInfo.regs.regs[r], r + 1, userhInfo.regs.regs[r + 1], r + 2, userhInfo.regs.regs[r + 2], r + 3, userhInfo.regs.regs[r + 3], r + 4, userhInfo.regs.regs[r + 4]); } LOGD("\tLR=%-12llx SP=%-12llx PC=%-12llx\n", userhInfo.regs.regs[30], userhInfo.regs.sp, userhInfo.regs.pc);
LOGD("\tprocess status:%-12llx orig_x0:%-12llx syscallno:%-12llx\n", userhInfo.regs.pstate, userhInfo.regs.orig_x0, userhInfo.regs.syscallno); LOGD("==========================================================================\n"); } }
|
清空硬件断点命中信息
1 2
| driver.CleanHwBpInfo(); LOGD("调用驱动 CleanHwBpInfo()\n");
|
硬件断点的分类
根据 rwProcMem33 大佬的代码来看
硬件断点分为以下几类
1 2 3 4 5 6 7 8 9
| enum { HW_BREAKPOINT_EMPTY = 0, HW_BREAKPOINT_R = 1, HW_BREAKPOINT_W = 2, HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W, HW_BREAKPOINT_X = 4, HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X, };
|
硬件断点的长度为
1 2 3 4 5 6 7
| enum { HW_BREAKPOINT_LEN_1 = 1, HW_BREAKPOINT_LEN_2 = 2, HW_BREAKPOINT_LEN_4 = 4, HW_BREAKPOINT_LEN_8 = 8, };
|
硬件断点的设置
1
| driver.AddProcessHwBp(hProcess, (uint64_t)address, HW_BREAKPOINT_LEN_4, HW_BREAKPOINT_R);
|
其中,hProcess 是从内核中拿到的线程句柄,address 为断点地址,HW_BREAKPOINT_LEN_4 为断点长度,HW_BREAKPOINT_R 为断点分类.
最后
测试 app Github 地址:
https://github.com/PShocker/HwBpApp
Releases:
https://github.com/PShocker/PShocker.github.io/releases/tag/HwBpApp