ps5-kstuff: add "run in foreign process" kekcall

Also adds support for arbitrary mprotect & mdbg_call without creds.
This commit is contained in:
Sergey Lisov committed 2023-08-21 01:16:40 +03:00
1 parent 2dc99448fb
commit d0cdc83e8a
11 files changed
+151 -46

No files matched your search

+25
View File
@@ -696,6 +696,7 @@ void* mmap20(void* addr, size_t sz, int prot, int flags, int fd, off_t offset)
static uint64_t sys_write;
static uint64_t sys_sigaction;
static uint64_t sys_mdbg_call;
static void fix_sigaction_17_9(uint64_t* regs)
{
@@ -763,6 +764,30 @@ int get_self_auth_info_20(const char* path, void* buf)
return 0;
}
static void fix_mdbg_call(uint64_t* regs)
{
SKIP_SCHEDULER
if(regs[0] == sys_write)
regs[0] = sys_mdbg_call;
else if(regs[0] == kdata_base - 0x631ea9)
regs[5] = 1;
}
int mdbg_call_20(void* a, void* b, void* c)
{
r0gdb_instrument(0);
int(*p_write)(void*, void*, void*) = dlsym((void*)0x2001, "_write");
trace_prog = fix_mdbg_call;
if(!sys_write)
kmemcpy(&sys_write, (void*)(kdata_base + 0x1709c0 + 48*SYS_write + 8), 8);
if(!sys_mdbg_call)
kmemcpy(&sys_mdbg_call, (void*)(kdata_base + 0x1709c0 + 48*573 + 8), 8);
set_trace();
int ans = p_write(a, b, c);
trace_prog = 0;
return ans;
}
static uint64_t fncall_fn = 0;
static uint64_t fncall_args[6];
static uint64_t fncall_ans = 0;
+3
View File
@@ -70,6 +70,9 @@ int sigaction20(int sig, const struct sigaction* neww, struct sigaction* oldd);
//get_self_auth_info that works
int get_self_auth_info_20(const char* path, void* buf);
//mdbg_call that works
int mdbg_call_20(void* a, void* b, void* c);
//kernel function call
uint64_t r0gdb_kfncall(uint64_t kfn, ...);
+1 -1
View File
@@ -33,4 +33,4 @@ uelf/crt.o: uelf/crt.asm
yasm uelf/crt.asm -f elf64 -o uelf/crt.o
uelf/uelf: uelf/*.c uelf/*.h structs.h uelf/crt.o
gcc -Wl,-Bsymbolic -O0 -g -isystem ../freebsd-headers -nostdinc -nostdlib -mgeneral-regs-only -fno-stack-protector -fPIE -fPIC -shared -ffreestanding -fno-builtin uelf/crt.o uelf/*.c -o uelf/uelf
gcc -Wl,-Bsymbolic -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 -g -isystem ../freebsd-headers -nostdinc -nostdlib -mgeneral-regs-only -fno-stack-protector -fPIE -fPIC -shared -ffreestanding -fno-builtin uelf/crt.o uelf/*.c -o uelf/uelf
+1 -1
View File
@@ -19,7 +19,7 @@ uelf/crt.o: uelf/crt.asm
yasm uelf/crt.asm -f elf64 -o uelf/crt.o
uelf/uelf: uelf/*.c uelf/*.h structs.h uelf/crt.o
gcc -Wl,-zmax-page-size=4096 -Wl,-Bsymbolic -O0 -g -DFREEBSD -std=gnu11 -nostdlib -fno-stack-protector -fPIE -fPIC -shared -ffreestanding -fno-builtin uelf/crt.o uelf/*.c -o uelf/uelf
gcc -Wl,-zmax-page-size=4096 -Wl,-Bsymbolic -Wl,-gc-sections -ffunction-sections -fdata-sections -O0 -g -DFREEBSD -std=gnu11 -nostdlib -fno-stack-protector -fPIE -fPIC -shared -ffreestanding -fno-builtin uelf/crt.o uelf/*.c -o uelf/uelf
freebsd-loader: uelf/uelf kelf freebsd-loader.c
gcc -O0 -g -std=gnu11 freebsd-loader.c -mno-red-zone -o freebsd-loader
+1
View File
@@ -7,3 +7,4 @@ Calls:
* rax = 0x100000027, rdi = X -> copy dr0-dr3 and dr6-dr7 to user address X
* rax = 0x200000027, rdi = X -> copy dr0-dr3 and dr6-dr7 from user address X
* rax = 0x300000027, rdi = X -> returns rdmsr(X)
* rax = 0x500000027, rdi = pid, rsi = syscno, rdx = X -> call syscall in foreign process, with args read from user address X
+8
View File
@@ -322,9 +322,12 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
"loadSelfSegment_epilogue"+zero,
"loadSelfSegment_watchpoint"+zero,
"loadSelfSegment_watchpoint_lr"+zero,
"mdbg_call_fix"+zero,
"mini_syscore_header"+zero,
"mov_cr3_rax"+zero,
"mov_rdi_cr3"+zero,
"mprotect_fix_start"+zero,
"mprotect_fix_end"+zero,
"nop_ret"+zero,
".pcpu"+zero,
"pop_all_except_rdi_iret"+zero,
@@ -375,9 +378,12 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
kdata_base - 0x8a54cd, // loadSelfSegment_epilogue
kdata_base - 0x2cc918, // loadSelfSegment_watchpoint
kdata_base - 0x8a5727, // loadSelfSegment_watchpoint_lr
kdata_base - 0x631ea9, // mdbg_call_fix
kdata_base + 0xdc16e8, // mini_syscore_header
kdata_base - 0x396f9e, // mov_cr3_rax
kdata_base - 0x39700e, // mov_rdi_cr3
kdata_base - 0x90ac61, // mprotect_fix_start
kdata_base - 0x90ac5b, // mprotect_fix_end
kdata_base - 0x28a3a0, // nop_ret
0x1234, // .pcpu
kdata_base - 0x9cf8a7, // pop_all_except_rdi_iret
@@ -455,6 +461,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
kelf_bases[cpu] = (uint64_t)kelf;
kelf_entries[cpu] = (uint64_t)entry;
}
r0gdb_wrmsr(0xc0000084, r0gdb_rdmsr(0xc0000084) | 0x100);
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done loading\npatching idt... ", (uintptr_t)29);
uint64_t cr3 = r0gdb_read_cr3();
for(int cpu = 0; cpu < NCPUS; cpu++)
@@ -482,6 +489,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
struct sigaction sa;
sigaction(SIGBUS, 0, &sa);
sigaction(SIGTRAP, &sa, 0);
copyin(IDT+16*179+5, "\x89", 1);
asm volatile("ud2");
return 0;
}
+3
View File
@@ -19,9 +19,12 @@
%define iret_rsp (iret_rip+24)
%define iret_ss (iret_rip+32)
%define td_proc 8
%define td_pcb 0x3f8
%define td_retval 0x408
%define p_pid 0xbc
%define pcb_gsbase 0x48
%define pcb_flags 0x100
+61 -9
View File
@@ -1,20 +1,24 @@
#include <errno.h>
#include <sys/sysent.h>
#include <string.h>
#include "kekcall.h"
#include "traps.h"
#include "utils.h"
extern char syscall_after[];
extern char doreti_iret[];
extern char nop_ret[];
extern char copyout[];
extern char copyin[];
extern struct sysent sysents[];
int handle_kekcall(uint64_t* regs, uint64_t* args, uint32_t nr)
{
if(nr == 1)
{
uint64_t stack_frame[13] = {
uint64_t stack_frame[12] = {
(uint64_t)doreti_iret,
(uint64_t)syscall_after, regs[CS], regs[EFLAGS], regs[RSP], regs[SS],
(uint64_t)nop_ret, regs[CS], regs[EFLAGS], regs[RSP], regs[SS],
};
read_dbgregs(stack_frame+6);
if(!get_pcb_dbregs())
@@ -28,24 +32,33 @@ int handle_kekcall(uint64_t* regs, uint64_t* args, uint32_t nr)
regs[RSI] = args[RDI];
regs[RDX] = 48;
regs[RIP] = (uint64_t)copyout;
return ENOSYS;
}
else if(nr == 2)
{
uint64_t stack_frame[13] = {(uint64_t)doreti_iret, MKTRAP(TRAP_KEKCALL, 1), [12] = regs[RDI]};
uint64_t stack_frame[14] = {(uint64_t)doreti_iret, MKTRAP(TRAP_KEKCALL, 1), [12] = regs[RDI]};
push_stack(regs, stack_frame, sizeof(stack_frame));
regs[RDI] = args[RDI];
regs[RSI] = regs[RSP] + 48;
regs[RDX] = 48;
regs[RIP] = (uint64_t)copyin;
return ENOSYS;
}
else if(nr == 3)
{
return rdmsr(args[RDI], &args[RAX]) ? 0 : EFAULT;
}
else if(nr == 0x42)
regs[CS] |= 1;
//nr 4 reserved for wrmsr
else if(nr == 5)
{
uint64_t stack_frame[16] = {(uint64_t)doreti_iret, MKTRAP(TRAP_KEKCALL, 2)};
stack_frame[6] = args[RDI];
stack_frame[7] = args[RSI];
stack_frame[14] = regs[RDI];
push_stack(regs, stack_frame, sizeof(stack_frame));
regs[RDI] = args[RDX];
regs[RSI] = regs[RSP] + 64;
regs[RDX] = 48;
regs[RIP] = (uint64_t)copyin;
}
else if(nr == 0xffffffff)
{
args[RAX] = 0;
@@ -58,13 +71,52 @@ void handle_kekcall_trap(uint64_t* regs, uint32_t trap)
{
if(trap == 1)
{
uint64_t stack_frame[12];
uint64_t stack_frame[14];
pop_stack(regs, stack_frame, sizeof(stack_frame));
regs[RIP] = (uint64_t)syscall_after;
regs[RIP] = stack_frame[13];
if((uint32_t)regs[RAX])
return;
kpoke64(stack_frame[11]+td_retval, 0);
set_pcb_dbregs();
write_dbgregs(stack_frame+5);
}
else if(trap == 2)
{
uint64_t stack_frame[15];
pop_stack(regs, stack_frame, sizeof(stack_frame));
if((uint32_t)regs[RAX])
{
pop_stack(regs, regs+RIP, 8);
return;
}
uint32_t pid = stack_frame[5];
uint32_t sysc_no = stack_frame[6];
int64_t proc = kpeek64(stack_frame[13]+td_proc);
while(proc < -0x100000000)
proc = kpeek64(proc+8);
while(proc && (uint32_t)kpeek64(proc+p_pid) != pid)
proc = kpeek64(proc);
if(!proc)
{
regs[RAX] = ESRCH;
pop_stack(regs, regs+RIP, 8);
return;
}
regs[RDI] = kpeek64(proc+16);
uint64_t stack_frame_2[14] = {(uint64_t)doreti_iret, MKTRAP(TRAP_KEKCALL, 3), [6] = stack_frame[13], regs[RDI]};
memcpy(stack_frame_2+8, stack_frame+7, 48);
push_stack(regs, stack_frame_2, sizeof(stack_frame_2));
regs[RAX] = (uint64_t)&sysents[sysc_no];
regs[RIP] = kpeek64((uint64_t)&sysents[sysc_no].sy_call);
regs[RSI] = regs[RSP] + 64;
handle_syscall(regs, 0);
}
else if(trap == 3)
{
uint64_t stack_frame[14];
pop_stack(regs, stack_frame, sizeof(stack_frame));
if(!(uint32_t)regs[RAX])
kpoke64(stack_frame[5]+td_retval, kpeek64(stack_frame[6]+td_retval));
regs[RIP] = stack_frame[13];
}
}
+45 -31
View File
@@ -11,6 +11,7 @@
#include "traps.h"
#include "kekcall.h"
#include "fself.h"
#include "syscall_fixes.h"
int have_error_code;
@@ -25,6 +26,44 @@ extern char int1_handler[];
extern char int13_handler[];
extern uint64_t wrmsr_args;
void handle_syscall(uint64_t* regs, int allow_kekcall)
{
#define IS_PPR(which) (regs[RAX] == (uint64_t)&sysents[SYS_##which])
#ifdef FREEBSD
#define IS_PS4(which) 0
#else
#define IS_PS4(which) (regs[RAX] == (uint64_t)&sysents2[SYS_##which])
#endif
#define IS(which) (IS_PPR(which) || IS_PS4(which))
if(IS_PPR(getppid) && allow_kekcall)
{
uint64_t args[NREGS] = {0};
copy_from_kernel(args, regs[RSP]+syscall_rsp_to_regs_stash+8, sizeof(args));
int err = handle_kekcall(regs, args, args[RAX]>>32);
if(err != ENOSYS)
{
if(!err)
kpoke64(regs[RDI]+td_retval, args[RAX]);
regs[RAX] = err;
pop_stack(regs, regs+RIP, 8);
}
}
#ifndef FREEBSD
else if(IS(execve)
|| IS(dynlib_load_prx)
|| IS(get_self_auth_info)
|| IS(get_sdk_compiled_version)
|| IS_PPR(get_ppr_sdk_compiled_version))
handle_fself_syscall(regs);
else if(IS(mprotect)
|| IS_PPR(mdbg_call))
handle_syscall_fix(regs);
#endif
#undef IS
#undef IS_PS4
#undef IS_PPR
}
void handle(uint64_t* regs)
{
if(!(regs[CS] & 3))
@@ -76,37 +115,10 @@ from_userspace:
else if(regs[RIP] == (uint64_t)syscall_before)
{
regs[RAX] |= 0xffffull << 48;
#define IS_PPR(which) (regs[RAX] == (uint64_t)&sysents[SYS_##which])
#ifdef FREEBSD
#define IS_PS4(which) 0
#else
#define IS_PS4(which) (regs[RAX] == (uint64_t)&sysents2[SYS_##which])
#endif
#define IS(which) (IS_PPR(which) || IS_PS4(which))
if(IS_PPR(getppid))
{
uint64_t args[NREGS] = {0};
copy_from_kernel(args, regs[RSP]+syscall_rsp_to_regs_stash, sizeof(args));
int err = handle_kekcall(regs, args, args[RAX]>>32);
if(err != ENOSYS)
{
if(!err)
kpoke64(regs[RDI]+td_retval, args[RAX]);
regs[RAX] = err;
regs[RIP] = (uint64_t)syscall_after;
}
}
#ifndef FREEBSD
else if(IS(execve)
|| IS(dynlib_load_prx)
|| IS(get_self_auth_info)
|| IS(get_sdk_compiled_version)
|| IS_PPR(get_ppr_sdk_compiled_version))
handle_fself_syscall(regs);
#endif
#undef IS
#undef IS_PS4
#undef IS_PPR
regs[RSI] = regs[RSP] + syscall_rsp_to_rsi;
push_stack(regs, (const uint64_t[1]){(uint64_t)syscall_after}, 8);
regs[RIP] = kpeek64(regs[RAX]+8);
handle_syscall(regs, 1);
}
else if(regs[RIP] == (uint64_t)doreti_iret)
{
@@ -134,6 +146,8 @@ from_userspace:
return;
else if(handle_fself_parasites(regs))
return;
else if(try_handle_syscall_fix_trap(regs))
return;
#endif
else
{
+2 -4
View File
@@ -151,8 +151,7 @@ int wrmsr(uint32_t which, uint64_t value)
void start_syscall_with_dbgregs(uint64_t* regs, const uint64_t* dbgregs)
{
regs[RSI] = regs[RSP] + syscall_rsp_to_rsi;
uint64_t stack_frame[13] = {
uint64_t stack_frame[12] = {
(uint64_t)doreti_iret,
MKTRAP(TRAP_UTILS, 1), 0, 0, 0, 0,
};
@@ -160,7 +159,6 @@ void start_syscall_with_dbgregs(uint64_t* regs, const uint64_t* dbgregs)
push_stack(regs, stack_frame, sizeof(stack_frame));
set_pcb_dbregs();
write_dbgregs(dbgregs);
regs[RIP] = kpeek64(regs[RAX] + 8);
}
void handle_utils_trap(uint64_t* regs, uint32_t trapno)
@@ -170,6 +168,6 @@ void handle_utils_trap(uint64_t* regs, uint32_t trapno)
uint64_t stack_frame[12];
pop_stack(regs, stack_frame, sizeof(stack_frame));
write_dbgregs(stack_frame+5);
regs[RIP] = (uint64_t)syscall_after;
regs[RIP] = stack_frame[11];
}
}
+1
View File
@@ -17,6 +17,7 @@ void read_dbgregs(uint64_t* dr);
void write_dbgregs(const uint64_t* dr);
void start_syscall_with_dbgregs(uint64_t* regs, const uint64_t* dbgregs);
void handle_utils_trap(uint64_t* regs, uint32_t trapno);
void handle_syscall(uint64_t* regs, int allow_kekcall);
int rdmsr(uint32_t which, uint64_t* ans);
int wrmsr(uint32_t which, uint64_t value);