簡體   English   中英

ptrace 更改系統調用編號 arm64

[英]ptrace change syscall number arm64

我正在嘗試使用 ptrace 在 linux arm64 上將調用從一個系統調用更改為另一個系統調用。

據我了解,系統調用號在 x8 中,讀取系統調用的寄存器證實了這一點。 我更改了這個數字並調用了 SETREGSET 並且調用了舊的系統調用而不是新的系統調用。 當我檢查從 syscall x8 返回的寄存器設置為我給他的 syscall 時,它應該是。

更改同一系統調用的其他參數有效。

我看到一些地方使用 PTRACE_SET_SYSCALL 但我找不到很多關於它的信息,我嘗試使用它但它似乎在這個拱形結構中不受支持,它沒有定義並且寫入數字因為不存在而失敗。

我究竟做錯了什么? 為什么不起作用?

這是代碼,為了簡單起見,我刪除了打印和驗證,對於這個例子,我只是試圖停止寫入系統調用:

ptrace(PTRACE_ATTACH, pid, NULL, NULL);

int status;
waitpid(pid, &status, 0);
while (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) == 0)
{
    waitpid(pid, &status, 0);

    struct user_pt_regs regs;
    struct iovec io;
    io.iov_base = &regs;
    io.iov_len = sizeof(regs);

    ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &io);

    // reg[7] is 0 before syscall and 1 after
    if (regs.regs[7] == 0)
    {
        // Change write syscall
        if (regs.regs[8] == 64)
        {
            // Change the syscall to getpid (doesn't matter)
            regs.regs[8] = 172;

            ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, &io);
        }
    }
}

至於tracee,一個簡單的hello world with write with sleep;

char buf[] = "hello world\n";
while(1)
{
    write(1, buf, sizeof(buf));
    sleep(5);
}

雖然程序運行時沒有錯誤並打印正確的寄存器,但系統調用不會改變,它會繼續打印 hello world

在 arm64 上,出於兼容性原因,內核將即將執行的系統調用存儲在單獨的變量pt_regs.syscallno中,而ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov)確實更改了寄存器(請參閱內核源代碼中struct pt_regs的定義: commit:eec4df2/arch/arm64/include/asm/ptrace.h:178 )。

當在 arm 或 arm64 上並且使用CONFIG_COMPAT=yes編譯內核時,可以通過ptrace(PTRACE_SET_SYSCALL, pid, NULL, syscallno)更改系統調用號。

對於沒有CONFIG_COMPAT=yes的 arm64 內核,您需要ptrace(PTRACE_SETREGSET, pid, NT_ARM_SYSTEM_CALL, &iov)

例子:

int syscallno;
struct iovec iov = {
    .iov_base = &syscallno,
    .iov_len = sizeof (int),
};
ptrace(PTRACE_SETREGSET, traceePid, NT_ARM_SYSTEM_CALL, &iov);

NT_ARM_SYSTEM_CALL 的NT_ARM_SYSTEM_CALL定義如下: commit:eec4df2/arch/arm64/kernel/ptrace.c:1173

使用SYS_writeSYS_chdir類的參數阻止系統調用的另一種方法是將參數設置為無效地址,因此它將失敗並顯示EINVAL

struct user_regs_struct regs;
struct iovec iov = {
    .iov_base = &regs,
    .iov_len = sizeof (struct user_regs_struct),
};
ptrace(PTRACE_GETREGSET, traceePid, NT_PRSTATUS, &iov);
regs.regs[0] = 123;
regs.regs[1] = 456;
regs.regs[3] = 789;
ptrace(PTRACE_SETREGSET, traceePid, NT_PRSTATUS, &iov);

在系統調用中注冊使用: Chromium OS Docs

出於某種原因,您似乎必須在寄存器0設置系統調用號,而不是像 aarch64 ABI 所期望的那樣設置為8

// Change the syscall to getpid (doesn't matter)
regs.regs[0] = 172;

我不確定為什么會這樣; 也許 ptrace 在進入syscall函數時停止執行進程,然后將第一個參數(在寄存器 0 中)移動到寄存器 8 本身中的實際系統調用號參數。

暫無
暫無

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

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