Compare commits
2 Commits
f6e533cc94
...
197cc3098d
| Author | SHA1 | Date | |
|---|---|---|---|
| 197cc3098d | |||
| b2b2189c51 |
9
Makefile
9
Makefile
@@ -25,6 +25,7 @@ EMU_OBJ := build/emulated.riscv.elf
|
|||||||
EMU_OBJ_LICENSE ?= build/license
|
EMU_OBJ_LICENSE ?= build/license
|
||||||
EMU_OBJ_LICENSE_IF_EXISTS := $(wildcard $(EMU_OBJ_LICENSE))
|
EMU_OBJ_LICENSE_IF_EXISTS := $(wildcard $(EMU_OBJ_LICENSE))
|
||||||
|
|
||||||
|
README_FILE ?= build/README.md
|
||||||
ZIP_FILE ?= build/challenge.zip
|
ZIP_FILE ?= build/challenge.zip
|
||||||
ZIP_FILE_IF_EXISTS := $(wildcard $(ZIP_FILE))
|
ZIP_FILE_IF_EXISTS := $(wildcard $(ZIP_FILE))
|
||||||
|
|
||||||
@@ -70,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
|
||||||
@@ -90,7 +91,7 @@ $(EMU_OBJ_LICENSE): $(EMU_OBJ) $(HOST_EXE_ENCRYPTOR) | build
|
|||||||
ifneq ($(EMU_OBJ_LICENSE_IF_EXISTS),)
|
ifneq ($(EMU_OBJ_LICENSE_IF_EXISTS),)
|
||||||
rm $(EMU_OBJ_LICENSE_IF_EXISTS)
|
rm $(EMU_OBJ_LICENSE_IF_EXISTS)
|
||||||
endif
|
endif
|
||||||
$(HOST_EXE_ENCRYPTOR) $(EMU_OBJ) $@
|
$(HOST_EXE_ENCRYPTOR) $(EMU_OBJ) $@ $(README_FILE)
|
||||||
|
|
||||||
# Build (unencrypted) license file
|
# Build (unencrypted) license file
|
||||||
$(EMU_OBJ): $(EMU_OBJ_FILES) | build
|
$(EMU_OBJ): $(EMU_OBJ_FILES) | build
|
||||||
@@ -98,7 +99,7 @@ $(EMU_OBJ): $(EMU_OBJ_FILES) | build
|
|||||||
|
|
||||||
|
|
||||||
# Bundle the challenge
|
# Bundle the challenge
|
||||||
$(ZIP_FILE): $(HOST_EXE) $(EMU_OBJ_LICENSE) | build
|
$(ZIP_FILE): $(HOST_EXE) $(EMU_OBJ_LICENSE) $(README_FILE) | build
|
||||||
ifneq ($(ZIP_FILE_IF_EXISTS),)
|
ifneq ($(ZIP_FILE_IF_EXISTS),)
|
||||||
rm $(ZIP_FILE_IF_EXISTS)
|
rm $(ZIP_FILE_IF_EXISTS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -8,12 +8,13 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if (argc != 3) {
|
if (argc != 4) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* input = argv[1];
|
char* input = argv[1];
|
||||||
char* output = argv[2];
|
char* output = argv[2];
|
||||||
|
char* readme = argv[3];
|
||||||
|
|
||||||
hw_info_t hwinfo = {0};
|
hw_info_t hwinfo = {0};
|
||||||
if(get_hw_info(&hwinfo) != 0){
|
if(get_hw_info(&hwinfo) != 0){
|
||||||
@@ -103,5 +104,15 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
fprintf(stderr, "Wrote encrypted license file to %s\n", output);
|
fprintf(stderr, "Wrote encrypted license file to %s\n", output);
|
||||||
|
|
||||||
|
FILE* f_readme = fopen(readme, "w+");
|
||||||
|
fprintf(f_readme, "Oh, and one more thing you should know...\n");
|
||||||
|
fprintf(f_readme, "This doesn't just run on any hardware, I don't know how they did it\n");
|
||||||
|
fprintf(f_readme, "but it only works on my %s processor\n", hwinfo.model_name);
|
||||||
|
fprintf(f_readme, "running linux (version %s) with %s kb of RAM\n", hwinfo.os_version, hwinfo.mem_total);
|
||||||
|
fprintf(f_readme, "You'll find a way, slime. I'm sorry that I can't give you any more details\n");
|
||||||
|
fprintf(f_readme, "this is the last message I could get out before they... you know... ⛓️👮♂️\n");
|
||||||
|
fprintf(f_readme, "\n");
|
||||||
|
fprintf(f_readme, "- ASNT aka. Apfelsaftnaturtrüb\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_string(pid_t pid, unsigned long addr, char *buf, size_t max)
|
||||||
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fopen(const char *path, const char *mode) {
|
static void handle_openat(pid_t pid, struct user_regs_struct *regs)
|
||||||
init_real_fopen();
|
{
|
||||||
|
unsigned long path_ptr = regs->rsi;
|
||||||
|
char orig[4096] = {0};
|
||||||
|
if (read_string(pid, path_ptr, orig, sizeof(orig)) < 0)
|
||||||
|
return;
|
||||||
|
if (strncmp(orig, "/proc/", 6) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (path && strncmp(path, "/proc/", 6) == 0) {
|
char newpath[4096];
|
||||||
const char *rel_suffix = path + 1;
|
snprintf(newpath, sizeof(newpath), ".%s", orig + 1);
|
||||||
size_t len = strlen(rel_suffix) + 4;
|
|
||||||
char *new_path = malloc(len);
|
|
||||||
if (!new_path) {
|
|
||||||
fprintf(stderr, "proc_redirect: malloc failed\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
new_path[0] = '.';
|
|
||||||
new_path[1] = '/';
|
|
||||||
new_path[2] = '.';
|
|
||||||
strcpy(new_path + 3, rel_suffix);
|
|
||||||
|
|
||||||
FILE *f = real_fopen(new_path, mode);
|
/* Scratch space below the red zone, safe from any live stack frame */
|
||||||
free(new_path);
|
unsigned long scratch = regs->rsp - 256 - sizeof(newpath);
|
||||||
return f;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return real_fopen(path, mode);
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s <program> [args...]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ®s) == 0)
|
||||||
|
{
|
||||||
|
if (regs.orig_rax == SYS_openat)
|
||||||
|
{
|
||||||
|
handle_openat(pid, ®s);
|
||||||
|
}
|
||||||
|
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, ®s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user