Skip to content

Instantly share code, notes, and snippets.

@alifarazz
Created August 26, 2024 19:10
Show Gist options
  • Save alifarazz/a0e28369d8683b711fc9eb816fca3c78 to your computer and use it in GitHub Desktop.
Save alifarazz/a0e28369d8683b711fc9eb816fca3c78 to your computer and use it in GitHub Desktop.
#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