Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ptrace为execve捕获许多陷阱_C_System Calls_Ptrace - Fatal编程技术网

Ptrace为execve捕获许多陷阱

Ptrace为execve捕获许多陷阱,c,system-calls,ptrace,C,System Calls,Ptrace,我正在使用ptrace拦截系统调用。除了我截获了16个对execve的调用(8个用于系统前调用,8个用于系统后调用)之外,一切似乎都很正常 我见过没有它的工作示例,但我尝试使用标志PTRACE\u O\u TRACESYSGOOD 其他人表示我应该只看到一个前置/后置+一个信号,但他们没有使用PTRACE\u O\u TRACESYSGOOD 我的输出如下所示: Intercepted rt_sigprocmask[14] Syscall returned with value 0 Interc

我正在使用ptrace拦截系统调用。除了我截获了16个对execve的调用(8个用于系统前调用,8个用于系统后调用)之外,一切似乎都很正常

我见过没有它的工作示例,但我尝试使用标志
PTRACE\u O\u TRACESYSGOOD

其他人表示我应该只看到一个前置/后置+一个信号,但他们没有使用
PTRACE\u O\u TRACESYSGOOD

我的输出如下所示:

Intercepted rt_sigprocmask[14]
Syscall returned with value 0
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value -2
Intercepted execve[59]
Syscall returned with value 0
Tracer: Received signal: 5
Intercepted brk[12]
...
其余输出与
strace
输出匹配

每个“截获”和“返回的系统调用”对应一个
waitid()
call。一个用于再现此内容的极简示例代码:

#include <sys/types.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/vfs.h>
#include <sys/ptrace.h>
#include <sys/reg.h>     /* For constants ORIG_EAX, etc */
#include <string.h>
#include <sys/wait.h>
#include <sys/syscall.h>    /* For SYS_write, etc */
#include <unistd.h>
#include <stdio.h>

int main(){
  pid_t pid = fork();

  // Child.
  if(pid == 0){
    ptrace(PTRACE_TRACEME, 0, NULL, NULL);

    // Wait for parent to be ready.
    raise(SIGSTOP);
    execlp("pwd", "pwd", NULL);
    return 0;
  }
  // Tracer.
  else{
    struct user_regs_struct regs;
    bool isPre = true;
    int status;
    // Wait for child to stop itself.
    waitpid(pid, &status, 0);
    ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD);

    while(true){
      ptrace(PTRACE_SYSCALL, pid, 0, 0);
      pid  = waitpid(pid, &status, 0);

      // Check if tracee has exited.
      if (WIFEXITED(status)){
    return 0;
      }

      // This is a stop caused by a system call exit-pre/exit-post.
      if(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP |0x80) ){
        ptrace(PTRACE_GETREGS, pid, NULL, &regs);

        if(isPre){
          printf("Intercepted syscall: %llu\n", regs.orig_rax);
          isPre = ! isPre;
        }else{
          printf("Done with system call!\n");
          isPre = ! isPre;
        }
      }else{
        printf("Tracer: Received signal: %d\n", WSTOPSIG(status));
      }
    }
  }

  return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括/*用于常数ORIG_EAX等*/
#包括
#包括
#包括/*用于系统写入等*/
#包括
#包括
int main(){
pid_t pid=fork();
//孩子。
如果(pid==0){
ptrace(ptrace_TRACEME,0,NULL,NULL);
//等待家长准备好。
升起(停止);
execlp(“pwd”,“pwd”,NULL);
返回0;
}
//追踪器。
否则{
结构用户\u注册表\u结构注册表;
bool isPre=true;
智力状态;
//等孩子停下来。
waitpid(pid和status,0);
ptrace(ptrace_SETOPTIONS、pid、NULL、ptrace_O_TRACESYSGOOD);
while(true){
ptrace(ptrace_系统调用,pid,0,0);
pid=waitpid(pid和状态,0);
//检查tracee是否已退出。
如果(妻子退出(状态)){
返回0;
}
//这是由系统调用exit pre/exit post导致的停止。
如果(WIFSTOPPED(状态)和&WSTOPSIG(状态)=(SIGTRAP | 0x80)){
ptrace(ptrace_GETREGS、pid、NULL和regs);
如果(isPre){
printf(“截获的系统调用:%llu\n”,regs.orig\u rax);
isPre=!isPre;
}否则{
printf(“完成系统调用!\n”);
isPre=!isPre;
}
}否则{
printf(“跟踪器:接收信号:%d\n”,WSTOPSIG(状态));
}
}
}
返回0;
}
恐怕我误解了
execve
,或者
PTRACE\u O\u TRACESYSGOOD
。 我在Lubuntu 16.04上运行这个,内核版本为4.10.0-37-generic


编辑:系统调用的固定返回值。

没有问题。对
execlp
的一次调用通常会导致对
execve
的多次调用,每个调用(最后一次除外)都将
enoint
作为错误代码返回

尽管Unix和Linux手册的第2节(系统调用)中经常记录了
execlp
execvp
,但它们是作为用户区函数实现的。他们查看
$PATH
并对每个
$PATH
组件和可执行文件名的串联调用
execve
,直到其中一个execve成功或全部失败

以下是一些来源,说明了发生的情况:

if (strchr(file, '/'))
    return execve(file, argv, envp);

if (!path) path = "/usr/local/bin:/bin:/usr/bin";
...
for(p=path; ; p=z) {
    char b[l+k+1];
    z = strchr(p, ':');
    if (!z) z = p+strlen(p);
    if (z-p >= l) {
        if (!*z++) break;
        continue;
    }
    memcpy(b, p, z-p);
    b[z-p] = '/';
    memcpy(b+(z-p)+(z>p), file, k+1);
    execve(b, argv, envp);
    if (errno == EACCES) seen_eacces = 1;
    else if (errno != ENOENT) return -1;
    if (!*z++) break;
}
if (seen_eacces) errno = EACCES;
return -1;

完美这正是我想要的!因为像
strace
这样的工具只显示一个对execve的调用,所以我认为我出错了。