首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为execve捕获许多陷阱

为execve捕获许多陷阱
EN

Stack Overflow用户
提问于 2017-10-29 23:47:50
回答 1查看 624关注 0票数 1

我正在使用ptrace来拦截系统呼叫。一切看起来都很好,除了我拦截了16个请求(8个用于预系统调用,8个用于post系统调用)。

我已经看过没有它的工作示例,但是我尝试使用标志PTRACE_O_TRACESYSGOOD

其他对ptrace问题的解答表示我应该只看到一个前置/发布+一个信号,但是他们没有使用PTRACE_O_TRACESYSGOOD

我的输出看起来是:

代码语言:javascript
复制
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的输出相匹配。

每个“截获”和"Syscall返回“对应于一个waitid()调用。这是一个极简的示例代码,用于复制以下内容:

代码语言:javascript
复制
#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;
}

我担心我错过了execve,或PTRACE_O_TRACESYSGOOD。我是在Lubuntu16.04上运行的,内核版本为4.10.0-37-泛型。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-31 15:43:39

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

尽管execlpexecvp经常记录在Unix和execvp手册的第2节(系统调用)中,但它们是作为userland函数实现的。他们通过$PATH查看每个$PATH组件和可执行名称的连接,并调用execve,直到一个execve成功或全部失败为止。

下面是一些来自musl的源代码,它说明了发生了什么:

代码语言:javascript
复制
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;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47006441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档