I'm trying to build a simple version of starce, which shows you the first x syscalls a process made. The problem is that currently it seems like every syscall appears twice (except execve
and exit_group
).
This is the code I use to get the syscalls:
import os
import ctypes
# Get libc:
libc = ctypes.CDLL('/lib/x86_64-linux-gnu/libc.so.6')
# Define Constants:
PTRACE_PEEKTEXT = 1
PTRACE_PEEKDATA = 2
PTRACE_POKETEXT = 4
PTRACE_POKEDATA = 5
PTRACE_CONT = 7
PTRACE_SINGLESTEP = 9
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_TRACEME = 0
PTRACE_SYSCALL = 24
PTRACE_PEEKUSER = 32
class user_regs_struct(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong),
("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong),
("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong),
("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong),
("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong),
("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong),
("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong),
("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong),
("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong),
("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong),
("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong),
("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong),
("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong),
("gs", ctypes.c_ulonglong),
]
ptrace = libc.ptrace
ptrace.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]
ptrace.restype = ctypes.c_int
pid = 123 # whatever PID you need
syscalls = []
while len(syscalls) < 1024:
try:
_, status = os.waitpid(pid, os.WUNTRACED)
if os.WIFEXITED(status):
break
except:
break
regs = user_regs_struct()
ptrace(PTRACE_GETREGS, pid, 0, ctypes.byref(regs))
syscalls.append(regs.orig_rax)
ptrace(PTRACE_SYSCALL, pid, 0, 0)
And the first 16 syscalls I get for example when running on ls
are these:
execve, brk, brk, arch_prctl, arch_prctl, access, access, openat, openat, fstat, fstat, mmap, mmap, close, close, openat
While if I run strace, the first 16 are these:
execve, brk, arch_prctl, access, openat, fstat, mmap, close, openat, read, fstat, mmap, mmap, mprotect, mmap, mmap
As you can see, my code outputs each syscall twice.
What can cause this? And how can it be fixed?
After digging a bit in other threads here, I found that every syscall is supposed to appear twice, once before it was called, and another time after it was called.
So the solution will be to simply to add the syscall to the list only once every two iterations.