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> +#+ +:+ +#+ */
|
/* 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;
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
15
srcs/main.c
15
srcs/main.c
|
|
@ -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);
|
||||||
}
|
}
|
||||||
239
srcs/utils.c
239
srcs/utils.c
|
|
@ -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, ®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);
|
read_regs(pid, ®s);
|
||||||
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)
|
||||||
|
{
|
||||||
|
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)
|
// If it fails, we’ll just print the basic signal name
|
||||||
{
|
valid = 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);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (binary_type == 32)
|
else
|
||||||
{
|
{
|
||||||
if (regs.orig_eax >= g_syscalls_86_len)
|
valid = 1;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
//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