Compare commits

..

No commits in common. "091a8666a55a905c755d3c735c440fe75f8b947f" and "12fcd59a281b41e21041d6ba2583ac008df0a730" have entirely different histories.

124
main.c
View File

@ -84,13 +84,13 @@ void hook_process_invoke(char *program, char **argv, char **envp) {
for (size_t i = 0;; i++) { for (size_t i = 0;; i++) {
if (argv[i] == NULL) if (argv[i] == NULL)
break; break;
printf(" argv[%zu]=%s\n", i, argv[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 (envp[i] == NULL)
// break;
// printf("==> envp[%zu]=%s\n", i, envp[i]);
// }
for (size_t i = 0;; i++) { for (size_t i = 0;; i++) {
if (argv[i] == NULL) if (argv[i] == NULL)
@ -120,53 +120,70 @@ static void tracee(int argc, char **argv) {
die("tracee start failed: %m"); die("tracee start failed: %m");
} }
static void tracer(pid_t ppid) { static void tracer(pid_t pid) {
int status = 0; int status = 0;
if (waitpid(ppid, &status, 0) < 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)
die("waitpid failed: %m"); 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 | unsigned long ptrace_options = PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK |
PTRACE_O_TRACEVFORK | PTRACE_O_TRACESYSGOOD; PTRACE_O_TRACEVFORK | PTRACE_O_TRACESYSGOOD;
if (ptrace(PTRACE_SETOPTIONS, ppid, NULL, ptrace_options) < 0) { if (ptrace(PTRACE_SETOPTIONS, pid, NULL, ptrace_options) < 0) {
perror("ptrace(PTRACE_SETOPTIONS)"); perror("ptrace(PTRACE_SETOPTIONS)");
ptrace(PTRACE_DETACH, ppid, NULL, NULL); ptrace(PTRACE_DETACH, pid, NULL, NULL);
die("bruh bruh cannot trace pid %d", ppid); die("bruh bruh cannot trace pid %d", pid);
} }
ptrace(PTRACE_SYSCALL, ppid, 0, 0); ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
int sysenter = 0;
while (1) { while (1) {
pid_t pid = waitpid(-1, &status, __WALL); ptrace(PTRACE_SYSCALL, pid, 0, 0);
waitpid(pid, &status, __WALL);
if (WIFEXITED(status) || WIFSIGNALED(status)) { if (WIFEXITED(status) || WIFSIGNALED(status)) {
// printf("[%d] child ded\n", pid); printf("[%d] child ded\n", pid);
if (pid == ppid) { break;
// the main process dies
break;
}
continue;
} }
if (!WIFSTOPPED(status)) { if (!WIFSTOPPED(status)) {
printf("[%d] what's this?\n", pid); printf("[%d] what's this?\n", pid);
ptrace(PTRACE_CONT, pid, 0, 0); // ptrace(PTRACE_CONT, pid, 0, 0);
continue; continue;
} }
// special events handled first // special events handled first
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8)) || if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) {
status >> 8 == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) || printf("[%d] clone\n", pid);
status >> 8 == (SIGTRAP | (PTRACE_EVENT_FORK << 8))) { // 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);
int spawn_pid; int spawn_pid;
if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &spawn_pid) == -1) { if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &spawn_pid) == -1) {
die("can't get lower child pid\n"); die("can't get lower child pid\n");
} }
// printf("[%d] spawn => %d\n", pid, spawn_pid); printf("=> %d\n", spawn_pid);
tracer(spawn_pid);
ptrace(PTRACE_SYSCALL, spawn_pid, 0, 0); // ptrace(PTRACE_CONT, pid, 0, 0);
ptrace(PTRACE_SYSCALL, pid, 0, 0);
continue; continue;
} }
@ -175,41 +192,35 @@ static void tracer(pid_t ppid) {
ptrace(PTRACE_GETEVENTMSG, pid, 0, &event_msg); ptrace(PTRACE_GETEVENTMSG, pid, 0, &event_msg);
if (WSTOPSIG(status) == (SIGTRAP | 0x80)) { if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
if (sysenter) {
sysenter = 1;
continue;
}
struct user_regs_struct regs; struct user_regs_struct regs;
if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) { if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1) {
// TODO: this reaches, even though the stop reason is syscall die("Cannot get registers");
// printf("error=%d pid=%d\n", errno, pid); return;
printf("Cannot get registers\n");
continue;
} }
if (regs.rax != -ENOSYS) {
// syscall exit
ptrace(PTRACE_SYSCALL, pid, 0, 0);
continue;
}
const int EXECVE_SYSCALL = 59;
const int EXECVEAT_SYSCALL = 322;
int syscall = regs.orig_rax; int syscall = regs.orig_rax;
if (syscall == EXECVE_SYSCALL || syscall == EXECVEAT_SYSCALL) { const int EXECVE_SYSCALL = 59;
if (syscall == EXECVE_SYSCALL) {
sysenter = 1;
printf("[%d] execve %d\n", pid, syscall); printf("[%d] execve %d\n", pid, syscall);
char *program; // RDI: const char *filename
char **argv; // RSI: char *const argv[]
char **envp; // RDX: char *const envp[]
if (syscall == EXECVE_SYSCALL) { char *program;
read_string_ptrace(pid, (void *)regs.rdi, &program); 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); char **argv;
} read_string_array_ptrace(pid, (void *)regs.rsi, &argv);
if (syscall == EXECVEAT_SYSCALL) {
read_string_ptrace(pid, (void *)regs.rsi, &program); char **envp;
read_string_array_ptrace(pid, (void *)regs.rdx, &argv); read_string_array_ptrace(pid, (void *)regs.rdx, &envp);
read_string_array_ptrace(pid, (void *)regs.r10, &envp);
}
hook_process_invoke(program, argv, envp); hook_process_invoke(program, argv, envp);
@ -217,14 +228,7 @@ static void tracer(pid_t ppid) {
free(argv); free(argv);
free(envp); 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);
} }
} }