使用 ptrace 提取系统调用名称和参数

Extracting system call name and arguments using ptrace

我正在完成一项作业,其中我必须使用 ptrace 实现类似 strace 的功能。到目前为止,我已经找到了如何提取系统调用号和 return 值,如下所示:

//In parent process
struct user_regs_struct regs;
ptrace( PTRACE_GETREGS, child_pid, 0, &regs ); 
//child_pid is the pid of child process executing the required program
//or system call passed as command line arguments
syscall_num = regs.orig_rax;
syscall_retval = regs.rax;

但我一直没能找到如何提取系统调用名称和参数。 谁能推荐一个方法?

要获得系统调用的参数,你必须一个一个地读取寄存器。为此,您需要知道哪些寄存器将存储系统调用的哪些参数。几个月前我自己写了一个这样的程序。基本上每个寄存器存储的是这样的:

regs.rdi - Stores the first argument

regs.rsi - Stores the second argument

regs.rdx - Stores the third argument

regs.r10 - Stores the fourth argument

regs.r8 - Stores the fifth argument

regs.r9 - Stores the sixth argument

table 提供了更详尽的描述(请注意它特定于 x86-64 体系结构)。

现在,您必须仔细阅读每个系统调用的文档,才能分别理解和编写代码。有不同的方法来读取不同的参数。


让我们用 read() 系统调用来演示这一点。

我们将了解不同类型的参数并了解如何访问它们。

1st argument (int fd)

因为是数字所以会直接保存在寄存器中regs.rdi.

在我的代码中,我需要获取 fd 指向的文件,所以我使用了以下代码。

sprintf(fdpath,"/proc/%u/fd/%llu",proc,regs.rdi);
size = readlink(fdpath, filepath, 256);  //this gives the filepath for a particular fd
filepath[size] = '[=10=]';
printf("File-%s-\n", filepath);

2nd argument (void *buf) ptr to input buffer

要阅读此内容,您需要使用 PTRACE_PEEKDATA / PTRACE_PEEKTEXT 请求(ptrace() 的第一个参数)来读取字节。由于 ptrace() 一次读取而 returns 仅 8 个字节,因此您需要使用 long 变量迭代地执行此操作。应该有另一个 char * 指向内存的开头,稍后将用于读取字符串。

我使用的代码如下。

char message[1000];
char* temp_char2 = message;
int j = 0;
long temp_long;

while( j < (regs.rdx/8) ) //regs.rdx stores the size of the input buffer
{
    temp_long = ptrace(PTRACE_PEEKDATA, proc, regs.rsi + (j*8) , NULL);
    memcpy(temp_char2, &temp_long, 8);
    temp_char2 += sizeof(long);
    ++j;
}
message[regs.rdx] = '[=11=]';
printf("Message-%s-\n\n", message);

我只能说这些了。我猜你可以通过这种方式读取大部分系统调用的几乎所有参数。

至于系统调用的名称。我 OS 映射并制作了一个手动 switch 案例来获取系统调用的名称。


希望这对您有所帮助。 :)

我会将 regs.orig_rax 映射到系统调用的 const 列表,您可以从 /usr/include/x86_64-linux-gnu/asm/unistd_64 中获取列表。

如果你想知道指向注册表地址的是什么,我建议你阅读 https://groogroot.eu/the-ptrace-system-call/ 方法 read_addr_into_buff,我确实用它来阅读 regs.rsi 当 __NR_write 检测到 SC。