1de*_*der 5 c linux ptrace system-calls
我正在尝试编写一个跟踪系统调用的程序.我很难完成这项工作.我尝试调用fork()来创建自己的实例(代码),然后监视生成的子进程.
目标是父进程返回子进程进行的每个系统调用的索引并将其输出到屏幕.不知何故,它没有按计划运作.
这是代码:
#include <unistd.h> /* for read(), write(), close(), fork() */
#include <fcntl.h> /* for open() */
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
pid_t child;
long orig_eax;
child = fork();
if (0 == child)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if (argc != 3) {
fprintf(stderr, "Usage: copy <filefrom> <fileto>\n");
return 1;
}
int c;
size_t file1_fd, file2_fd;
if ((file1_fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[1]);
return 1;
}
if ((file2_fd = open(argv[2], O_WRONLY | O_CREAT)) < 0) {
fprintf(stderr, "copy: can't open %s\n", argv[2]);
return 1;
}
while (read(file1_fd, &c, 1) > 0)
write(file2_fd, &c, 1);
}
else
{
wait(NULL);
orig_eax = ptrace (PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
printf("copy made a system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码基于以下代码:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h> /* For constants
ORIG_EAX etc */
int main()
{
pid_t child;
long orig_eax;
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/bin/ls", "ls", NULL);
}
else {
wait(NULL);
orig_eax = ptrace(PTRACE_PEEKUSER,
child, 4 * ORIG_EAX,
NULL);
printf("The child made a "
"system call %ld\n", orig_eax);
ptrace(PTRACE_CONT, child, NULL, NULL);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个的输出是:
The child made a system call 11
Run Code Online (Sandbox Code Playgroud)
这是exec系统调用的索引.
根据wait()的手册页:
All of these system calls are used to wait for state changes in a child
of the calling process, and obtain information about the child whose
state has changed. A state change is considered to be: the child terminated;
the child was stopped by a signal; or the child was resumed by
a signal.
Run Code Online (Sandbox Code Playgroud)
我理解的方式是,每次用户程序调用系统调用时,内核将首先检查是否在执行系统调用例程之前跟踪进程,并使用信号暂停该进程并将控制权返回给父进程.这不是状态改变吗?
问题是当孩子调用ptrace(TRACEME)
它时自己设置为跟踪但实际上并没有停止 - 它一直持续到它调用exec
(在这种情况下它停止了SIGTRAP),或者它得到一些其他信号.因此,为了让您的父母看到它做什么没有执行电话,您需要安排孩子接收信号.最简单的方法是在呼叫raise(SIGCONT);
后立即让孩子呼叫(或任何其他信号)ptrace(TRACEME)
现在在父级中,您只需等待(一次)并假设孩子现在在系统调用时停止.如果它停在信号处,则不会出现这种情况,因此您需要调用wait(&status)
以获取子状态并调用WIFSTOPPED(status)
并WSTOPSIG(status)
查看为什么它已停止.如果由于系统调用而停止,则信号将为SIGTRAP.
如果要在客户端中看到多个系统调用,则需要在循环中执行所有这些操作; 就像是:
while(1) {
wait(&status);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
// stopped before or after a system call -- query the child and print out info
}
if (WIFEXITED(status) || WIFSIGNALED(status)) {
// child has exited or terminated
break;
}
ptrace(PTRACE_SYSCALL, 0, 0, 0); // ignore any signal and continue the child
}
Run Code Online (Sandbox Code Playgroud)
请注意,它将为每个系统调用停止TWICE - 一次在系统调用之前,第二次在系统调用完成之后.
在你的父母中,你想监控多少个电话?如果你想要多个,你将需要某种循环。
请注意示例中的这一行,这很重要:
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)
查看手册页,子级需要执行 aPTRACE_TRACEME
和 an操作exec
,或者父级需要使用 进行跟踪PTRACE_ATTACH
。我在你的代码中没有看到:
父级可以通过调用 fork(2) 并让生成的子级执行 PTRACE_TRACEME,然后(通常)执行 exec(3) 来启动跟踪。或者,父进程可以使用 PTRACE_ATTACH 开始跟踪现有进程。