Skip to content

Instantly share code, notes, and snippets.

@qookei
Last active May 18, 2022 21:11
Show Gist options
  • Select an option

  • Save qookei/5d8916c4ca77f77c8b2cbb268d9380a3 to your computer and use it in GitHub Desktop.

Select an option

Save qookei/5d8916c4ca77f77c8b2cbb268d9380a3 to your computer and use it in GitHub Desktop.
C with "classes"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#define __USE_GNU
#include <signal.h>
#include <ucontext.h>
#define OBJ_MAGIC_HIGH 0xDEADBEEF00000000
#define OBJ_MAGIC_MASK 0xFFFFFFFF00000000
#define FOO_OBJ_ID 1
#define BAR_OBJ_ID 2
struct foo {
// impl detail
uint64_t obj_magic__;
int (*swap_i)(int i);
void (*log_self)();
// impl detail
char swap_i_call_impl__[8];
char log_self_call_impl__[8];
// member values
int i;
};
struct bar {
// impl detail
uint64_t obj_magic__;
void (*log_foo)(struct foo *f);
void (*log_self)();
// impl detail
char log_foo_call_impl__[8];
char log_self_call_impl__[8];
// member values
const char *name;
};
int foo_swap_i_impl(struct foo *this, int i) {
int old_i = this->i;
this->i = i;
return old_i;
}
void foo_log_self_impl(struct foo *this) {
printf("Hello this is [struct foo %p], my i is %d\n", this, this->i);
}
void bar_log_foo_impl(struct bar *this, struct foo *foo) {
printf("Hello this is [struct bar %p], named '%s', given foo says:\n\t", this, this->name);
foo->log_self();
}
void bar_log_self_impl(struct bar *this) {
printf("Hello this is [struct bar %p], named '%s'\n", this, this->name);
}
struct foo *new_foo() {
struct foo *f = malloc(sizeof(struct foo));
f->obj_magic__ = OBJ_MAGIC_HIGH + FOO_OBJ_ID;
f->swap_i_call_impl__[0] = 0x0f; // | ud2
f->swap_i_call_impl__[1] = 0x0b; // /
f->swap_i = (int(*)(int))f->swap_i_call_impl__;
f->log_self_call_impl__[0] = 0x0f; // | ud2
f->log_self_call_impl__[1] = 0x0b; // /
f->log_self = (void(*)())f->log_self_call_impl__;
f->i = 0;
// memory barrier to prevent initialization being moved after
// member function calls at -O3
asm volatile ("" : "+m"(*f) :: "memory");
return f;
}
struct bar *new_bar() {
struct bar *f = malloc(sizeof(struct bar));
f->obj_magic__ = OBJ_MAGIC_HIGH + BAR_OBJ_ID;
f->log_foo_call_impl__[0] = 0x0f; // | ud2
f->log_foo_call_impl__[1] = 0x0b; // /
f->log_foo = (void(*)(struct foo *))f->log_foo_call_impl__;
f->log_self_call_impl__[0] = 0x0f; // | ud2
f->log_self_call_impl__[1] = 0x0b; // /
f->log_self = (void(*)(int))f->log_self_call_impl__;
f->name = "Unnamed";
// memory barrier to prevent initialization being moved after
// member function calls at -O3
asm volatile ("" : "+m"(*f) :: "memory");
return f;
}
static void impl_sig_handler(int sig, siginfo_t *si, void *ctx) {
ucontext_t *uctx = ctx;
if (sig == SIGSEGV) {
if (!(uctx->uc_mcontext.gregs[REG_ERR] & (1 << 4)))
// Not an instruction fetch fault
goto err;
}
uint64_t fault_ptr = (uint64_t)si->si_addr;
if (fault_ptr & 7)
goto err;
uint64_t *search_ptr = (uint64_t *)fault_ptr;
void *base = NULL;
// Limit search depth to 800 bytes
for (int i = 0; i < 100; i++) {
if ((*search_ptr & OBJ_MAGIC_MASK) == OBJ_MAGIC_HIGH) {
base = search_ptr;
break;
}
search_ptr--;
}
if (!base)
goto err;
uint32_t object_id = *search_ptr & ~OBJ_MAGIC_MASK;
uint64_t method_offset = fault_ptr - (uint64_t)base;
int was_resolved = 1;
switch (object_id) {
case FOO_OBJ_ID: {
switch (method_offset) {
case offsetof(struct foo, swap_i_call_impl__): {
uctx->uc_mcontext.gregs[REG_RIP] = (uint64_t)foo_swap_i_impl;
uctx->uc_mcontext.gregs[REG_RSI] = uctx->uc_mcontext.gregs[REG_RDI];
uctx->uc_mcontext.gregs[REG_RDI] = (uint64_t)base;
} break;
case offsetof(struct foo, log_self_call_impl__): {
uctx->uc_mcontext.gregs[REG_RIP] = (uint64_t)foo_log_self_impl;
uctx->uc_mcontext.gregs[REG_RDI] = (uint64_t)base;
} break;
default:
was_resolved = 0;
}
} break;
case BAR_OBJ_ID: {
switch (method_offset) {
case offsetof(struct bar, log_foo_call_impl__): {
uctx->uc_mcontext.gregs[REG_RIP] = (uint64_t)bar_log_foo_impl;
uctx->uc_mcontext.gregs[REG_RSI] = uctx->uc_mcontext.gregs[REG_RDI];
uctx->uc_mcontext.gregs[REG_RDI] = (uint64_t)base;
} break;
case offsetof(struct bar, log_self_call_impl__): {
uctx->uc_mcontext.gregs[REG_RIP] = (uint64_t)bar_log_self_impl;
uctx->uc_mcontext.gregs[REG_RDI] = (uint64_t)base;
} break;
default:
was_resolved = 0;
}
} break;
default:
was_resolved = 0;
}
if (!was_resolved) {
err:
signal(sig, SIG_DFL);
}
}
void setup_runtime() {
struct sigaction s;
s.sa_flags = SA_SIGINFO;
s.sa_sigaction = impl_sig_handler;
sigemptyset(&s.sa_mask);
sigaction(SIGSEGV, &s, 0);
sigaction(SIGILL, &s, 0);
}
int main() {
setup_runtime();
struct foo *f = new_foo();
struct bar *b = new_bar();
f->swap_i(32);
f->log_self();
b->log_self();
b->log_foo(f);
b->name = "Named bar";
b->log_self();
b->log_foo(f);
free(f);
free(b);
}
@StaticSaga
Copy link
Copy Markdown

no.

@Frityet
Copy link
Copy Markdown

Frityet commented May 18, 2022

holy shit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment