first draft, should work but have to try on a x86 machine

This commit is contained in:
thrieg 2025-12-11 23:30:45 +01:00
parent a933468d61
commit 6414474ce0
4 changed files with 206 additions and 61 deletions

View file

@ -6,7 +6,7 @@
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */ /* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/12/11 04:06:00 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 <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <sys/wait.h>
#include <signal.h>
#include "../libft/libft.h" #include "../libft/libft.h"
//returns 64 for x84_64, or 32 for 32 bits, -1 for open/read error, -2 for unrecognised file type //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); 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 { typedef struct s_syscall_desc {
const char *name; const char *name;

View file

@ -6,7 +6,7 @@
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */ /* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/12/11 05:56:09 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 = 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]);

View file

@ -6,13 +6,13 @@
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */ /* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/12/11 04:07:30 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" #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; int in_syscall = 0;
while (1) { while (1) {
@ -41,21 +41,22 @@ int main_loop(size_t binary_type)
// syscall-enter or syscall-exit // syscall-enter or syscall-exit
if (!in_syscall) { if (!in_syscall) {
// ENTRY // ENTRY
read_regs_and_print_entry(pid); read_regs_and_print_entry(pid, binary_type);
in_syscall = 1; in_syscall = 1;
} else { } else {
// EXIT // EXIT
read_regs_and_print_exit(pid); read_regs_and_print_exit(pid, binary_type);
in_syscall = 0; in_syscall = 0;
} }
} else { } else {
// A real signal: print it, then let it continue // A real signal: print it
print_signal(pid, sig); print_signal(pid, sig);
// pass down the signal to the actual program // pass down the signal to the actual program
if (ptrace(PTRACE_SYSCALL, pid, 0, sig) == -1) break; 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) int main(int argc, char **argv)
@ -104,7 +105,7 @@ int main(int argc, char **argv)
ptrace(PTRACE_SETOPTIONS, pid, 0, opts); ptrace(PTRACE_SETOPTIONS, pid, 0, opts);
// 5) Enter main trace loop // 5) Enter main trace loop
return (main_loop((size_t)binary_bits)); return (main_loop((size_t)binary_bits, pid));
} }
return (EXIT_SUCCESS); return (EXIT_SUCCESS);
} }

View file

@ -6,7 +6,7 @@
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */ /* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */ /* +#+#+#+#+#+ +#+ */
/* Created: 2025/12/11 04:31:15 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) void read_regs_and_print_entry(pid_t pid, size_t binary_type)
{ {
struct user_regs_struct regs; struct user_regs_struct regs;
read_regs(pid, &regs);
long long args[6];
fill_args(args, &regs, binary_type);
unsigned char argc = 6;
const char *syscall_name = get_syscall_name(binary_type, &regs, &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, &regs); read_regs(pid, &regs);
if (binary_type == 64) 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)
{ {
if (regs.orig_rax >= g_syscalls_64_len) siginfo_t si;
int valid = 0;
// Try to get the siginfo from the kernel
if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == -1)
{ {
printf("unknown syscall(%ld, %lld, %lld, %lld, %lld, %lld, %lld)\n", // If it fails, well just print the basic signal name
(long long)regs.orig_rax, valid = 0;
(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 else
{ {
const char *syscall_name = g_syscalls_64[regs.orig_rax]->name; valid = 1;
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);
} }
//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);
} }
else if (binary_type == 32) /* For faults like SIGSEGV, SIGBUS, SIGILL, print fault address */
if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL)
{ {
if (regs.orig_eax >= g_syscalls_86_len) /* si_addr is a void* pointing to the faulting address */
{ printf(", si_addr=%p", si.si_addr);
printf("unknown syscall(%ld, %lld, %lld, %lld, %lld, %lld, %lld)\n", }
(long)regs.orig_eax, printf("} ---\n");
(long)regs.ebx,
(long)regs.ecx,
(long)regs.edx,
(long)regs.esi,
(long)regs.edi,
(long)regs.ebp);
} }
else else
{ {
const char *syscall_name = g_syscalls_86[regs.orig_eax]->name; // Fallback if GETSIGINFO failed: just print the signal
int argc = g_syscalls_64[regs.orig_eax]->argc; printf("--- %s ---\n", name);
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);
}
} }
fflush(stdout);
} }