使用 ptrace 提取系统调用名称和参数 [英] Extracting system call name and arguments using ptrace

查看:28
本文介绍了使用 ptrace 提取系统调用名称和参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一项任务,其中我必须使用 ptrace 实现类似 strace 的功能.到目前为止,我已经找到了如何像这样提取系统调用号和返回值:

//在父进程中struct user_regs_struct regs;ptrace( PTRACE_GETREGS, child_pid, 0, &regs );//child_pid 是执行所需程序的子进程的pid//或系统调用作为命令行参数传递syscall_num = regs.orig_rax;syscall_retval = regs.rax;

但我一直无法找到如何提取系统调用名称和参数.任何人都可以提出一种方法吗?

解决方案

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

<块引用>

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);大小 = 读取链接(fdpath,文件路径,256);//这给出了特定文件的文件路径文件路径[大小] = '\0';printf("文件-%s-\n", 文件路径);

<块引用>

输入缓冲区的第二个参数 (void *buf) ptr

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

我使用的代码如下.

char message[1000];char* temp_char2 = 消息;int j = 0;长 temp_long;while( j <(regs.rdx/8) )//regs.rdx 存储输入缓冲区的大小{temp_long = ptrace(PTRACE_PEEKDATA, proc, regs.rsi + (j*8), NULL);memcpy(temp_char2, &temp_long, 8);temp_char2 += sizeof(long);++j;}消息[regs.rdx] = '\0';printf("Message-%s-\n\n", message);

<小时>

我只能这么说.我想你可以通过这种方式读取大多数系统调用的几乎所有参数.

至于系统调用的名称.我进行了操作系统映射,并进行了手动switch case 以获取系统调用的名称.

<小时>

希望这会有所帮助.:)

I am working on an assignment in which i have to implement strace like functionality using ptrace. So far, I have found out how to extract system call number and return value like this:

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

But I haven't been able to find how to extract system call name and arguments. Can anyone suggest a way?

解决方案

To get the arguments of the system call you have to read the registers one by one. For that you need to know which registers will be storing which parameters of the system call. Few months back I had written one such program myself. Basically what each register stores is this:

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

This table presents a more elaborated description (notice that it's specific to x86-64 architecture).

Now, you have to go through the documentation of each system call to understand and code for them separately. There are different ways to read different arguments.


Lets take the read() system call to demonstrate this.

We will see the different kinds of arguments and see how to access them.

1st argument (int fd)

Since it is a number it will be saved directly in the register regs.rdi.

In my code, i needed to get the file to which that fd was pointing at so i used the following code.

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

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

To read this you would need to use PTRACE_PEEKDATA / PTRACE_PEEKTEXT request (the first argument of ptrace()) to read the bytes. Since ptrace() reads and returns only 8 bytes at a time, you need to do this iteratively using a long variable. There should be another char * pointing in the beginning of the memory, that would be used later to read the string.

The code that I used is the following.

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


Thats all I can say. I guess you can read almost all the parameters of most of the system calls this way.

As for the name of the system call. I the OS mapping and made a manual switch case to get the name of the system call.


Hope this helps. :)

这篇关于使用 ptrace 提取系统调用名称和参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆