重新编码Strace,为什么我无法捕捉到“写入系统调用”?
我目前正在重新编码 Strace 命令。
我了解此命令的目标,并且可以从可执行文件中捕获一些系统调用。
我的问题是:为什么我没有赶上“写”系统调用?
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <wait.h>
int main(int argc, char* argv[]) {
int status;
pid_t pid;
struct user_regs_struct regs;
int counter = 0;
int in_call =0;
switch(pid = fork()) {
case -1:
perror("fork");
exit(1);
case 0:
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execvp(argv[1], argv + 1);
break;
default:
wait(&status);
while (status == 1407) {
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
if(!in_call) {
printf("SystemCall %lld called with %lld, %lld, %lldn",regs.orig_rax,
regs.rbx, regs.rcx, regs.rdx);
in_call=1;
counter ++;
}
else
in_call = 0;
ptrace(PTRACE_SYSEMU, pid, NULL, NULL);
wait(&status);
}
}
printf("Total Number of System Calls = %dn", counter);
return 0;
}
这是使用我的程序的输出:
./strace ./my_program
SystemCall 59 called with 0, 0, 0
SystemCall 60 called with 0, 4198437, 5
Total Number of System Calls = 2
59代表execve 系统调用。
60代表退出系统调用。这是使用真正的 strace的输出:
strace ./my_program
execve("./my_program", ["./bin_asm_write"], 0x7ffd2929ae70 /* 67 vars */) = 0
write(1, "Toton", 5Toto
) = 5
exit(0) = ?
+++ exited with 0 +++
如您所见,我的程序没有捕获write syscall。
我不明白为什么,你有什么想法吗?
谢谢您的回答。
回答
你的 while 循环设置得相当奇怪——你有这个in_call标志,你可以在 0 和 1 之间来回切换,并且你只在它为 0 时打印系统调用。最终结果是,当你捕获每个系统调用时,你只打印所有其他系统调用。因此,当您接到 write 调用时,标志为 1 并且您不打印任何内容。
另一个奇怪的是,您使用的是 PTRACE_SYSEMU 而不是 PTRACE_SYSCALL。SYSEMU 用于模拟系统调用,因此系统调用实际上根本不会运行(它会被跳过);通常,您的 ptracing 程序会执行系统调用应该自己执行的任何操作,然后调用 PTRACE_SETREGS 以使用适当的返回值设置被跟踪者的寄存器,然后再次调用 PTRACE_SYSEMU 以运行到下一个系统调用。
in_call如果您实际使用 PTRACE_SYSCALL,您的标记会更有意义,因为这将在每个系统调用中停止两次——一次是在进入系统调用时,第二次是在调用返回时。但是,它也会因信号而停止,因此您需要解码状态以查看是否发生了信号。