如何使用ptrace(2)更改系统调用的行为? [英] How to use ptrace(2) to change behaviour of syscalls?

查看:193
本文介绍了如何使用ptrace(2)更改系统调用的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否存在使用ptrace来影响其他进程执行的指南或示例(尤其是ARM指南)或示例库?例如,为了使其相信某些数据出现在文件描述符上(即释放select/poll并显示一些结果,并在内核之前应答"以下读取的系统调用).期望涉及到PTRACE_SYSEMU.

Are there any guides or examples (especially ARM ones) or libraries of using ptrace to affect execution of other process? For example, to make it believe that some data is appeared on file descriptor (i.e. release select/poll with some result and "answer" the following read syscall before the kernel). Expecting something involving PTRACE_SYSEMU.

可以通过便携式方式完成吗?我想要类似libc的LD_PRELOAD技巧,但可以在运行时附加.

Can it be done in portable way? I want something like libc-overriding LD_PRELOAD trick, but which can be attached at runtime.

可以用某些gdb命令完成吗?

Can it be done with some gdb commands?

理想的变体是,如果有一些库,我可以在进行实际调用(或模拟它们)之前轻松,方便地将其挂接到syscall并进行编辑,例如

Ideal variant would be if there is some library where I can easily and portably hook into syscalls and edit them before of after the actual call is made (or emulate them), like when doing it using LD_PRELOAD.

@link 是否有使用PTRACE_SYSEMU的良好指南?

@link Any good guides on using PTRACE_SYSEMU?

推荐答案

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

You can use the PTRACE_SYSCALL request: it restarts the child process (just like PTRACE_CONT) but arranges for it to stop at the next entry to or exit from a system call. For example (assume a kernel built for 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(),因此它将被停止.

The child prints its PID and delivers a signal to itself. Because of the prior call to ptrace() this means it will be stopped.

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

The parent waits for this to happen and restarts the child with PTRACE_SYSCALL, then waits. Next, the child invokes the getpid system call and it is stopped once again. The parent process uses the PTRACE_GETREGS invocation to peek into the child's registers, where eax holds the system call number. The parent changes this to the system call number of getppid, then once again allows the child to continue. Because the system call number has changed prior to the invocation of the system call, the child will now invoke getppid instead of getpid.

为此目的使用ptrace可能是可移植的,但我尚未对其进行测试.在gdb中,您还可以使用catch syscall命令.

Using ptrace for this purpose may be portable, but I have not tested it. In gdb, you can also use the catch syscall command.

这篇关于如何使用ptrace(2)更改系统调用的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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