From 6414474ce0c06cc13602ff047faa2fb6b0122a1b Mon Sep 17 00:00:00 2001 From: thrieg Date: Thu, 11 Dec 2025 23:30:45 +0100 Subject: [PATCH] first draft, should work but have to try on a x86 machine --- includes/ft_strace.h | 9 +- includes/syscalls_x86.h | 4 +- srcs/main.c | 15 +-- srcs/utils.c | 239 +++++++++++++++++++++++++++++++--------- 4 files changed, 206 insertions(+), 61 deletions(-) diff --git a/includes/ft_strace.h b/includes/ft_strace.h index 587b694..d32bee3 100644 --- a/includes/ft_strace.h +++ b/includes/ft_strace.h @@ -6,7 +6,7 @@ /* By: thrieg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/12/11 04:06:00 by thrieg #+# #+# */ -/* Updated: 2025/12/11 05:54:47 by thrieg ### ########.fr */ +/* Updated: 2025/12/11 23:17:28 by thrieg ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,12 +16,19 @@ #include #include #include +#include #include +#include #include +#include +#include #include "../libft/libft.h" //returns 64 for x84_64, or 32 for 32 bits, -1 for open/read error, -2 for unrecognised file type ssize_t binary_type(char *path_to_binary); +void read_regs_and_print_exit(pid_t pid, size_t binary_type); +void read_regs_and_print_entry(pid_t pid, size_t binary_type); +void print_signal(pid_t pid, int sig); typedef struct s_syscall_desc { const char *name; diff --git a/includes/syscalls_x86.h b/includes/syscalls_x86.h index f938ae2..8fb2fa9 100644 --- a/includes/syscalls_x86.h +++ b/includes/syscalls_x86.h @@ -6,7 +6,7 @@ /* By: thrieg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/12/11 05:56:09 by thrieg #+# #+# */ -/* Updated: 2025/12/11 05:58:14 by thrieg ### ########.fr */ +/* Updated: 2025/12/11 23:25:53 by thrieg ### ########.fr */ /* */ /* ************************************************************************** */ @@ -402,4 +402,4 @@ static const t_syscall_desc g_syscalls_32[] = { }; const size_t g_syscalls_32_len = - sizeof(g_syscalls_64) / sizeof(g_syscalls_64[0]); + sizeof(g_syscalls_32) / sizeof(g_syscalls_32[0]); diff --git a/srcs/main.c b/srcs/main.c index 2729023..6cf86ed 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -6,13 +6,13 @@ /* By: thrieg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/12/11 04:07:30 by thrieg #+# #+# */ -/* Updated: 2025/12/11 04:59:32 by thrieg ### ########.fr */ +/* Updated: 2025/12/11 23:25:15 by thrieg ### ########.fr */ /* */ /* ************************************************************************** */ #include "../includes/ft_strace.h" -int main_loop(size_t binary_type) +int main_loop(size_t binary_type, pid_t pid) { int in_syscall = 0; while (1) { @@ -41,21 +41,22 @@ int main_loop(size_t binary_type) // syscall-enter or syscall-exit if (!in_syscall) { // ENTRY - read_regs_and_print_entry(pid); + read_regs_and_print_entry(pid, binary_type); in_syscall = 1; } else { // EXIT - read_regs_and_print_exit(pid); + read_regs_and_print_exit(pid, binary_type); in_syscall = 0; } } else { - // A real signal: print it, then let it continue + // A real signal: print it print_signal(pid, sig); // pass down the signal to the actual program if (ptrace(PTRACE_SYSCALL, pid, 0, sig) == -1) break; - waitpid(pid, &status, 0); + //waitpid(pid, &status, 0); } } + return (EXIT_SUCCESS); } int main(int argc, char **argv) @@ -104,7 +105,7 @@ int main(int argc, char **argv) ptrace(PTRACE_SETOPTIONS, pid, 0, opts); // 5) Enter main trace loop - return (main_loop((size_t)binary_bits)); + return (main_loop((size_t)binary_bits, pid)); } return (EXIT_SUCCESS); } \ No newline at end of file diff --git a/srcs/utils.c b/srcs/utils.c index 3587560..aae4032 100644 --- a/srcs/utils.c +++ b/srcs/utils.c @@ -6,7 +6,7 @@ /* By: thrieg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/12/11 04:31:15 by thrieg #+# #+# */ -/* Updated: 2025/12/11 06:14:12 by thrieg ### ########.fr */ +/* Updated: 2025/12/11 23:27:01 by thrieg ### ########.fr */ /* */ /* ************************************************************************** */ @@ -60,62 +60,199 @@ static void read_regs(pid_t pid, struct user_regs_struct *regs) } } +static void fill_args(long long args[6], struct user_regs_struct *regs, size_t binary_type) +{ + if (binary_type == 64) + { + args[0] = (long long)regs->rdi; + args[1] = (long long)regs->rsi; + args[2] = (long long)regs->rdx; + args[3] = (long long)regs->r10; + args[4] = (long long)regs->r8; + args[5] = (long long)regs->r9; + } + else if (binary_type == 32) + { + args[0] = (long long)(long)regs->ebx; + args[1] = (long long)(long)regs->ecx; + args[2] = (long long)(long)regs->edx; + args[3] = (long long)(long)regs->esi; + args[4] = (long long)(long)regs->edi; + args[5] = (long long)(long)regs->ebp; + } +} + +//also sets argc, returns NULL if syscall not recognised +static const char *get_syscall_name(size_t binary_type, struct user_regs_struct *regs, unsigned char *argc) +{ + if (binary_type == 64 && regs->orig_rax < g_syscalls_64_len) + { + *argc = g_syscalls_64[regs->orig_rax].argc; + return (g_syscalls_64[regs->orig_rax].name); + } + else if (binary_type == 32 && regs->orig_eax < g_syscalls_32_len) + { + *argc = g_syscalls_32[regs->orig_eax].argc; + return (g_syscalls_32[regs->orig_eax].name); + } + *argc = 6; + return (NULL); +} + void read_regs_and_print_entry(pid_t pid, size_t binary_type) { struct user_regs_struct regs; + read_regs(pid, ®s); + long long args[6]; + fill_args(args, ®s, binary_type); + unsigned char argc = 6; + const char *syscall_name = get_syscall_name(binary_type, ®s, &argc); + if (syscall_name) + { + char buffer[400]; //shouldn't be able to overflow because we just print the 64bits registers' values in hex without trying to interpret the string or anything, so max len = syscall_name + 20*argc (64 bit in hex is 16 chars) + ssize_t buffer_len = snprintf(buffer, sizeof(buffer), "%s(", syscall_name); + if (buffer_len < 0) + { + printf("error: unexpected syscall name"); + return; + } + for (unsigned char i = 0; i < argc; i++) + { + ssize_t wrote; + if (i > 0) + { + wrote = snprintf(buffer + buffer_len, sizeof(buffer) - buffer_len, + ", %lld", args[i]); + } + else + { + wrote = snprintf(buffer + buffer_len, sizeof(buffer) - buffer_len, + "%lld", args[i]); + } + if (wrote < 0) + { + //shouldn't happen + break; + } + buffer_len += wrote; + } + if ((size_t)buffer_len < sizeof(buffer) - 2) + { + buffer[buffer_len++] = ')'; + buffer[buffer_len] = '\0'; + } + else + { + buffer[sizeof(buffer) - 1] = '\0'; + } + printf("%-100s", buffer); + } + else + { + char placeholder_syscall_name[50]; //max 20 chars in a 64 bit register rax at worst, + leeway + snprintf(placeholder_syscall_name, sizeof(placeholder_syscall_name), "unknown_syscall_id_%zu", binary_type == 32 ? (size_t)regs.orig_eax : (size_t)regs.orig_rax); + char buffer[400]; //shouldn't be able to overflow because we just print the 64bits registers' values in hex without trying to interpret the string or anything, so max len = syscall_name + 20*argc (64 bit in hex is 16 chars) + ssize_t buffer_len = snprintf(buffer, sizeof(buffer), "%s(", placeholder_syscall_name); + if (buffer_len < 0) + { + printf("error: unexpected syscall name"); + return; + } + for (unsigned char i = 0; i < argc; i++) + { + ssize_t wrote; + if (i > 0) + { + wrote = snprintf(buffer + buffer_len, sizeof(buffer) - buffer_len, + ", %lld", args[i]); + } + else + { + wrote = snprintf(buffer + buffer_len, sizeof(buffer) - buffer_len, + "%lld", args[i]); + } + if (wrote < 0) + { + //shouldn't happen + break; + } + buffer_len += wrote; + } + if ((size_t)buffer_len < sizeof(buffer) - 2) + { + buffer[buffer_len++] = ')'; + buffer[buffer_len] = '\0'; + } + else + { + buffer[sizeof(buffer) - 1] = '\0'; + } + printf("%-100s", buffer); + } +} + +void read_regs_and_print_exit(pid_t pid, size_t binary_type) +{ + struct user_regs_struct regs; + long ret; + read_regs(pid, ®s); if (binary_type == 64) + ret = (long)regs.rax; + else + ret = (long)regs.eax; + printf(" = %ld\n", ret); + fflush(stdout); +} + +void print_signal(pid_t pid, int sig) +{ + siginfo_t si; + int valid = 0; + + // Try to get the siginfo from the kernel + if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == -1) { - if (regs.orig_rax >= g_syscalls_64_len) - { - printf("unknown syscall(%ld, %lld, %lld, %lld, %lld, %lld, %lld)\n", - (long long)regs.orig_rax, - (long long)regs.rdi, - (long long)regs.rsi, - (long long)regs.rdx, - (long long)regs.r10, - (long long)regs.r8, - (long long)regs.r9); - } - else - { - const char *syscall_name = g_syscalls_64[regs.orig_rax]->name; - int argc = g_syscalls_64[regs.orig_rax]->argc; - printf("%s(%ld, %lld, %lld, %lld, %lld, %lld, %lld)\n", - syscall, - (long long)regs.rdi, - (long long)regs.rsi, - (long long)regs.rdx, - (long long)regs.r10, - (long long)regs.r8, - (long long)regs.r9); - } + // If it fails, we’ll just print the basic signal name + valid = 0; } - else if (binary_type == 32) + else { - if (regs.orig_eax >= g_syscalls_86_len) - { - printf("unknown syscall(%ld, %lld, %lld, %lld, %lld, %lld, %lld)\n", - (long)regs.orig_eax, - (long)regs.ebx, - (long)regs.ecx, - (long)regs.edx, - (long)regs.esi, - (long)regs.edi, - (long)regs.ebp); - } - else - { - const char *syscall_name = g_syscalls_86[regs.orig_eax]->name; - int argc = g_syscalls_64[regs.orig_eax]->argc; - printf("%s(%lld, %lld, %lld, %lld, %lld, %lld)\n", - syscall_name, - (long)regs.ebx, - (long)regs.ecx, - (long)regs.edx, - (long)regs.esi, - (long)regs.edi, - (long)regs.ebp); - } + valid = 1; } -} \ No newline at end of file + + //Basic signal name + const char *name = strsignal(sig); + if (!name) + name = "UNKNOWN"; + + if (valid) + { + /* Print something like: + --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=1234, si_uid=1000} --- + */ + printf("--- %s {", name); + printf("si_signo=%d, ", si.si_signo); + printf("si_code=%d", si.si_code); + + /* Some signals have extra fields — decode some common ones */ + if (si.si_code == SI_USER || si.si_code == SI_QUEUE) + { + /* Sender PID and UID */ + printf(", si_pid=%d, si_uid=%d", si.si_pid, si.si_uid); + } + /* For faults like SIGSEGV, SIGBUS, SIGILL, print fault address */ + if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL) + { + /* si_addr is a void* pointing to the faulting address */ + printf(", si_addr=%p", si.si_addr); + } + printf("} ---\n"); + } + else + { + // Fallback if GETSIGINFO failed: just print the signal + printf("--- %s ---\n", name); + } + fflush(stdout); +}