Skip to content
Anti-Analysisintermediate

ptrace Self-Attach

On Linux, a process calls ptrace(PTRACE_TRACEME) on itself so that any debugger trying to attach later fails — a single process can only be traced once.

A Linux process may be traced by only one tracer at a time. Malware exploits this by tracing itself: if ptrace(PTRACE_TRACEME, 0, 0, 0) succeeds, no debugger is attached and a later gdb/strace attach will fail with EPERM. If the call returns -1, a debugger is already present.

Example

c
#include <sys/ptrace.h>

if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
    // Already being traced — bail out.
    _exit(1);
}

The same self-attach via the raw syscall convention disassembles like this:

asm
; ptrace(PTRACE_TRACEME=0, 0, 0, 0) via syscall(2)
xor     edi, edi              ; arg1 request = PTRACE_TRACEME (0)
xor     esi, esi              ; arg2 pid  = 0
xor     edx, edx              ; arg3 addr = 0
xor     r10d, r10d            ; arg4 data = 0
mov     eax, 101             ; __NR_ptrace = 101
syscall                       ; rax = result (-1 on EPERM if already traced)
cmp     rax, -1               ; return == -1 ?
je      already_traced        ; debugger attached -> bail out

Bypass

  • LD_PRELOAD a stub that makes ptrace always return 0.
  • Patch the syscall / check at runtime, or set /proc/sys/kernel/yama/ptrace_scope.
  • Under GDB, catch syscall ptrace and force the return value, or run with a seccomp-based ptrace interposer.
Votes

Comments(0)