gpt4 book ai didi

c++ - PTRACE_TRACEME 的范围是多少?

转载 作者:太空宇宙 更新时间:2023-11-04 09:18:34 25 4
gpt4 key购买 nike

如果我有这样的代码:

void child() {
do_something();
ptrace(PTRACE_TRACEME, 0, 0, 0);
do_some_other_things();
}

那么 do_something() 会被父级跟踪吗?

我在 linux 文档中找到了,没有这样的东西。它只是说这个应该在tracee中调用。

PTRACE_TRACEME

Indicate that this process is to be traced by its parent. Aprocess probably shouldn't make this request if its parentisn't expecting to trace it. (pid, addr, and data areignored.)

最佳答案

参见 How Debuggers Work Part 1为了更好的解释,但总而言之,不,它不会跟踪 do_something() 函数,直到被跟踪者收到信号。

在您引用的同一 ma​​n ptraceptrace 调用的描述中:

A process can initiate a trace by calling fork(2) and having the resulting child do a PTRACE_TRACEME, followed (typically) by an execve(2). Alternatively, one process may commence tracing another process using PTRACE_ATTACH or PTRACE_SEIZE.

While being traced, the tracee will stop each time a signal is delivered, even if the signal is being ignored. (An exception is SIGKILL, which has its usual effect.) The tracer will be notified at its next call to waitpid(2) (or one of the related "wait" system calls); that call will return a status value containing information that indicates the cause of the stop in the tracee.

当 tracee 调用 exec 时,它会收到一个信号,这就是它停止的原因。

为了说明,跟踪器程序 mainer.c 没有花里胡哨的东西:

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

int main(int argc, char ** argv)
{
pid_t child_pid;
char * programname = argv[1];

child_pid = fork();
if (child_pid == 0)
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(programname, programname, NULL);
}

else if (child_pid > 0)
{
int status;

wait(&status);

while (WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child_pid, 0, &regs);
unsigned instr = ptrace(PTRACE_PEEKTEXT, child_pid, regs.eip, 0);
printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr);

ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0);

wait(&status);
}

}
}

当 tracee 命中 exec 时,它将收到一个信号并将控制权传递给正在等待的父进程。要跟踪的汇编程序,在跟踪 C 程序以提取任何有用信息时,发生的事情太多了:

; hello.asm
section .text
global _start

_start:
mov edx,len1
mov ecx,hello1
mov ebx,1
mov eax,4

int 0x80


mov edx,len2
mov ecx,hello2
mov ebx,1
mov eax,4

int 0x80

mov eax,1
int 0x80

section .data
hello1 db "Hello",0xA
len1 equ $ - hello1

hello2 db "World",0xA
len2 equ $ - hello2

运行这个,./mainer hello

EIP = 0x08048080, instr = 0x00000000
EIP = 0x08048085, instr = 0x00000000
EIP = 0x0804808a, instr = 0x00000000
EIP = 0x0804808f, instr = 0x00000000
EIP = 0x08048094, instr = 0x00000000
Hello
EIP = 0x08048096, instr = 0x00000000
EIP = 0x0804809b, instr = 0x00000000
EIP = 0x080480a0, instr = 0x00000000
EIP = 0x080480a5, instr = 0x00000000
EIP = 0x080480aa, instr = 0x00000000
World
EIP = 0x080480ac, instr = 0x00000000
EIP = 0x080480b1, instr = 0x00000000

如果我们修改 mainer.c,使子进程在执行之前调用 do_something(),那么跟踪的结果是完全相同的。这就是我修改的方式,如果你喜欢结果是一样的,你可以自己确认。

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

int do_something(void) //added this function
{
printf("Doing something");
return 0;
}


int main(int argc, char ** argv)
{
pid_t child_pid;
char * programname = argv[1];

child_pid = fork();
if (child_pid == 0)
{
ptrace(PTRACE_TRACEME, 0, 0, 0);
do_something(); //added this function call
execl(programname, programname, NULL);
}

else if (child_pid > 0)
{
int status;

wait(&status);

while (WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, child_pid, 0, &regs);
unsigned instr = ptrace(PTRACE_PEEKTEXT, child_pid, regs.eip, 0);
printf("EIP = 0x%08x, instr = 0x%08x\n", regs.eip, instr);

ptrace(PTRACE_SINGLESTEP, child_pid, 0, 0);

wait(&status);
}

}
}

所以tracee在接收到信号之前不会停止,这是调用exec时发生的情况,调用函数不会为tracee产生信号,但是还有其他方法可以向tracee发送信号并开始跟踪,尽管它们不像 exec 和 wait 那样整洁。

关于c++ - PTRACE_TRACEME 的范围是多少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44534366/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com