【问题标题】:Why does ptrace not recognize the function?为什么 ptrace 无法识别该功能?
【发布时间】:2014-05-29 17:12:40
【问题描述】:

我无法弄清楚为什么函数每次运行时都会返回“没有这样的过程”错误消息,但只需使用相同的指令内联即可产生所需的输出。

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void getregs(pid_t proc, struct user_regs_struct *regs);

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

        if(proc == 0) {
                if(ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1) {
                       perror("traceme");
                       exit(0);
                }

                if(execl("child", "child", NULL) == -1) {
                       perror("execl");
                       exit(0);
                }
        } else {
                wait(&proc);
                struct user_regs_struct regs;
                ptrace(PTRACE_GETREGS, proc, NULL, &regs);
                printf("eax: %08x\n", (unsigned int)regs.eax);
                getregs(proc, &regs);
                ptrace(PTRACE_CONT, proc, NULL, NULL);
        }

        return 0;
}

void getregs(pid_t proc, struct user_regs_struct *regs) {
        if(ptrace(PTRACE_GETREGS, proc, NULL, &regs) == -1) {
                perror("GETREGS");
                exit(1);
        }

        printf("eax: %08x\n", (unsigned int)regs->eax);
}

当我运行它时,我得到了

~$ ./tracer 
eax: 0000002f 
GETREGS: No such process

我不明白为什么getregs() 返回那个错误。这几乎就像它超出了某事的范围?

另外,有些无关紧要的事情:无论我尝试什么进程,EAX 总是设置为0000002f execl()。这是自然的吗?我不知道我是否正确地分叉了子进程。我需要为此提出一个关于 SO 的新问题吗?

【问题讨论】:

    标签: c ptrace


    【解决方案1】:

    您遇到此错误是因为您正在修改包含在变量 proc 中的进程标识符 (PID) 的值,方法是将其地址传递给 wait(2) 系统调用。

    wait 系统调用将更改 proc 的值,并在其终止时返回您的子进程的状态。因此,当您使用procptrace 中引用您的子进程时,它的值很可能是无效的并且不引用现有进程。

    正如 @lornix 所注意到的,确保在 getregs 函数中将正确的指针传递给 ptrace

    【讨论】:

    • 我已经更新了代码。我也尝试完全删除wait(2),但没有任何改变。
    • getregs 中的段错误?删除 &。为我工作。
    • @user3407764 那是因为您在 getregs 函数中将 0 传递给 ptrace,而不是传递 proc 变量。
    • 代码在键盘上看起来不错,看不出有什么问题,除非 execl("child"... 调用出现问题。顺便说一句,您应该使用 @987654332 检查函数的返回值@ 而不是 == -1,因为有许多可能的错误返回值,但只有一个好的返回值 (== 0)。Arg!恭喜 @HalimQarroum,在 getregs ptrace 调用中错过了那个 0。
    • 您对waitpid 的使用在功能上与wait 相同。不管你用哪一个。 wait 总体上更容易。
    【解决方案2】:
    void getregs(pid_t proc, struct user_regs_struct *regs) {
            if(ptrace(PTRACE_GETREGS, proc, NULL, &regs) == -1) {
    

    您需要在 ptrace 调用中取消引用 regs。 (在这种情况下删除 &

            if(ptrace(PTRACE_GETREGS, proc, NULL, regs) == -1) {
    

    您使用 regs 的 ADDRESS 调用 getregs,因此 getregs 的 regs 不像主代码中的结构,它是一个指向结构的指针。


    编辑:想通了

    您在等待调用中使用/重新分配 proc,不应该这样做。等待的参数是一个状态值,而不是特定子进程的 pid。等待 waits 对于 any 孩子,请参阅 waitpid 以了解特定于 pid 的等待。

    试试:

    int wait_status;
    wait(&wait_status);
    

    代替当前的等待函数调用。

    【讨论】:

    • 不幸的是,这并没有解决它。还是一样的错误。
    • 哎呀!忽略了显而易见的......你有一个名为'child'的程序正在'execl'函数中执行吗?您不是在 main 中检查 ptrace 函数的返回状态,而是在 getregs 中检查它。修改 main 以检查返回状态返回相同的“没有这样的过程”。没有任何东西正在运行,因为“孩子”不存在可以运行。 (另外,execl 不使用 PATH 查找程序,所以必须提供完整路径,使用 execlp 让它使用 PATH 查找可执行文件)
    • 是的,在修订版中,我正在检查 execl 和 ptrace_traceme 的返回值,它们没有显示任何错误。
    【解决方案3】:

    您的两个 ptrace 呼叫的行为方式相同。不同之处在于您忽略了内联的返回值,而检查了函数中的返回值。

    EAX 值是红鲱鱼:结构未初始化,因为PTRACE_GETREGS 失败。

    wait 函数不采用进程 ID。它等待某个进程终止并将其状态放入由指针传入的整数值中。

    你想要waitpid(如果你想等待一个特定的子进程)。当您知道只有一个时,简单的函数wait 很有用:

    int status;
    if (wait(&status)) { ... }
    

    【讨论】:

    • 我在内联 ptrace 调用周围添加了一个 if 语句,并检查它是否返回 -1,但没有。此外,我将等待更改为waitpid(-1, &amp;status, 0);,其中状态是某个整数变量。就像上面的 Halim Qarroum 一样,它将 EAX 更改为 00000000,但没有解决 getregs 问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 2019-02-17
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多