You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ptrace(2)修改系统调用行为?getpid返回异常原因求解

问题原因解析
  • 寄存器修改错误:x86_64架构Linux下,orig_rax寄存器用于存储系统调用号,系统调用的返回值会存储在rax寄存器中。你将orig_rax修改为999,内核会识别为要执行编号为999的系统调用,而当前系统并不存在999号系统调用,会返回-ENOSYS错误,ENOSYS的数值恰好为38,因此子进程拿到的返回值就是-38。
  • 拦截时机错误:你当前是在系统调用进入内核前的断点处停止,此时系统调用尚未执行,若要修改返回值,需要等系统调用执行完成、返回用户态前的断点处再修改返回值寄存器。
正确实现逻辑

要修改getpid的返回值为999,按如下步骤操作即可:

  1. 子进程触发系统调用进入断点后,首先确认当前系统调用号(orig_rax等于SYS_getpid)
  2. 继续运行进程,等待系统调用执行完成触发退出断点
  3. 读取子进程寄存器,直接修改rax的值为999
  4. 恢复子进程运行即可
修正后代码
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <syscall.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>


int main(int argc, char **argv)
{
    int pid = fork();
    if (pid == 0) { //child
        ptrace(PTRACE_TRACEME, 0, 0, 0);
        kill(getpid(), SIGSTOP);
        int r = getpid();
        printf("child pid %d from child\n", r);
    } else { //parent
        printf("child pid %d from parent\n", pid);
        waitpid(pid, 0, 0);
        // 第一次SYSCALL停在系统调用入口
        ptrace(PTRACE_SYSCALL, pid, 0, 0);
        waitpid(pid, 0, 0);

        struct user_regs_struct uregs;
        ptrace(PTRACE_GETREGS, pid, 0, &uregs);

        if (uregs.orig_rax == SYS_getpid) {
            puts("Yes! It is getpid.");
            // 继续到系统调用退出断点
            ptrace(PTRACE_SYSCALL, pid, 0, 0);
            waitpid(pid, 0, 0);
            // 读取寄存器修改返回值
            ptrace(PTRACE_GETREGS, pid, 0, &uregs);
            uregs.rax = 999;
            ptrace(PTRACE_SETREGS, pid, 0, &uregs);
            ptrace(PTRACE_CONT, pid, 0, 0);
        } else {
            puts("NO!!! It is not getpid.");
        }
        // 等待子进程结束避免僵尸进程
        waitpid(pid, 0, 0);
    }
    return 0;
}

运行上述代码后即可看到子进程输出的getpid返回值为999。

内容的提问来源于stack exchange,提问作者Anonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 23:54:04