Ptrace Mechanics (M2.0)
The Ptrace State Machine
Section titled “The Ptrace State Machine”ptrace is the primary mechanism for implementing debuggers and system call tracers on Linux.
The Stop-Inspect-Resume Cycle
Section titled “The Stop-Inspect-Resume Cycle”- PTRACE_SYSCALL: The tracer tells the kernel: “Let the child run until it hits a syscall entry or exit.”
- Wait: The tracer calls
waitpid()and sleeps. - Wake Up: When the child makes a syscall, the kernel freezes it and wakes the tracer.
- Inspect: The tracer reads the CPU registers (
PTRACE_GETREGS).
The AMD64 Syscall ABI
Section titled “The AMD64 Syscall ABI”On Linux x86_64, arguments are passed via specific registers. Understanding this map is critical for interception.
| Register | Usage | Example (openat) |
|---|---|---|
| RAX | Syscall Number | 257 (openat) |
| RDI | Argument 1 | dirfd (Directory File Descriptor) |
| RSI | Argument 2 | *pathname (Memory Address of string) |
| RDX | Argument 3 | flags (Read/Write mode) |
| R10 | Argument 4 | mode (Permissions) |
Critical Note: The return value of the syscall is placed in
RAXafter the syscall exits. On entry,RAXholds the ID.
PTRACE_PEEKDATA (The Eye)
Section titled “PTRACE_PEEKDATA (The Eye)”Reading memory from another process is not direct. You cannot dereference a pointer from the child.
long data = ptrace(PTRACE_PEEKDATA, child_pid, addr, NULL);- Unit: Reads 1 word (8 bytes on 64-bit).
- Method: To read a string, you must loop, reading 8 bytes at a time, and stitching them together until you find
\0.
PTRACE_O_TRACEFORK (The Net)
Section titled “PTRACE_O_TRACEFORK (The Net)”New in M2.0
To track an entire process tree (Parent Child Grandchild), we cannot rely on PTRACE_TRACEME alone. We must set the Trace Fork option.
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEFORK);Behavior:
- When the traced process calls
fork()orclone(), the kernel automatically stops the new child. - The Kernel sends a
PTRACE_EVENT_FORKsignal to the Tracer. - The Tracer detects this event and adds the new PID to its internal tracking table.
This ensures Zero-Gap Coverage: The child is captured before it executes its first instruction.