#define _GNU_SOURCE
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <elf.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <dirent.h>
#include <asm/ptrace.h>
// 修复1: 正确定义ARM64硬件调试寄存器
#ifndef NT_ARM_HW_BREAK
#define NT_ARM_HW_BREAK 0x402 // 执行断点
#endif
#ifndef NT_ARM_HW_WATCH
#define NT_ARM_HW_WATCH 0x403 // 观察点
#endif
// 修复2: 正确定义调试寄存器状态结构体
struct user_hwdebug_state {
uint32_t dbg_info; // 调试信息
uint32_t pad; // 填充
struct {
uint64_t addr; // 地址寄存器
uint64_t ctrl; // 控制寄存器
} dbg_regs[16]; // 最大16个断点
};
// 获取线程ID
int get_threads(pid_t pid, pid_t *threads, int max_threads) {
char path[64];
int count = 0;
snprintf(path, sizeof(path), "/proc/%d/task", pid);
DIR *dir = opendir(path);
if (!dir) {
perror("opendir failed");
return 0;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (count >= max_threads) break;
if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
threads[count++] = atoi(entry->d_name);
}
}
closedir(dir);
return count;
}
// 附加到进程
bool attach_to_process(pid_t pid) {
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
perror("【错误】附加主进程失败");
return false;
}
int status;
if (waitpid(pid, &status, 0) < 0) {
perror("【错误】等待主进程失败");
return false;
}
pid_t threads[64];
int thread_count = get_threads(pid, threads, 64);
if (thread_count == 0) {
fprintf(stderr, "【警告】未找到任何线程\n");
return false;
}
for (int i = 0; i < thread_count; i++) {
pid_t tid = threads[i];
if (tid == pid) continue;
if (ptrace(PTRACE_ATTACH, tid, NULL, NULL) < 0) {
perror("【错误】附加子线程失败");
continue;
}
if (waitpid(tid, &status, 0) < 0) {
perror("【错误】等待子线程失败");
ptrace(PTRACE_DETACH, tid, NULL, NULL);
continue;
}
printf("【已附加线程】tid=%d\n", tid);
}
return true;
}
// 修复3: 正确设置硬件断点
bool set_hw_breakpoint(pid_t pid, pid_t thread_id, uintptr_t addr, int len, int type) {
// 选择寄存器集类型
int nt_type = (type == 0) ? NT_ARM_HW_BREAK : NT_ARM_HW_WATCH;
struct user_hwdebug_state dbg_regs;
struct iovec iov = { .iov_base = &dbg_regs, .iov_len = sizeof(dbg_regs) };
// 获取当前状态
if (ptrace(PTRACE_GETREGSET, thread_id, nt_type, &iov) < 0) {
perror("【错误】PTRACE_GETREGSET获取失败");
return false;
}
// 查找空闲槽位
int slot = -1;
for (int i = 0; i < 16; i++) {
if (dbg_regs.dbg_regs[i].addr == 0) {
slot = i;
break;
}
}
if (slot == -1) {
fprintf(stderr, "【错误】线程%d无可用硬件断点\n", thread_id);
return false;
}
// 设置控制寄存器
uint64_t ctrl_value = 0;
if (type == 0) { // 执行断点
ctrl_value = (1 << 0) | // 启用
(0b01 << 8); // 用户空间(EL0)
} else { // 观察点
// 计算BAS掩码
uint64_t bas = 0;
switch (len) {
case 1: bas = 0x1; break;
case 2: bas = 0x3; break;
case 4: bas = 0xF; break;
case 8: bas = 0xFF; break;
default:
fprintf(stderr, "【错误】无效长度: %d\n", len);
return false;
}
ctrl_value = (1 << 0) | // 启用
(0b01 << 8); // 用户空间(EL0)
// 设置类型
if (type == 1) { // 读
ctrl_value |= (0b01 << 3); // Load
} else if (type == 2) { // 写
ctrl_value |= (0b10 << 3); // Store
} else if (type == 3) { // 读写
ctrl_value |= (0b11 << 3); // Load/Store
}
// 设置长度(BAS)
ctrl_value |= (bas << 16);
}
// 设置地址和控制寄存器
dbg_regs.dbg_regs[slot].addr = addr;
dbg_regs.dbg_regs[slot].ctrl = ctrl_value;
// 应用设置
if (ptrace(PTRACE_SETREGSET, thread_id, nt_type, &iov) < 0) {
perror("【错误】PTRACE_SETREGSET设置失败");
return false;
}
printf("【线程%d断点设置成功】 地址:0x%llx 类型:%s 长度:%d字节\n",
thread_id, (unsigned long long)addr,
type == 0 ? "执行" : type == 1 ? "读" : type == 2 ? "写" : "读写",
len);
return true;
}
// 清除所有硬件断点
bool clear_all_hw_breakpoints(pid_t thread_id) {
struct user_hwdebug_state dbg_regs;
struct iovec iov = { .iov_base = &dbg_regs, .iov_len = sizeof(dbg_regs) };
// 清除执行断点
memset(&dbg_regs, 0, sizeof(dbg_regs));
if (ptrace(PTRACE_SETREGSET, thread_id, NT_ARM_HW_BREAK, &iov) < 0) {
perror("【错误】清除执行断点失败");
}
// 清除观察点
memset(&dbg_regs, 0, sizeof(dbg_regs));
if (ptrace(PTRACE_SETREGSET, thread_id, NT_ARM_HW_WATCH, &iov) < 0) {
perror("【错误】清除观察点失败");
return false;
}
return true;
}
// 获取寄存器信息
bool get_registers(pid_t tid, struct user_pt_regs *regs) {
struct iovec iov = { .iov_base = regs, .iov_len = sizeof(*regs) };
if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) < 0) {
perror("【错误】PTRACE_GETREGSET获取失败");
return false;
}
return true;
}
int main() {
pid_t target_pid;
printf("【输入目标进程PID】\n");
scanf("%d", &target_pid);
if (geteuid() != 0) {
fprintf(stderr, "【错误】需要root权限\n");
return 1;
}
if (!attach_to_process(target_pid)) {
fprintf(stderr, "【致命错误】无法附加目标进程\n");
return 1;
}
uintptr_t bp_addr;
printf("【输入断点地址(十六进制)】\n");
scanf("%llx", (unsigned long long *)&bp_addr);
int len, type;
printf("【选择断点类型(0:执行,1:读,2:写,3:读写)】\n");
scanf("%d", &type);
if (type != 0) {
printf("【输入断点长度(1,2,4,8字节)】\n");
scanf("%d", &len);
// 检查长度有效性
if (len != 1 && len != 2 && len != 4 && len != 8) {
fprintf(stderr, "【错误】无效长度,使用默认值4字节\n");
len = 4;
}
} else {
len = 4; // 执行断点长度固定
}
pid_t threads[64];
int thread_count = get_threads(target_pid, threads, 64);
for (int i = 0; i < thread_count; i++) {
pid_t tid = threads[i];
printf("【处理线程】tid=%d\n", tid);
if (!set_hw_breakpoint(target_pid, tid, bp_addr, len, type)) {
fprintf(stderr, "【警告】线程%d断点设置失败\n", tid);
continue;
}
}
printf("【恢复进程执行...】\n");
if (ptrace(PTRACE_CONT, target_pid, NULL, NULL) < 0) {
perror("【错误】恢复执行失败");
return 1;
}
printf("【等待断点触发...】\n");
int status;
pid_t wait_pid = waitpid(-1, &status, 0);
bool breakpoint_hit = false;
for (int i = 0; i < thread_count; i++) {
pid_t tid = threads[i];
int nt_type = (type == 0) ? NT_ARM_HW_BREAK : NT_ARM_HW_WATCH;
struct user_hwdebug_state dbg_regs;
struct iovec iov = { .iov_base = &dbg_regs, .iov_len = sizeof(dbg_regs) };
if (ptrace(PTRACE_GETREGSET, tid, nt_type, &iov) < 0) {
perror("【错误】获取调试寄存器失败");
continue;
}
for (int j = 0; j < 16; j++) {
if (dbg_regs.dbg_regs[j].addr == bp_addr &&
(dbg_regs.dbg_regs[j].ctrl & 0x1)) {
breakpoint_hit = true;
printf("\n【断点命中!】\n");
printf("触发线程:tid=%d\n", tid);
printf("命中地址:0x%llx\n", (unsigned long long)bp_addr);
const char *type_str = type == 0 ? "执行" :
type == 1 ? "读" :
type == 2 ? "写" : "读写";
printf("类型:%s | 长度:%d字节\n", type_str, len);
struct user_pt_regs regs;
if (get_registers(tid, ®s)) {
printf("\n寄存器状态:\n");
printf("PC=0x%llx (程序计数器)\n", (unsigned long long)regs.pc);
printf("LR=0x%llx (链接寄存器x30)\n", (unsigned long long)regs.regs[30]);
printf("SP=0x%llx (栈指针sp)\n", (unsigned long long)regs.sp);
printf("X0=0x%llx, X1=0x%llx, X2=0x%llx, X3=0x%llx\n",
(unsigned long long)regs.regs[0],
(unsigned long long)regs.regs[1],
(unsigned long long)regs.regs[2],
(unsigned long long)regs.regs[3]);
}
break;
}
}
if (breakpoint_hit) break;
}
if (!breakpoint_hit) {
printf("\n【未检测到断点命中,恢复进程执行...】\n");
ptrace(PTRACE_CONT, target_pid, NULL, NULL);
}
printf("\n【清理断点...】\n");
for (int i = 0; i < thread_count; i++) {
pid_t tid = threads[i];
if (!clear_all_hw_breakpoints(tid)) {
fprintf(stderr, "【警告】线程%d断点清除失败\n", tid);
} else {
printf("【已清除线程】tid=%d的断点\n", tid);
}
}
printf("\n【分离调试会话...】\n");
for (int i = 0; i < thread_count; i++) {
pid_t tid = threads[i];
if (ptrace(PTRACE_DETACH, tid, NULL, NULL) < 0) {
perror("【错误】分离线程失败");
}
}
return 0;
}
Android NDK: src/ptrace断点.cpp.bak
[arm64-v8a] Compile++ : 无痕hook.sh <= ptrace断点.cpp
jni/src/ptrace断点.cpp:25:8: error: redefinition of
'user_hwdebug_state'
struct user_hwdebug_state {
^
/data/data/com.aide.ui.mgai/no_backup/ndksupport-1710240003/android-ndk-aide/sysroot/usr/include/aarch64-linux-android/asm/ptrace.h:61:8: note:
previous definition is here
struct user_hwdebug_state {
^
1 error generated.
make: *** [/data/data/com.aide.ui.mgai/no_backup/ndksupport-1710240003/android-ndk-aide/build/core/build-binary.mk:530: obj/local/arm64-v8a/objs/无痕hook.sh/src/ptrace 断点.o] Error 1
修复好报错问题完整发给我