如何使用ptrace(2)来改变syscalls的行为?

有没有任何指南或例子(尤其是ARM的)或使用ptrace库来影响其他进程的执行? 例如,为了使它相信一些数据出现在文件描述符上(即释放select/轮询一些结果和“回答”下面的内核之前读取系统调用)。 期待涉及PTRACE_SYSEMU的事情。

可以用便携的方式来完成吗? 我想要像libc重写LD_PRELOAD技巧,但可以在运行时附加。

可以用一些gdb命令来完成吗?

理想的变种是,如果有一些库可以方便地挂载到系统调用中,并在实际调用(或模拟它们)之前进行编辑,就像使用LD_PRELOAD进行调用一样。

@link 使用PTRACE_SYSEMU的任何好的指南?

Solutions Collecting From Web of "如何使用ptrace(2)来改变syscalls的行为?"

您可以使用PTRACE_SYSCALL请求:它将重新启动子进程(就像PTRACE_CONT),但会安排它在下一个进入或退出系统调用时停止。 例如(假设为x86构建的内核):

 #include <sys/ptrace.h> #include <signal.h> #include <linux/user.h> #include <sys/types.h> #include <sys/wait.h> int main(int argc, char **argv) { int status = 0, pid, r; struct user_regs_struct uregs; if ((pid = fork()) == 0) { printf("pid = %d, ppid = %d\n", getpid(), getppid()); ptrace(PTRACE_TRACEME, 0, 0, 0); kill(getpid(), SIGINT); r = getpid(); printf("%d\n", r); } else { wait(&status); ptrace(PTRACE_SYSCALL, pid, 0, 0); wait(&status); ptrace(PTRACE_GETREGS, pid, 0, &uregs); /* this prints the syscall number of getpid */ printf("syscall nr: %d\n", uregs.orig_eax); /* 64 is syscall number of getppid */ uregs.orig_eax = 64; ptrace(PTRACE_SETREGS, pid, 0, &uregs); ptrace(PTRACE_CONT, pid, 0, 0); wait(&status); if(WIFEXITED(status)) printf("we're done\n"); } } 

孩子打印它的PID,并传递一个信号给自己。 由于事先调用ptrace()这意味着它将被停止。

父母等待这种情况发生,并用PTRACE_SYSCALL重新启动孩子,然后等待。 接下来,子getpid调用getpid系统调用,并再次停止。 父进程使用PTRACE_GETREGS调用来查看子进程的寄存器,其中eax保存系统调用号。 父母将其更改为getppid的系统调用号,然后再次允许孩子继续。 由于在调用系统调用之前系统调用号已经改变,孩子现在将调用getppid而不是getpid

为此目的使用ptrace可能是可移植的,但我还没有测试过。 在gdb中,你也可以使用catch syscall命令。