1912 字
10 分钟
Linux ptrace 调用速查表

本文整理了常用及现代内核支持的 ptrace 请求(requests)、选项(options)与事件(events),并说明各参数的语义与典型用法。跨架构/内核版本可能存在差异,实际以目标系统头文件 include/uapi/linux/ptrace.h 与手册页为准。

函数签名#

long ptrace(int request, pid_t pid, void *addr, void *data); syscall 101
  • request: PTRACE_* 请求常量。
  • pid: 要操作的”被跟踪线程”(tracee)的 TID(线程 ID)。除 PTRACE_TRACEME 外,其它请求通常要求 tracee 处于”ptrace-stop”状态。
  • addr / data: 随请求变化;本文在每个请求条目中说明其含义。
  • 返回值:成功返回非负值(部分请求返回读取到的数据),失败返回 -1 并设置 errno

请求(Requests)#

请求作用addrdata备注/典型用法
PTRACE_TRACEME调用线程声明自身可被其父进程跟踪忽略忽略一般随后 raise(SIGSTOP),父进程 wait() 观测到停止后开始跟踪;仅由 tracee 使用
PTRACE_PEEKTEXT读取 tracee 指令空间一个机器字目标地址忽略旧接口,现代更常用 PTRACE_PEEKDATA/process_vm_readv
PTRACE_PEEKDATA读取 tracee 数据空间一个机器字目标地址忽略经典读接口,返回值即读取内容(失败为 -1
PTRACE_PEEKUSER读取旧版”用户区”寄存器块一个机器字偏移忽略旧接口,现代用 PTRACE_GETREGSET/GETREGS 替代
PTRACE_POKETEXT写入 tracee 指令空间一个机器字目标地址要写入的字常用于设置断点(写入 int3
PTRACE_POKEDATA写入 tracee 数据空间一个机器字目标地址要写入的字常用于修改内存缓冲/变量
PTRACE_POKEUSER写旧版”用户区”一个机器字偏移要写入的字旧接口,不推荐
PTRACE_CONT继续运行 tracee忽略或 0将要注入的信号或 0解除 ptrace-stop,并可投递信号到 tracee
PTRACE_KILL终止 tracee忽略忽略直接杀死被跟踪线程
PTRACE_SINGLESTEP单步执行一条指令忽略或 0信号或 0单步后再次进入 ptrace-stop
PTRACE_SYSCALL在下次系统调用入口/出口处停止忽略或 0信号或 0用于系统调用跟踪
PTRACE_ATTACH附加到已存在的线程,令其进入停止态忽略忽略传统 attach,tracee 会 SIGSTOP,需 wait() 等待
PTRACE_DETACH从 tracee 分离并继续运行忽略或 0信号或 0解除跟踪,常配合 PTRACE_CONT 的语义
PTRACE_GETREGS复制通用寄存器到 tracer 缓冲忽略指向 struct user_regs_struct旧接口;跨架构兼容推荐 GETREGSET
PTRACE_SETREGS从 tracer 缓冲写回通用寄存器忽略指向 struct user_regs_struct旧接口
PTRACE_GETFPREGS获取 FPU 寄存器忽略指向 struct user_fpregs_struct旧接口
PTRACE_SETFPREGS设置 FPU 寄存器忽略指向 struct user_fpregs_struct旧接口
PTRACE_GETFPXREGS获取 x86 扩展 FPU(SSE)寄存器忽略指向 struct user_fpxregs_structx86 专用旧接口
PTRACE_SETFPXREGS设置 x86 扩展 FPU(SSE)寄存器忽略指向 struct user_fpxregs_structx86 专用旧接口
PTRACE_SETOPTIONS设置跟踪选项(见 Options)忽略选项位掩码必须在 tracee 停止时调用
PTRACE_GETEVENTMSG读取最近事件的附加消息忽略指向 unsigned long如 fork/clone 事件中的子 TID
PTRACE_GETSIGINFO获取待投递信号的 siginfo_t忽略指向 siginfo_t读取造成停止的信号信息
PTRACE_SETSIGINFO设置将要投递的 siginfo_t忽略指向 siginfo_t修改下次投递信号的细节
PTRACE_GETREGSET通过 NT_* 类型读取寄存器集合addr 为 regset 类型data 指向 struct iovec现代接口,跨架构统一
PTRACE_SETREGSET通过 NT_* 类型写寄存器集合addr 为 regset 类型data 指向 struct iovec现代接口,跨架构统一
PTRACE_SEIZE无信号/无停止地附加忽略或 0选项位掩码现代 attach,后续用 PTRACE_INTERRUPT 主动停止
PTRACE_INTERRUPT强制使 tracee 进入 ptrace-stop忽略忽略SEIZE 配合使用,无需发送信号
PTRACE_LISTEN继续等待下一个”组停止”(group-stop)忽略忽略仅在 SEIZE 模式下使用
PTRACE_PEEKSIGINFO扫描待处理信号队列指向 struct ptrace_peeksiginfo_args指向 siginfo_t 缓冲可批量读取若干 siginfo_t
PTRACE_GETSIGMASK读取 tracee 的信号屏蔽集addrsigset_t 大小data 指向 sigset_tSEIZE 模式
PTRACE_SETSIGMASK设置 tracee 的信号屏蔽集addrsigset_t 大小data 指向 sigset_tSEIZE 模式
PTRACE_SECCOMP_GET_FILTER读取 seccomp 过滤器(BPF 程序)addr 为过滤器索引data 指向缓冲仅在支持 seccomp 的新内核上可用
PTRACE_SECCOMP_GET_METADATA读取 seccomp 过滤器元信息addr 为过滤器索引data 指向元信息结构新内核可用

架构特定(x86/i386 等)旧接口:PTRACE_GET_THREAD_AREAPTRACE_SET_THREAD_AREA 等;仅在对应架构/旧内核有效,现代代码建议统一使用 GETREGSET/SETREGSET

请求数值(x86_64)速查#

PTRACE_TRACEME = 0
PTRACE_PEEKTEXT = 1
PTRACE_PEEKDATA = 2
PTRACE_PEEKUSER = 3
PTRACE_POKETEXT = 4
PTRACE_POKEDATA = 5
PTRACE_POKEUSER = 6
PTRACE_CONT = 7
PTRACE_KILL = 8
PTRACE_SINGLESTEP = 9
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_GETFPREGS = 14
PTRACE_SETFPREGS = 15
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_GETFPXREGS = 18 ; x86 旧接口
PTRACE_SETFPXREGS = 19 ; x86 旧接口
PTRACE_SYSCALL = 24
PTRACE_SETOPTIONS = 0x4200
PTRACE_GETEVENTMSG = 0x4201
PTRACE_GETSIGINFO = 0x4202
PTRACE_SETSIGINFO = 0x4203
PTRACE_GETREGSET = 0x4204
PTRACE_SETREGSET = 0x4205
PTRACE_SEIZE = 0x4206
PTRACE_INTERRUPT = 0x4207
PTRACE_LISTEN = 0x4208
PTRACE_PEEKSIGINFO = 0x4209
PTRACE_GETSIGMASK = 0x420A
PTRACE_SETSIGMASK = 0x420B
PTRACE_SECCOMP_GET_FILTER = 0x420C
PTRACE_SECCOMP_GET_METADATA= 0x420D
; 系统调用号(x86_64)
SYS_ptrace = 101

注:以上为 Linux x86_64 常见定义;不同架构或更老内核可能有所差异,务必以目标系统的 include/uapi/linux/ptrace.h 为准。

Shellcode 参数约定(x86_64)#

  • rax: 系统调用号(如 SYS_ptrace = 101
  • rdi, rsi, rdx, r10, r8, r9: 对应系统调用第 1–6 个参数

示例:ptrace(PTRACE_TRACEME, 0, 0, 0) 的最小汇编片段(x86_64 Linux):

; 将当前线程置为可被父进程跟踪(仅 tracee 自身可用)
mov rax, 101 ; SYS_ptrace
xor rdi, rdi ; request = PTRACE_TRACEME (0)
xor rsi, rsi ; pid = 0
xor rdx, rdx ; addr = 0
xor r10, r10 ; data = 0
syscall
; 常见做法:随后触发停止,便于父进程接管
; mov rax, 62 ; SYS_kill
; mov rdi, 0 ; getpid() 可用时传自身 pid;在纯汇编中可先调用 getpid(39)
; mov rsi, 19 ; SIGSTOP
; syscall

选项(Options,配合 PTRACE_SETOPTIONS/PTRACE_SEIZE#

  • PTRACE_O_TRACESYSGOOD: 在系统调用停止时将 SIGTRAP 的高位标记(0x80),便于区分普通 SIGTRAP
  • PTRACE_O_TRACEFORK: 跟踪 fork() 产生的子进程,生成 PTRACE_EVENT_FORK
  • PTRACE_O_TRACEVFORK: 跟踪 vfork(),生成 PTRACE_EVENT_VFORK
  • PTRACE_O_TRACECLONE: 跟踪 clone(),生成 PTRACE_EVENT_CLONE
  • PTRACE_O_TRACEEXEC: 跟踪 execve(),生成 PTRACE_EVENT_EXEC
  • PTRACE_O_TRACEVFORKDONE: 跟踪 vfork 结束,生成 PTRACE_EVENT_VFORK_DONE
  • PTRACE_O_TRACEEXIT: 在进程退出前停止,生成 PTRACE_EVENT_EXIT
  • PTRACE_O_TRACESECCOMP: 在 seccomp 触发时停止,生成 PTRACE_EVENT_SECCOMP
  • PTRACE_O_EXITKILL: 若 tracer 终止,则被跟踪的所有 tracee 也被终止(内核 3.8+)。
  • PTRACE_O_SUSPEND_SECCOMP: 在被跟踪期间暂时挂起 seccomp(较新内核)。

选项必须在 tracee 处于 ptrace-stop 的状态下设置;SEIZE 模式可在 attach 之初一次性提供选项掩码。


事件(Events,配合 PTRACE_GETEVENTMSG#

  • PTRACE_EVENT_FORK = 1:fork() 产生的子进程。
  • PTRACE_EVENT_VFORK = 2:vfork() 产生的子进程。
  • PTRACE_EVENT_CLONE = 3:clone() 产生的子线程/进程。
  • PTRACE_EVENT_EXEC = 4:执行了新的程序映像(execve)。
  • PTRACE_EVENT_VFORK_DONE = 5:vfork 结束并恢复父进程。
  • PTRACE_EVENT_EXIT = 6:将要退出,tracee 在最后时刻停止。
  • PTRACE_EVENT_SECCOMP = 7:触发了 seccomp 过滤器。
  • PTRACE_EVENT_STOP = 128:SEIZE 模式下的主动或组停止。

当出现上述事件停止时,PTRACE_GETEVENTMSG 可获取事件相关的附加信息(如子 TID)。


相关结构#

使用 PTRACE_GETREGS 得到的寄存器顺序如下:

user_regs_struct

使用建议与注意事项#

  • 现代代码优先使用:PTRACE_SEIZE/PTRACE_INTERRUPT 管理生命周期,PTRACE_GETREGSET/SETREGSET 访问寄存器,PTRACE_PEEKSIGINFO/GETSIGMASK 管理信号。
  • 传统 ATTACH 需要 wait()/waitpid() 与信号握手;SEIZE 可无信号附加,随后用 INTERRUPT 进入停止态。
  • 读/写 tracee 大块内存推荐使用 process_vm_readv/process_vm_writev(非 ptrace),效率更高;POKE/PEEK 适合小粒度修改或设断点。
  • 跨架构时,不要假定旧接口的寄存器布局;使用 NT_PRSTATUS/NT_FPREGSETregset 类型通过 iovec 读写。

参考资料#

数值常量与支持范围以目标机器内核版本与头文件为准;若需精确值,请查阅目标系统的 include/uapi/linux/ptrace.hasm/ptrace.h

Linux ptrace 调用速查表
https://0xh3y3.github.io/posts/ptrace/
作者
0xh3y3
发布于
2026-04-20
许可协议
CC BY-NC-SA 4.0