2017-06-14 114 views
0

如果我有這樣的代碼:PTRACE_TRACEME的範圍是什麼?

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

然後將do_something()由家長進行跟蹤?

我在linux文檔中發現,沒有這種東西。它只是說這應該在tracee中被調用。

PTRACE_TRACEME

表明,該過程是要由它的父進行跟蹤。如果其父 不希望跟蹤它,則 進程可能不應該發出此請求。 (PID,地址和數據 忽略)。

回答

1

一個更好的解釋見How Debuggers Work Part 1,但總的來說,沒有,也不會直到tracee接收的信號跟蹤do_something()函數。

ptrace的調用來自同一人ptrace的你引用的描述:

一個進程可以通過調用fork(2),並具有 所產生的孩子做一個 啓動跟蹤PTRACE_TRACEME,後面(通常)由execve(2)。或者,一個進程可以開始使用PTRACE_ATTACH或PTRACE_SEIZE跟蹤另一個進程。

被跟蹤時,即使信號 被忽略,每次信號傳遞時,tracee都會停止。 (SIGKILL有個例外,它有其通常的作用)。在下一次waitpid(2)調用(或相關的「等待」系統調用之一)時,跟蹤器將會通知 ;該呼叫 將返回一個狀態值,其中包含指示 tracee中停止原因的信息。

當tracee調用exec時,它會收到一個信號,這就是它停止的原因。

要illustrace,示蹤程序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_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_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的信號會發生什麼,但也有其他的方式來發送發信號給追蹤者並開始追蹤,儘管他們不像執行和等待那樣整潔。