Skip to content

Commit

Permalink
♻️ refactor analysis routine
Browse files Browse the repository at this point in the history
  • Loading branch information
froz42 committed Oct 10, 2023
1 parent 26dca80 commit fc0d22e
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 96 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ SRCS += syscall/syscall_get_description.c \
syscall/syscall_log.c \
syscall/syscall_log_param.c \
syscall/syscall_is_execve.c \
syscall/param_log/param_log_memseg.c
syscall/param_log/param_log_memseg.c \
syscall/syscall_handle.c

# registers srcs

Expand Down
28 changes: 27 additions & 1 deletion includes/syscall_strace.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ typedef struct {
const arg_type_t arg_types[6];
} syscall_description_t;

#define MAX_SYSCALL_NO 0x17f

typedef enum
{
NOT_ENCOUNTERED,
ENCOUNTERED,
ERROR
} execve_status_t;

typedef struct
{
execve_status_t status;
register_type_t register_type;
} analysis_routine_data_t;

#define NO_STATUS -1

#define ELEM_COUNT(x) (sizeof(x) / sizeof(x[0]))

/**
Expand Down Expand Up @@ -85,4 +102,13 @@ void syscall_log_return(pid_t pid, user_regs_t *regs, register_type_t regs_type)
* @param type
* @return bool_t true if syscall is execve, false otherwise
*/
bool_t syscall_is_execve(uint64_t syscall_no, register_type_t type);
bool_t syscall_is_execve(uint64_t syscall_no, register_type_t type);

/**
* @brief Handle a syscall
*
* @param pid the pid of the tracee
* @param data the data of the analysis routine
* @return int the status code of the tracee or NO_STATUS if no status code is available
*/
int syscall_handle(pid_t pid, analysis_routine_data_t *data);
2 changes: 1 addition & 1 deletion libft/srcs/string/ft_escape.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ char *ft_escape(const char *str, size_t size)
escaped_str + j,
escaped_size - j,
"\\%u",
(unsigned char)str[i] % 256);
(unsigned char)str[i]);
if (added < 0)
{
free(escaped_str);
Expand Down
101 changes: 8 additions & 93 deletions srcs/analysis/analysis_routine.c
Original file line number Diff line number Diff line change
@@ -1,104 +1,19 @@
#include <sys/ptrace.h>
#include <bool_t.h>
#include <sys/types.h>
#include <stddef.h>
#include <sys/wait.h>
#include <stdio.h>
#include <analysis.h>
#include <signal.h>
#include <ft_strace_utils.h>
#include <errno.h>
#include <syscall_strace.h>
#include <user_registers.h>
#include <sys/uio.h>
#include <elf.h>
#include <registers.h>
#include <ft_printf.h>

#define MAX_SYSCALL_NO 0x14c

#define SYS_EXECVE 0x3b

typedef enum
{
NOT_ENCOUNTERED,
ENCOUNTERED,
ERROR
} execve_status_t;

typedef struct
{
execve_status_t status;
register_type_t register_type;
} analysis_routine_data_t;

#define NO_STATUS -1

int handle_syscall(pid_t pid, analysis_routine_data_t *data)
{
user_regs_t regs_before = {0};
struct iovec regs_before_iov;

regs_before_iov.iov_base = &regs_before;
regs_before_iov.iov_len = sizeof(regs_before);
if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &regs_before_iov) < 0)
{
log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(1) failed", true);
return NO_STATUS;
}
register_type_t register_type_before = registers_get_type(regs_before_iov.iov_len);
if (data->register_type != register_type_before)
{
data->register_type = register_type_before;
ft_dprintf(STDERR_FILENO, "[ Process PID=%d runs in 32 bit mode. ]\n", pid);
}
uint64_t syscall_no = registers_get_syscall(&regs_before, register_type_before);
if (syscall_no > MAX_SYSCALL_NO)
return NO_STATUS;

if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0)
{
log_error("handle_syscall", "ptrace failed", true);
return NO_STATUS;
}
bool_t is_execve = syscall_is_execve(syscall_no, register_type_before);
if (data->status == ERROR && !is_execve)
return NO_STATUS;
if (data->status == NOT_ENCOUNTERED && !is_execve)
return NO_STATUS;
bool_t should_log = data->status == ENCOUNTERED || (data->status != ERROR && is_execve);
if (should_log)
syscall_log_name_params(pid, &regs_before, register_type_before);
int status;
if (waitpid(pid, &status, 0) < 0)
{
log_error("handle_syscall", "waitpid failed", true);
return NO_STATUS;
}
if (WIFEXITED(status) || WIFSIGNALED(status))
{
ft_dprintf(STDERR_FILENO, ") = ?\n");
return status;
}
user_regs_t regs_after;
struct iovec regs_after_iov;

regs_after_iov.iov_base = &regs_after;
regs_after_iov.iov_len = sizeof(regs_after);
if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &regs_after_iov) < 0)
{
log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(2) failed", true);
return NO_STATUS;
}
register_type_t register_type_after = registers_get_type(regs_after_iov.iov_len);
if (data->status == NOT_ENCOUNTERED && syscall_no == SYS_EXECVE)
data->status = (int64_t)registers_get_return(&regs_after, register_type_after) < 0 ? ERROR : ENCOUNTERED;
if (should_log)
syscall_log_params_return(pid, syscall_no, &regs_after, register_type_after);
return NO_STATUS;
}

int handle_status(int status)
/**
* @brief Handle the status of the tracee
*
* @param status the status of the tracee
* @return int the status code of the tracee or NO_STATUS if no status code is available
*/
static int handle_status(int status)
{
if (status == NO_STATUS)
return NO_STATUS;
Expand Down Expand Up @@ -135,7 +50,7 @@ int analysis_routine(pid_t pid)
int status_code = handle_status(status);
if (status_code != NO_STATUS)
return status_code;
status_code = handle_status(handle_syscall(pid, &data));
status_code = handle_status(syscall_handle(pid, &data));
if (status_code != NO_STATUS)
return status_code;
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0)
Expand Down
120 changes: 120 additions & 0 deletions srcs/syscall/syscall_handle.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include <syscall_strace.h>
#include <sys/uio.h>
#include <sys/ptrace.h>
#include <ft_printf.h>
#include <elf.h>
#include <sys/wait.h>
#include <ft_strace_utils.h>

/**
* @brief Handle the syscall before it is executed
*
* @param pid the pid of the tracee
* @param data the data of the analysis routine
* @param syscall_no the syscall number pointer to be filled
* @param is_execve pointer to be filled with whether the syscall is an execve
* @return int NO_STATUS if the caller must return, 1 if the syscall must be logged, 0 otherwise
*/
static int handle_before_syscall(
pid_t pid,
analysis_routine_data_t *data,
uint64_t *syscall_no,
bool_t *is_execve)
{
user_regs_t regs_before;
struct iovec regs_before_iov;

regs_before_iov.iov_base = &regs_before;
regs_before_iov.iov_len = sizeof(regs_before);
if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &regs_before_iov) < 0)
{
log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(1) failed", true);
return NO_STATUS;
}
register_type_t register_type_before = registers_get_type(regs_before_iov.iov_len);
if (data->register_type != register_type_before)
{
data->register_type = register_type_before;
ft_dprintf(STDERR_FILENO, "[ Process PID=%d runs in 32 bit mode. ]\n", pid);
}
*syscall_no = registers_get_syscall(&regs_before, register_type_before);
if (*syscall_no > MAX_SYSCALL_NO)
return NO_STATUS;
*is_execve = syscall_is_execve(*syscall_no, register_type_before);
if (data->status == ERROR && !*is_execve)
return NO_STATUS;
if (data->status == NOT_ENCOUNTERED && !*is_execve)
return NO_STATUS;
bool_t should_log = data->status == ENCOUNTERED || (data->status != ERROR && *is_execve);
if (should_log)
syscall_log_name_params(pid, &regs_before, register_type_before);
return should_log;
}

/**
* @brief Handle the syscall after it is executed
*
* @param pid the pid of the tracee
* @param data the data of the analysis routine
* @param syscall_no the syscall number
* @param should_log whether the syscall should be logged
* @param is_execve whether the syscall is an execve
* @return int NO_STATUS in every case
*/
static int handle_syscall_after(
pid_t pid,
analysis_routine_data_t *data,
uint64_t syscall_no,
int should_log,
bool_t is_execve)
{
user_regs_t regs_after;
struct iovec regs_after_iov;

regs_after_iov.iov_base = &regs_after;
regs_after_iov.iov_len = sizeof(regs_after);
if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &regs_after_iov) < 0)
{
log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(2) failed", true);
return NO_STATUS;
}
register_type_t register_type_after = registers_get_type(regs_after_iov.iov_len);
if (data->status == NOT_ENCOUNTERED && is_execve)
data->status = (int64_t)registers_get_return(&regs_after, register_type_after) < 0 ? ERROR : ENCOUNTERED;
if (should_log)
syscall_log_params_return(pid, syscall_no, &regs_after, register_type_after);
return NO_STATUS;
}

/**
* @brief Handle a syscall
*
* @param pid the pid of the tracee
* @param data the data of the analysis routine
* @return int the status code of the tracee or NO_STATUS if no status code is available
*/
int syscall_handle(pid_t pid, analysis_routine_data_t *data)
{
uint64_t syscall_no;
bool_t is_execve;
int should_log = handle_before_syscall(pid, data, &syscall_no, &is_execve);
if (should_log == NO_STATUS)
return NO_STATUS;
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0)
{
log_error("handle_syscall", "ptrace failed", true);
return NO_STATUS;
}
int status;
if (waitpid(pid, &status, 0) < 0)
{
log_error("handle_syscall", "waitpid failed", true);
return NO_STATUS;
}
if (WIFEXITED(status) || WIFSIGNALED(status))
{
ft_dprintf(STDERR_FILENO, ") = ?\n");
return status;
}
return handle_syscall_after(pid, data, syscall_no, should_log, is_execve);
}

0 comments on commit fc0d22e

Please sign in to comment.