diff --git a/.gitmodules b/.gitmodules index 59680eb..4637bf0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,9 @@ [submodule "linux/ps4-kexec-900"] path = linux/ps4-kexec-900 url = https://github.com/sleirsgoevy/ps4-kexec +[submodule "ps5-kstuff/BearSSL"] + path = ps5-kstuff/BearSSL + url = https://www.bearssl.org/git/BearSSL +[submodule "ps5-kstuff/libtomcrypt"] + path = ps5-kstuff/libtomcrypt + url = https://github.com/libtom/libtomcrypt diff --git a/ps5-kstuff/BearSSL b/ps5-kstuff/BearSSL new file mode 160000 index 0000000..79c060e --- /dev/null +++ b/ps5-kstuff/BearSSL @@ -0,0 +1 @@ +Subproject commit 79c060eea3eea1257797f15ea1608a9a9923aa6f diff --git a/ps5-kstuff/Makefile b/ps5-kstuff/Makefile index 0d1fd4c..abfb161 100644 --- a/ps5-kstuff/Makefile +++ b/ps5-kstuff/Makefile @@ -32,5 +32,11 @@ structs.h: structs.inc 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 -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 +uelf/uelf: uelf/*.c uelf/*.h structs.h uelf/crt.o BearSSL/build/libbearssl.a libtomcrypt/libtomcrypt.a + 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 -fvisibility=hidden -ffreestanding uelf/crt.o uelf/*.c -L BearSSL/build -lbearssl -L libtomcrypt -ltomcrypt -o uelf/uelf + +BearSSL/build/libbearssl.a: build_bearssl.sh overrides.h + bash build_bearssl.sh + +libtomcrypt/libtomcrypt.a: build_libtomcrypt.sh overrides.h + bash build_libtomcrypt.sh diff --git a/ps5-kstuff/build_bearssl.sh b/ps5-kstuff/build_bearssl.sh new file mode 100644 index 0000000..c87ef61 --- /dev/null +++ b/ps5-kstuff/build_bearssl.sh @@ -0,0 +1,2 @@ +cd BearSSL +for i in clean "lib -j$(nproc)"; do make CC='gcc -nostdlib -nostdinc -isystem /proc/'$$'/cwd/../../freebsd-headers -isystem /nix/store/b7hvml0m3qmqraz1022fwvyyg6fc1vdy-gcc-12.2.0/lib/gcc/x86_64-unknown-linux-gnu/12.2.0/include -O0 -g -ffreestanding -mgeneral-regs-only -ffunction-sections -fdata-sections -fvisibility=hidden -include /proc/'$$'/cwd/../overrides.h' $i; done diff --git a/ps5-kstuff/build_libtomcrypt.sh b/ps5-kstuff/build_libtomcrypt.sh new file mode 100644 index 0000000..0164852 --- /dev/null +++ b/ps5-kstuff/build_libtomcrypt.sh @@ -0,0 +1,2 @@ +cd libtomcrypt +for i in clean -j$(nproc); do make CC='gcc -nostdlib -nostdinc -isystem /proc/'$$'/cwd/../../freebsd-headers -isystem /nix/store/b7hvml0m3qmqraz1022fwvyyg6fc1vdy-gcc-12.2.0/lib/gcc/x86_64-unknown-linux-gnu/12.2.0/include -O0 -g -ffreestanding -mgeneral-regs-only -ffunction-sections -fdata-sections -fPIE -fPIC -fvisibility=hidden -include /proc/'$$'/cwd/../overrides.h' $i; done diff --git a/ps5-kstuff/libtomcrypt b/ps5-kstuff/libtomcrypt new file mode 160000 index 0000000..b96e96c --- /dev/null +++ b/ps5-kstuff/libtomcrypt @@ -0,0 +1 @@ +Subproject commit b96e96cf8b22a931e8e91098ac37bc72f9e2f033 diff --git a/ps5-kstuff/main.c b/ps5-kstuff/main.c index c0634e2..4f83fc4 100644 --- a/ps5-kstuff/main.c +++ b/ps5-kstuff/main.c @@ -202,11 +202,14 @@ extern char uek_end[]; asm(".section .text\nkekcall:\nmov 8(%rsp), %rax\njmp *p_kekcall(%rip)"); -int kekcall(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f, uint64_t nr); +uint64_t kekcall(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f, uint64_t nr); -#define KEKCALL_GETPPID 0x000000027 -#define KEKCALL_READ_DR 0x100000027 -#define KEKCALL_WRITE_DR 0x200000027 +#define KEKCALL_GETPPID 0x000000027 +#define KEKCALL_READ_DR 0x100000027 +#define KEKCALL_WRITE_DR 0x200000027 +#define KEKCALL_RDMSR 0x300000027 +#define KEKCALL_REMOTE_SYSCALL 0x500000027 +#define KEKCALL_CHECK 0xffffffff00000027 void* p_kekcall; void* dlsym(void*, const char*); @@ -276,7 +279,6 @@ void build_uelf_cr3(uint64_t uelf_cr3, void* uelf_base[2]) int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) { r0gdb_init(ds, a, b, c, d); - dbg_enter(); uint64_t percpu_ist4[NCPUS]; for(int cpu = 0; cpu < NCPUS; cpu++) copyout(&percpu_ist4[cpu], TSS(cpu)+28+4*8, 8); @@ -286,6 +288,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) uint64_t int13_handler; copyout(&int13_handler, IDT+16*13, 2); copyout((char*)&int13_handler + 2, IDT+16*13+6, 6); + dbg_enter(); gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"allocating kernel memory... ", (uintptr_t)28); for(int i = 0; i < 0x300; i += 2) r0gdb_kmalloc(0x100); @@ -296,11 +299,16 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) mem_blocks[i+1] = (mem_blocks[i] ? mem_blocks[i] + (1<<23) : 0); } gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\n", (uintptr_t)5); + uint64_t shared_area = (uint64_t)kmalloc(8192); + shared_area = ((shared_area - 1) | 4095) + 1; + kmemzero((void*)shared_area, 4096); + shared_area = virt2phys(shared_area) + (1ull << 39); volatile int zero = 0; //hack to force runtime calculation of string pointers const char* symbols[] = { "add_rsp_iret"+zero, "copyin"+zero, "copyout"+zero, + "crypt_message_resolve"+zero, "decryptSelfBlock_epilogue"+zero, "decryptSelfBlock_watchpoint"+zero, "decryptSelfBlock_watchpoint_lr"+zero, @@ -336,11 +344,13 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) "rdmsr_end"+zero, "rdmsr_start"+zero, "rep_movsb_pop_rbp_ret"+zero, + "sceSblServiceCryptAsync_deref_singleton"+zero, "sceSblServiceIsLoadable2"+zero, "sceSblServiceMailbox"+zero, "sceSblServiceMailbox_lr_decryptSelfBlock"+zero, "sceSblServiceMailbox_lr_loadSelfSegment"+zero, "sceSblServiceMailbox_lr_verifyHeader"+zero, + "shared_area"+zero, "soo_ioctl"+zero, "syscall_after"+zero, "syscall_before"+zero, @@ -357,6 +367,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) kdata_base - 0x9cf853, // add_rsp_iret kdata_base - 0x9908e0, // copyin kdata_base - 0x990990, // copyout + kdata_base - 0x479d60, // crypt_message_resolve kdata_base - 0x8a52c3, // decryptSelfBlock_epilogue kdata_base - 0x2cc88e, // decryptSelfBlock_watchpoint kdata_base - 0x8a538a, // decryptSelfBlock_watchpoint_lr @@ -392,11 +403,13 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) kdata_base - 0x9d6cf9, // rdmsr_end kdata_base - 0x9d6d02, // rdmsr_start kdata_base - 0x990a55, // rep_movsb_pop_rbp_ret + kdata_base - 0x8ed902, // sceSblServiceCryptAsync_deref_singleton kdata_base - 0x8a5c40, // sceSblServiceIsLoadable2 kdata_base - 0x6824c0, // sceSblServiceMailbox kdata_base - 0x8a5014, // sceSblServiceMailbox_lr_decryptSelfBlock kdata_base - 0x8a5541, // sceSblServiceMailbox_lr_loadSelfSegment kdata_base - 0x8a58bc, // sceSblServiceMailbox_lr_verifyHeader + shared_area, // shared_area kdata_base - 0x96eb98, // soo_ioctl kdata_base - 0x8022ee, // syscall_after kdata_base - 0x802311, // syscall_before @@ -424,6 +437,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) uint64_t uelf_bases[NCPUS]; uint64_t kelf_bases[NCPUS]; uint64_t kelf_entries[NCPUS]; + uint64_t uelf_cr3s[NCPUS]; for(int cpu = 0; cpu < NCPUS; cpu++) { char buf[] = "loading on cpu ..\n"; @@ -451,6 +465,7 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) char* uelf = load_kelf(uek, symbols, values, uelf_base, &uelf_entry, 0x400000); uintptr_t uelf_cr3 = (uintptr_t)kmalloc(24576); uelf_cr3 = ((uelf_cr3 + 4095) | 4095) - 4095; + uelf_cr3s[cpu] = uelf_cr3; values[uelf_cr3_idx] = virt2phys(uelf_cr3); values[uelf_entry_idx] = (uintptr_t)uelf_entry - (uintptr_t)uelf_base[0] + 0x400000; void* entry = 0; @@ -480,16 +495,343 @@ int main(void* ds, int a, int b, uintptr_t c, uintptr_t d) kmemcpy((char*)(IDT+16*2), (char*)&iret, 2); kmemcpy((char*)(IDT+16*2+6), (char*)&iret+2, 6); //kmemzero((char*)(IDT+16*1), 16); - gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\npatching sysentvec... ", (uintptr_t)27); - copyin(kdata_base + 0xd11bb8 + 14, &(const uint16_t[1]){0xdeb7}, 2); - copyin(kdata_base + 0xd11d30 + 14, &(const uint16_t[1]){0xdeb7}, 2); + gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\napplying kdata patches... ", (uintptr_t)31); + copyin(kdata_base + 0xd11bb8 + 14, &(const uint16_t[1]){0xdeb7}, 2); //native sysentvec + copyin(kdata_base + 0xd11d30 + 14, &(const uint16_t[1]){0xdeb7}, 2); //ps4 sysentvec + copyin(kdata_base + 0x2e31830 + 11*8 + 2*8 + 6, &(const uint16_t[1]){0xdeb7}, 2); //crypt xts + copyin(kdata_base + 0x2e31830 + 11*8 + 9*8 + 6, &(const uint16_t[1]){0xdeb7}, 2); //crypt xts gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\n", (uintptr_t)5); p_kekcall = (char*)dlsym((void*)0x2001, "getpid") + 7; //restore the gdb_stub's SIGTRAP handler struct sigaction sa; sigaction(SIGBUS, 0, &sa); sigaction(SIGTRAP, &sa, 0); - copyin(IDT+16*179+5, "\x89", 1); + sigaction(SIGPIPE, &sa, 0); + copyin(IDT+16*9+5, "\x8e", 1); + copyin(IDT+16*179+5, "\x8e", 1); asm volatile("ud2"); return 0; } + +/* +TEMPORARY CODE + +This should either go to some separate place ("utils.c" in r0gdb perhaps), or be removed completely. +*/ + +#define sysctl __sysctl +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYS_mdbg_call 573 +#define SYS_dynlib_dlsym 591 +#define SYS_dynlib_get_info_ex 608 + +void inject_payload(int pid) +{ + if(kekcall(0, 0, 0, 0, 0, 0, KEKCALL_CHECK)) + return; + static int sock = -1; + if(sock < 0) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr = {.s_addr = 0}, + .sin_port = __builtin_bswap16(9020), + }; + bind(sock, (void*)&sin, sizeof(sin)); + listen(sock, 1); + } + int sock2 = accept(sock, 0, 0); + char* buf = mmap(0, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + size_t sz = 0; + size_t cap = 16384; + for(;;) + { + if(sz == cap) + { + cap *= 2; + char* buf2 = mmap(0, cap, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + for(size_t i = 0; i < sz; i++) + buf2[i] = buf[i]; + munmap(buf, sz); + buf = buf2; + } + ssize_t chk = read(sock2, buf+sz, cap-sz); + if(chk <= 0) + break; + sz += chk; + } + static const char shellcode[] = { + 0x55, //push rbp + 0x48, 0x8b, 0xfc, //mov rdi, rsp + 0x31, 0xf6, //xor esi, esi + 0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, //movabs rdx, ... + 0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, //movabs rcx, ... + 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, //movabs rax, ... + 0xff, 0xd0, //call rax + 0x31, 0xff, //xor edi, edi + 0xb8, SYS_thr_exit&255, SYS_thr_exit>>8, 0, 0, + 0xff, 0x25, 0, 0, 0, 0, //jmp qword [rip] + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if(cap - sz < sizeof(shellcode)) + { + cap *= 2; + char* buf2 = mmap(0, cap, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + for(size_t i = 0; i < sz; i++) + buf2[i] = buf[i]; + munmap(buf, sz); + buf = buf2; + } + size_t shellcode_offset = sz; + for(size_t i = 0; i < sizeof(shellcode); i++) + buf[sz++] = shellcode[i]; + uint64_t target_pointer = kekcall(pid, SYS_mmap, (uint64_t)(const uint64_t[6]){0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL); + if(target_pointer + 1 <= 4096) + asm volatile("ud2"); + uint64_t target_stack = kekcall(pid, SYS_mmap, (uint64_t)(const uint64_t[6]){0, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL); + if(target_stack + 1 <= 4096) + asm volatile("ud2"); + if(kekcall(pid, SYS_mprotect, (uint64_t)(const uint64_t[6]){target_pointer, sz, PROT_READ|PROT_WRITE|PROT_EXEC}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL)) + asm volatile("ud2"); + *(uint64_t*)(buf+shellcode_offset+8) = target_pointer; + kekcall(pid, SYS_dynlib_dlsym, (uint64_t)(const uint64_t[6]){0x2001, (uint64_t)"sceKernelDlsym", (uint64_t)(buf+shellcode_offset+18)}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL); + if(!*(uint64_t*)(buf+shellcode_offset+18)) + asm volatile("ud2"); + kekcall(pid, SYS_dynlib_dlsym, (uint64_t)(const uint64_t[6]){0x2001, (uint64_t)"pthread_create", (uint64_t)(buf+shellcode_offset+28)}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL); + if(!*(uint64_t*)(buf+shellcode_offset+28)) + asm volatile("ud2"); + kekcall(pid, SYS_dynlib_dlsym, (uint64_t)(const uint64_t[6]){0x2001, (uint64_t)"getpid", (uint64_t)(buf+shellcode_offset+51)}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL); + if(!*(uint64_t*)(buf+shellcode_offset+51)) + asm volatile("ud2"); + *(uint64_t*)(buf+shellcode_offset+51) += 7; + { + uint64_t arg1[4] = {1, 0x13}; + uint64_t arg2[8] = {pid, target_pointer, (uint64_t)buf, sz}; + uint64_t arg3[4] = {0}; + if(kekcall((uint64_t)arg1, (uint64_t)arg2, (uint64_t)arg3, 0, 0, 0, SYS_mdbg_call)) + asm volatile("ud2"); + } + { + uint64_t arg1[4] = {1, 0x13}; + uint64_t arg2[8] = {pid, target_stack+16, (uint64_t)&target_stack, 8}; + uint64_t arg3[4] = {0}; + if(kekcall((uint64_t)arg1, (uint64_t)arg2, (uint64_t)arg3, 0, 0, 0, SYS_mdbg_call)) + asm volatile("ud2"); + } + { + uint64_t arg1[4] = {1, 0x13}; + uint64_t arg2[8] = {pid, target_stack+0x1a8, (uint64_t)&target_stack, 8}; + uint64_t arg3[4] = {0}; + if(kekcall((uint64_t)arg1, (uint64_t)arg2, (uint64_t)arg3, 0, 0, 0, SYS_mdbg_call)) + asm volatile("ud2"); + } + munmap(buf, sz); + { + struct thr_param param = {0}; + long x, y; + param.start_func = (void*)(target_pointer+shellcode_offset); + param.stack_base = (void*)target_stack; + param.stack_size = 65536; + param.tls_size = 1; + param.arg = 0; + if(kekcall(pid, SYS_sysarch, (uint64_t)(const uint64_t[6]){AMD64_GET_FSBASE, (uint64_t)¶m.tls_base}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL)) + asm volatile("ud2"); + if(kekcall(pid, SYS_thr_new, (uint64_t)(const uint64_t[6]){(uint64_t)¶m, sizeof(param)}, 0, 0, 0, KEKCALL_REMOTE_SYSCALL)) + asm volatile("ud2"); + } +} + +void* klog_server(void* arg) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = 0 }, + .sin_port = 0x0e27, //9998 + }; + bind(sock, (void*)&sin, sizeof(sin)); + listen(sock, 1); +new_conn: + int sock2 = accept(sock, NULL, NULL); + char buf[512]; + int fd1 = open("/dev/klog", O_RDONLY); + for(;;) + { + ssize_t chk = read(fd1, buf, sizeof(buf)); + if(chk < 0) + break; + char* p = buf; + while(chk > 0) + { + ssize_t chk1 = write(sock2, p, chk); + if(chk1 <= 0) + { + close(sock2); + goto new_conn; + } + chk -= chk1; + p += chk1; + } + } +} + +int find_proc(const char* name) +{ + char buf[1097] = {0}; + for(int pid = 1; pid < 1024; pid++) + { + size_t sz = 1096; + int key[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + sysctl(key, 4, buf, &sz, 0, 0); + const char* a = buf + 447; + const char* b = name; + while(*a && *a++ == *b++); + if(!*a && !*b) + return pid; + } + return -1; +} + +static int64_t do_remote_syscall(int pid, int sysc, ...) +{ + static uint64_t args_p = 0; + if(!args_p) + args_p = r0gdb_kmalloc(48); + uint64_t args[6]; + va_list l; + va_start(l, sysc); + for(int i = 0; i < 6; i++) + args[i] = va_arg(l, uint64_t); + va_end(l); + uint64_t proc; + uint64_t target = 0; + copyout(&proc, kdata_base+0x27edcb8, 8); + while(proc) + { + uint32_t pid1; + copyout(&pid1, proc+0xbc, 4); + if(pid1 == pid) + { + target = proc; + break; + } + copyout(&proc, proc, 8); + } + if(!target) + asm volatile("ud2"); + uint64_t target_thread; + copyout(&target_thread, target+16, 8); + copyin(args_p, args, 48); + uint64_t syscall_fn; + copyout(&syscall_fn, kdata_base+0x1709c0+48*sysc+8, 8); + int err = r0gdb_kfncall(syscall_fn, target_thread, args_p); + if(err) + return -err; + int64_t ans; + copyout(&ans, target_thread+0x408, 8); + return ans; +} + +struct module_segment +{ + uint64_t addr; + uint32_t size; + uint32_t flags; +}; + +struct module_info_ex +{ + size_t st_size; + char name[256]; + int id; + uint32_t tls_index; + uint64_t tls_init_addr; + uint32_t tls_init_size; + uint32_t tls_size; + uint32_t tls_offset; + uint32_t tls_align; + uint64_t init_proc_addr; + uint64_t fini_proc_addr; + uint64_t reserved1; + uint64_t reserved2; + uint64_t eh_frame_hdr_addr; + uint64_t eh_frame_addr; + uint32_t eh_frame_hdr_size; + uint32_t eh_frame_size; + struct module_segment segments[4]; + uint32_t segment_count; + uint32_t ref_count; +}; + +static uint64_t shellcore_args_base; + +static void temp_patch_shellcore(int do_lk) +{ + int pid = find_proc("SceShellCore"); + struct module_info_ex mod_info; + mod_info.st_size = sizeof(mod_info); + do_remote_syscall(pid, SYS_dynlib_get_info_ex, 0, 0, &mod_info); + uint64_t shellcore_base = mod_info.eh_frame_hdr_addr - 0x13c0000; + mod_info.st_size = sizeof(mod_info); + do_remote_syscall(pid, SYS_dynlib_get_info_ex, 0x2001, 0, &mod_info); + uint64_t libkernel_base = mod_info.eh_frame_hdr_addr - 0x44000; + shellcore_args_base = do_remote_syscall(pid, SYS_mmap, 0, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); + struct + { + uint64_t addr; + void* data; + size_t sz; + } patches[] = { + {shellcore_base+0x974fe0, "\x31\xc0\xc3", 3}, + {shellcore_base+0x974bb0, "\x31\xc0\xc3", 3}, + {shellcore_base+0x5307f9, "\xeb\x04", 2}, + {shellcore_base+0x26f35c, "\xeb\x04", 2}, + {shellcore_base+0x54e1f0, "\xeb", 1}, + {shellcore_base+0x536e1d, "\x90\xe9", 2}, + {libkernel_base+0x18f0, "\x48\xb8\xef\xbe\xad\xde\xef\xbe\xad\xde\x48\x89\x38\x48\x89\x70\x08\x48\x89\x50\x10\xeb\xfe", do_lk ? 23 : 0}, + {libkernel_base+0x18f2, &shellcore_args_base, do_lk ? 8 : 0}, + }; + for(int i = 0; i < sizeof(patches) / sizeof(*patches); i++) + { + uint64_t arg1[4] = {1, 0x13}; + uint64_t arg2[8] = {pid, patches[i].addr, (uint64_t)patches[i].data, patches[i].sz}; + uint64_t arg3[4] = {0}; + mdbg_call_20(arg1, arg2, arg3); + } +} + +static void* get_nmount_args(void) +{ + int pid = find_proc("SceShellCore"); + uint64_t args[3]; +#define READ(dst, src, sz) (mdbg_call_20((uint64_t[4]){1, 0x12}, (uint64_t[8]){pid, (src), (uint64_t)(dst), (sz)}, (uint64_t[4]){})) + READ(args, shellcore_args_base, 24); + uint64_t* ptrs = malloc(sizeof(*ptrs) * args[1] * 2); + READ(ptrs, args[0], sizeof(*ptrs) * args[1] * 2); + for(int i = 0; i < args[1]; i++) + { + uint64_t ptr = ptrs[2*i]; + uint64_t sz = ptrs[2*i+1]; + char* buf = malloc(sz+1); + READ(buf, ptr, sz); + buf[sz] = 0; + ptrs[2*i] = (uint64_t)buf; + } +#undef READ + return ptrs; +} + +int my_nmount(void* a, int b, int c) +{ + return kekcall((uintptr_t)a, b, c, 0, 0, 0, SYS_nmount); +} diff --git a/ps5-kstuff/overrides.h b/ps5-kstuff/overrides.h new file mode 100644 index 0000000..8fdb92d --- /dev/null +++ b/ps5-kstuff/overrides.h @@ -0,0 +1,15 @@ +/* disable use of POSIX functions */ +#undef __linux__ +#undef __unix__ + +/* disable XMM intrinsics */ +#undef __x86_64__ + +/* for BearSSL */ +#define BR_64 1 +#define BR_INT128 1 + +/* for libtomcrypt */ +#define ARGTYPE 3 +#define TAB_SIZE 1 +#define LTC_NO_TEST 1 diff --git a/ps5-kstuff/structs-ps5.inc b/ps5-kstuff/structs-ps5.inc index 53ecb9c..1d18a43 100644 --- a/ps5-kstuff/structs-ps5.inc +++ b/ps5-kstuff/structs-ps5.inc @@ -25,6 +25,7 @@ %define p_pid 0xbc +%define pcb_fsbase 0x40 %define pcb_gsbase 0x48 %define pcb_flags 0x100 diff --git a/ps5-kstuff/uelf/crt.asm b/ps5-kstuff/uelf/crt.asm index 9837b71..5f4e469 100644 --- a/ps5-kstuff/uelf/crt.asm +++ b/ps5-kstuff/uelf/crt.asm @@ -3,6 +3,8 @@ use64 global yield global memcpy +global memset +global memmove global cr3_phys global trap_frame global wrmsr_args @@ -25,6 +27,32 @@ mov rcx, rdx rep movsb ret +memset: +movzx eax, sil +mov rsi, rdi +mov rcx, rdx +rep stosb +mov rax, rsi +ret + +memmove: +mov rax, rdi +sub rax, rsi +cmp rax, rdx +jae memcpy +test rax, rax +je .mov_rax_rdi_ret +lea rdi, [rdi+rdx-1] +lea rsi, [rsi+rdx-1] +mov rcx, rdx +std +rep movsb +cld +inc rdi +.mov_rax_rdi_ret: +mov rax, rdi +ret + ; rdi = trap_frame ; rsi = cr3 of caller ; rdx = our cr3 (currently unused) diff --git a/ps5-kstuff/uelf/fakekeys.c b/ps5-kstuff/uelf/fakekeys.c new file mode 100644 index 0000000..6918ffa --- /dev/null +++ b/ps5-kstuff/uelf/fakekeys.c @@ -0,0 +1,44 @@ +#include "fakekeys.h" +#include +#include + +extern struct +{ + uint64_t bitmask; + char pad[24]; + char key_data[63][32]; +} shared_area; + +int register_fake_key(const char key_data[32]) +{ + uint64_t mask, mask1; + mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); + do + { + mask1 = (mask | (mask + 1)) & ((1ull << 63) - 1); + if(mask1 == mask) + return -1; + } + while(!__atomic_compare_exchange_n(&shared_area.bitmask, &mask, mask1, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); + int key_idx = 63 - __builtin_clzll(mask ^ mask1); + memcpy(shared_area.key_data[key_idx], key_data, 32); + return key_idx; +} + +void unregister_fake_key(int key_id) +{ + uint64_t mask, mask1; + mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); + do + mask1 = mask & ~(1ull << key_id); + while(!__atomic_compare_exchange_n(&shared_area.bitmask, &mask, mask1, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); +} + +int get_fake_key(int key_id, char key_data[32]) +{ + uint64_t mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); + if(!(mask & (1ull << key_id))) + return 0; + memcpy(key_data, shared_area.key_data[key_id], 32); + return 1; +} diff --git a/ps5-kstuff/uelf/fakekeys.h b/ps5-kstuff/uelf/fakekeys.h new file mode 100644 index 0000000..f970acb --- /dev/null +++ b/ps5-kstuff/uelf/fakekeys.h @@ -0,0 +1,5 @@ +#pragma once + +int register_fake_key(const char key_data[32]); +void unregister_fake_key(int key_id); +int get_fake_key(int key_id, char key_data[32]); diff --git a/ps5-kstuff/uelf/fpkg.c b/ps5-kstuff/uelf/fpkg.c new file mode 100644 index 0000000..2f71514 --- /dev/null +++ b/ps5-kstuff/uelf/fpkg.c @@ -0,0 +1,188 @@ +#include +#include "fpkg.h" +#include "utils.h" +#include "traps.h" +#include "log.h" +#include "pfs_crypto.h" +#include "fakekeys.h" + +extern char sceSblServiceMailbox[]; +extern char sceSblServiceCryptAsync_deref_singleton[]; +extern char crypt_message_resolve[]; +extern char doreti_iret[]; + +extern char kdata_base[]; + +#define IDX_TO_HANDLE(x) (0x13374100 | ((uint8_t)((x)+1))) +#define HANDLE_TO_IDX(x) ((((x) & 0xffffff00) == 0x13374100 ? ((int)(uint8_t)(x)) : (int)0) - 1) + +static void crypto_request_emulated(uint64_t* regs, uint64_t msg, uint32_t status) +{ + uint64_t frame[7] = { + (uint64_t)doreti_iret, + MKTRAP(TRAP_FPKG, 1), 0, 0, 0, 0, + 0 + }; + push_stack(regs, frame, sizeof(frame)); + regs[RIP] = (uint64_t)crypt_message_resolve; + regs[RDI] = msg; + regs[RSI] = status; +} + +static int handle_crypto_request(uint64_t* regs) +{ + uint64_t dbgregs[6] = {0}; + read_dbgregs(dbgregs); + //if(dbgregs[0] == 0x1337) + { + //uint64_t req = regs[R13]; + uint64_t msg = regs[R14]; + /*if(msg != kpeek64(req)) + { + log_word(0xdead0008dead0008); + log_word(req); + log_word(msg); + return 0; + }*/ + uint64_t msg_data[32]; + copy_from_kernel(msg_data, msg, sizeof(msg_data)); + if((msg_data[0] & 0x7fffffff) == 0x9132000) // SHA256HMAC with key handle + { + int idx = HANDLE_TO_IDX(msg_data[20]); + //log_word(0xfee10006dead0000|(uint16_t)idx); + if(idx < 0) + return 0; + uint8_t key[32]; + if(!get_fake_key(idx, key)) + return 0; + if(msg_data[3] != msg_data[1] * 8) + return 0; + //log_word(0xdead0006dead0007); + uint8_t hash[32] = {0}; + if(pfs_hmac_virtual(hash, key, msg_data[2], msg_data[1])) + { + crypto_request_emulated(regs, msg, -1); + return 1; + } + /*for(int i = 0; i < 4; i++) + log_word(*(uint64_t*)(hash+8*i));*/ + copy_to_kernel(msg+32, hash, 32); + crypto_request_emulated(regs, msg, 0); + return 1; + /*for(int i = 0; i < 16; i++) + { + uint8_t tmp = key[i]; + key[i] = key[31-i]; + key[31-i] = tmp; + } + kpoke64(msg, msg_data[0] & ~(1ull << 20)); + copy_to_kernel(msg+160, key, 32); + for(int i = 32; i < 256; i += 8) + kpoke64(msg+i, 0x100000001);*/ + } + else if((msg_data[0] & 0x7ffff7ff) == 0x2108000) // AES-XTS decrypt/encrypt with key handle + { + int idx = HANDLE_TO_IDX(msg_data[5]); + //log_word(0xfee10006dead0100|(uint16_t)idx); + if(idx < 0) + return 0; + uint8_t key[32]; + if(!get_fake_key(idx, key)) + return 0; + if(pfs_xts_virtual(msg_data[3], msg_data[2], key, msg_data[4], msg_data[1], (msg_data[0] & 0x800) >> 11)) + crypto_request_emulated(regs, msg, -1); + else + crypto_request_emulated(regs, msg, 0); + return 1; + /*kpoke64(msg, msg_data[0] & ~(1ull << 20)); + copy_to_kernel(msg+40, key, 32);*/ + } + /*log_word(0xdead0006dead0006); + log_word(msg); + for(int i = 0; i < 32; i++) + log_word(msg_data[i]); + log_word(0xdead0006ffffffff);*/ + } + return 0; +} + +int try_handle_fpkg_trap(uint64_t* regs) +{ + if(regs[RIP] == (uint64_t)kdata_base - 0x94a7f5) + { + uint64_t req[8]; + copy_from_kernel(req, regs[RDX], 64); + uint64_t p_eekpfs = 0; + memcpy(&p_eekpfs, DMEM+req[2]+32, 8); + uint8_t eekpfs[256] = {0}; + memcpy(eekpfs, DMEM+p_eekpfs, 256); + uint8_t crypt_seed[16]; + memcpy(crypt_seed, DMEM+req[3]+0x370, 16); + uint8_t ek[32] = {}, sk[32] = {}; + if(pfs_derive_fake_keys(eekpfs, crypt_seed, ek, sk)) + { + /*log_word(0xdead0004dead0001); + { + uint64_t* q = ek; + for(int i = 0; i < 4; i++) + log_word(q[i]); + } + { + uint64_t* q = sk; + for(int i = 0; i < 4; i++) + log_word(q[i]); + }*/ + int key1 = register_fake_key(ek); + if(key1 >= 0) + { + int key2 = register_fake_key(sk); + if(key2 >= 0) + { + regs[RIP] += 5; + regs[RAX] = 0; + uint32_t fake_resp[4] = {0, 0, IDX_TO_HANDLE(key1), IDX_TO_HANDLE(key2)}; + copy_to_kernel(regs[RDX], fake_resp, sizeof(fake_resp)); + } + } + } + } + else if(regs[RIP] == (uint64_t)sceSblServiceCryptAsync_deref_singleton) + { + if(!handle_crypto_request(regs)) + { + regs[RAX] |= -1ull << 48; + regs[RBX] |= -1ull << 48; + } + } + /*else if(regs[RIP] == (uint64_t)kdata_base - 0x94a7a0) + { + log_word(0xdead0004dead0005); + log_word(regs[R13]); + log_word(regs[R14]); + }*/ + else + return 0; + return 1; +} + +void handle_fpkg_trap(uint64_t* regs, uint32_t trapno) +{ + if(trapno == 1) + { + uint64_t frame[12]; + pop_stack(regs, frame, sizeof(frame)); + regs[RBX] = frame[7]; + regs[R14] = frame[8]; + regs[R15] = frame[9]; + regs[RBP] = frame[10]; + regs[RIP] = frame[11]; + regs[RAX] = 0; + } +} + +static const uint64_t dbgregs_for_nmount[6] = {0x1337, (uint64_t)kdata_base - 0x94a7f5, 0, 0, 0, 0x404}; + +void handle_fpkg_syscall(uint64_t* regs) +{ + start_syscall_with_dbgregs(regs, dbgregs_for_nmount); +} diff --git a/ps5-kstuff/uelf/fpkg.h b/ps5-kstuff/uelf/fpkg.h new file mode 100644 index 0000000..127a313 --- /dev/null +++ b/ps5-kstuff/uelf/fpkg.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +void handle_fpkg_syscall(uint64_t* regs); +void handle_fpkg_trap(uint64_t* regs, uint32_t trapno); +int try_handle_fpkg_trap(uint64_t* regs); diff --git a/ps5-kstuff/uelf/kekcall.c b/ps5-kstuff/uelf/kekcall.c index 4efe7b5..93e9f1c 100644 --- a/ps5-kstuff/uelf/kekcall.c +++ b/ps5-kstuff/uelf/kekcall.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include "kekcall.h" #include "traps.h" @@ -105,17 +107,35 @@ void handle_kekcall_trap(uint64_t* regs, uint32_t trap) 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); + if(sysc_no == SYS_sysarch && (uint32_t)stack_frame[7] == AMD64_GET_FSBASE) + { + stack_frame_2[1] = MKTRAP(TRAP_KEKCALL, 4); + stack_frame_2[8] = kpeek64(kpeek64(regs[RDI]+td_pcb)+pcb_fsbase); + kpoke64(stack_frame[13]+td_retval, 0); + } + else + kpoke64(regs[RDI]+td_retval, 0); 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); + if(sysc_no == SYS_sysarch && (uint32_t)stack_frame[7] == AMD64_GET_FSBASE) + { + regs[RIP] = (uint64_t)copyout; + regs[RDI] = regs[RSP] + 64; + regs[RSI] = stack_frame[8]; + regs[RDX] = 8; + } + else + { + regs[RIP] = kpeek64((uint64_t)&sysents[sysc_no].sy_call); + regs[RSI] = regs[RSP] + 64; + handle_syscall(regs, 0); + } } - else if(trap == 3) + else if(trap == 3 || trap == 4) { uint64_t stack_frame[14]; pop_stack(regs, stack_frame, sizeof(stack_frame)); - if(!(uint32_t)regs[RAX]) + if(trap == 3 && !(uint32_t)regs[RAX]) kpoke64(stack_frame[5]+td_retval, kpeek64(stack_frame[6]+td_retval)); regs[RIP] = stack_frame[13]; } diff --git a/ps5-kstuff/uelf/main.c b/ps5-kstuff/uelf/main.c index a14d436..6cc23d3 100644 --- a/ps5-kstuff/uelf/main.c +++ b/ps5-kstuff/uelf/main.c @@ -11,6 +11,7 @@ #include "traps.h" #include "kekcall.h" #include "fself.h" +#include "fpkg.h" #include "syscall_fixes.h" int have_error_code; @@ -55,6 +56,8 @@ void handle_syscall(uint64_t* regs, int allow_kekcall) || IS(get_sdk_compiled_version) || IS_PPR(get_ppr_sdk_compiled_version)) handle_fself_syscall(regs); + else if(IS(nmount)) + handle_fpkg_syscall(regs); else if(IS(mprotect) || IS_PPR(mdbg_call)) handle_syscall_fix(regs); @@ -138,6 +141,7 @@ from_userspace: case TRAP_KEKCALL: handle_kekcall_trap(regs, TRAP_IDX(lr)); break; #ifndef FREEBSD case TRAP_FSELF: handle_fself_trap(regs, TRAP_IDX(lr)); break; + case TRAP_FPKG: handle_fpkg_trap(regs, TRAP_IDX(lr)); break; #endif } } @@ -146,6 +150,8 @@ from_userspace: return; else if(handle_fself_parasites(regs)) return; + else if(try_handle_fpkg_trap(regs)) + return; else if(try_handle_syscall_fix_trap(regs)) return; #endif diff --git a/ps5-kstuff/uelf/pfs_crypto.c b/ps5-kstuff/uelf/pfs_crypto.c new file mode 100644 index 0000000..bea027c --- /dev/null +++ b/ps5-kstuff/uelf/pfs_crypto.c @@ -0,0 +1,105 @@ +#include +#include +#include "pfs_crypto.h" +#include "utils.h" +#include "../BearSSL/inc/bearssl.h" +#include "../libtomcrypt/src/headers/tomcrypt.h" + +static const uint8_t ypkg_n[256] = {0xc6, 0xcf, 0x71, 0xe7, 0xe5, 0x9a, 0xf0, 0xd1, 0x2a, 0x2c, 0x45, 0x8b, 0xf9, 0x2a, 0xe, 0xc1, 0x43, 0x5, 0x8b, 0xc3, 0x71, 0x17, 0x80, 0x1d, 0xcd, 0x49, 0x7d, 0xde, 0x35, 0x9d, 0x25, 0x9b, 0xa0, 0xd7, 0xa0, 0xf2, 0x7d, 0x6c, 0x8, 0x7e, 0xaa, 0x55, 0x2, 0x68, 0x2b, 0x23, 0xc6, 0x44, 0xb8, 0x44, 0x18, 0xeb, 0x56, 0xcf, 0x16, 0xa2, 0x48, 0x3, 0xc9, 0xe7, 0x4f, 0x87, 0xeb, 0x3d, 0x30, 0xc3, 0x15, 0x88, 0xbf, 0x20, 0xe7, 0x9d, 0xff, 0x77, 0xc, 0xde, 0x1d, 0x24, 0x1e, 0x63, 0xa9, 0x4f, 0x8a, 0xbf, 0x5b, 0xbe, 0x60, 0x19, 0x68, 0x33, 0x3b, 0xfc, 0xed, 0x9f, 0x47, 0x4e, 0x5f, 0xf8, 0xea, 0xcb, 0x3d, 0x0, 0xbd, 0x67, 0x1, 0xf9, 0x2c, 0x6d, 0xc6, 0xac, 0x13, 0x64, 0xe7, 0x67, 0x14, 0xf3, 0xdc, 0x52, 0x69, 0x6a, 0xb9, 0x83, 0x2c, 0x42, 0x30, 0x13, 0x1b, 0xb2, 0xd8, 0xa5, 0x2, 0xd, 0x79, 0xed, 0x96, 0xb1, 0xd, 0xf8, 0xcc, 0xc, 0xdf, 0x81, 0x95, 0x4f, 0x3, 0x58, 0x9, 0x57, 0xe, 0x80, 0x69, 0x2e, 0xfe, 0xff, 0x52, 0x77, 0xea, 0x75, 0x28, 0xa8, 0xfb, 0xc9, 0xbe, 0xbf, 0x9f, 0xbb, 0xb7, 0x79, 0x8e, 0x18, 0x5, 0xe1, 0x80, 0xbd, 0x50, 0x34, 0x94, 0x81, 0xd3, 0x53, 0xc2, 0x69, 0xa2, 0xd2, 0x4c, 0xcf, 0x6c, 0xf4, 0x57, 0x2c, 0x10, 0x4a, 0x3f, 0xfb, 0x22, 0xfd, 0x8b, 0x97, 0xe2, 0xc9, 0x5b, 0xa6, 0x2b, 0xcd, 0xd6, 0x1b, 0x6b, 0xdb, 0x68, 0x7f, 0x4b, 0xc2, 0xa0, 0x50, 0x34, 0xc0, 0x5, 0xe5, 0x8d, 0xef, 0x24, 0x67, 0xff, 0x93, 0x40, 0xcf, 0x2d, 0x62, 0xa2, 0xa0, 0x50, 0xb1, 0xf1, 0x3a, 0xa8, 0x3d, 0xfd, 0x80, 0xd1, 0xf9, 0xb8, 0x5, 0x22, 0xaf, 0xc8, 0x35, 0x45, 0x90, 0x58, 0x8e, 0xe3, 0x3a, 0x7c, 0xbd, 0x3e, 0x27}; +static const uint8_t ypkg_d[256] = {0x7f, 0x76, 0xcd, 0xe, 0xe2, 0xd4, 0xde, 0x5, 0x1c, 0xc6, 0xd9, 0xa8, 0xe, 0x8d, 0xfa, 0x7b, 0xca, 0x1e, 0xaa, 0x27, 0x1a, 0x40, 0xf8, 0xf1, 0x22, 0x87, 0x35, 0xdd, 0xdb, 0xfd, 0xee, 0xf8, 0xc2, 0xbc, 0xbd, 0x1, 0xfb, 0x8b, 0xe2, 0x3e, 0x63, 0xb2, 0xb1, 0x22, 0x5c, 0x56, 0x49, 0x6e, 0x11, 0xbe, 0x7, 0x44, 0xb, 0x9a, 0x26, 0x66, 0xd1, 0x49, 0x2c, 0x8f, 0xd3, 0x1b, 0xcf, 0xa4, 0xa1, 0xb8, 0xd1, 0xfb, 0xa4, 0x9e, 0xd2, 0x21, 0x28, 0x83, 0x9, 0x8a, 0xf6, 0xa0, 0xb, 0xa3, 0xd6, 0xf, 0x9b, 0x63, 0x68, 0xcc, 0xbc, 0xc, 0x4e, 0x14, 0x5b, 0x27, 0xa4, 0xa9, 0xf4, 0x2b, 0xb9, 0xb8, 0x7b, 0xc0, 0xe6, 0x51, 0xad, 0x1d, 0x77, 0xd4, 0x6b, 0xb9, 0xce, 0x20, 0xd1, 0x26, 0x66, 0x7e, 0x5e, 0x9e, 0xa2, 0xe9, 0x6b, 0x90, 0xf3, 0x73, 0xb8, 0x52, 0x8f, 0x44, 0x11, 0x3, 0xc, 0x13, 0x97, 0x39, 0x3d, 0x13, 0x22, 0x58, 0xd5, 0x43, 0x82, 0x49, 0xda, 0x6e, 0x7c, 0xa1, 0xc5, 0x8c, 0xa5, 0xb0, 0x9, 0xe0, 0xce, 0x3d, 0xdf, 0xf4, 0x9d, 0x3c, 0x97, 0x15, 0xe2, 0x6a, 0xc7, 0x2b, 0x3c, 0x50, 0x93, 0x23, 0xdb, 0xba, 0x4a, 0x22, 0x66, 0x44, 0xac, 0x78, 0xbb, 0xe, 0x1a, 0x27, 0x43, 0xb5, 0x71, 0x67, 0xaf, 0xf4, 0xab, 0x48, 0x46, 0x93, 0x73, 0xd0, 0x42, 0xab, 0x93, 0x63, 0xe5, 0x6c, 0x9a, 0xde, 0x50, 0x24, 0xc0, 0x23, 0x7d, 0x99, 0x79, 0x3f, 0x22, 0x7, 0xe0, 0xc1, 0x48, 0x56, 0x1b, 0xdf, 0x83, 0x9, 0x12, 0xb4, 0x2d, 0x45, 0x6b, 0xc9, 0xc0, 0x68, 0x85, 0x99, 0x90, 0x79, 0x96, 0x1a, 0xd7, 0xf5, 0x4d, 0x1f, 0x37, 0x83, 0x40, 0x4a, 0xec, 0x39, 0x37, 0xa6, 0x80, 0x92, 0x7d, 0xc5, 0x80, 0xc7, 0xd6, 0x6f, 0xfe, 0x8a, 0x79, 0x89, 0xc6, 0xb1}; + +static const br_rsa_public_key ypkg = { + .n = (void*)ypkg_n, + .nlen = sizeof(ypkg_n), + .e = (void*)ypkg_d, + .elen = sizeof(ypkg_d), +}; + +static void pfs_gen_key(uint32_t idx, const uint8_t* seed, const uint8_t* ekpfs, uint8_t* out) +{ + br_hmac_key_context key_ctx; + br_hmac_key_init(&key_ctx, &br_sha256_vtable, ekpfs, 32); + br_hmac_context ctx; + br_hmac_init(&ctx, &key_ctx, 0); + br_hmac_update(&ctx, &idx, sizeof(idx)); + br_hmac_update(&ctx, seed, 16); + br_hmac_out(&ctx, out); +} + +int pfs_derive_fake_keys(const uint8_t* p_eekpfs, const uint8_t* crypt_seed, uint8_t* ek, uint8_t* sk) +{ + uint8_t eekpfs[256]; + memcpy(eekpfs, p_eekpfs, 256); + if(!br_rsa_i62_public(eekpfs, 256, &ypkg)) + return 0; + if(eekpfs[0] != 0 || eekpfs[1] != 2) + return 0; + size_t idx = 1; + while(idx < 256 && eekpfs[idx]) + idx++; + if(idx != 255 - 32) + return 0; + uint8_t* ekpfs = eekpfs+idx+1; + pfs_gen_key(1, crypt_seed, ekpfs, ek); + pfs_gen_key(2, crypt_seed, ekpfs, sk); + return 1; +} + +int pfs_hmac_virtual(uint8_t* out, const uint8_t* key, uint64_t data, size_t data_size) +{ + br_hmac_key_context key_ctx; + br_hmac_key_init(&key_ctx, &br_sha256_vtable, key, 32); + br_hmac_context ctx; + br_hmac_init(&ctx, &key_ctx, 0); + while(data_size) + { + uint64_t chunk_cur; + uint64_t chunk_end; + if(!virt2phys(data, &chunk_cur, &chunk_end)) + return -1; + size_t chk = chunk_end - chunk_cur; + if(chk > data_size) + chk = data_size; + br_hmac_update(&ctx, DMEM+chunk_cur, chk); + data += chk; + data_size -= chk; + } + br_hmac_out(&ctx, out); + return 0; +} + +int pfs_xts_virtual(uint64_t dst, uint64_t src, const uint8_t* key, uint64_t start, uint32_t count, int is_encrypt) +{ + enum { SECTOR_SIZE = 4096 }; + static int aes_cipher = -1; + if(aes_cipher < 0) + { + aes_cipher = register_cipher(&aes_desc); + if(aes_cipher < 0) + { + log_word(0xdeaddeaddeaddead); + log_word(aes_cipher); + return -1; + } + } + symmetric_xts xts = {}; + xts_start(aes_cipher, key+16, key, 16, 0, &xts); + while(count--) + { + static uint8_t input[SECTOR_SIZE], output[SECTOR_SIZE]; + uint64_t tweak[2] = {start, 0}; + if(copy_from_kernel(input, src, SECTOR_SIZE)) + return -1; + if(is_encrypt) + xts_encrypt(input, SECTOR_SIZE, output, (void*)tweak, &xts); + else + xts_decrypt(input, SECTOR_SIZE, output, (void*)tweak, &xts); + if(copy_to_kernel(dst, output, SECTOR_SIZE)) + return -1; + dst += SECTOR_SIZE; + src += SECTOR_SIZE; + start++; + } + xts_done(&xts); + return 0; +} diff --git a/ps5-kstuff/uelf/pfs_crypto.h b/ps5-kstuff/uelf/pfs_crypto.h new file mode 100644 index 0000000..39cef10 --- /dev/null +++ b/ps5-kstuff/uelf/pfs_crypto.h @@ -0,0 +1,6 @@ +#pragma once +#include + +int pfs_derive_fake_keys(const uint8_t* p_eekpfs, const uint8_t* crypt_seed, uint8_t* ek, uint8_t* sk); +int pfs_hmac_virtual(uint8_t* out, const uint8_t* key, uint64_t data, size_t data_size); +int pfs_xts_virtual(uint64_t dst, uint64_t src, const uint8_t* key, uint64_t start, uint32_t count, int is_encrypt); diff --git a/ps5-kstuff/uelf/traps.h b/ps5-kstuff/uelf/traps.h index de17b68..8beb37c 100644 --- a/ps5-kstuff/uelf/traps.h +++ b/ps5-kstuff/uelf/traps.h @@ -5,6 +5,7 @@ enum TRAP_UTILS = 0xdead0000, TRAP_KEKCALL, TRAP_FSELF, + TRAP_FPKG, }; #define MKTRAP(kind, idx) (((uint64_t)(kind) << 32) | ((uint64_t)(idx))) diff --git a/ps5-kstuff/uelf/utils.c b/ps5-kstuff/uelf/utils.c index b9c790a..95c8b52 100644 --- a/ps5-kstuff/uelf/utils.c +++ b/ps5-kstuff/uelf/utils.c @@ -19,6 +19,7 @@ int virt2phys(uint64_t addr, uint64_t* phys, uint64_t* phys_limit) if(!(next_pml & 1)) { log_word(0xdeaddeaddeaddead); + log_word((uint64_t)__builtin_return_address(0)); return 0; } if((next_pml & 128) || i == 12) @@ -40,7 +41,10 @@ int copy_from_kernel(void* dst, uint64_t src, uint64_t sz) while(sz) { if(!virt2phys(src, &phys, &phys_end)) + { + log_word((uint64_t)__builtin_return_address(0)); return EFAULT; + } size_t chk = phys_end - phys; if(sz < chk) chk = sz; @@ -59,7 +63,10 @@ int copy_to_kernel(uint64_t dst, const void* src, uint64_t sz) while(sz) { if(!virt2phys(dst, &phys, &phys_end)) + { + log_word((uint64_t)__builtin_return_address(0)); return EFAULT; + } size_t chk = phys_end - phys; if(sz < chk) chk = sz; diff --git a/ps5-kstuff/uelf/utils.h b/ps5-kstuff/uelf/utils.h index b54d8ea..2ffffff 100644 --- a/ps5-kstuff/uelf/utils.h +++ b/ps5-kstuff/uelf/utils.h @@ -2,6 +2,7 @@ #include #include #include "structs.h" +#include "log.h" extern uint64_t cr3_phys; extern uint64_t trap_frame; @@ -23,8 +24,9 @@ int wrmsr(uint32_t which, uint64_t value); static inline uint64_t kpeek64(uintptr_t kptr) { - uint64_t ans; - copy_from_kernel(&ans, kptr, sizeof(ans)); + uint64_t ans = 0; + if(copy_from_kernel(&ans, kptr, sizeof(ans))) + log_word((uint64_t)__builtin_return_address(0)); return ans; }