linux - 如何使用 ptrace(2) 改变系统调用的行为?

标签 linux code-injection system-calls ptrace

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

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

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

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

@link Any good guides on using PTRACE_SYSEMU?

最佳答案

您可以使用 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");
    }
}

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

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

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

关于linux - 如何使用 ptrace(2) 改变系统调用的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13426561/

相关文章:

php - 如何使用 SQL 注入(inject)提取登录信息?

c - 如何在Linux中查找执行文件?

windows - 如何在linux上应用windows SVN制作的diff?

c - 为什么long long int不会溢出?

java - 将对象注入(inject) Jersey 资源

c++ - dylib 析构函数不会被调用

linux - splice() 用于匿名内存——有什么性能优势吗?

c - readv和writev的工作流程。使用 readv 和 writev 而不是使用 read 和 write 的所有优点是什么?

linux - Linux 中每个进程的最大打开文件数

linux - 在linux中如何控制gcc生成的文件的权限?