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

3

我正在完成一个任务,需要使用ptrace实现类似于strace的功能。到目前为止,我已经找到如何提取系统调用号和返回值,就像这样:

//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;

但是我找不到如何提取系统调用的名称和参数。有人能提供一种方法吗?


1
如果你仔细阅读strace()的代码,你会有一些想法。此外,展示你在这里所要求的内容实际上需要一个非常大的答案。 - Haris
1
好的,我正在为您撰写答案,尽我所知进行说明。希望对您有所帮助。 - Haris
2个回答

12
要获取系统调用的参数,您需要逐个读取寄存器。为此,您需要知道哪些寄存器将存储系统调用的哪些参数。几个月前,我自己编写了一个这样的程序。基本上每个寄存器存储的内容如下:

regs.rdi - 存储第一个参数

regs.rsi - 存储第二个参数

regs.rdx - 存储第三个参数

regs.r10 - 存储第四个参数

regs.r8 - 存储第五个参数

regs.r9 - 存储第六个参数

表格 提供了更详细的描述(请注意,它是特定于x86-64架构的)。

现在,您必须查阅每个系统调用的文档,以理解并单独为它们编写代码。有不同的方法来读取不同的参数。


让我们以read()系统调用来演示这个。

我们将看到不同种类的参数,并学习如何访问它们。

第一个参数(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] = '\0';
printf("File-%s-\n", filepath);

第二个参数(void *buf)是指向输入缓冲区的指针

要读取此内容,您需要使用 PTRACE_PEEKDATA / PTRACE_PEEKTEXT 请求(ptrace() 的第一个参数)来读取字节。由于 ptrace() 一次只读取并返回 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] = '\0';
printf("Message-%s-\n\n", message);

这是我能说的全部了。我想你可以通过这种方式读取大多数系统调用的几乎所有参数。

至于系统调用的名称。我进行了操作系统映射并手动创建了一个switch case来获取系统调用的名称。


希望这可以有所帮助。 :)

返回值呢?它们也能像单个寄存器那样“轻松”地存储吗? - user7659542
@traducerad,是的实际上.. 它被存储在 regs.rax 寄存器中.. - Haris

0

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

如果您想知道寄存器地址指向什么,我建议您阅读https://groogroot.eu/the-ptrace-system-call/中的read_addr_into_buff方法。当检测到__NR_write SC时,我使用它来读取regs.rsi。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接