first draft, should work but have to try on a x86 machine
This commit is contained in:
parent
a933468d61
commit
6414474ce0
4 changed files with 206 additions and 61 deletions
|
|
@ -6,7 +6,7 @@
|
|||
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.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
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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]);
|
||||
|
|
|
|||
15
srcs/main.c
15
srcs/main.c
|
|
@ -6,13 +6,13 @@
|
|||
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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);
|
||||
}
|
||||
221
srcs/utils.c
221
srcs/utils.c
|
|
@ -6,7 +6,7 @@
|
|||
/* By: thrieg <thrieg@student.42mulhouse.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* 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);
|
||||
if (binary_type == 64)
|
||||
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)
|
||||
{
|
||||
if (regs.orig_rax >= g_syscalls_64_len)
|
||||
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("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);
|
||||
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
|
||||
{
|
||||
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);
|
||||
wrote = snprintf(buffer + buffer_len, sizeof(buffer) - buffer_len,
|
||||
"%lld", args[i]);
|
||||
}
|
||||
if (wrote < 0)
|
||||
{
|
||||
//shouldn't happen
|
||||
break;
|
||||
}
|
||||
else if (binary_type == 32)
|
||||
buffer_len += wrote;
|
||||
}
|
||||
if ((size_t)buffer_len < sizeof(buffer) - 2)
|
||||
{
|
||||
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);
|
||||
buffer[buffer_len++] = ')';
|
||||
buffer[buffer_len] = '\0';
|
||||
}
|
||||
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);
|
||||
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 it fails, we’ll just print the basic signal name
|
||||
valid = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = 1;
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue