簡體   English   中英

ptrace - 與子進程通信

[英]Ptrace - communication with child process

我想以下列方式使用ptrace (偽代碼):

孩子:

    foo();
    now that foo is done parent should use ptrace to change things
    parent did what he wanted to do
    bar();  

家長:

pid = fork();
if (pid == 0)
    //child
    exec(child_program)
else
    //parent
    attach ptrace
    let child run
    use ptrace to modify it's data
    let child continue
  1. 孩子應該如何與父母溝通它已完成foo並准備好進行修改? raise(SIGSTOP)也許?

  2. 父母應該如何等待孩子運行foo

我認為我們可以假設在使用pthread之前沒有引發 SIGSTOP。

我可能會誤解它,但是您是否有任何特定原因想要將 `ptrace` 用於看起來像 IPC(進程間通信)的內容? Linux 上的`ptrace` *通常不太適合* IPC,您不應該真正使用它來修改子進程中的數據。 如果您希望您的子進程與父進程通信,則有多種不同的方法可以實現上述任務(即 Unix 域套接字、管道、信號量、共享內存),我建議您在嘗試使用 IPC 之前先查看它們`ptrace`。


編輯:

您可以使用信號量讓父sem_overview等待子sem_overview (請參閱 Linux 手冊頁中的sem_overview )並執行您需要執行的操作。 您可以使用sem_open創建一個命名信號量,並讓子sem_open在父sem_open等待它,讓子sem_open在完成上述任務后通知信號量。

或者,讓被跟蹤的子進程使用斷點指令,該指令將通過SIGTRAP停止它,允許您wait它,然后執行您需要執行的操作。 我相信 GDB 使用類似的方法進行調試(修補指令)。 如果您使用的是 x86,以下代碼應該適用於在您的代碼中發出斷點指令:

asm volatile ("int3;")

我還可以建議使用process_vm_writev而不是ptrace函數來寫入進程內存( PTRACE_POKETEXT ),因為它們可以對進程內存進行批量讀取/寫入。

為了進一步參考,我認為debuggers_part2_code是一個很好的例子,說明如何推出自己的調試工具。

你說你想在執行的某個時刻修改他跟蹤進程的寄存器。 您可能應該嘗試澄清您的問題,因為它並不清楚您真正想要實現的目標:首先為什么要修改寄存器。 您希望在寄存器中找到什么? 為什么要更改這些值?

您確定不想與套接字和/或共享內存通信嗎? 您可能應該提供一個更詳細的示例來解釋您要做什么。

現有代碼中的斷點

您在跟蹤的過程中有此代碼:

foo();
// You want to modify something there.
bar();

foo()bar() ,真的不清楚寄存器中的內容。 假設我們使用的是 x86_64。

如果在foo返回時中斷:

  • EAX 包含foo的返回值(如果有),無論如何它在調用者中被忽略(因此修改它沒有多大意義);

  • 被調用者保存的寄存器可能包含來自調用者的一些值,但您必須弄亂 DWARF 信息以試圖從中獲得一些意義;

  • 調用者保存的寄存器將不包含任何有用的內容(但您可以使用 DWARF 展開信息來查找其他一些在調用者中有意義的數據)。

bar的調用位置(在調用者中或在bar的開頭)中斷對您來說可能更有趣,因為您可以訪問bar的參數。 您可以在跟蹤器進程中修改它們,如果需要,您甚至可以強制使用一個值進行返回調用。

提高信號

另一種解決方案是發出信號:

foo();
raise(SIGTRAP);
bar();

和以前一樣,不清楚寄存器中的內容,您可能必須使用 DWARF 來嘗試定位感興趣的數據(可能有效也可能無效)。

一個(可能)更干凈的解決方案是通過指令引發異常:

int     $3

問題是如果你的程序沒有在跟蹤器下運行,它就會死掉。

為追蹤器添加一個鈎子

一個更簡潔的解決方案是在foobar之間添加另一個函數:

foo();
int res = delegate_to_tracer(x, y, z);
bar();

其中delegate_to_tracer可以存根為:

int delegate_to_tracer(int x, int y, int z)
{
  // No-op implementation used when there is no tracer:
  return 0;
}

您現在可以在此函數的開頭添加一個斷點,以便在跟蹤器中處理它的功能:

  • 您可以訪問參數;

  • 你可以修改它們;

  • 您可以使用給定的返回值強制返回。

另一個類似的解決方案是使用靜態跟蹤點( SDTUST ),但嘗試修改它們的數據可能沒有多大意義。

偽造系統調用

您可以使用系統調用來與跟蹤器通信:

  • 要么使用未使用的系統調用NR_tuxcall ?)

  • 要么使用一個未使用的系統調用號(但它可能會在某個時候被使用);

  • 或者通過蹲一個現有的。

這個想法是,如果它不在您的跟蹤器下運行,系統調用將因SIGSYS (或其他)而失敗。 但是,在您的跟蹤器下,您將攔截系統調用並自行處理。

進行 tuxcall:

movq    $184, %rax # tuxcall
movq    $42,  %edi # param1
syscall

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM