Created
August 26, 2024 19:10
-
-
Save alifarazz/a0e28369d8683b711fc9eb816fca3c78 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <linux/prctl.h> /* Definition of PR_* constants */ | |
#include <sys/prctl.h> | |
#include <sys/syscall.h> /* for __NR_write */ | |
#include <ucontext.h> /* REG_RBP, REG_RSP */ | |
#include <unistd.h> /* for write(2) */ | |
#include <assert.h> | |
#include <inttypes.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <signal.h> | |
#define GLIBC_PATH "/usr/lib/libc.so.6" | |
static void setup_sigsys_handler(); | |
static size_t syswrite(int, const void *, int); | |
static ssize_t mywrite(int, const void *, size_t); | |
static void handle_sigsys(int, siginfo_t *, void *); | |
static void find_glibc_bounds(size_t *, size_t *); | |
const int test_type = 0; | |
#define SYSCALL_DISPATCH_ON(x) ((x) = SYSCALL_DISPATCH_FILTER_BLOCK) | |
#define SYSCALL_DISPATCH_OFF(x) ((x) = SYSCALL_DISPATCH_FILTER_ALLOW) | |
extern char __executable_start; | |
extern char __etext; | |
static int8_t g_sel = SYSCALL_DISPATCH_FILTER_BLOCK; | |
static const char *const msg_glibc = "Write syscall GLIBC\n"; | |
static const char *const msg_mine = "Write syscall ME\n"; | |
#define CBUF_LEN 256 | |
char cbuf[CBUF_LEN]; | |
int main(int argc, char *argv[]) { | |
int test_type = 1; | |
if (argc == 2) | |
test_type = atoi(argv[1]); | |
else | |
exit(-1); | |
long ret; | |
setup_sigsys_handler(); | |
unsigned long exec_start = (unsigned long)&__executable_start; | |
unsigned long exec_end = (unsigned long)&__etext; | |
unsigned long glibc_start, glibc_end; | |
find_glibc_bounds(&glibc_start, &glibc_end); | |
unsigned long sud_offset = 0, sud_size = 0; | |
switch (test_type) { | |
case 0: // Exclude Me | |
sud_offset = exec_start; | |
const size_t lmt = 101258; // NOTE: found by binary search by hand, lol! | |
sud_size = glibc_start - exec_start + lmt; | |
break; | |
case 2: // Include Everyone ???? ask Ryan | |
// sud_offset = 101257; // TODO: this doesn't work | |
case 1: // Exclude Glibc | |
sud_offset += glibc_start; | |
sud_size = glibc_end - glibc_start; | |
} | |
SYSCALL_DISPATCH_OFF(g_sel); | |
ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, sud_offset, | |
sud_size, &g_sel); | |
assert(ret == 0); | |
// clang-format off | |
SYSCALL_DISPATCH_ON(g_sel); | |
write (1, msg_glibc, strlen(msg_glibc)); | |
mywrite(1, msg_mine, strlen(msg_mine) ); | |
write (1, msg_glibc, strlen(msg_glibc)); | |
mywrite(1, msg_mine, strlen(msg_mine) ); | |
write (1, msg_glibc, strlen(msg_glibc)); | |
// clang-format on | |
SYSCALL_DISPATCH_OFF(g_sel); | |
ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_OFF, 0, 0, NULL); | |
assert(ret == 0); | |
return 0; | |
} | |
static void setup_sigsys_handler() { | |
long ret; | |
struct sigaction act; | |
sigset_t mask; | |
memset(&act, 0, sizeof(act)); | |
sigemptyset(&mask); | |
act.sa_sigaction = handle_sigsys; | |
act.sa_flags = SA_SIGINFO; //| SA_NODEFER; | |
act.sa_mask = mask; | |
ret = sigaction(SIGSYS, &act, NULL); | |
if (ret != 0) { | |
perror("sigaction"); | |
exit(-1); | |
} | |
} | |
static void find_glibc_bounds(size_t *start, size_t *end) { | |
assert(end && start); | |
// find the memory region which loads the glibc | |
FILE *f = fopen("/proc/self/maps", "r"); | |
if (!f) { | |
perror("fopen"); | |
exit(1); | |
} | |
char buf[4096]; | |
while (fgets(buf, sizeof(buf), f)) { | |
unsigned long st, en; | |
char mode[5]; | |
unsigned long offset; | |
char device[8]; | |
char inode[12]; | |
char path[256]; | |
int ret; | |
#ifdef PRINT_MAPPING | |
printf("%s", buf); | |
#endif | |
if ((ret = sscanf(buf, "%lx-%lx %4s %lx %7s %11s %255s\n", &st, &en, mode, | |
&offset, device, inode, path)) == EOF) { | |
fprintf(stderr, "parse /proc/self/maps failed\n"); | |
exit(1); | |
} | |
// found the text section of glibc | |
if (strcmp(path, GLIBC_PATH) == 0 && strcmp(mode, "r-xp") == 0) { | |
*start = st; | |
*end = en; | |
} | |
} | |
fclose(f); | |
if (!*start || !*end) { | |
fprintf(stderr, "glibc not loaded!\n"); | |
exit(0); | |
} | |
} | |
inline static ssize_t mywrite(int fd, const void *buf, size_t size) { | |
ssize_t ret; | |
asm volatile("syscall" | |
: "=a"(ret) | |
// EDI RSI RDX | |
: "0"(__NR_write), "D"(fd), "S"(buf), "d"(size) | |
: "rcx", "r11", "memory"); | |
return ret; | |
} | |
static size_t syswrite(int fd, const void *buf, int len) { | |
snprintf(cbuf, CBUF_LEN, | |
"{ " | |
"write %d, %p, %d\n\t", | |
fd, buf, len); | |
write(2, cbuf, strlen(cbuf)); | |
size_t ret = write(fd, buf, len); | |
snprintf(cbuf, CBUF_LEN, " syswrite ret: %zu\n}\n", ret); | |
write(2, cbuf, strlen(cbuf)); | |
return ret; | |
} | |
static __attribute__((no_stack_protector)) void | |
handle_sigsys(int signum, siginfo_t *info, void *context) { | |
if (signum != SIGSYS) { | |
exit(-3); | |
} | |
SYSCALL_DISPATCH_OFF(g_sel); | |
ucontext_t *uctx = context; | |
mcontext_t *mctx = &uctx->uc_mcontext; | |
greg_t *greg = mctx->gregs; | |
// good luck if you don't know asm | |
greg[REG_RAX] = syswrite((int)greg[REG_RDI], (const void *)greg[REG_RSI], | |
(size_t)greg[REG_RDX]); | |
SYSCALL_DISPATCH_ON(g_sel); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment