fix: static build + new syscall spoofer

This commit is contained in:
2026-05-17 19:23:06 +02:00
parent b2b2189c51
commit 197cc3098d
2 changed files with 154 additions and 30 deletions

View File

@@ -71,11 +71,11 @@ host: $(HOST_EXE) $(HOST_EXE_SPOOFER)
# Build the main challenge executable # Build the main challenge executable
$(HOST_EXE): $(HOST_SRC) | build $(HOST_EXE): $(HOST_SRC) | build
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC) -o $@ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -static $(HOST_INCLUDE) $(HOST_SRC) -o $@
# Build the spoofer # Build the spoofer
$(HOST_EXE_SPOOFER): $(HOST_SRC_SPOOFER) | build $(HOST_EXE_SPOOFER): $(HOST_SRC_SPOOFER) | build
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -shared -fPIC $^ -o $@ -ldl $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $^ -o $@ -ldl
# Build the encryptor # Build the encryptor
$(HOST_EXE_ENCRYPTOR): $(HOST_SRC_ENCRYPTOR) | build $(HOST_EXE_ENCRYPTOR): $(HOST_SRC_ENCRYPTOR) | build

View File

@@ -1,40 +1,164 @@
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <dlfcn.h> #include <errno.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/uio.h>
#include <sys/syscall.h>
#include <fcntl.h>
static FILE *(*real_fopen)(const char *path, const char *mode) = NULL; static void write_mem(pid_t pid, unsigned long addr, const char *buf, size_t len)
{
static void init_real_fopen(void) { struct iovec local = {(void *)buf, len};
if (!real_fopen) { struct iovec remote = {(void *)addr, len};
real_fopen = dlsym(RTLD_NEXT, "fopen"); if (process_vm_writev(pid, &local, 1, &remote, 1, 0) < 0)
if (!real_fopen) { {
fprintf(stderr, "proc_redirect: dlsym(fopen) failed: %s\n", dlerror()); perror("spoofer: process_vm_writev");
abort(); abort();
}
} }
} }
FILE *fopen(const char *path, const char *mode) { static int read_string(pid_t pid, unsigned long addr, char *buf, size_t max)
init_real_fopen(); {
struct iovec local = {buf, max};
struct iovec remote = {(void *)addr, max};
ssize_t n = process_vm_readv(pid, &local, 1, &remote, 1, 0);
if (n < 0)
return -1;
buf[n < (ssize_t)max ? (size_t)n : max - 1] = '\0';
buf[strnlen(buf, max - 1)] = '\0';
return 0;
}
if (path && strncmp(path, "/proc/", 6) == 0) { static void handle_openat(pid_t pid, struct user_regs_struct *regs)
const char *rel_suffix = path + 1; {
size_t len = strlen(rel_suffix) + 4; unsigned long path_ptr = regs->rsi;
char *new_path = malloc(len); char orig[4096] = {0};
if (!new_path) { if (read_string(pid, path_ptr, orig, sizeof(orig)) < 0)
fprintf(stderr, "proc_redirect: malloc failed\n"); return;
abort(); if (strncmp(orig, "/proc/", 6) != 0)
} return;
new_path[0] = '.';
new_path[1] = '/';
new_path[2] = '.';
strcpy(new_path + 3, rel_suffix);
FILE *f = real_fopen(new_path, mode); char newpath[4096];
free(new_path); snprintf(newpath, sizeof(newpath), ".%s", orig + 1);
return f;
/* Scratch space below the red zone, safe from any live stack frame */
unsigned long scratch = regs->rsp - 256 - sizeof(newpath);
write_mem(pid, scratch, newpath, strlen(newpath) + 1);
struct user_regs_struct r = *regs;
r.rsi = scratch;
if (ptrace(PTRACE_SETREGS, pid, NULL, &r) < 0)
perror("spoofer: PTRACE_SETREGS");
else
fprintf(stderr, "spoofer: redirected '%s' -> '%s'\n", orig, newpath);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "usage: %s <program> [args...]\n", argv[0]);
return 1;
} }
return real_fopen(path, mode); pid_t pid = fork();
if (pid < 0)
{
perror("fork");
return 1;
}
if (pid == 0)
{
if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0)
{
perror("spoofer: PTRACE_TRACEME");
_exit(1);
}
execvp(argv[1], argv + 1);
perror("spoofer: execvp");
_exit(1);
}
int status;
if (waitpid(pid, &status, 0) < 0)
{
perror("waitpid");
return 1;
}
if (!WIFSTOPPED(status))
{
fprintf(stderr, "spoofer: unexpected initial status %d\n", status);
return 1;
}
if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
(void *)(long)(PTRACE_O_TRACESYSGOOD | PTRACE_O_EXITKILL)) < 0)
{
perror("spoofer: PTRACE_SETOPTIONS");
return 1;
}
int in_syscall = 0;
while (1)
{
if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0)
{
perror("spoofer: PTRACE_SYSCALL");
break;
}
if (waitpid(pid, &status, 0) < 0)
{
perror("waitpid");
break;
}
if (WIFEXITED(status) || WIFSIGNALED(status))
break;
if (!WIFSTOPPED(status))
continue;
int sig = WSTOPSIG(status);
if (sig == (SIGTRAP | 0x80))
{
if (!in_syscall)
{
struct user_regs_struct regs;
if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == 0)
{
if (regs.orig_rax == SYS_openat)
{
handle_openat(pid, &regs);
}
else if (regs.orig_rax == SYS_open)
{
/* SYS_open: rdi=path — copy to rsi so handle_openat works */
regs.rsi = regs.rdi;
handle_openat(pid, &regs);
}
}
}
in_syscall ^= 1;
}
else
{
/* Forward real signals to the tracee */
ptrace(PTRACE_SYSCALL, pid, NULL, (void *)(long)sig);
in_syscall = 0;
continue;
}
}
if (WIFEXITED(status))
return WEXITSTATUS(status);
if (WIFSIGNALED(status))
return 128 + WTERMSIG(status);
return 0;
} }