Files
PSFree-Enhanced-Dockerized/src/kpatch/750.c

271 lines
8.5 KiB
C
Raw Normal View History

2025-06-07 03:06:24 -07:00
/* Copyright (C) 2024-2025 anonymous
This file is part of PSFree.
PSFree is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
PSFree is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
// 7.50, 7.51, 7.55
#include "types.h"
#include "utils.h"
struct kexec_args {
u64 entry;
u64 arg1;
u64 arg2;
u64 arg3;
u64 arg4;
u64 arg5;
};
2025-06-11 03:28:59 -07:00
static inline void restore(void *kbase, struct kexec_args *uap);
static inline void patch_aio(void *kbase);
2025-06-11 03:28:59 -07:00
static inline void do_patch(void *kbase);
2025-06-07 03:06:24 -07:00
__attribute__((section (".text.start")))
int kpatch(void *td, struct kexec_args *uap) {
2025-06-11 03:28:59 -07:00
const u64 xfast_syscall_off = 0x1c0;
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
do_patch(kbase);
patch_aio(kbase);
2025-06-11 03:28:59 -07:00
restore(kbase, uap);
2025-06-07 03:06:24 -07:00
return 0;
}
__attribute__((always_inline))
2025-06-11 03:28:59 -07:00
static inline void restore(void *kbase, struct kexec_args *uap) {
2025-06-07 03:06:24 -07:00
u8 *pipe = uap->arg1;
u8 *pipebuf = uap->arg2;
for (int i = 0; i < 0x18; i++) {
pipe[i] = pipebuf[i];
}
u64 *pktinfo_field = uap->arg3;
*pktinfo_field = 0;
u64 *pktinfo_field2 = uap->arg4;
*pktinfo_field2 = 0;
2025-06-09 18:02:12 -07:00
u64 *sysent_661_save = uap->arg5;
for (int i = 0; i < 0x30; i += 8) {
write64(kbase, 0x1129f30 + i, sysent_661_save[i / 8]);
}
2025-06-07 03:06:24 -07:00
}
__attribute__((always_inline))
static inline void patch_aio(void *kbase) {
2025-08-26 00:47:35 -07:00
disable_cr0_wp();
const u64 aio_off = 0xb20f5;
2025-08-26 00:47:35 -07:00
// patch = {0xeb, 0x03}
write16(kbase, aio_off, 0x03eb);
// offset = 0x10e
// patch = {0xe9, 0xf2, 0xfe, 0xff, 0xff}
write32(kbase, aio_off + 0x10e, 0xfffef2e9);
write8(kbase, aio_off + 0x112, 0xff);
// offset = 0x5
// patch = {0x41, 0x83, 0xbe, 0xa0, 0x04, 0x00, 0x00, 0x00}
write64(kbase, aio_off + 0x5, 0x00000004a0be8341);
// offset = 0x13
// patch = {0x49, 0x8b, 0x86, 0xd0, 0x04, 0x00, 0x00}
write32(kbase, aio_off + 0x13, 0xd0868b49);
write16(kbase, aio_off + 0x17, 0x0004);
write8(kbase, aio_off + 0x19, 0x00);
// offset = 0x20
// patch = {0x49, 0x8b, 0xb6, 0xb0, 0x04, 0x00, 0x00}
write32(kbase, aio_off + 0x20, 0xb0b68b49);
write16(kbase, aio_off + 0x24, 0x0004);
write8(kbase, aio_off + 0x26, 0x00);
// offset = 0x38
// patch = {0x49, 0x8b, 0x86, 0x40, 0x05, 0x00, 0x00}
write32(kbase, aio_off + 0x38, 0x40868b49);
write16(kbase, aio_off + 0x3c, 0x0005);
write8(kbase, aio_off + 0x3e, 0x00);
// offset = 0x45
// patch = {0x49, 0x8b, 0xb6, 0x20, 0x05, 0x00, 0x00}
write32(kbase, aio_off + 0x45, 0x20b68b49);
write16(kbase, aio_off + 0x49, 0x0005);
write8(kbase, aio_off + 0x4b, 0x00);
// offset = 0x5d
2025-09-05 10:35:26 -07:00
// patch = {0x49, 0x8d, 0xbe, 0xc0, 0x00, 0x00, 0x00}
2025-08-26 00:47:35 -07:00
write32(kbase, aio_off + 0x5d, 0xc0be8d49);
write16(kbase, aio_off + 0x61, 0x0000);
write8(kbase, aio_off + 0x63, 0x00);
// offset = 0x69
// patch = {0x49, 0x8d, 0xbe, 0xe0, 0x00, 0x00, 0x00}
write32(kbase, aio_off + 0x69, 0xe0be8d49);
write16(kbase, aio_off + 0x6d, 0x0000);
write8(kbase, aio_off + 0x6f, 0x00);
// offset = 0x7c
// patch = {0x49, 0x8d, 0xbe, 0x00, 0x01, 0x00, 0x00}
write32(kbase, aio_off + 0x7c, 0x00be8d49);
write16(kbase, aio_off + 0x80, 0x0001);
write8(kbase, aio_off + 0x82, 0x00);
// offset = 0x88
// patch = {0x49, 0x8d, 0xbe, 0x20, 0x01, 0x00, 0x00}
write32(kbase, aio_off + 0x88, 0x20be8d49);
write16(kbase, aio_off + 0x8c, 0x0001);
write8(kbase, aio_off + 0x8e, 0x00);
// offset = 0x99
// patch = {0x4c, 0x89, 0xf7}
write16(kbase, aio_off + 0x99, 0x894c);
write8(kbase, aio_off + 0x9b, 0xf7);
enable_cr0_wp();
}
2025-06-07 03:06:24 -07:00
__attribute__((always_inline))
2025-06-11 03:28:59 -07:00
static inline void do_patch(void *kbase) {
2025-06-07 03:06:24 -07:00
disable_cr0_wp();
// ChendoChap's patches from pOOBs4
2025-06-24 04:33:14 -07:00
write16(kbase, 0x637394, 0x00eb); // veriPatch
2025-06-07 03:06:24 -07:00
write8(kbase, 0xadd, 0xeb); // bcopy
write8(kbase, 0x28f74d, 0xeb); // bzero
write8(kbase, 0x28f791, 0xeb); // pagezero
write8(kbase, 0x28f80d, 0xeb); // memcpy
write8(kbase, 0x28f851, 0xeb); // pagecopy
write8(kbase, 0x28f9fd, 0xeb); // copyin
write8(kbase, 0x28fead, 0xeb); // copyinstr
write8(kbase, 0x28ff7d, 0xeb); // copystr
2025-06-24 04:33:14 -07:00
// stop sysVeri from causing a delayed panic on suspend
write16(kbase, 0x637ccf, 0x00eb);
2025-06-07 03:06:24 -07:00
// 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, 0x4c6, 0xe990);
2025-06-24 04:33:14 -07:00
write16(kbase, 0x4bd, 0x00eb);
write16(kbase, 0x4b9, 0x00eb);
2025-06-07 03:06:24 -07:00
// 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, 0x37a327, 0xeb);
// 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);
// }
2025-07-19 22:21:55 -07:00
write16(kbase, 0x3014c8, 0x04eb);
2025-06-07 03:06:24 -07:00
2025-06-24 04:33:14 -07:00
// TODO: Description of this patch. patch sys_dynlib_load_prx()
2025-06-07 03:06:24 -07:00
write16(kbase, 0x451e04, 0xe990);
// patch sys_dynlib_dlsym() to allow dynamic symbol resolution everywhere
// call ...
// mov r14, qword [rbp - 0xad0]
// cmp eax, 0x4000000
// jb ... ; patch jb to jmp
write16(kbase, 0x4523c4, 0xe990);
// 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, 0x29a30, 0xc3c03148);
// 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, 0xdb17d, 0x37);
write8(kbase, 0xdb180, 0x37);
// 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]");
// }
const u64 sysent_11_off = 0x1122550;
// .sy_narg = 2
write32(kbase, sysent_11_off, 2);
// .sy_call = gadgets['jmp qword ptr [rsi]']
write64(kbase, sysent_11_off + 8, kbase + 0x1f842);
// .sy_thrcnt = SY_THR_STATIC
write32(kbase, sysent_11_off + 0x2c, 1);
enable_cr0_wp();
}