From e00138a68681e4f4bb06d6e53f1c6bbda9fef064 Mon Sep 17 00:00:00 2001 From: gggaa2152 <60614405+gggaa2152@users.noreply.github.com> Date: Thu, 23 Jul 2026 08:32:29 +0800 Subject: [PATCH] Update injector.cpp --- injector.cpp | 141 +++++++++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 62 deletions(-) diff --git a/injector.cpp b/injector.cpp index 1b5951ebc..ccc045b4d 100644 --- a/injector.cpp +++ b/injector.cpp @@ -1,7 +1,11 @@ -// injector.cpp – Android ptrace 注入器 (arm64) -// 使用 PTRACE_GETREGSET / PTRACE_SETREGSET 兼容 Android NDK +// injector.cpp – 改进版 Android ptrace 注入器 (arm64) // 编译: arm64-linux-android-clang++ -static -std=c++17 injector.cpp -o injector -// 运行: adb push injector /data/local/tmp/ && adb shell su -c /data/local/tmp/injector [so_path] [package_name] +// 用法: +// ./injector [so_path] [package_name] // 自动查找进程 +// ./injector [so_path] [pid] // 直接指定 PID(第三个参数为数字) +// 示例: +// ./injector /data/local/tmp/libcheat.so com.tencent.jkchess +// ./injector /data/local/tmp/libcheat.so 12345 #include #include @@ -17,14 +21,14 @@ #include #include #include -#include // NT_PRSTATUS -#include // user_pt_regs +#include +#include +#include #include #include #include -// ---------- 工具函数 ---------- -// 根据进程名获取 PID +// ---------- 通过 cmdline 精确查找进程 ---------- int find_pid_by_name(const char* proc_name) { DIR* dir = opendir("/proc"); if (!dir) return -1; @@ -34,27 +38,32 @@ int find_pid_by_name(const char* proc_name) { if (entry->d_type != DT_DIR) continue; int tmp_pid = atoi(entry->d_name); if (tmp_pid <= 0) continue; - char path[256]; - snprintf(path, sizeof(path), "/proc/%d/comm", tmp_pid); - FILE* fp = fopen(path, "r"); + char cmdline_path[256]; + snprintf(cmdline_path, sizeof(cmdline_path), "/proc/%d/cmdline", tmp_pid); + FILE* fp = fopen(cmdline_path, "r"); if (fp) { - char comm[64] = {0}; - if (fgets(comm, sizeof(comm), fp)) { - comm[strcspn(comm, "\n")] = 0; - if (strcmp(comm, proc_name) == 0) { + char cmdline[256] = {0}; + size_t n = fread(cmdline, 1, sizeof(cmdline) - 1, fp); + fclose(fp); + if (n > 0) { + // cmdline 的第一个字符串是命令(包含路径) + char* pkg = cmdline; + // 去除路径前缀 + char* last_slash = strrchr(pkg, '/'); + if (last_slash) pkg = last_slash + 1; + // 比较完整包名 + if (strcmp(pkg, proc_name) == 0) { pid = tmp_pid; - fclose(fp); break; } } - fclose(fp); } } closedir(dir); return pid; } -// 读取远程进程内存 +// ---------- 远程内存读写辅助 ---------- long ptrace_readdata(int pid, unsigned long addr, void* buffer, size_t size) { for (size_t i = 0; i < size; i += sizeof(long)) { long data = ptrace(PTRACE_PEEKDATA, pid, addr + i, 0); @@ -64,7 +73,6 @@ long ptrace_readdata(int pid, unsigned long addr, void* buffer, size_t size) { return 0; } -// 写入远程进程内存 long ptrace_writedata(int pid, unsigned long addr, const void* buffer, size_t size) { for (size_t i = 0; i < size; i += sizeof(long)) { long data = 0; @@ -75,8 +83,7 @@ long ptrace_writedata(int pid, unsigned long addr, const void* buffer, size_t si return 0; } -// 在远程进程中调用 dlopen 并加载库 -// 成功返回 0,失败返回 -1 +// ---------- 注入主逻辑 ---------- int ptrace_inject(int pid, const char* so_path) { // 1. 附加进程 if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { @@ -91,7 +98,7 @@ int ptrace_inject(int pid, const char* so_path) { return -1; } - // 2. 保存原始寄存器(用于恢复) + // 2. 保存原始寄存器 struct user_pt_regs regs, orig_regs; struct iovec iov = { ®s, sizeof(regs) }; if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1) { @@ -101,23 +108,21 @@ int ptrace_inject(int pid, const char* so_path) { } orig_regs = regs; - // 3. 在远程进程中分配内存,用于存放 so 路径 + // 3. 在远程进程中分配内存存放 SO 路径 size_t path_len = strlen(so_path) + 1; - // 使用 mmap 分配匿名内存 (ARM64 系统调用号 222) - regs.regs[0] = 0; // addr - regs.regs[1] = path_len; // length - regs.regs[2] = PROT_READ | PROT_WRITE;// prot - regs.regs[3] = MAP_PRIVATE | MAP_ANONYMOUS; // flags - regs.regs[4] = -1; // fd - regs.regs[5] = 0; // offset - regs.regs[8] = 222; // syscall number (mmap) + regs.regs[0] = 0; + regs.regs[1] = path_len; + regs.regs[2] = PROT_READ | PROT_WRITE; + regs.regs[3] = MAP_PRIVATE | MAP_ANONYMOUS; + regs.regs[4] = -1; + regs.regs[5] = 0; + regs.regs[8] = 222; // mmap syscall iov.iov_base = ®s; iov.iov_len = sizeof(regs); if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov) == -1) { perror("ptrace setregset for mmap"); ptrace(PTRACE_DETACH, pid, 0, 0); return -1; } - // 执行系统调用 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) == -1) { perror("ptrace syscall"); ptrace(PTRACE_DETACH, pid, 0, 0); @@ -129,7 +134,6 @@ int ptrace_inject(int pid, const char* so_path) { ptrace(PTRACE_DETACH, pid, 0, 0); return -1; } - // 获取返回值(分配的地址) struct user_pt_regs ret_regs; iov.iov_base = &ret_regs; iov.iov_len = sizeof(ret_regs); if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov) == -1) { @@ -145,17 +149,15 @@ int ptrace_inject(int pid, const char* so_path) { } printf("Allocated remote memory at 0x%lx\n", remote_addr); - // 4. 将 so 路径写入远程内存 + // 4. 写入 SO 路径 if (ptrace_writedata(pid, remote_addr, so_path, path_len) == -1) { perror("ptrace writedata"); ptrace(PTRACE_DETACH, pid, 0, 0); return -1; } - // 5. 获取远程进程中 dlopen 的地址 - // 方法:从本地 dlopen 地址减去本地 libdl.so 基址,再加上远程 libdl.so 基址 + // 5. 获取远程 dlopen 地址 void* local_dlopen = (void*)dlopen; - // 获取本地 libdl.so 基址 FILE* maps = fopen("/proc/self/maps", "r"); if (!maps) { perror("fopen self maps"); @@ -178,7 +180,6 @@ int ptrace_inject(int pid, const char* so_path) { } unsigned long local_dlopen_offset = (unsigned long)local_dlopen - local_libdl_base; - // 获取远程 libdl.so 基址 char remote_maps_path[64]; snprintf(remote_maps_path, sizeof(remote_maps_path), "/proc/%d/maps", pid); maps = fopen(remote_maps_path, "r"); @@ -203,20 +204,18 @@ int ptrace_inject(int pid, const char* so_path) { unsigned long remote_dlopen_addr = remote_libdl_base + local_dlopen_offset; printf("Remote dlopen address: 0x%lx\n", remote_dlopen_addr); - // 6. 调用远程 dlopen(so_path, RTLD_LAZY) - regs = orig_regs; // 恢复成刚 attach 时的状态 - regs.regs[0] = remote_addr; // 路径指针 - regs.regs[1] = RTLD_LAZY; // 第二个参数 - regs.pc = remote_dlopen_addr; // 跳转到 dlopen - regs.regs[30] = 0x0; // LR = 0,执行完会 crash + // 6. 调用远程 dlopen + regs = orig_regs; + regs.regs[0] = remote_addr; + regs.regs[1] = RTLD_LAZY; + regs.pc = remote_dlopen_addr; + regs.regs[30] = 0x0; // LR = 0,执行后崩溃以便我们捕获 iov.iov_base = ®s; iov.iov_len = sizeof(regs); if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov) == -1) { perror("ptrace setregset for dlopen"); ptrace(PTRACE_DETACH, pid, 0, 0); return -1; } - - // 让远程进程继续执行 dlopen,然后会因 PC=0 而 crash if (ptrace(PTRACE_CONT, pid, 0, 0) == -1) { perror("ptrace cont"); ptrace(PTRACE_DETACH, pid, 0, 0); @@ -224,7 +223,6 @@ int ptrace_inject(int pid, const char* so_path) { } waitpid(pid, &status, 0); if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) { - // 预期的段错误,因为 LR=0 printf("dlopen executed (segfault expected)\n"); } else { fprintf(stderr, "unexpected stop: status=%d\n", status); @@ -232,9 +230,7 @@ int ptrace_inject(int pid, const char* so_path) { return -1; } - // 7. 清理:远程内存可以不释放,进程会继续运行,so 已加载 - - // 8. 恢复原始寄存器并 detach + // 7. 恢复寄存器并 detach iov.iov_base = &orig_regs; iov.iov_len = sizeof(orig_regs); if (ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov) == -1) { perror("restore regs"); @@ -248,25 +244,46 @@ int ptrace_inject(int pid, const char* so_path) { return 0; } +// ---------- 主函数 ---------- int main(int argc, char** argv) { - const char* target_name = "com.tencent.jkchess"; - const char* so_path = "/data/data/com.tencent.jkchess/libcheat.so"; // 默认路径 + const char* so_path = "/data/local/tmp/libcheat.so"; // 默认路径 + const char* target = "com.tencent.jkchess"; // 默认包名 + int pid = -1; if (argc >= 2) so_path = argv[1]; - if (argc >= 3) target_name = argv[2]; - - printf("Injecting %s into %s ...\n", so_path, target_name); - - int pid = find_pid_by_name(target_name); - if (pid <= 0) { - fprintf(stderr, "Process %s not found\n", target_name); - return 1; + if (argc >= 3) { + // 检查第三个参数是否为纯数字(PID) + bool is_number = true; + for (int i = 0; argv[2][i]; i++) { + if (!isdigit(argv[2][i])) { is_number = false; break; } + } + if (is_number) { + pid = atoi(argv[2]); + printf("Using specified PID: %d\n", pid); + } else { + target = argv[2]; + } + } + if (argc >= 4) { + // 如果第四个参数存在,则作为 PID(覆盖之前的推断) + pid = atoi(argv[3]); + printf("Using specified PID (from arg4): %d\n", pid); } - printf("Found PID: %d\n", pid); - // 检查 so 文件是否存在 + if (pid <= 0) { + printf("Searching for process '%s' ...\n", target); + pid = find_pid_by_name(target); + if (pid <= 0) { + fprintf(stderr, "Process '%s' not found. Please ensure the game is running.\n", target); + fprintf(stderr, "You can also specify PID manually: %s \n", argv[0]); + return 1; + } + printf("Found PID: %d\n", pid); + } + + // 检查 SO 文件是否存在 if (access(so_path, F_OK) == -1) { - fprintf(stderr, "SO file %s does not exist\n", so_path); + fprintf(stderr, "SO file '%s' does not exist\n", so_path); return 1; }