PTRACE_TRACEME 的范围是多少?
What is the range for PTRACE_TRACEME?
如果我有这样的代码:
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. A
process probably shouldn't make this request if its parent
isn't expecting to trace it. (pid, addr, and data are
ignored.)
请参阅How Debuggers Work Part 1以获得更好的解释,但总而言之,不会,直到被跟踪者收到信号后才会跟踪do_something() 函数。
在 ptrace 调用的描述中,您引用了同一个 man ptrace:
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, ®s);
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, ®s);
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 和 begin tracing,尽管它们不像 exec 和 wait 那样整洁。
如果我有这样的代码:
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. A process probably shouldn't make this request if its parent isn't expecting to trace it. (pid, addr, and data are ignored.)
请参阅How Debuggers Work Part 1以获得更好的解释,但总而言之,不会,直到被跟踪者收到信号后才会跟踪do_something() 函数。
在 ptrace 调用的描述中,您引用了同一个 man ptrace:
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, ®s);
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, ®s);
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 和 begin tracing,尽管它们不像 exec 和 wait 那样整洁。