├── README.md ├── fake_installer ├── .gitignore ├── Makefile ├── convert_payload.sh └── source │ ├── main.c │ └── payload_data.inc └── fake_payload ├── .gitignore ├── Makefile ├── fake_payload.x ├── include ├── elf_helper.h ├── freebsd_helper.h ├── sbl_helper.h ├── sections.h ├── self_helper.h └── sparse.h └── source ├── fself.c └── main.c /README.md: -------------------------------------------------------------------------------- 1 | Patches and hooks to enable fself/fpkg loading for 4.05, as described by flatz in his writeup. 2 | 3 | https://twitter.com/flat_z/status/949571698390683649 4 | 5 | ShellCore patches (for fake PKG support) not yet implemented. 6 | -------------------------------------------------------------------------------- /fake_installer/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | FTPS4 3 | *.bin 4 | *.sh 5 | temp.* -------------------------------------------------------------------------------- /fake_installer/Makefile: -------------------------------------------------------------------------------- 1 | LIBPS4 := $(PS4SDK)/libPS4 2 | 3 | TEXT := 0x926200000 4 | DATA := 0x926300000 5 | 6 | CC := gcc 7 | AS := gcc 8 | OBJCOPY := objcopy 9 | ODIR := build 10 | SDIR := source 11 | IDIRS := -I$(LIBPS4)/include -I. -Iinclude 12 | LDIRS := -L$(LIBPS4) -L. -Llib 13 | CFLAGS := $(IDIRS) -O3 -std=gnu11 -fno-builtin -nostartfiles -nostdlib -fno-strict-aliasing -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=large 14 | SFLAGS := -nostartfiles -nostdlib -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=large 15 | LFLAGS := $(LDIRS) -Xlinker -T $(LIBPS4)/linker.x -Wl,--build-id=none -Ttext=$(TEXT) -Tdata=$(DATA) 16 | CFILES := $(wildcard $(SDIR)/*.c) 17 | SFILES := $(wildcard $(SDIR)/*.s) 18 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%.o, $(SFILES)) 19 | 20 | LIBS := -lPS4 21 | 22 | TARGET = $(shell basename $(CURDIR)).bin 23 | 24 | $(TARGET): $(ODIR) $(OBJS) 25 | $(CC) $(LIBPS4)/crt0.s $(ODIR)/*.o -o temp.t $(CFLAGS) $(LFLAGS) $(LIBS) 26 | $(OBJCOPY) -R .sc_rop temp.t temp.u 27 | $(OBJCOPY) -O binary temp.u $(TARGET) 28 | rm -f temp.t temp.u 29 | 30 | $(ODIR)/%.o: $(SDIR)/%.c 31 | $(CC) -c -o $@ $< $(CFLAGS) 32 | 33 | $(ODIR)/%.o: $(SDIR)/%.s 34 | $(AS) -c -o $@ $< $(SFLAGS) 35 | 36 | $(ODIR): 37 | @mkdir $@ 38 | 39 | .PHONY: clean 40 | 41 | clean: 42 | rm -f $(TARGET) $(ODIR)/*.o 43 | -------------------------------------------------------------------------------- /fake_installer/convert_payload.sh: -------------------------------------------------------------------------------- 1 | hexdump -v -e '16/1 "0x%02x," "\n"' ../fake_payload/fake_payload.bin > source/payload_data.inc -------------------------------------------------------------------------------- /fake_installer/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ps4.h" 4 | 5 | const uint8_t payload_data_const[] = 6 | { 7 | #include "payload_data.inc" 8 | }; 9 | 10 | uint64_t __readmsr(unsigned long __register) 11 | { 12 | unsigned long __edx; 13 | unsigned long __eax; 14 | __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register)); 15 | return (((uint64_t)__edx) << 32) | (uint64_t)__eax; 16 | } 17 | 18 | #define X86_CR0_WP (1 << 16) 19 | 20 | static inline __attribute__((always_inline)) uint64_t readCr0(void) 21 | { 22 | uint64_t cr0; 23 | __asm__ volatile ("movq %0, %%cr0" : "=r" (cr0) : : "memory"); 24 | return cr0; 25 | } 26 | 27 | static inline __attribute__((always_inline)) void writeCr0(uint64_t cr0) 28 | { 29 | __asm__ volatile("movq %%cr0, %0" : : "r" (cr0) : "memory"); 30 | } 31 | 32 | struct payload_info 33 | { 34 | uint8_t* buffer; 35 | size_t size; 36 | }; 37 | 38 | struct syscall_install_payload_args 39 | { 40 | void* syscall_handler; 41 | struct payload_info* payload_info; 42 | }; 43 | 44 | struct real_info 45 | { 46 | const size_t kernel_offset; 47 | const size_t payload_offset; 48 | }; 49 | 50 | struct cave_info 51 | { 52 | const size_t kernel_call_offset; 53 | const size_t kernel_ptr_offset; 54 | const size_t payload_offset; 55 | }; 56 | 57 | struct disp_info 58 | { 59 | const size_t call_offset; 60 | const size_t cave_offset; 61 | }; 62 | 63 | struct payload_header 64 | { 65 | uint64_t signature; 66 | size_t real_info_offset; 67 | size_t cave_info_offset; 68 | size_t disp_info_offset; 69 | size_t entrypoint_offset; 70 | }; 71 | 72 | int syscall_install_payload(void* td, struct syscall_install_payload_args* args) 73 | { 74 | uint64_t cr0; 75 | typedef uint64_t vm_offset_t; 76 | typedef uint64_t vm_size_t; 77 | typedef void* vm_map_t; 78 | 79 | void* (*kernel_memcpy)(void* dst, const void* src, size_t len); 80 | void (*kernel_printf)(const char* fmt, ...); 81 | vm_offset_t (*kmem_alloc)(vm_map_t map, vm_size_t size); 82 | 83 | uint8_t* kernel_base = (uint8_t*)(__readmsr(0xC0000082) - 0x30EB30); 84 | 85 | *(void**)(&kernel_printf) = &kernel_base[0x347580]; 86 | *(void**)(&kernel_memcpy) = &kernel_base[0x286CF0]; 87 | *(void**)(&kmem_alloc) = &kernel_base[0x369500]; 88 | vm_map_t kernel_map = *(void**)&kernel_base[0x1FE71B8]; 89 | 90 | kernel_printf("\n\n\n\npayload_installer: starting\n"); 91 | kernel_printf("payload_installer: kernel base=%lx\n", kernel_base); 92 | 93 | if (!args->payload_info) 94 | { 95 | kernel_printf("payload_installer: bad payload info\n"); 96 | return -1; 97 | } 98 | 99 | uint8_t* payload_data = args->payload_info->buffer; 100 | size_t payload_size = args->payload_info->size; 101 | struct payload_header* payload_header = (struct payload_header*)payload_data; 102 | 103 | if (!payload_data || 104 | payload_size < sizeof(payload_header) || 105 | payload_header->signature != 0x5041594C4F414433ull) 106 | { 107 | kernel_printf("payload_installer: bad payload data\n"); 108 | return -2; 109 | } 110 | 111 | int desired_size = (payload_size + 0x3FFFull) & ~0x3FFFull; // align size 112 | 113 | // TODO(idc): clone kmem_alloc instead of patching directly 114 | cr0 = readCr0(); 115 | writeCr0(cr0 & ~X86_CR0_WP); 116 | kernel_base[0x36958D] = 7; 117 | kernel_base[0x3695A5] = 7; 118 | writeCr0(cr0); 119 | 120 | kernel_printf("payload_installer: kmem_alloc\n"); 121 | uint8_t* payload_buffer = (uint8_t*)kmem_alloc(kernel_map, desired_size); 122 | if (!payload_buffer) 123 | { 124 | kernel_printf("payload_installer: kmem_alloc failed\n"); 125 | return -3; 126 | } 127 | 128 | // TODO(idc): clone kmem_alloc instead of patching directly 129 | cr0 = readCr0(); 130 | writeCr0(cr0 & ~X86_CR0_WP); 131 | kernel_base[0x36958D] = 3; 132 | kernel_base[0x3695A5] = 3; 133 | writeCr0(cr0); 134 | 135 | kernel_printf("payload_installer: installing...\n"); 136 | kernel_printf("payload_installer: target=%lx\n", payload_buffer); 137 | kernel_printf("payload_installer: payload=%lx,%lu\n", 138 | payload_data, payload_size); 139 | 140 | kernel_printf("payload_installer: memcpy\n"); 141 | kernel_memcpy((void*)payload_buffer, payload_data, payload_size); 142 | 143 | kernel_printf("payload_installer: patching payload pointers\n"); 144 | if (payload_header->real_info_offset != 0 && 145 | payload_header->real_info_offset + sizeof(struct real_info) <= payload_size) 146 | { 147 | struct real_info* real_info = 148 | (struct real_info*)(&payload_data[payload_header->real_info_offset]); 149 | for ( 150 | ; real_info->payload_offset != 0 && real_info->kernel_offset != 0 151 | ; ++real_info) 152 | { 153 | uint64_t* payload_target = 154 | (uint64_t*)(&payload_buffer[real_info->payload_offset]); 155 | void* kernel_target = &kernel_base[real_info->kernel_offset]; 156 | *payload_target = (uint64_t)kernel_target; 157 | kernel_printf(" %x(%lx) = %x(%lx)\n", 158 | real_info->payload_offset, payload_target, 159 | real_info->kernel_offset, kernel_target); 160 | } 161 | } 162 | 163 | kernel_printf("payload_installer: patching caves\n"); 164 | if (payload_header->cave_info_offset != 0 && 165 | payload_header->cave_info_offset + sizeof(struct cave_info) <= payload_size) 166 | { 167 | struct cave_info* cave_info = 168 | (struct cave_info*)(&payload_data[payload_header->cave_info_offset]); 169 | for ( 170 | ; cave_info->kernel_call_offset != 0 && 171 | cave_info->kernel_ptr_offset != 0 && 172 | cave_info->payload_offset != 0 173 | ; ++cave_info) 174 | { 175 | uint8_t* kernel_call_target = &kernel_base[cave_info->kernel_call_offset]; 176 | uint8_t* kernel_ptr_target = &kernel_base[cave_info->kernel_ptr_offset]; 177 | void* payload_target = &payload_buffer[cave_info->payload_offset]; 178 | int32_t new_disp = (int32_t)(kernel_ptr_target - &kernel_call_target[6]); 179 | 180 | if (&kernel_call_target[6] == kernel_ptr_target) 181 | { 182 | kernel_printf(" %lx(%lx) = %d\n", 183 | cave_info->kernel_call_offset, kernel_call_target, 184 | new_disp); 185 | 186 | if ((uint64_t)(kernel_ptr_target - &kernel_call_target[6]) != 0) 187 | { 188 | kernel_printf(" error: new_disp != 0!\n"); 189 | } 190 | } 191 | else 192 | { 193 | kernel_printf(" %lx(%lx) -> %lx(%lx) = %d\n", 194 | cave_info->kernel_call_offset, kernel_call_target, 195 | cave_info->kernel_ptr_offset, kernel_ptr_target, 196 | new_disp); 197 | 198 | if ((uint64_t)(kernel_ptr_target - &kernel_call_target[6]) > UINT32_MAX) 199 | { 200 | kernel_printf(" error: new_disp > UINT32_MAX!\n"); 201 | } 202 | } 203 | kernel_printf(" %lx(%lx)\n", 204 | cave_info->payload_offset, payload_target); 205 | 206 | #pragma pack(push,1) 207 | struct 208 | { 209 | uint8_t op[2]; 210 | int32_t disp; 211 | } 212 | jmp; 213 | #pragma pack(pop) 214 | jmp.op[0] = 0xFF; 215 | jmp.op[1] = 0x25; 216 | jmp.disp = new_disp; 217 | cr0 = readCr0(); 218 | writeCr0(cr0 & ~X86_CR0_WP); 219 | kernel_memcpy(kernel_call_target, &jmp, sizeof(jmp)); 220 | kernel_memcpy(kernel_ptr_target, &payload_target, sizeof(void*)); 221 | writeCr0(cr0); 222 | } 223 | } 224 | 225 | kernel_printf("payload_installer: patching calls\n"); 226 | if (payload_header->disp_info_offset != 0 && 227 | payload_header->disp_info_offset + sizeof(struct disp_info) <= payload_size) 228 | { 229 | struct disp_info* disp_info = 230 | (struct disp_info*)(&payload_data[payload_header->disp_info_offset]); 231 | for ( 232 | ; disp_info->call_offset != 0 && disp_info->cave_offset != 0 233 | ; ++disp_info) 234 | { 235 | uint8_t* cave_target = &kernel_base[disp_info->cave_offset]; 236 | uint8_t* call_target = &kernel_base[disp_info->call_offset]; 237 | 238 | int32_t new_disp = (int32_t)(cave_target - &call_target[5]); 239 | 240 | kernel_printf(" %lx(%lx)\n", 241 | disp_info->call_offset + 1, &call_target[1]); 242 | kernel_printf(" %lx(%lx) -> %lx(%lx) = %d\n", 243 | disp_info->call_offset + 5, &call_target[5], 244 | disp_info->cave_offset, cave_target, 245 | new_disp); 246 | 247 | cr0 = readCr0(); 248 | writeCr0(cr0 & ~X86_CR0_WP); 249 | *((int32_t*)&call_target[1]) = new_disp; 250 | writeCr0(cr0); 251 | } 252 | } 253 | 254 | if (payload_header->entrypoint_offset != 0 && 255 | payload_header->entrypoint_offset < payload_size) 256 | { 257 | kernel_printf("payload_installer: entrypoint\n"); 258 | void (*payload_entrypoint)(); 259 | *((void**)&payload_entrypoint) = 260 | (void*)(&payload_buffer[payload_header->entrypoint_offset]); 261 | payload_entrypoint(); 262 | } 263 | 264 | kernel_printf("payload_installer: done\n"); 265 | return 0; 266 | } 267 | 268 | int _main(void) 269 | { 270 | uint8_t* payload_data = (uint8_t*)(&payload_data_const[0]); 271 | size_t payload_size = sizeof(payload_data_const); 272 | 273 | initKernel(); 274 | struct payload_info payload_info; 275 | payload_info.buffer = payload_data; 276 | payload_info.size = payload_size; 277 | errno = 0; 278 | int result = kexec(&syscall_install_payload, &payload_info); 279 | return !result ? 0 : errno; 280 | } 281 | -------------------------------------------------------------------------------- /fake_installer/source/payload_data.inc: -------------------------------------------------------------------------------- 1 | #error "convert fake_payload.bin to byte array" 2 | -------------------------------------------------------------------------------- /fake_payload/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | FTPS4 3 | *.bin 4 | *.sh 5 | temp.* -------------------------------------------------------------------------------- /fake_payload/Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | OBJCOPY := objcopy 3 | ODIR := build 4 | SDIR := source 5 | IDIRS := -Iinclude 6 | CFLAGS := $(IDIRS) -O3 -std=gnu11 -fno-builtin -nostartfiles -nostdlib -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=small -fpie 7 | LFLAGS := -Xlinker -T ./fake_payload.x -Wl,--build-id=none 8 | CFILES := $(wildcard $(SDIR)/*.c) 9 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(CFILES)) 10 | 11 | TARGET = $(shell basename $(CURDIR)).bin 12 | 13 | $(TARGET): $(ODIR) $(OBJS) 14 | $(CC) $(ODIR)/*.o -o temp.t $(CFLAGS) $(LFLAGS) 15 | $(OBJCOPY) -O binary temp.t $(TARGET) 16 | rm -f temp.t 17 | 18 | $(ODIR)/%.o: $(SDIR)/%.c 19 | $(CC) -c -o $@ $< $(CFLAGS) 20 | 21 | $(ODIR): 22 | @mkdir $@ 23 | 24 | .PHONY: clean 25 | 26 | clean: 27 | rm -f $(TARGET) $(ODIR)/*.o 28 | -------------------------------------------------------------------------------- /fake_payload/fake_payload.x: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(_start) 5 | 6 | PHDRS 7 | { 8 | header_seg PT_LOAD; 9 | code_seg PT_LOAD; 10 | rdata_seg PT_LOAD; 11 | data_seg PT_LOAD; 12 | bad_rdata_seg PT_LOAD; 13 | bad_data_seg PT_LOAD; 14 | bad_bss_seg PT_LOAD; 15 | } 16 | 17 | SECTIONS 18 | { 19 | . = 0; 20 | .payload_header : { *(.payload_header) } : header_seg 21 | .payload_code : { *(.payload_code) } : code_seg 22 | .payload_data : { *(.payload_rdata .rdata) } : rdata_seg 23 | .payload_data : { *(.payload_data) } : data_seg 24 | . = 0x100000; 25 | .data : { *(.data) } : bad_data_seg 26 | .bss : { *(.bss) } : bad_bss_seg 27 | /DISCARD/ : { *(*) } 28 | } 29 | -------------------------------------------------------------------------------- /fake_payload/include/elf_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_HELPER_H 2 | #define __ELF_HELPER_H 3 | 4 | #define ELF_IDENT_SIZE 0x10 5 | #define ELF_EHDR_EXT_SIZE 0x1000 6 | 7 | #define ELF_IDENT_MAG0 0 8 | #define ELF_IDENT_MAG1 1 9 | #define ELF_IDENT_MAG2 2 10 | #define ELF_IDENT_MAG3 3 11 | #define ELF_IDENT_CLASS 4 12 | #define ELF_IDENT_DATA 5 13 | 14 | #define ELF_CLASS_64 2 15 | #define ELF_DATA_LSB 1 16 | 17 | #define ELF_TYPE_NONE 0 18 | #define ELF_TYPE_EXEC 2 19 | 20 | #define ELF_MACHINE_X86_64 0x3E 21 | 22 | #define ELF_PHDR_TYPE_NULL 0x0 23 | #define ELF_PHDR_TYPE_LOAD 0x1 24 | #define ELF_PHDR_TYPE_SCE_DYNLIBDATA 0x61000000 25 | #define ELF_PHDR_TYPE_SCE_RELRO 0x61000010 26 | #define ELF_PHDR_TYPE_SCE_COMMENT 0x6FFFFF00 27 | #define ELF_PHDR_TYPE_SCE_VERSION 0x6FFFFF01 28 | 29 | #define ELF_PHDR_FLAG_X 0x1 30 | #define ELF_PHDR_FLAG_W 0x2 31 | #define ELF_PHDR_FLAG_R 0x4 32 | 33 | #define ELF_ET_EXEC 0x2 34 | #define ELF_ET_SCE_EXEC 0xFE00 35 | #define ELF_ET_SCE_EXEC_ASLR 0xFE10 36 | #define ELF_ET_SCE_DYNAMIC 0xFE18 37 | 38 | typedef uint16_t elf64_half_t; 39 | typedef uint32_t elf64_word_t; 40 | typedef uint64_t elf64_xword_t; 41 | typedef uint64_t elf64_off_t; 42 | typedef uint64_t elf64_addr_t; 43 | 44 | struct elf64_ehdr 45 | { 46 | uint8_t ident[ELF_IDENT_SIZE]; 47 | elf64_half_t type; 48 | elf64_half_t machine; 49 | elf64_word_t version; 50 | elf64_addr_t entry; 51 | elf64_off_t phoff; 52 | elf64_off_t shoff; 53 | elf64_word_t flags; 54 | elf64_half_t ehsize; 55 | elf64_half_t phentsize; 56 | elf64_half_t phnum; 57 | elf64_half_t shentsize; 58 | elf64_half_t shnum; 59 | elf64_half_t shstrndx; 60 | }; 61 | 62 | struct elf64_phdr 63 | { 64 | elf64_word_t type; 65 | elf64_word_t flags; 66 | elf64_off_t offset; 67 | elf64_addr_t vaddr; 68 | elf64_addr_t paddr; 69 | elf64_xword_t filesz; 70 | elf64_xword_t memsz; 71 | elf64_xword_t align; 72 | }; 73 | 74 | struct elf64_shdr 75 | { 76 | elf64_word_t name; 77 | elf64_word_t type; 78 | elf64_xword_t flags; 79 | elf64_addr_t addr; 80 | elf64_off_t offset; 81 | elf64_xword_t size; 82 | elf64_word_t link; 83 | elf64_word_t info; 84 | elf64_xword_t addralign; 85 | elf64_xword_t entsize; 86 | }; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /fake_payload/include/freebsd_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __FREEBSD_HELPER_H 2 | #define __FREEBSD_HELPER_H 3 | 4 | #define ESRCH 3 5 | #define ENOMEM 12 6 | #define EINVAL 22 7 | #define ENOTSUP 45 8 | 9 | struct lock_object 10 | { 11 | const char* lo_name; 12 | uint32_t lo_flags; 13 | uint32_t lo_data; 14 | void* lo_witness; 15 | }; 16 | 17 | struct mtx 18 | { 19 | struct lock_object lock_object; 20 | volatile void* mtx_lock; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /fake_payload/include/sbl_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __SBL_HELPER_H 2 | #define __SBL_HELPER_H 3 | 4 | struct sbl_mapped_page_group; 5 | 6 | #define SIZEOF_SBL_MAP_LIST_ENTRY 0x50 // sceSblDriverMapPages 7 | 8 | TYPE_BEGIN(struct sbl_map_list_entry, SIZEOF_SBL_MAP_LIST_ENTRY); 9 | TYPE_FIELD(struct sbl_map_list_entry* next, 0x00); 10 | TYPE_FIELD(struct sbl_map_list_entry* prev, 0x08); 11 | TYPE_FIELD(unsigned long cpu_va, 0x10); 12 | TYPE_FIELD(unsigned int num_page_groups, 0x18); 13 | TYPE_FIELD(unsigned long gpu_va, 0x20); 14 | TYPE_FIELD(struct sbl_mapped_page_group* page_groups, 0x28); 15 | TYPE_FIELD(unsigned int num_pages, 0x30); 16 | TYPE_FIELD(unsigned long flags, 0x38); 17 | TYPE_FIELD(struct proc* proc, 0x40); 18 | TYPE_FIELD(void* vm_page, 0x48); 19 | TYPE_END(); 20 | 21 | #define SBL_MSG_SERVICE_MAILBOX_MAX_SIZE 0x80 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /fake_payload/include/sections.h: -------------------------------------------------------------------------------- 1 | #ifndef __SECTIONS_H 2 | #define __SECTIONS_H 3 | 4 | #define PAYLOAD_DUMMY __attribute((section(".payload_dummy"))) 5 | #define PAYLOAD_HEADER __attribute__((section(".payload_header"))) 6 | #define PAYLOAD_CODE __attribute__((section(".payload_code"))) 7 | #define PAYLOAD_DATA __attribute__((section(".payload_data"))) 8 | #define PAYLOAD_RDATA __attribute__((section(".payload_rdata"))) 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /fake_payload/include/self_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __SELF_HELPER_H 2 | #define __SELF_HELPER_H 3 | 4 | #define SELF_DIGEST_SIZE 0x20 5 | #define SELF_CONTENT_ID_SIZE 0x13 6 | #define SELF_RANDOM_PAD_SIZE 0x0D 7 | #define SELF_MAX_HEADER_SIZE 0x4000 8 | 9 | enum self_format 10 | { 11 | SELF_FORMAT_NONE, 12 | SELF_FORMAT_ELF, 13 | SELF_FORMAT_SELF, 14 | }; 15 | 16 | #define SIZEOF_SELF_CONTEXT 0x60 // sceSblAuthMgrAuthHeader:bzero(sbl_authmgr_context, 0x60) 17 | 18 | TYPE_BEGIN(struct self_context, SIZEOF_SELF_CONTEXT); 19 | TYPE_FIELD(enum self_format format, 0x00); 20 | TYPE_FIELD(int elf_auth_type, 0x04); /* auth id is based on that */ 21 | TYPE_FIELD(unsigned int total_header_size, 0x08); 22 | TYPE_FIELD(int ctx_id, 0x1C); 23 | TYPE_FIELD(uint64_t svc_id, 0x20); 24 | TYPE_FIELD(int buf_id, 0x30); 25 | TYPE_FIELD(uint8_t* header, 0x38); 26 | TYPE_FIELD(struct mtx lock, 0x40); 27 | TYPE_END(); 28 | 29 | #define SIZEOF_SELF_HEADER 0x20 30 | 31 | TYPE_BEGIN(struct self_header, SIZEOF_SELF_HEADER); 32 | TYPE_FIELD(uint32_t magic, 0x00); 33 | #define SELF_MAGIC 0x1D3D154F 34 | #define ELF_MAGIC 0x464C457F 35 | TYPE_FIELD(uint8_t version, 0x04); 36 | TYPE_FIELD(uint8_t mode, 0x05); 37 | TYPE_FIELD(uint8_t endian, 0x06); 38 | TYPE_FIELD(uint8_t attr, 0x07); 39 | TYPE_FIELD(uint32_t key_type, 0x08); 40 | TYPE_FIELD(uint16_t header_size, 0x0C); 41 | TYPE_FIELD(uint16_t meta_size, 0x0E); 42 | TYPE_FIELD(uint64_t file_size, 0x10); 43 | TYPE_FIELD(uint16_t num_entries, 0x18); 44 | TYPE_FIELD(uint16_t flags, 0x1A); 45 | TYPE_END(); 46 | 47 | #define SIZEOF_SELF_ENTRY 0x20 48 | 49 | TYPE_BEGIN(struct self_entry, SIZEOF_SELF_ENTRY); 50 | TYPE_FIELD(uint64_t props, 0x00); 51 | TYPE_FIELD(uint64_t offset, 0x08); 52 | TYPE_FIELD(uint64_t file_size, 0x10); 53 | TYPE_FIELD(uint64_t memory_size, 0x18); 54 | TYPE_END(); 55 | 56 | #define SIZEOF_SELF_EX_INFO 0x40 57 | 58 | TYPE_BEGIN(struct self_ex_info, SIZEOF_SELF_EX_INFO); 59 | TYPE_FIELD(uint64_t paid, 0x00); 60 | TYPE_FIELD(uint64_t ptype, 0x08); 61 | #define SELF_PTYPE_FAKE 0x1 62 | TYPE_FIELD(uint64_t app_version, 0x10); 63 | TYPE_FIELD(uint64_t fw_version, 0x18); 64 | TYPE_FIELD(uint8_t digest[SELF_DIGEST_SIZE], 0x20); 65 | TYPE_END(); 66 | 67 | #define SIZEOF_SELF_AUTH_INFO 0x88 // sceSblAuthMgrIsLoadable2:bzero(auth_info, 0x88) 68 | 69 | TYPE_BEGIN(struct self_auth_info, SIZEOF_SELF_AUTH_INFO); 70 | TYPE_FIELD(uint64_t paid, 0x00); 71 | TYPE_FIELD(uint64_t caps[4], 0x08); 72 | TYPE_FIELD(uint64_t attrs[4], 0x28); 73 | TYPE_FIELD(uint8_t unk[0x40], 0x48); 74 | TYPE_END(); 75 | 76 | #define SIZEOF_SELF_FAKE_AUTH_INFO (sizeof(uint64_t) + SIZEOF_SELF_AUTH_INFO) 77 | 78 | TYPE_BEGIN(struct self_fake_auth_info, SIZEOF_SELF_FAKE_AUTH_INFO); 79 | TYPE_FIELD(uint64_t size, 0x00); 80 | TYPE_FIELD(struct self_auth_info info, 0x08); 81 | TYPE_END(); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /fake_payload/include/sparse.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPARSE_H 2 | #define __SPARSE_H 3 | 4 | #define JOIN_HELPER(x, y) x##y 5 | #define JOIN(x, y) JOIN_HELPER(x, y) 6 | 7 | #define TYPE_PAD(size) char JOIN(_pad_, __COUNTER__)[size] 8 | #define TYPE_VARIADIC_BEGIN(name) name { union { 9 | #define TYPE_BEGIN(name, size) name { union { TYPE_PAD(size) 10 | #define TYPE_END(...) }; } __VA_ARGS__ 11 | #define TYPE_FIELD(field, offset) struct { TYPE_PAD(offset); field; } 12 | 13 | #define TYPE_CHECK_SIZE(name, size) \ 14 | _Static_assert(sizeof(name) == (size), "Size of " #name " != " #size) 15 | 16 | #define TYPE_CHECK_FIELD_OFFSET(name, member, offset) \ 17 | _Static_assert(offsetof(name, member) == (offset), "Offset of " #name "." #member " != " #offset) 18 | 19 | #define TYPE_CHECK_FIELD_SIZE(name, member, size) \ 20 | _Static_assert(sizeof(((name*)0)->member) == (size), "Size of " #name "." #member " != " #size) 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /fake_payload/source/fself.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sections.h" 5 | #include "sparse.h" 6 | #include "freebsd_helper.h" 7 | #include "elf_helper.h" 8 | #include "self_helper.h" 9 | #include "sbl_helper.h" 10 | 11 | #define PAGE_SIZE 0x4000 12 | 13 | typedef uint64_t vm_offset_t; 14 | 15 | extern void* M_TEMP PAYLOAD_DATA; 16 | extern void* (*real_malloc)(unsigned long size, void* type, int flags) PAYLOAD_DATA; 17 | extern void (*real_free)(void* addr, void* type) PAYLOAD_DATA; 18 | 19 | extern void (*real_dealloc)(void*) PAYLOAD_DATA; 20 | extern void* (*real_memcpy)(void* dst, const void* src, size_t len) PAYLOAD_DATA; 21 | extern void (*real_printf)(const char* fmt, ...) PAYLOAD_DATA; 22 | 23 | extern int (*real_sceSblServiceMailbox)(unsigned long service_id, uint8_t request[SBL_MSG_SERVICE_MAILBOX_MAX_SIZE], void* response) PAYLOAD_DATA; 24 | extern int (*real_sceSblAuthMgrGetSelfInfo)(struct self_context* ctx, struct self_ex_info** info) PAYLOAD_DATA; 25 | extern void (*real_sceSblAuthMgrSmStart)(void**) PAYLOAD_DATA; 26 | extern int (*real_sceSblAuthMgrIsLoadable2)(struct self_context* ctx, struct self_auth_info* old_auth_info, int path_id, struct self_auth_info* new_auth_info) PAYLOAD_DATA; 27 | extern int (*real_sceSblAuthMgrVerifyHeader)(struct self_context* ctx) PAYLOAD_DATA; 28 | 29 | const struct sbl_map_list_entry** sbl_driver_mapped_pages PAYLOAD_DATA; 30 | const uint8_t* mini_syscore_self_binary PAYLOAD_DATA; 31 | 32 | PAYLOAD_CODE static inline void* alloc(uint32_t size) 33 | { 34 | return real_malloc(size, M_TEMP, 2); 35 | } 36 | 37 | PAYLOAD_CODE static inline void dealloc(void* addr) 38 | { 39 | real_free(addr, M_TEMP); 40 | } 41 | 42 | PAYLOAD_CODE static inline const struct sbl_map_list_entry* sceSblDriverFindMappedPageListByGpuVa(vm_offset_t gpu_va) 43 | { 44 | const struct sbl_map_list_entry* entry; 45 | if (!gpu_va) 46 | { 47 | return NULL; 48 | } 49 | entry = *sbl_driver_mapped_pages; 50 | while (entry) 51 | { 52 | if (entry->gpu_va == gpu_va) 53 | { 54 | return entry; 55 | } 56 | entry = entry->next; 57 | } 58 | return NULL; 59 | } 60 | 61 | PAYLOAD_CODE static inline vm_offset_t sceSblDriverGpuVaToCpuVa(vm_offset_t gpu_va, size_t* num_page_groups) 62 | { 63 | const struct sbl_map_list_entry* entry = sceSblDriverFindMappedPageListByGpuVa(gpu_va); 64 | if (!entry) 65 | { 66 | return 0; 67 | } 68 | if (num_page_groups) 69 | { 70 | *num_page_groups = entry->num_page_groups; 71 | } 72 | return entry->cpu_va; 73 | } 74 | 75 | PAYLOAD_CODE static inline int sceSblAuthMgrGetSelfAuthInfoFake(struct self_context* ctx, struct self_auth_info* info) 76 | { 77 | struct self_header* hdr; 78 | struct self_fake_auth_info* fake_info; 79 | 80 | if (ctx->format == SELF_FORMAT_SELF) 81 | { 82 | hdr = (struct self_header*)ctx->header; 83 | fake_info = (struct self_fake_auth_info*)(ctx->header + hdr->header_size + hdr->meta_size - 0x100); 84 | if (fake_info->size == sizeof(fake_info->info)) 85 | { 86 | real_memcpy(info, &fake_info->info, sizeof(*info)); 87 | return 0; 88 | } 89 | return -37; 90 | } 91 | else 92 | { 93 | return -35; 94 | } 95 | } 96 | 97 | PAYLOAD_CODE static inline int is_fake_self(struct self_context* ctx) 98 | { 99 | struct self_ex_info* ex_info; 100 | if (ctx && ctx->format == SELF_FORMAT_SELF) 101 | { 102 | if (real_sceSblAuthMgrGetSelfInfo(ctx, &ex_info)) 103 | { 104 | return 0; 105 | } 106 | return ex_info->ptype == SELF_PTYPE_FAKE; 107 | } 108 | return 0; 109 | } 110 | 111 | PAYLOAD_CODE static inline int sceSblAuthMgrGetElfHeader(struct self_context* ctx, struct elf64_ehdr** ehdr) 112 | { 113 | struct self_header* self_hdr; 114 | struct elf64_ehdr* elf_hdr; 115 | size_t pdata_size; 116 | 117 | if (ctx->format == SELF_FORMAT_ELF) 118 | { 119 | elf_hdr = (struct elf64_ehdr*)ctx->header; 120 | if (ehdr) 121 | { 122 | *ehdr = elf_hdr; 123 | } 124 | return 0; 125 | } 126 | else if (ctx->format == SELF_FORMAT_SELF) 127 | { 128 | self_hdr = (struct self_header*)ctx->header; 129 | pdata_size = self_hdr->header_size - sizeof(struct self_entry) * self_hdr->num_entries - sizeof(struct self_header); 130 | if (pdata_size >= sizeof(struct elf64_ehdr) && (pdata_size & 0xF) == 0) 131 | { 132 | elf_hdr = (struct elf64_ehdr*)((uint8_t*)self_hdr + sizeof(struct self_header) + sizeof(struct self_entry) * self_hdr->num_entries); 133 | if (ehdr) 134 | { 135 | *ehdr = elf_hdr; 136 | } 137 | return 0; 138 | } 139 | return -37; 140 | } 141 | return -35; 142 | } 143 | 144 | static const uint8_t s_auth_info_for_exec[] PAYLOAD_RDATA = 145 | { 146 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x20, 147 | 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 150 | 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 155 | }; 156 | 157 | static const uint8_t s_auth_info_for_dynlib[] PAYLOAD_RDATA = 158 | { 159 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 | 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x00, 0x30, 162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 163 | 0x00, 0x40, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 168 | }; 169 | 170 | PAYLOAD_CODE static int build_self_auth_info_fake(struct self_context* ctx, struct self_auth_info* parent_auth_info, struct self_auth_info* auth_info) 171 | { 172 | struct self_auth_info fake_auth_info; 173 | struct self_ex_info* ex_info; 174 | struct elf64_ehdr* ehdr = NULL; 175 | int result; 176 | 177 | if (!ctx || !parent_auth_info || !auth_info) 178 | { 179 | result = EINVAL; 180 | goto error; 181 | } 182 | 183 | if (!is_fake_self(ctx)) 184 | { 185 | result = EINVAL; 186 | goto error; 187 | } 188 | 189 | result = real_sceSblAuthMgrGetSelfInfo(ctx, &ex_info); 190 | if (result) 191 | { 192 | goto error; 193 | } 194 | 195 | result = sceSblAuthMgrGetElfHeader(ctx, &ehdr); 196 | if (result) 197 | { 198 | goto error; 199 | } 200 | 201 | if (!ehdr) 202 | { 203 | result = ESRCH; 204 | goto error; 205 | } 206 | 207 | result = sceSblAuthMgrGetSelfAuthInfoFake(ctx, &fake_auth_info); 208 | if (result) 209 | { 210 | switch (ehdr->type) 211 | { 212 | case ELF_ET_EXEC: 213 | case ELF_ET_SCE_EXEC: 214 | case ELF_ET_SCE_EXEC_ASLR: 215 | { 216 | real_memcpy(&fake_auth_info, s_auth_info_for_exec, sizeof(fake_auth_info)); 217 | result = 0; 218 | break; 219 | } 220 | 221 | case ELF_ET_SCE_DYNAMIC: 222 | { 223 | real_memcpy(&fake_auth_info, s_auth_info_for_dynlib, sizeof(fake_auth_info)); 224 | result = 0; 225 | break; 226 | } 227 | 228 | default: 229 | { 230 | result = ENOTSUP; 231 | goto error; 232 | } 233 | } 234 | 235 | fake_auth_info.paid = ex_info->paid; 236 | 237 | // TODO: overwrite low bits of PAID with title id number 238 | } 239 | 240 | if (auth_info) 241 | { 242 | real_memcpy(auth_info, &fake_auth_info, sizeof(*auth_info)); 243 | } 244 | 245 | error: 246 | return result; 247 | } 248 | 249 | PAYLOAD_CODE int my_sceSblAuthMgrIsLoadable2(struct self_context* ctx, struct self_auth_info* old_auth_info, int path_id, struct self_auth_info* new_auth_info) 250 | { 251 | if (ctx->format == SELF_FORMAT_ELF || is_fake_self(ctx)) 252 | { 253 | return build_self_auth_info_fake(ctx, old_auth_info, new_auth_info); 254 | } 255 | else 256 | { 257 | return real_sceSblAuthMgrIsLoadable2(ctx, old_auth_info, path_id, new_auth_info); 258 | } 259 | } 260 | 261 | static inline int auth_self_header(struct self_context* ctx) 262 | { 263 | struct self_header* hdr; 264 | unsigned int old_total_header_size, new_total_header_size; 265 | int old_format; 266 | uint8_t* tmp; 267 | int is_unsigned; 268 | int result; 269 | 270 | is_unsigned = ctx->format == SELF_FORMAT_ELF || is_fake_self(ctx); 271 | if (is_unsigned) 272 | { 273 | old_format = ctx->format; 274 | old_total_header_size = ctx->total_header_size; 275 | 276 | /* take a header from mini-syscore.elf */ 277 | hdr = (struct self_header*)mini_syscore_self_binary; 278 | 279 | new_total_header_size = hdr->header_size + hdr->meta_size; 280 | 281 | tmp = (uint8_t*)alloc(new_total_header_size); 282 | if (!tmp) 283 | { 284 | result = ENOMEM; 285 | goto error; 286 | } 287 | 288 | /* temporarily swap an our header with a header from a real SELF file */ 289 | real_memcpy(tmp, ctx->header, new_total_header_size); 290 | real_memcpy(ctx->header, hdr, new_total_header_size); 291 | 292 | /* it's now SELF, not ELF or whatever... */ 293 | ctx->format = SELF_FORMAT_SELF; 294 | ctx->total_header_size = new_total_header_size; 295 | 296 | /* call the original method using a real SELF file */ 297 | result = real_sceSblAuthMgrVerifyHeader(ctx); 298 | 299 | /* restore everything we did before */ 300 | real_memcpy(ctx->header, tmp, new_total_header_size); 301 | ctx->format = old_format; 302 | ctx->total_header_size = old_total_header_size; 303 | 304 | dealloc(tmp); 305 | } 306 | else 307 | { 308 | result = real_sceSblAuthMgrVerifyHeader(ctx); 309 | } 310 | 311 | error: 312 | return result; 313 | } 314 | 315 | PAYLOAD_CODE int my_sceSblAuthMgrVerifyHeader(struct self_context* ctx) 316 | { 317 | void* dummy; 318 | real_sceSblAuthMgrSmStart(&dummy); 319 | return auth_self_header(ctx); 320 | } 321 | 322 | PAYLOAD_CODE int my_sceSblAuthMgrSmLoadSelfSegment__sceSblServiceMailbox(unsigned long service_id, uint8_t* request, void* response) 323 | { 324 | /* getting a stack frame of a parent function */ 325 | uint8_t* frame = (uint8_t*)__builtin_frame_address(1); 326 | /* finding a pointer to a context's structure */ 327 | struct self_context* ctx = *(struct self_context**)(frame - 0x110); 328 | int is_unsigned = ctx && is_fake_self(ctx); 329 | if (is_unsigned) 330 | { 331 | *(int*)(response + 0x04) = 0; /* setting error field to zero, thus we have no errors */ 332 | return 0; 333 | } 334 | return real_sceSblServiceMailbox(service_id, request, response); 335 | } 336 | 337 | PAYLOAD_CODE int my_sceSblAuthMgrSmLoadSelfBlock__sceSblServiceMailbox(unsigned long service_id, uint8_t* request, void* response) 338 | { 339 | struct self_context* ctx; 340 | register struct self_context* ctx_reg __asm__("r12"); 341 | vm_offset_t segment_data_gpu_va = *(unsigned long*)(request + 0x08); 342 | vm_offset_t cur_data_gpu_va = *(unsigned long*)(request + 0x50); 343 | vm_offset_t cur_data2_gpu_va = *(unsigned long*)(request + 0x58); 344 | unsigned int data_offset = *(unsigned int*)(request + 0x44); 345 | unsigned int data_size = *(unsigned int*)(request + 0x48); 346 | vm_offset_t segment_data_cpu_va, cur_data_cpu_va, cur_data2_cpu_va; 347 | unsigned int size1; 348 | 349 | ctx = ctx_reg; 350 | 351 | int is_unsigned = ctx && (ctx->format == SELF_FORMAT_ELF || is_fake_self(ctx)); 352 | int result; 353 | 354 | if (is_unsigned) 355 | { 356 | /* looking into lists of GPU's mapped memory regions */ 357 | segment_data_cpu_va = sceSblDriverGpuVaToCpuVa(segment_data_gpu_va, NULL); 358 | cur_data_cpu_va = sceSblDriverGpuVaToCpuVa(cur_data_gpu_va, NULL); 359 | cur_data2_cpu_va = cur_data2_gpu_va ? sceSblDriverGpuVaToCpuVa(cur_data2_gpu_va, NULL) : 0; 360 | 361 | if (segment_data_cpu_va && cur_data_cpu_va) 362 | { 363 | if (cur_data2_gpu_va && cur_data2_gpu_va != cur_data_gpu_va && data_offset > 0) 364 | { 365 | /* data spans two consecutive memory's pages, so we need to copy twice */ 366 | size1 = PAGE_SIZE - data_offset; 367 | real_memcpy((char*)segment_data_cpu_va, (char*)cur_data_cpu_va + data_offset, size1); 368 | real_memcpy((char*)segment_data_cpu_va + size1, (char*)cur_data2_cpu_va, data_size - size1); 369 | } 370 | else 371 | { 372 | real_memcpy((char*)segment_data_cpu_va, (char*)cur_data_cpu_va + data_offset, data_size); 373 | } 374 | } 375 | 376 | *(int*)(request + 0x04) = 0; /* setting error field to zero, thus we have no errors */ 377 | result = 0; 378 | } 379 | else 380 | { 381 | result = real_sceSblServiceMailbox(service_id, request, response); 382 | } 383 | 384 | return result; 385 | } 386 | -------------------------------------------------------------------------------- /fake_payload/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sections.h" 5 | #include "sparse.h" 6 | #include "freebsd_helper.h" 7 | #include "elf_helper.h" 8 | #include "self_helper.h" 9 | #include "sbl_helper.h" 10 | 11 | void* M_TEMP PAYLOAD_DATA; 12 | void* (*real_malloc)(unsigned long size, void* type, int flags) PAYLOAD_DATA; 13 | void (*real_free)(void* addr, void* type) PAYLOAD_DATA; 14 | 15 | void (*real_dealloc)(void*) PAYLOAD_DATA; 16 | void* (*real_memcpy)(void* dst, const void* src, size_t len) PAYLOAD_DATA; 17 | void (*real_printf)(const char* fmt, ...) PAYLOAD_DATA; 18 | 19 | int (*real_sceSblServiceMailbox)(unsigned long service_id, uint8_t request[SBL_MSG_SERVICE_MAILBOX_MAX_SIZE], void* response) PAYLOAD_DATA; 20 | int (*real_sceSblAuthMgrGetSelfInfo)(struct self_context* ctx, struct self_ex_info** info) PAYLOAD_DATA; 21 | void (*real_sceSblAuthMgrSmStart)(void**) PAYLOAD_DATA; 22 | int (*real_sceSblAuthMgrIsLoadable2)(struct self_context* ctx, struct self_auth_info* old_auth_info, int path_id, struct self_auth_info* new_auth_info) PAYLOAD_DATA; 23 | int (*real_sceSblAuthMgrVerifyHeader)(struct self_context* ctx) PAYLOAD_DATA; 24 | 25 | extern const struct sbl_map_list_entry** sbl_driver_mapped_pages PAYLOAD_DATA; 26 | extern const uint8_t* mini_syscore_self_binary PAYLOAD_DATA; 27 | 28 | extern int my_sceSblAuthMgrIsLoadable2(struct self_context* ctx, struct self_auth_info* old_auth_info, int path_id, struct self_auth_info* new_auth_info) PAYLOAD_CODE; 29 | extern int my_sceSblAuthMgrVerifyHeader(struct self_context* ctx) PAYLOAD_CODE; 30 | extern int my_sceSblAuthMgrSmLoadSelfSegment__sceSblServiceMailbox(unsigned long service_id, uint8_t* request, void* response) PAYLOAD_CODE; 31 | extern int my_sceSblAuthMgrSmLoadSelfBlock__sceSblServiceMailbox(unsigned long service_id, uint8_t* request, void* response) PAYLOAD_CODE; 32 | 33 | PAYLOAD_CODE void my_entrypoint() 34 | { 35 | // initialization, etc 36 | } 37 | 38 | struct real_info 39 | { 40 | const size_t kernel_offset; 41 | const void* payload_target; 42 | }; 43 | 44 | struct cave_info 45 | { 46 | const size_t kernel_call_offset; 47 | const size_t kernel_ptr_offset; 48 | const void* payload_target; 49 | }; 50 | 51 | struct disp_info 52 | { 53 | const size_t call_offset; 54 | const size_t cave_offset; 55 | }; 56 | 57 | struct real_info real_infos[] PAYLOAD_DATA = 58 | { 59 | { 0x1D1700, &real_malloc }, 60 | { 0x1D18D0, &real_free }, 61 | { 0x286CF0, &real_memcpy }, 62 | { 0x347580, &real_printf }, 63 | { 0x606F40, &real_sceSblServiceMailbox }, 64 | { 0x614A80, &real_sceSblAuthMgrIsLoadable2 }, 65 | { 0x614AE0, &real_sceSblAuthMgrVerifyHeader }, 66 | { 0x615360, &real_sceSblAuthMgrGetSelfInfo }, 67 | { 0x6153F0, &real_sceSblAuthMgrSmStart }, 68 | { 0x134B730, &M_TEMP }, 69 | { 0x136B3E8, &mini_syscore_self_binary }, 70 | { 0x234ED68, &sbl_driver_mapped_pages }, 71 | { 0, NULL }, 72 | }; 73 | 74 | #define ADJACENT(x) \ 75 | x, x + 6 76 | struct cave_info cave_infos[] PAYLOAD_DATA = 77 | { 78 | { ADJACENT(0x6116F1), &my_sceSblAuthMgrIsLoadable2 }, 79 | { ADJACENT(0x612EA1), &my_sceSblAuthMgrVerifyHeader }, 80 | { ADJACENT(0x617A32), &my_sceSblAuthMgrSmLoadSelfSegment__sceSblServiceMailbox }, 81 | { ADJACENT(0x617B80), &my_sceSblAuthMgrSmLoadSelfBlock__sceSblServiceMailbox }, 82 | { 0, 0, NULL }, 83 | }; 84 | #undef ADJACENT 85 | 86 | struct disp_info disp_infos[] PAYLOAD_DATA = 87 | { 88 | { 0x6119B5, 0x6116F1 }, // my_sceSblAuthMgrIsLoadable2 89 | { 0x612149, 0x612EA1 }, // my_sceSblAuthMgrVerifyHeader 90 | { 0x612D81, 0x612EA1 }, // my_sceSblAuthMgrVerifyHeader 91 | { 0x616A6D, 0x617A32 }, // my_sceSblAuthMgrSmLoadSelfSegment__sceSblServiceMailbox 92 | { 0x6176C4, 0x617B80 }, // my_sceSblAuthMgrSmLoadSelfBlock__sceSblServiceMailbox 93 | { 0, 0 }, 94 | }; 95 | 96 | struct 97 | { 98 | uint64_t signature; 99 | struct real_info* real_infos; 100 | struct cave_info* cave_infos; 101 | struct disp_info* disp_infos; 102 | void* entrypoint; 103 | } 104 | payload_header PAYLOAD_HEADER = 105 | { 106 | 0x5041594C4F414433ull, 107 | real_infos, 108 | cave_infos, 109 | disp_infos, 110 | &my_entrypoint, 111 | }; 112 | 113 | // dummies -- not included in output payload binary 114 | 115 | void PAYLOAD_DUMMY dummy() 116 | { 117 | dummy(); 118 | } 119 | 120 | int _start() 121 | { 122 | return 0; 123 | } 124 | --------------------------------------------------------------------------------