[dev] follow all forks

This commit is contained in:
nganhkhoa 2025-05-21 00:06:54 +07:00
parent 12fcd59a28
commit 9c6f5c64fb

116
main.c
View File

@ -84,13 +84,13 @@ void hook_process_invoke(char *program, char **argv, char **envp) {
for (size_t i = 0;; i++) {
if (argv[i] == NULL)
break;
printf("==> argv[%zu]=%s\n", i, argv[i]);
}
for (size_t i = 0;; i++) {
if (envp[i] == NULL)
break;
printf("==> envp[%zu]=%s\n", i, envp[i]);
printf(" argv[%zu]=%s\n", i, argv[i]);
}
// for (size_t i = 0;; i++) {
// if (envp[i] == NULL)
// break;
// printf("==> envp[%zu]=%s\n", i, envp[i]);
// }
for (size_t i = 0;; i++) {
if (argv[i] == NULL)
@ -120,70 +120,53 @@ static void tracee(int argc, char **argv) {
die("tracee start failed: %m");
}
static void tracer(pid_t pid) {
static void tracer(pid_t ppid) {
int status = 0;
// preliminary stop
// works for both SIGSTOP of the main tracee
// as well as their children when stopped by ptrace trace fork
if (waitpid(pid, &status, 0) < 0)
if (waitpid(ppid, &status, 0) < 0)
die("waitpid failed: %m");
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
kill(pid, SIGKILL);
die("tracer: unexpected wait status: %x", status);
}
// capture these "fork" syscalls
// and then capture execve syscall
// fork vfork clone clone3
unsigned long ptrace_options = PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK |
PTRACE_O_TRACEVFORK | PTRACE_O_TRACESYSGOOD;
if (ptrace(PTRACE_SETOPTIONS, pid, NULL, ptrace_options) < 0) {
if (ptrace(PTRACE_SETOPTIONS, ppid, NULL, ptrace_options) < 0) {
perror("ptrace(PTRACE_SETOPTIONS)");
ptrace(PTRACE_DETACH, pid, NULL, NULL);
die("bruh bruh cannot trace pid %d", pid);
ptrace(PTRACE_DETACH, ppid, NULL, NULL);
die("bruh bruh cannot trace pid %d", ppid);
}
ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
ptrace(PTRACE_SYSCALL, ppid, 0, 0);
int sysenter = 0;
while (1) {
ptrace(PTRACE_SYSCALL, pid, 0, 0);
waitpid(pid, &status, __WALL);
pid_t pid = waitpid(-1, &status, __WALL);
if (WIFEXITED(status) || WIFSIGNALED(status)) {
printf("[%d] child ded\n", pid);
break;
// printf("[%d] child ded\n", pid);
if (pid == ppid) {
// the main process dies
break;
}
continue;
}
if (!WIFSTOPPED(status)) {
printf("[%d] what's this?\n", pid);
// ptrace(PTRACE_CONT, pid, 0, 0);
ptrace(PTRACE_CONT, pid, 0, 0);
continue;
}
// special events handled first
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
printf("[%d] clone\n", pid);
// ptrace(PTRACE_CONT, pid, 0, 0);
continue;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) {
printf("[%d] fork\n", pid);
// ptrace(PTRACE_CONT, pid, 0, 0);
continue;
}
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_VFORK << 8))) {
printf("[%d] vfork\n", pid);
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8)) ||
status >> 8 == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) ||
status >> 8 == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) {
int spawn_pid;
if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &spawn_pid) == -1) {
die("can't get lower child pid\n");
}
printf("=> %d\n", spawn_pid);
tracer(spawn_pid);
// printf("[%d] spawn => %d\n", pid, spawn_pid);
// ptrace(PTRACE_CONT, pid, 0, 0);
ptrace(PTRACE_SYSCALL, spawn_pid, 0, 0);
ptrace(PTRACE_SYSCALL, pid, 0, 0);
continue;
}
@ -192,35 +175,39 @@ static void tracer(pid_t pid) {
ptrace(PTRACE_GETEVENTMSG, pid, 0, &event_msg);
if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
if (sysenter) {
sysenter = 1;
continue;
}
struct user_regs_struct regs;
if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) {
die("Cannot get registers");
return;
continue;
}
if (regs.rax != -ENOSYS) {
// syscall exit
ptrace(PTRACE_SYSCALL, pid, 0, 0);
continue;
}
int syscall = regs.orig_rax;
const int EXECVE_SYSCALL = 59;
if (syscall == EXECVE_SYSCALL) {
sysenter = 1;
const int EXECVEAT_SYSCALL = 322;
int syscall = regs.orig_rax;
if (syscall == EXECVE_SYSCALL || syscall == EXECVEAT_SYSCALL) {
printf("[%d] execve %d\n", pid, syscall);
// RDI: const char *filename
// RSI: char *const argv[]
// RDX: char *const envp[]
char *program;
read_string_ptrace(pid, (void *)regs.rdi, &program);
char **argv;
read_string_array_ptrace(pid, (void *)regs.rsi, &argv);
char **envp;
read_string_array_ptrace(pid, (void *)regs.rdx, &envp);
if (syscall == EXECVE_SYSCALL) {
read_string_ptrace(pid, (void *)regs.rdi, &program);
read_string_array_ptrace(pid, (void *)regs.rsi, &argv);
read_string_array_ptrace(pid, (void *)regs.rdx, &envp);
}
if (syscall == EXECVEAT_SYSCALL) {
read_string_ptrace(pid, (void *)regs.rsi, &program);
read_string_array_ptrace(pid, (void *)regs.rdx, &argv);
read_string_array_ptrace(pid, (void *)regs.r10, &envp);
}
hook_process_invoke(program, argv, envp);
@ -228,7 +215,14 @@ static void tracer(pid_t pid) {
free(argv);
free(envp);
}
// TODO: capture other syscalls also
// renameat -> track file renames
// printf("syscall %d\n", syscall);
}
// ask to wait for syscall of the currently stopped process
ptrace(PTRACE_SYSCALL, pid, 0, 0);
}
}