【问题标题】:Extracting system call name and arguments using ptrace使用 ptrace 提取系统调用名称和参数
【发布时间】:2016-01-30 15:26:17
【问题描述】:

我正在执行一项任务,我必须使用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;

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

【问题讨论】:

  • 你应该通过strace()的代码,你会有所了解。此外,向您展示您在这里提出的问题实际上需要一个非常大的答案。
  • 好的,我正在为你写一个答案,把我知道的都写出来。希望对您有所帮助。

标签: c unix system-calls strace ptrace


【解决方案1】:

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

regs.rdi - 存储第一个参数

regs.rsi - 存储第二个参数

regs.rdx - 存储第三个参数

regs.r10 - 存储第四个参数

regs.r8 - 存储第五个参数

regs.r9 - 存储第六个参数

table 提供了更详细的描述(请注意,它特定于 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);

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

至于系统调用的名称。我做了 OS 映射并手动做了一个switch case 来获取系统调用的名字。


希望这会有所帮助。 :)

【讨论】:

  • 返回值呢?它们是否也“轻松”地存储在一个寄存器中?
  • @traducerad,实际上是的.. 它存储在 regs.rax 寄存器中..
【解决方案2】:

我会将 regs.orig_rax 映射到系统调用的 const 列表,您可以从 /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。

【讨论】:

    猜你喜欢
    • 2012-08-14
    • 2012-04-04
    • 2017-01-03
    • 2012-04-03
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2020-11-30
    • 2012-10-23
    相关资源
    最近更新 更多