【问题标题】:How to use ptrace(2) to change behaviour of syscalls?如何使用 ptrace(2) 改变系统调用的行为?
【发布时间】:2012-11-05 18:24:29
【问题描述】:

是否有使用ptrace 影响其他进程执行的任何指南或示例(尤其是ARM 的)或库?例如,让它相信一些数据出现在文件描述符上(即释放 select/poll 并在内核之前“回答”以下读取系统调用)。期待涉及 PTRACE_SYSEMU 的内容。

它可以以便携的方式完成吗?我想要类似 libc-overriding LD_PRELOAD 技巧的东西,但可以在运行时附加。

可以用一些gdb命令来完成吗?

理想的变体是,如果有一些库,我可以轻松便携地挂接到系统调用并在实际调用之前或之后编辑它们(或模拟它们),例如when doing it using LD_PRELOAD

@link Any good guides on using PTRACE_SYSEMU?

【问题讨论】:

标签: linux code-injection system-calls ptrace


【解决方案1】:

您可以使用 PTRACE_SYSCALL 请求:它重新启动子进程(就像 PTRACE_CONT 一样)但安排它在下一次进入或退出系统调用时停止。例如(假设为 x86 构建的内核):

#include <sys/ptrace.h>
#include <signal.h>
#include <linux/user.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char **argv)
{
    int status = 0, pid, r;
    struct user_regs_struct uregs;

    if ((pid = fork()) == 0) {
        printf("pid = %d, ppid = %d\n", getpid(), getppid());
        ptrace(PTRACE_TRACEME, 0, 0, 0);
        kill(getpid(), SIGINT);
        r = getpid();
        printf("%d\n", r);
    } else {
        wait(&status);
        ptrace(PTRACE_SYSCALL, pid, 0, 0);
        wait(&status);
        ptrace(PTRACE_GETREGS, pid, 0, &uregs);

        /* this prints the syscall number of getpid */
        printf("syscall nr: %d\n", uregs.orig_eax);
        /* 64 is syscall number of getppid */
        uregs.orig_eax = 64;
        ptrace(PTRACE_SETREGS, pid, 0, &uregs);
        ptrace(PTRACE_CONT, pid, 0, 0);
        wait(&status);
        if(WIFEXITED(status))
            printf("we're done\n");
    }
}

孩子打印它的 PID 并向它自己传递一个信号。由于之前调用了ptrace(),这意味着它将被停止。

父级等待这发生并使用 PTRACE_SYSCALL 重新启动子级,然后等待。接下来,子进程调用getpid 系统调用并再次停止。父进程使用 PTRACE_GETREGS 调用来查看子进程的寄存器,其中eax 保存系统调用号。父级将此更改为getppid 的系统调用号,然后再次允许子级继续。由于在调用系统调用之前系统调用号已更改,因此子进程现在将调用 getppid 而不是 getpid

为此目的使用ptrace 可能是可移植的,但我还没有测试过。在gdb中,也可以使用catch syscall命令。

【讨论】:

  • 对于 x86 也有 injcode(可能还有其他一些工具)。用于此类事物的库或(例如)ARM 示例呢?它可以在比 CPU 寄存器旋转更高的级别上完成吗?
  • 我不熟悉 injcode,但从它的描述来看,它看起来是可能的。一般来说,如果你想搞乱进程内部,ptrace(以及调试器)可能是你可以获得的最高抽象级别。
  • 例如,使用 gdb 命令的级别高于 ptrace。也许中间有一些东西(一些“libptrace”提供了易于使用的 API,用于以各种方式跟踪其他进程;注意:现有的“libptrace”似乎也仅限于 x86...)?
  • 希望其他人可以回答这个问题。
  • 在我的例子中,父母接到了对write的电话。我认为 glibc 缓存了 getpid() 的结果。
猜你喜欢
  • 1970-01-01
  • 2012-10-23
  • 2017-01-03
  • 1970-01-01
  • 2012-04-03
  • 2012-08-14
  • 2013-12-24
  • 2011-07-26
  • 1970-01-01
相关资源
最近更新 更多