Resolve ShellCore mount hooks from dynamic imports

This commit is contained in:
EchoStretch committed 2026-09-19 16:42:37 -06:00
1 parent e8f6819656
commit 47e6c23311
62 files changed
+493 -945

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ clean:
dl.o: dl.c
gcc -c -isystem ../freebsd-headers -nostdinc -fno-stack-protector dl.c -o dl.o -fPIE -ffreestanding
crt-elf-c.o: crt-elf-c.c
crt-elf-c.o: crt-elf-c.c r0gdb-bootstrap.h shellcore-imports.h
gcc -c -isystem ../freebsd-headers -nostdinc -fno-stack-protector -O3 crt-elf-c.c -o crt-elf-c.o -fPIE -ffreestanding
crt.o: crt.asm
+15 -1
View File
@@ -1,5 +1,6 @@
#include <sys/types.h>
#include "r0gdb-bootstrap.h"
#include "shellcore-imports.h"
struct specter_args
{
@@ -13,8 +14,21 @@ struct specter_args
uint64_t _start(void* dlsym, int master, int victim, uint64_t pktopts, uint64_t kdata_base);
void elf_main(struct specter_args* args)
intptr_t (*kstuff_dynlib_resolve)(int pid, uint32_t handle, const char* nid);
int (*kstuff_dynlib_handle)(int pid, const char* name, uint32_t* handle);
kstuff_shellcore_imports_fn kstuff_shellcore_imports;
void elf_main(struct specter_args* args, uint64_t resolver_magic,
intptr_t (*resolver)(int, uint32_t, const char*),
int (*handle_lookup)(int, const char*, uint32_t*),
kstuff_shellcore_imports_fn import_lookup)
{
if(resolver_magic == KSTUFF_DYNLIB_RESOLVER_MAGIC)
{
kstuff_dynlib_resolve = resolver;
kstuff_dynlib_handle = handle_lookup;
kstuff_shellcore_imports = import_lookup;
}
struct r0gdb_bootstrap bootstrap = {
.magic = R0GDB_BOOTSTRAP_MAGIC,
.rwpipe = {args->pipe[0], args->pipe[1]},
+1
View File
@@ -4,6 +4,7 @@
#include <stdint.h>
#define R0GDB_BOOTSTRAP_MAGIC UINT64_C(0x5230474442504950)
#define KSTUFF_DYNLIB_RESOLVER_MAGIC UINT64_C(0x4b53544650524731)
struct r0gdb_bootstrap {
uint64_t magic;
+33
View File
@@ -0,0 +1,33 @@
#ifndef KSTUFF_SHELLCORE_IMPORTS_H
#define KSTUFF_SHELLCORE_IMPORTS_H
#include <stdint.h>
enum {
SHELLCORE_IMPORT_CLOSE,
SHELLCORE_IMPORT_OPEN,
SHELLCORE_IMPORT_PREAD,
SHELLCORE_IMPORT_MOUNT_GAME,
SHELLCORE_IMPORT_UMOUNT_GAME,
SHELLCORE_IMPORT_MOUNT_PPR,
SHELLCORE_IMPORT_UMOUNT_PPR,
SHELLCORE_IMPORT_COUNT
};
#define SHELLCORE_IMPORT_BIT(index) (1u << (index))
static const char *const shellcore_import_nids[SHELLCORE_IMPORT_COUNT] = {
"bY-PO6JhzhQ", /* close */
"wuCroIGjt2g", /* open */
"ezv-RSBNKqI", /* pread */
"FtGP5aXKFQU", /* sceFsMountGamePkg */
"UQTSykySQ40", /* sceFsUmountGamePkg */
"MiUxeleLYUc", /* sceFsMountPprPkg */
"S5+bpaH0TWk", /* sceFsUmountPprPkg */
};
typedef int (*kstuff_shellcore_imports_fn)(int pid, uint64_t image_base,
uint32_t required_mask,
uint64_t got[SHELLCORE_IMPORT_COUNT]);
#endif
+2 -3
View File
@@ -25,7 +25,7 @@ endif
LOADER_OPT ?= -O2
CFLAGS += -Wall -Werror
CPPFLAGS += -Iinclude
CPPFLAGS += -Iinclude -I$(PS5_PAYLOAD_SDK)/src/crt
LDFLAGS += -lz \
-lSceSystemService \
@@ -45,7 +45,7 @@ all: kstuff.elf
../ps5-kstuff/payload.bin: .FORCE
$(MAKE) -C ../ps5-kstuff/
kstuff.elf: ../ps5-kstuff/payload.bin $(SRC)
kstuff.elf: ../ps5-kstuff/payload.bin $(SRC) ../lib/r0gdb-bootstrap.h ../lib/shellcore-imports.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(LOADER_OPT) $(SRC) -o $@ $(LDFLAGS)
clean:
@@ -53,4 +53,3 @@ clean:
test: kstuff.elf
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
+12 -2
View File
@@ -48,6 +48,8 @@ along with this program; see the file COPYING. If not, see
#include "mount_helpers.h"
#include "shellui_patch.h"
#include "utils.h"
#include "../../lib/r0gdb-bootstrap.h"
#include "../../lib/shellcore-imports.h"
asm(".section .rodata\n"
".global ___ps5_kstuff_payload_bin\n"
@@ -55,6 +57,8 @@ asm(".section .rodata\n"
".incbin \"../../ps5-kstuff/payload.bin\"\n");
extern char ___ps5_kstuff_payload_bin[];
int shellcore_import_got(int pid, uint64_t image_base, uint32_t required_mask,
uint64_t got[SHELLCORE_IMPORT_COUNT]);
int patch_app_db(void);
int sceKernelSetProcessName(const char *name);
@@ -414,7 +418,11 @@ int main(void) {
}
}
void (*entry)(payload_args_t*) = base + ehdr->e_entry;
void (*entry)(payload_args_t*, uint64_t,
intptr_t (*)(int, uint32_t, const char*),
int (*)(int, const char*, uint32_t*),
kstuff_shellcore_imports_fn) =
base + ehdr->e_entry;
payload_args_t* args = payload_get_args();
// allow dlsym on 5.00+ - https://gist.github.com/TheOfficialFloW/7174351201b5260d7780780f4059bebf#file-exploitnetcontrolimpl-java-L851
@@ -425,7 +433,9 @@ int main(void) {
kernel_setlong(eboot_segments + 0x08, 0); // addr
kernel_setlong(eboot_segments + 0x10, 0xFFFFFFFFFFFFFFFFL); // size
entry(args);
entry(args, KSTUFF_DYNLIB_RESOLVER_MAGIC,
kernel_dynlib_resolve, kernel_dynlib_handle,
shellcore_import_got);
if(*args->payloadout == 0) {
puts("patching app.db");
*args->payloadout = patch_app_db();
+101
View File
@@ -0,0 +1,101 @@
#include <elf.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* The SDK keeps decrypted relocation and symbol tables in the dynlib object. */
#include <kernel.h>
#include "../../lib/shellcore-imports.h"
enum { SHELLCORE_JUMP_SLOT_RELOCATION = 7 };
_Static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf64_Sym) == 24,
"unexpected ShellCore relocation ABI");
int shellcore_import_got(int pid, uint64_t image_base, uint32_t required_mask,
uint64_t got[SHELLCORE_IMPORT_COUNT])
{
dynlib_obj_t obj;
dynlib_dynsec_t dynsec;
unsigned char *tables = NULL;
int result = -1;
const uint32_t valid_mask = (1u << SHELLCORE_IMPORT_COUNT) - 1;
if(!got)
return -1;
memset(got, 0, sizeof(uint64_t) * SHELLCORE_IMPORT_COUNT);
if(!required_mask || (required_mask & ~valid_mask))
return -1;
if(kernel_dynlib_obj(pid, 0, &obj) || obj.mapbase != image_base
|| !obj.dynsec || kernel_copyout(obj.dynsec, &dynsec, sizeof(dynsec)))
return -1;
if(obj.mapbase < 0x10000
|| obj.mapbase >= 0x0000800000000000ull
|| obj.mapsize < sizeof(uint64_t)
|| obj.mapsize >= 0x0000800000000000ull - obj.mapbase
|| !dynsec.pltrela || !dynsec.symtab || !dynsec.strtab
|| !dynsec.pltrelasize || dynsec.pltrelasize > 0x100000
|| dynsec.pltrelasize % sizeof(Elf64_Rela)
|| !dynsec.symtabsize || dynsec.symtabsize > 0x100000
|| dynsec.symtabsize % sizeof(Elf64_Sym)
|| !dynsec.strtabsize || dynsec.strtabsize > 0x100000)
return -1;
size_t tables_size = dynsec.pltrelasize + dynsec.symtabsize
+ dynsec.strtabsize;
tables = malloc(tables_size);
if(!tables)
return -1;
Elf64_Rela *rela = (Elf64_Rela *)tables;
Elf64_Sym *sym = (Elf64_Sym *)(tables + dynsec.pltrelasize);
char *str = (char *)(tables + dynsec.pltrelasize + dynsec.symtabsize);
if(kernel_copyout(dynsec.pltrela, rela, dynsec.pltrelasize)
|| kernel_copyout(dynsec.symtab, sym, dynsec.symtabsize)
|| kernel_copyout(dynsec.strtab, str, dynsec.strtabsize))
goto done;
size_t sym_count = dynsec.symtabsize / sizeof(*sym);
size_t rela_count = dynsec.pltrelasize / sizeof(*rela);
for(size_t i = 0; i < rela_count; i++)
{
if((uint32_t)rela[i].r_info != SHELLCORE_JUMP_SLOT_RELOCATION)
continue;
size_t sym_index = rela[i].r_info >> 32;
if(sym_index >= sym_count)
goto done;
size_t name_offset = sym[sym_index].st_name;
if(name_offset >= dynsec.strtabsize)
goto done;
if(dynsec.strtabsize - name_offset < 12)
continue;
const char *name = str + name_offset;
for(size_t j = 0; j < SHELLCORE_IMPORT_COUNT; j++)
{
if(!(required_mask & SHELLCORE_IMPORT_BIT(j))
|| memcmp(name, shellcore_import_nids[j], 11)
|| name[11] != '#')
continue;
if(got[j] || rela[i].r_offset > obj.mapsize - sizeof(uint64_t)
|| (rela[i].r_offset & (sizeof(uint64_t) - 1)))
goto done;
got[j] = image_base + rela[i].r_offset;
}
}
for(size_t j = 0; j < SHELLCORE_IMPORT_COUNT; j++)
{
if((required_mask & SHELLCORE_IMPORT_BIT(j)) && !got[j])
goto done;
for(size_t previous = 0; previous < j; previous++)
if(got[j] && got[j] == got[previous])
goto done;
}
result = 0;
done:
free(tables);
if(result)
memset(got, 0, sizeof(uint64_t) * SHELLCORE_IMPORT_COUNT);
return result;
}
+1 -1
View File
@@ -40,7 +40,7 @@ $(BUILD_CONFIG): FORCE
structs.inc: structs-ps5.inc
cp structs-ps5.inc structs.inc
payload.elf: ../lib/lib-elf-ps5.a ../prosper0gdb/prosper0gdb.o main.c kelf uelf/uelf.bin shellcore_hook/ppr_mount_940_blob.o $(BUILD_CONFIG) shellcore_patches/*
payload.elf: ../lib/lib-elf-ps5.a ../lib/shellcore-imports.h ../prosper0gdb/prosper0gdb.o main.c kelf uelf/uelf.bin shellcore_hook/ppr_mount_940_blob.o $(BUILD_CONFIG) shellcore_patches/*
gcc $(PAYLOAD_OPT) -isystem ../freebsd-headers -nostdinc -nostdlib -fno-stack-protector -static ../lib/lib-elf-ps5.a ../prosper0gdb/prosper0gdb.o shellcore_hook/ppr_mount_940_blob.o $(EXTRA_CFLAGS) -DKSTUFF_OBS=$(KSTUFF_OBS) main.c -DPS5KEK ../prosper0gdb/dbg.c -Wl,-gc-sections -o payload.elf -fPIE -ffreestanding -no-pie -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
payloa%.bin: payloa%.elf
+188 -370
View File
@@ -15,6 +15,7 @@
#include "../gdb_stub/dbg.h"
#include "uelf/structs.h"
#include "uelf/shared_area.h"
#include "../lib/shellcore-imports.h"
void* dlsym(void*, const char*);
void* memcpy(void * __restrict, const void * __restrict, size_t);
@@ -405,7 +406,9 @@ int phys_copyin(uint64_t vaddr, const void* src, uint64_t sz, uint64_t dmap, uin
size_t chk = phys_end - phys;
if(sz < chk)
chk = sz;
copyin(dmap+phys, p_src, chk);
ssize_t copied = copyin(dmap + phys, p_src, chk);
if(copied < 0 || (size_t)copied != chk)
return -1;
vaddr += chk;
p_src += chk;
sz -= chk;
@@ -426,7 +429,9 @@ static int phys_copyout(void* dst, uint64_t vaddr, uint64_t sz,
size_t chk = phys_end - phys;
if(sz < chk)
chk = sz;
copyout(p_dst, dmap + phys, chk);
ssize_t copied = copyout(p_dst, dmap + phys, chk);
if(copied < 0 || (size_t)copied != chk)
return -1;
vaddr += chk;
p_dst += chk;
sz -= chk;
@@ -550,8 +555,6 @@ static uint64_t remote_syscall(int pid, int nr,
#define SYS_mlock 203
#define SYS_mdbg_call 573
#define SYS_dynlib_dlsym 591
#define SYS_dynlib_get_list 592
#define SYS_dynlib_get_info_ex 608
#define SYS_dynlib_load_prx 594
#define SYS_get_self_auth_info 607
@@ -596,24 +599,6 @@ struct shellcore_patch
size_t sz;
};
struct shellcore_fpkg_offsets
{
/* Early ShellCore builds leave the package API GOT slots lazy until the
* first game launch. Those builds use verified direct call sites and a
* small executable tail trampoline instead of rewriting unresolved GOT. */
uint64_t ppr_call;
uint64_t ppr_cave;
uint64_t ppr_cave_size;
uint64_t close_plt;
uint64_t open_plt;
uint64_t pread_plt;
uint64_t mount_ppr_pkg_plt;
uint64_t getpid_plt;
uint64_t game_mount_calls[4];
uint64_t game_umount_calls[4];
uint64_t ppr_umount_call;
};
/*
* TODO(FW_PORT): add shellcore_patches/<major>_<minor>.h here after deriving
* every patch from that exact SceShellCore build. Patch offsets are relative
@@ -684,69 +669,6 @@ struct shellcore_fpkg_offsets
#include "shellcore_patches/13_42.h"
#include "shellcore_patches/13_60.h"
static const struct shellcore_fpkg_offsets* get_shellcore_fpkg_offsets(void)
{
switch(r0gdb_get_fw_version() >> 16)
{
#define SHELLCORE_FPKG_FW(x) \
case 0x ## x: return &shellcore_fpkg_offsets_ ## x
SHELLCORE_FPKG_FW(100);
SHELLCORE_FPKG_FW(101);
SHELLCORE_FPKG_FW(102);
SHELLCORE_FPKG_FW(112);
SHELLCORE_FPKG_FW(114);
SHELLCORE_FPKG_FW(200);
SHELLCORE_FPKG_FW(220);
SHELLCORE_FPKG_FW(225);
SHELLCORE_FPKG_FW(226);
SHELLCORE_FPKG_FW(230);
SHELLCORE_FPKG_FW(250);
SHELLCORE_FPKG_FW(270);
SHELLCORE_FPKG_FW(300);
SHELLCORE_FPKG_FW(310);
SHELLCORE_FPKG_FW(320);
SHELLCORE_FPKG_FW(321);
SHELLCORE_FPKG_FW(400);
SHELLCORE_FPKG_FW(402);
SHELLCORE_FPKG_FW(403);
SHELLCORE_FPKG_FW(450);
SHELLCORE_FPKG_FW(451);
SHELLCORE_FPKG_FW(500);
SHELLCORE_FPKG_FW(502);
SHELLCORE_FPKG_FW(510);
SHELLCORE_FPKG_FW(550);
SHELLCORE_FPKG_FW(600);
SHELLCORE_FPKG_FW(602);
SHELLCORE_FPKG_FW(650);
SHELLCORE_FPKG_FW(700);
SHELLCORE_FPKG_FW(701);
SHELLCORE_FPKG_FW(720);
SHELLCORE_FPKG_FW(740);
SHELLCORE_FPKG_FW(760);
SHELLCORE_FPKG_FW(761);
SHELLCORE_FPKG_FW(800);
SHELLCORE_FPKG_FW(820);
SHELLCORE_FPKG_FW(840);
SHELLCORE_FPKG_FW(860);
SHELLCORE_FPKG_FW(900);
SHELLCORE_FPKG_FW(905);
SHELLCORE_FPKG_FW(920);
SHELLCORE_FPKG_FW(940);
SHELLCORE_FPKG_FW(960);
SHELLCORE_FPKG_FW(1000);
SHELLCORE_FPKG_FW(1001);
SHELLCORE_FPKG_FW(1020);
SHELLCORE_FPKG_FW(1040);
SHELLCORE_FPKG_FW(1060);
SHELLCORE_FPKG_FW(1100);
SHELLCORE_FPKG_FW(1120);
SHELLCORE_FPKG_FW(1140);
/* Keep 11.60+ PPR/fPKG offset data disconnected from the runtime hook. */
#undef SHELLCORE_FPKG_FW
default: return 0;
}
}
extern char _start[];
static void relocate_shellcore_patches(struct shellcore_patch* patches, size_t n_patches)
@@ -907,6 +829,35 @@ static int shellcore_bytes_equal(const unsigned char* lhs,
return 1;
}
static int verify_shellcore_blob(uint64_t address, const unsigned char* blob,
size_t size, uint64_t dmap, uint64_t cr3)
{
unsigned char readback[0x400];
for(size_t offset = 0; offset < size; offset += sizeof(readback))
{
size_t length = size - offset;
if(length > sizeof(readback))
length = sizeof(readback);
if(phys_copyout(readback, address + offset, length, dmap, cr3)
|| !shellcore_bytes_equal(readback, blob + offset, length))
return -1;
}
return 0;
}
extern intptr_t (*kstuff_dynlib_resolve)(int pid, uint32_t handle,
const char* nid);
extern int (*kstuff_dynlib_handle)(int pid, const char* name,
uint32_t* handle);
extern kstuff_shellcore_imports_fn kstuff_shellcore_imports;
static const unsigned char shellcore_getpid_stub[] = {
0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, /* mov eax, SYS_getpid */
0x49, 0x89, 0xca, /* mov r10, rcx */
0x0f, 0x05, /* syscall */
0x72, 0x01, 0xc3 /* jc error; ret */
};
static int find_shellcore_blob_entry(const unsigned char* blob,
size_t blob_size, uint64_t marker,
size_t* entry_offset)
@@ -924,34 +875,31 @@ static int find_shellcore_blob_entry(const unsigned char* blob,
return count == 1 && *entry_offset < blob_size ? 0 : -1;
}
static int resolve_shellcore_plt(uint64_t shellcore_base,
uint64_t plt_offset,
static int read_shellcore_import(int pid, uint64_t shellcore_base,
uint64_t text_end, uint64_t got,
uint64_t dmap, uint64_t cr3,
int pid,
struct shellcore_locked_pages* locked,
uint64_t* got, uint64_t* target)
uint64_t* target, uint64_t* lazy_plt)
{
unsigned char plt[6];
if(!plt_offset
|| lock_shellcore_range(pid, shellcore_base + plt_offset,
sizeof(plt), locked)
|| phys_copyout(plt, shellcore_base + plt_offset, sizeof(plt),
dmap, cr3)
|| plt[0] != 0xff || plt[1] != 0x25)
if(!got || lock_shellcore_range(pid, got, sizeof(*target), locked)
|| phys_copyout(target, got, sizeof(*target), dmap, cr3)
|| *target < 0x10000 || *target >= 0x0000800000000000ull)
return -1;
int32_t displacement;
memcpy(&displacement, plt + 2, sizeof(displacement));
uint64_t resolved_got = shellcore_base + plt_offset
+ sizeof(plt) + displacement;
if(lock_shellcore_range(pid, resolved_got, sizeof(*target), locked)
|| phys_copyout(target, resolved_got, sizeof(*target), dmap, cr3)
|| *target < 0x10000 || *target >= 0x0000800000000000ull
/* An unresolved lazy slot points back to PLT+6. Redirecting that GOT
* entry would let the first resolver pass overwrite our wrapper. */
|| *target == shellcore_base + plt_offset + sizeof(plt))
return -1;
if(got)
*got = resolved_got;
*lazy_plt = 0;
if(*target >= shellcore_base + 6 && *target < text_end)
{
unsigned char plt[6];
uint64_t plt_addr = *target - sizeof(plt);
if(lock_shellcore_range(pid, plt_addr, sizeof(plt), locked)
|| phys_copyout(plt, plt_addr, sizeof(plt), dmap, cr3)
|| plt[0] != 0xff || plt[1] != 0x25)
return -1;
int32_t displacement;
memcpy(&displacement, plt + 2, sizeof(displacement));
if(*target + displacement != got)
return -1;
*lazy_plt = plt_addr;
}
return 0;
}
@@ -959,257 +907,117 @@ static int resolve_shellcore_syscall_trampoline(
int pid, uint64_t dmap, uint64_t cr3,
struct shellcore_locked_pages* locked, uint64_t* target)
{
enum { MAX_MODULES = 128 };
uint32_t handles[MAX_MODULES];
size_t module_count = MAX_MODULES;
static const char getpid_name[] = "getpid";
static const unsigned char expected[] = {
0x48, 0xc7, 0xc0, 0x14, 0x00, 0x00, 0x00, /* mov eax, SYS_getpid */
0x49, 0x89, 0xca, /* mov r10, rcx */
0x0f, 0x05 /* syscall */
};
if(remote_syscall(pid, SYS_dynlib_get_list, (uint64_t)handles,
MAX_MODULES, (uint64_t)&module_count, 0, 0, 0)
|| !module_count || module_count > MAX_MODULES)
return -1;
for(size_t i = 0; i < module_count; i++)
static const uint32_t libkernel_handles[] = {1, 0x2001};
for(size_t i = 0; i < sizeof(libkernel_handles)
/ sizeof(libkernel_handles[0]); i++)
{
uint64_t getpid_target = 0;
if(remote_syscall(pid, SYS_dynlib_dlsym, handles[i],
(uint64_t)getpid_name,
(uint64_t)&getpid_target, 0, 0, 0)
|| getpid_target < 0x10000
|| getpid_target >= 0x0000800000000000ull)
uint64_t address = kstuff_dynlib_resolve(
pid, libkernel_handles[i], "HoLVWNanBBc"); /* getpid */
if(address < 0x10000
|| address >= 0x0000800000000000ull
- sizeof(shellcore_getpid_stub))
continue;
unsigned char code[sizeof(expected)];
if(lock_shellcore_range(pid, getpid_target, sizeof(code), locked)
|| phys_copyout(code, getpid_target, sizeof(code), dmap, cr3)
|| !shellcore_bytes_equal(code, expected, sizeof(expected)))
unsigned char code[sizeof(shellcore_getpid_stub)];
if(phys_copyout(code, address, sizeof(code), dmap, cr3)
&& (lock_shellcore_range(pid, address, sizeof(code), locked)
|| phys_copyout(code, address, sizeof(code), dmap, cr3)))
continue;
*target = getpid_target + 7;
return 0;
if(shellcore_bytes_equal(code, shellcore_getpid_stub,
sizeof(code)))
{
*target = address + 7;
return 0;
}
}
return -1;
}
struct shellcore_direct_call
{
uint64_t offset;
unsigned int api;
};
static int install_shellcore_direct_fpkg_calls(
int pid, uint64_t shellcore_base, uint64_t dmap, uint64_t cr3,
const struct shellcore_fpkg_offsets* sc,
const uint64_t api_plt[4], const uint64_t api_wrapper[4],
struct shellcore_locked_pages* locked)
{
enum { API_COUNT = 4, TRAMPOLINE_SIZE = 16, MAX_CALLS = 10 };
struct shellcore_direct_call calls[MAX_CALLS];
unsigned char original[MAX_CALLS][5];
unsigned char patched[MAX_CALLS][5];
unsigned char trampolines[API_COUNT * TRAMPOLINE_SIZE];
unsigned char current[sizeof(trampolines)];
size_t count = 0;
#define ADD_DIRECT_CALL(which_offset, which_api) do { \
if((which_offset) && count < MAX_CALLS) { \
calls[count].offset = (which_offset); \
calls[count].api = (which_api); \
count++; \
} \
} while(0)
for(size_t i = 0; i < 4; i++)
ADD_DIRECT_CALL(sc->game_mount_calls[i], 0);
for(size_t i = 0; i < 4; i++)
ADD_DIRECT_CALL(sc->game_umount_calls[i], 1);
ADD_DIRECT_CALL(sc->ppr_call, 2);
ADD_DIRECT_CALL(sc->ppr_umount_call, 3);
#undef ADD_DIRECT_CALL
if(!sc->ppr_cave || sc->ppr_cave_size < sizeof(trampolines)
|| !sc->ppr_call || !sc->ppr_umount_call || count < 2)
return -1;
if(lock_shellcore_range(pid, shellcore_base + sc->ppr_cave,
sizeof(trampolines), locked)
|| phys_copyout(current, shellcore_base + sc->ppr_cave,
sizeof(trampolines), dmap, cr3))
return -1;
for(size_t i = 0; i < sizeof(trampolines); i++)
if(current[i])
return -1;
for(size_t i = 0; i < sizeof(trampolines); i++)
trampolines[i] = 0xcc;
for(size_t api = 0; api < API_COUNT; api++)
{
unsigned char* trampoline = trampolines + api * TRAMPOLINE_SIZE;
trampoline[0] = 0x48; /* movabs rax, api_wrapper[api] */
trampoline[1] = 0xb8;
memcpy(trampoline + 2, &api_wrapper[api], sizeof(api_wrapper[api]));
trampoline[10] = 0xff; /* jmp rax */
trampoline[11] = 0xe0;
}
/* Validate every call and its original destination before changing code. */
for(size_t i = 0; i < count; i++)
{
if(lock_shellcore_range(pid, shellcore_base + calls[i].offset,
sizeof(original[i]), locked)
|| phys_copyout(original[i], shellcore_base + calls[i].offset,
sizeof(original[i]), dmap, cr3)
|| original[i][0] != 0xe8)
return -1;
int32_t displacement;
memcpy(&displacement, original[i] + 1, sizeof(displacement));
if(calls[i].offset + sizeof(original[i]) + displacement
!= api_plt[calls[i].api])
return -1;
patched[i][0] = 0xe8;
int64_t wide = (int64_t)sc->ppr_cave
+ (int64_t)calls[i].api * TRAMPOLINE_SIZE
- (int64_t)(calls[i].offset + sizeof(patched[i]));
int32_t relative = (int32_t)wide;
if((int64_t)relative != wide)
return -1;
memcpy(patched[i] + 1, &relative, sizeof(relative));
}
if(phys_copyin(shellcore_base + sc->ppr_cave, trampolines,
sizeof(trampolines), dmap, cr3)
|| phys_copyout(current, shellcore_base + sc->ppr_cave,
sizeof(trampolines), dmap, cr3)
|| !shellcore_bytes_equal(current, trampolines, sizeof(trampolines)))
return -1;
size_t installed = 0;
for(; installed < count; installed++)
{
unsigned char verify[sizeof(patched[installed])];
if(phys_copyin(shellcore_base + calls[installed].offset,
patched[installed], sizeof(patched[installed]),
dmap, cr3)
|| phys_copyout(verify, shellcore_base + calls[installed].offset,
sizeof(verify), dmap, cr3)
|| !shellcore_bytes_equal(verify, patched[installed], sizeof(verify)))
break;
}
if(installed == count)
return 0;
/* A partially reachable wrapper is unsafe. Restore every touched call;
* return -2 if a reference may still remain so the RX mapping is kept. */
int rollback_failed = 0;
size_t touched = installed < count ? installed + 1 : installed;
for(size_t i = 0; i < touched; i++)
{
unsigned char verify[sizeof(original[i])];
if(phys_copyin(shellcore_base + calls[i].offset,
original[i], sizeof(original[i]), dmap, cr3)
|| phys_copyout(verify, shellcore_base + calls[i].offset,
sizeof(verify), dmap, cr3)
|| !shellcore_bytes_equal(verify, original[i], sizeof(verify)))
rollback_failed = 1;
}
return rollback_failed ? -2 : -1;
}
static int install_shellcore_ppr_hook(
int pid, uint64_t shellcore_base, uint64_t dmap, uint64_t cr3,
const struct shellcore_fpkg_offsets* sc,
int pid, uint64_t shellcore_base, uint64_t text_end,
uint64_t dmap, uint64_t cr3,
struct shellcore_locked_pages* locked)
{
const size_t blob_size = (size_t)(ppr_mount_940_blob_end
- ppr_mount_940_blob_start);
static unsigned char prepared_blob[SHELLCORE_FPKG_WRAPPER_MAP_SIZE];
uint64_t helper_target[3];
uint64_t api_got[4], api_target[4];
uint64_t helper_target[3] = {0};
uint64_t api_got[4] = {0}, api_target[4] = {0};
uint64_t import_got[SHELLCORE_IMPORT_COUNT];
uint64_t api_original_got[4] = {0};
uint64_t api_wrapper[4];
uint32_t fs_handle = 0;
int have_fs_handle = 0;
size_t game_mount_entry = 0;
size_t game_umount_entry = 0;
size_t ppr_umount_entry = 0;
int direct_calls = sc->ppr_umount_call != 0;
if(!sc->close_plt || !sc->open_plt || !sc->pread_plt
|| !sc->mount_ppr_pkg_plt || (!direct_calls && !sc->getpid_plt))
return shellcore_ppr_fail("fpkg scope: missing ShellCore offsets");
int game_only = (r0gdb_get_fw_version() >> 16) > 0x1140;
size_t api_count = game_only ? 2 : 4;
if(!blob_size || blob_size > sizeof(prepared_blob))
return shellcore_ppr_fail("fpkg scope: invalid wrapper blob size");
/* These four imports are consecutive pairs in every supported retail
* ShellCore. Validate every derived PLT before changing any state. */
const uint64_t api_plt[4] = {
sc->mount_ppr_pkg_plt - 0x40, /* sceFsMountGamePkg */
sc->mount_ppr_pkg_plt - 0x20, /* sceFsUmountGamePkg */
sc->mount_ppr_pkg_plt, /* sceFsMountPprPkg */
sc->mount_ppr_pkg_plt + 0x20, /* sceFsUmountPprPkg */
};
const uint64_t helper_plt[3] = {
sc->close_plt, sc->open_plt, sc->pread_plt
};
if(sc->mount_ppr_pkg_plt < 0x40)
return shellcore_ppr_fail("fpkg scope: invalid API PLT layout");
for(size_t i = 0; i < 3; i++)
uint32_t required_mask = SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_MOUNT_GAME)
| SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_UMOUNT_GAME);
if(!game_only)
required_mask |= SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_CLOSE)
| SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_OPEN)
| SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_PREAD)
| SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_MOUNT_PPR)
| SHELLCORE_IMPORT_BIT(SHELLCORE_IMPORT_UMOUNT_PPR);
if(kstuff_shellcore_imports(pid, shellcore_base, required_mask,
import_got))
return shellcore_ppr_fail("fpkg scope: ShellCore imports unavailable");
for(size_t i = 0; i < (game_only ? 0 : 3); i++)
{
unsigned char plt[6];
if(lock_shellcore_range(pid, shellcore_base + helper_plt[i],
sizeof(plt), locked)
|| phys_copyout(plt, shellcore_base + helper_plt[i], sizeof(plt),
dmap, cr3)
|| plt[0] != 0xff || plt[1] != 0x25)
return shellcore_ppr_fail("fpkg scope: helper PLT mismatch");
/* These GOT entries may also be lazy on early firmware. They are not
* redirected, so calling their PLT stubs is resolver-safe. */
helper_target[i] = shellcore_base + helper_plt[i];
uint64_t lazy_plt;
if(read_shellcore_import(pid, shellcore_base, text_end, import_got[i],
dmap, cr3, locked, &helper_target[i],
&lazy_plt))
return shellcore_ppr_fail("fpkg scope: helper import mismatch");
if(lazy_plt)
helper_target[i] = lazy_plt;
}
for(size_t i = 0; i < 4; i++)
for(size_t i = 0; i < api_count; i++)
{
if(direct_calls)
api_got[i] = import_got[SHELLCORE_IMPORT_MOUNT_GAME + i];
uint64_t lazy_plt;
if(read_shellcore_import(pid, shellcore_base, text_end, api_got[i],
dmap, cr3, locked, &api_target[i],
&lazy_plt))
return shellcore_ppr_fail(
"fpkg scope: package API import mismatch");
if(api_got[i] & (sizeof(api_got[i]) - 1))
return shellcore_ppr_fail("fpkg scope: unaligned API GOT slot");
for(size_t previous = 0; previous < i; previous++)
if(api_got[previous] == api_got[i])
return shellcore_ppr_fail("fpkg scope: duplicate API GOT slot");
api_original_got[i] = api_target[i];
if(lazy_plt)
{
unsigned char plt[6];
if(lock_shellcore_range(pid, shellcore_base + api_plt[i],
sizeof(plt), locked)
|| phys_copyout(plt, shellcore_base + api_plt[i], sizeof(plt),
dmap, cr3)
|| plt[0] != 0xff || plt[1] != 0x25)
if(!have_fs_handle)
{
if(kstuff_dynlib_handle(pid, "libSceFsInternalForVsh.prx",
&fs_handle))
return shellcore_ppr_fail(
"fpkg scope: package API module unavailable");
have_fs_handle = 1;
}
uint64_t address = kstuff_dynlib_resolve(pid, fs_handle,
shellcore_import_nids[SHELLCORE_IMPORT_MOUNT_GAME + i]);
if(address < 0x10000 || address >= 0x0000800000000000ull)
return shellcore_ppr_fail(
"fpkg scope: direct API PLT mismatch");
api_got[i] = 0;
api_target[i] = shellcore_base + api_plt[i];
"fpkg scope: package API export unavailable");
api_target[i] = address;
}
else if(resolve_shellcore_plt(shellcore_base, api_plt[i], dmap, cr3,
pid, locked,
&api_got[i], &api_target[i]))
return shellcore_ppr_fail("fpkg scope: package API PLT mismatch");
}
/* Direct syscall instructions outside libkernel are rejected by early
* firmware. Early ShellCore also leaves getpid@GOT lazy, so resolve the
* export from its loaded modules and validate the complete syscall stub.
* Later builds can keep using their already-resolved import target. */
/* A validated libkernel syscall instruction is required; getpid@GOT may
* still be lazy on any supported firmware. */
uint64_t syscall_target;
if(direct_calls)
{
if(resolve_shellcore_syscall_trampoline(pid, dmap, cr3, locked,
&syscall_target))
return shellcore_ppr_fail(
"fpkg scope: libkernel syscall trampoline unavailable");
}
else
{
uint64_t getpid_target;
if(resolve_shellcore_plt(shellcore_base, sc->getpid_plt, dmap, cr3,
pid, locked, 0, &getpid_target)
|| getpid_target + 7 < getpid_target)
return shellcore_ppr_fail(
"fpkg scope: getpid trampoline unavailable");
syscall_target = getpid_target + 7;
}
if(resolve_shellcore_syscall_trampoline(pid, dmap, cr3, locked,
&syscall_target))
return shellcore_ppr_fail(
"fpkg scope: libkernel syscall trampoline unavailable");
memcpy(prepared_blob, ppr_mount_940_blob_start, blob_size);
if(replace_shellcore_blob_u64(prepared_blob, blob_size,
@@ -1260,11 +1068,13 @@ static int install_shellcore_ppr_hook(
SHELLCORE_FPKG_WRAPPER_MAP_SIZE, 0, 0, 0, 0);
return shellcore_ppr_fail("fpkg scope: wrapper mlock failed");
}
if(phys_copyin(wrapper_base, prepared_blob, blob_size, dmap, cr3))
if(phys_copyin(wrapper_base, prepared_blob, blob_size, dmap, cr3)
|| verify_shellcore_blob(wrapper_base, prepared_blob, blob_size,
dmap, cr3))
{
remote_syscall(pid, SYS_munmap, wrapper_base,
SHELLCORE_FPKG_WRAPPER_MAP_SIZE, 0, 0, 0, 0);
return shellcore_ppr_fail("fpkg scope: wrapper write failed");
return shellcore_ppr_fail("fpkg scope: wrapper write verification failed");
}
if(remote_syscall(pid, SYS_mprotect, wrapper_base,
SHELLCORE_FPKG_WRAPPER_MAP_SIZE,
@@ -1279,53 +1089,50 @@ static int install_shellcore_ppr_hook(
api_wrapper[1] = wrapper_base + game_umount_entry;
api_wrapper[2] = wrapper_base;
api_wrapper[3] = wrapper_base + ppr_umount_entry;
if(direct_calls)
{
int result = install_shellcore_direct_fpkg_calls(
pid, shellcore_base, dmap, cr3, sc, api_plt, api_wrapper, locked);
if(result)
{
/* -2 means rollback could not prove that no call still reaches
* the wrapper, so retain its executable mapping. */
if(result != -2)
remote_syscall(pid, SYS_munmap, wrapper_base,
SHELLCORE_FPKG_WRAPPER_MAP_SIZE,
0, 0, 0, 0);
return shellcore_ppr_fail(
result == -2 ? "fpkg scope: direct-call rollback failed"
: "fpkg scope: direct-call install failed");
}
return 0;
}
size_t installed = 0;
for(; installed < 4; installed++)
size_t touched = 0;
for(; installed < api_count; installed++)
{
uint64_t current;
if(phys_copyout(&current, api_got[installed], sizeof(current),
dmap, cr3)
|| current != api_original_got[installed])
break;
touched = installed + 1;
if(phys_copyin(api_got[installed], &api_wrapper[installed],
sizeof(api_wrapper[installed]), dmap, cr3))
break;
uint64_t current;
if(phys_copyout(&current, api_got[installed], sizeof(current),
dmap, cr3)
|| current != api_wrapper[installed])
break;
}
if(installed != 4)
if(installed == api_count)
for(size_t i = 0; i < api_count; i++)
{
uint64_t current;
if(phys_copyout(&current, api_got[i], sizeof(current), dmap, cr3)
|| current != api_wrapper[i])
{
installed = i;
break;
}
}
if(installed != api_count)
{
int rollback_failed = 0;
size_t touched = installed + 1;
if(touched > 4)
touched = 4;
for(size_t i = 0; i < touched; i++)
{
uint64_t current = 0;
if(phys_copyin(api_got[i], &api_target[i],
sizeof(api_target[i]), dmap, cr3)
if(phys_copyin(api_got[i], &api_original_got[i],
sizeof(api_original_got[i]), dmap, cr3)
|| phys_copyout(&current, api_got[i], sizeof(current), dmap, cr3)
|| current != api_target[i])
|| current != api_original_got[i])
rollback_failed = 1;
}
/* Never unmap code while even one GOT slot may still reference it. */
if(!rollback_failed)
/* A thread may already be executing a wrapper even after its GOT
* entry is restored. Keep the mapping once any entry was touched. */
if(!touched && !rollback_failed)
remote_syscall(pid, SYS_munmap, wrapper_base,
SHELLCORE_FPKG_WRAPPER_MAP_SIZE, 0, 0, 0, 0);
return shellcore_ppr_fail(
@@ -1438,13 +1245,29 @@ enum kit_type kit = get_kit_type();
static int patch_shellcore(const struct shellcore_patch* patches, size_t n_patches, uint64_t eh_frame_offset)
{
shellcore_patch_failure = 0;
int install_fpkg_hook = get_kit_type() == KIT_RETAIL && patches;
if(install_fpkg_hook && (!kstuff_dynlib_handle || !kstuff_dynlib_resolve
|| !kstuff_shellcore_imports))
return shellcore_ppr_fail("fpkg scope: SDK resolver unavailable");
int pid = find_proc("SceShellCore");
if(pid <= 0)
return -1;
struct module_info_ex mod_info;
mod_info.st_size = sizeof(mod_info);
if (remote_syscall(pid, SYS_dynlib_get_info_ex, 0, 0,
(uint64_t)&mod_info, 0, 0, 0))
return -1;
uint64_t shellcore_base = mod_info.eh_frame_hdr_addr - eh_frame_offset;
if(install_fpkg_hook && (shellcore_base < 0x10000
|| shellcore_base >= 0x0000800000000000ull
|| !mod_info.segment_count
|| mod_info.segments[0].addr != shellcore_base
|| mod_info.segments[0].size < 6
|| mod_info.segments[0].size >= 0x0000800000000000ull
- shellcore_base))
return shellcore_ppr_fail("fpkg scope: invalid ShellCore text segment");
uint64_t text_end = mod_info.segments[0].addr
+ mod_info.segments[0].size;
uint64_t cr3, dmap;
if(get_proc_cr3(pid, &cr3, &dmap))
return -1;
@@ -1459,15 +1282,10 @@ static int patch_shellcore(const struct shellcore_patch* patches, size_t n_patch
if(phys_copyin(shellcore_base + patches[i].offset, patches[i].data, patches[i].sz, dmap, cr3))
return -1;
}
if(get_kit_type() == KIT_RETAIL)
{
const struct shellcore_fpkg_offsets* fpkg_offsets =
get_shellcore_fpkg_offsets();
if(fpkg_offsets
&& install_shellcore_ppr_hook(pid, shellcore_base, dmap, cr3,
fpkg_offsets, &locked))
return -1;
}
if(install_fpkg_hook
&& install_shellcore_ppr_hook(pid, shellcore_base, text_end,
dmap, cr3, &locked))
return -1;
return 0;
}
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_10_00
#define SHELLCORE_PATCHES_10_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1000 = {
.ppr_call = 0x75a3a7,
.ppr_cave = 0x17db610,
.ppr_cave_size = 0x9f0,
.close_plt = 0x17d27f0,
.open_plt = 0x17d3940,
.pread_plt = 0x17d3ac0,
.mount_ppr_pkg_plt = 0x17d5da0,
.getpid_plt = 0x17d2500,
};
static struct shellcore_patch shellcore_patches_1000_retail[] = {
{0xC03AC3, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC03AA8
{0xC03AA8, "\xe8\x33\xf8\xff\xff\x58\xc3", 7}, //call 0xC032E0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_10_01
#define SHELLCORE_PATCHES_10_01
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1001 = {
.ppr_call = 0x75a3a7,
.ppr_cave = 0x17db610,
.ppr_cave_size = 0x9f0,
.close_plt = 0x17d27f0,
.open_plt = 0x17d3940,
.pread_plt = 0x17d3ac0,
.mount_ppr_pkg_plt = 0x17d5da0,
.getpid_plt = 0x17d2500,
};
static struct shellcore_patch shellcore_patches_1001_retail[] = {
{0xC03AC3, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC03AA8
{0xC03AA8, "\xe8\x33\xf8\xff\xff\x58\xc3", 7}, //call 0xC032E0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_10_20
#define SHELLCORE_PATCHES_10_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1020 = {
.ppr_call = 0x75a3a7,
.ppr_cave = 0x17df8e0,
.ppr_cave_size = 0x720,
.close_plt = 0x17d6ab0,
.open_plt = 0x17d7c00,
.pread_plt = 0x17d7d80,
.mount_ppr_pkg_plt = 0x17da060,
.getpid_plt = 0x17d67c0,
};
static struct shellcore_patch shellcore_patches_1020_retail[] = {
{0xC07D93, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC07D78
{0xC07D78, "\xe8\x33\xf8\xff\xff\x58\xc3", 7}, //call 0xC075B0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_10_40
#define SHELLCORE_PATCHES_10_40
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1040 = {
.ppr_call = 0x75a2f7,
.ppr_cave = 0x17df900,
.ppr_cave_size = 0x700,
.close_plt = 0x17d6ad0,
.open_plt = 0x17d7c20,
.pread_plt = 0x17d7da0,
.mount_ppr_pkg_plt = 0x17da080,
.getpid_plt = 0x17d67e0,
};
static struct shellcore_patch shellcore_patches_1040_retail[] = {
{0xC07DB3, "\x52\xeb\xe2", 3}, // push rdx; jmp 0xC07D98
{0xC07D98, "\xe8\x33\xf8\xff\xff\x58\xc3", 7}, // call 0xC075D0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_10_60
#define SHELLCORE_PATCHES_10_60
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1060 = {
.ppr_call = 0x75bb87,
.ppr_cave = 0x17e1180,
.ppr_cave_size = 0x2e80,
.close_plt = 0x17d8350,
.open_plt = 0x17d94c0,
.pread_plt = 0x17d9640,
.mount_ppr_pkg_plt = 0x17db910,
.getpid_plt = 0x17d8060,
};
static struct shellcore_patch shellcore_patches_1060_retail[] = {
{0xC09643, "\x52\xeb\xe2", 3}, // push rdx; jmp 0xC09628
{0xC09628, "\xe8\x33\xf8\xff\xff\x58\xc3", 7}, // call 0xC08E60; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_11_00
#define SHELLCORE_PATCHES_11_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1100 = {
.ppr_call = 0x7bd458,
.ppr_cave = 0x18685a0,
.ppr_cave_size = 0x3a60,
.close_plt = 0x185f460,
.open_plt = 0x1860620,
.pread_plt = 0x18607a0,
.mount_ppr_pkg_plt = 0x1862b40,
.getpid_plt = 0x185f120,
};
static struct shellcore_patch shellcore_patches_1100_retail[] = {
{0xC57953, "\xE9\xC1\x01\x00\x00", 5}, // jmp 0xC57B19
{0xC57B19, "\x52\xE9\x53\x06\x00\x00", 6}, // push rdx; jmp 0xC58172
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_11_20
#define SHELLCORE_PATCHES_11_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1120 = {
.ppr_call = 0x7bd5c8,
.ppr_cave = 0x18689a0,
.ppr_cave_size = 0x3660,
.close_plt = 0x185f860,
.open_plt = 0x1860a20,
.pread_plt = 0x1860ba0,
.mount_ppr_pkg_plt = 0x1862f40,
.getpid_plt = 0x185f520,
};
static struct shellcore_patch shellcore_patches_1120_retail[] = {
{0xC57CE3, "\xE9\xC1\x01\x00\x00", 5}, // jmp 0xC57EA9
{0xC57EA9, "\x52\xE9\x53\x06\x00\x00", 6}, // push rdx; jmp 0xC58502
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_11_40
#define SHELLCORE_PATCHES_11_40
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_1140 = {
.ppr_call = 0x7becf8,
.ppr_cave = 0x186ace0,
.ppr_cave_size = 0x1320,
.close_plt = 0x1861ba0,
.open_plt = 0x1862d70,
.pread_plt = 0x1862ef0,
.mount_ppr_pkg_plt = 0x1865280,
.getpid_plt = 0x1861860,
};
static struct shellcore_patch shellcore_patches_1140_retail[] = {
{0xC59893, "\xE9\xC1\x01\x00\x00", 5}, // jmp 0xC59A59
{0xC59A59, "\x52\xE9\x53\x06\x00\x00", 6}, // push rdx; jmp 0xC5A0B2
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_1_00
#define SHELLCORE_PATCHES_1_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_100 = {
.ppr_call = 0x463461,
.ppr_cave = 0x1127640,
.ppr_cave_size = 0x9c0,
.close_plt = 0x111fa90,
.open_plt = 0x1120870,
.pread_plt = 0x11209e0,
.mount_ppr_pkg_plt = 0x1122620,
.getpid_plt = 0x111f790,
};
static struct shellcore_patch shellcore_patches_100_retail[] = {
{0x7e06bf, "\x31\xc0\x50\xeb\x00", 5},
{0x7e06c4, "\xe8\x77\x1a\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_1_01
#define SHELLCORE_PATCHES_1_01
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_101 = {
.ppr_call = 0x463461,
.ppr_cave = 0x1127640,
.ppr_cave_size = 0x9c0,
.close_plt = 0x111fa90,
.open_plt = 0x1120870,
.pread_plt = 0x11209e0,
.mount_ppr_pkg_plt = 0x1122620,
.getpid_plt = 0x111f790,
};
static struct shellcore_patch shellcore_patches_101_retail[] = {
{0x7e06bf, "\x31\xc0\x50\xeb\x00", 5},
{0x7e06c4, "\xe8\x77\x1a\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_1_02
#define SHELLCORE_PATCHES_1_02
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_102 = {
.ppr_call = 0x463461,
.ppr_cave = 0x1127640,
.ppr_cave_size = 0x9c0,
.close_plt = 0x111fa90,
.open_plt = 0x1120870,
.pread_plt = 0x11209e0,
.mount_ppr_pkg_plt = 0x1122620,
.getpid_plt = 0x111f790,
};
static struct shellcore_patch shellcore_patches_102_retail[] = {
{0x7e06bf, "\x31\xc0\x50\xeb\x00", 5},
{0x7e06c4, "\xe8\x77\x1a\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_1_12
#define SHELLCORE_PATCHES_1_12
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_112 = {
.ppr_call = 0x4638f1,
.ppr_cave = 0x11281d0,
.ppr_cave_size = 0x3e30,
.close_plt = 0x1120610,
.open_plt = 0x11213f0,
.pread_plt = 0x1121560,
.mount_ppr_pkg_plt = 0x11231c0,
.getpid_plt = 0x1120310,
};
static struct shellcore_patch shellcore_patches_112_retail[] = {
{0x7e0ccf, "\x31\xc0\x50\xeb\x00", 5},
{0x7e0cd4, "\xe8\x77\x1a\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_1_14
#define SHELLCORE_PATCHES_1_14
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_114 = {
.ppr_call = 0x463af1,
.ppr_cave = 0x11285f0,
.ppr_cave_size = 0x3a10,
.close_plt = 0x1120a30,
.open_plt = 0x1121810,
.pread_plt = 0x1121980,
.mount_ppr_pkg_plt = 0x11235e0,
.getpid_plt = 0x1120730,
};
static struct shellcore_patch shellcore_patches_114_retail[] = {
{0x7e0ecf, "\x31\xc0\x50\xeb\x00", 5},
{0x7e0ed4, "\xe8\x77\x1a\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_00
#define SHELLCORE_PATCHES_2_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_200 = {
.ppr_call = 0x4cfa61,
.ppr_cave = 0x12a3cf0,
.ppr_cave_size = 0x310,
.close_plt = 0x129bea0,
.open_plt = 0x129ce50,
.pread_plt = 0x129cf40,
.mount_ppr_pkg_plt = 0x129eb30,
.getpid_plt = 0x129bb70,
};
static struct shellcore_patch shellcore_patches_200_retail[] = {
{0x8835dc, "\x31\xc0\x50\xeb\x08", 5},
{0x8835e9, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_20
#define SHELLCORE_PATCHES_2_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_220 = {
.ppr_call = 0x4cfdb1,
.ppr_cave = 0x12a4160,
.ppr_cave_size = 0x3ea0,
.close_plt = 0x129c310,
.open_plt = 0x129d2c0,
.pread_plt = 0x129d3b0,
.mount_ppr_pkg_plt = 0x129efa0,
.getpid_plt = 0x129bfe0,
};
static struct shellcore_patch shellcore_patches_220_retail[] = {
{0x88392c, "\x31\xc0\x50\xeb\x08", 5},
{0x883939, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_25
#define SHELLCORE_PATCHES_2_25
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_225 = {
.ppr_call = 0x4d0301,
.ppr_cave = 0x12a5070,
.ppr_cave_size = 0x2f90,
.close_plt = 0x129d220,
.open_plt = 0x129e1d0,
.pread_plt = 0x129e2c0,
.mount_ppr_pkg_plt = 0x129feb0,
.getpid_plt = 0x129cef0,
};
static struct shellcore_patch shellcore_patches_225_retail[] = {
{0x883e7c, "\x31\xc0\x50\xeb\x08", 5},
{0x883e89, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_26
#define SHELLCORE_PATCHES_2_26
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_226 = {
.ppr_call = 0x4d1ab1,
.ppr_cave = 0x12a6a00,
.ppr_cave_size = 0x1600,
.close_plt = 0x129ebb0,
.open_plt = 0x129fb60,
.pread_plt = 0x129fc50,
.mount_ppr_pkg_plt = 0x12a1840,
.getpid_plt = 0x129e880,
};
static struct shellcore_patch shellcore_patches_226_retail[] = {
{0x88562c, "\x31\xc0\x50\xeb\x08", 5},
{0x885639, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_30
#define SHELLCORE_PATCHES_2_30
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_230 = {
.ppr_call = 0x4d2251,
.ppr_cave = 0x12a7880,
.ppr_cave_size = 0x780,
.close_plt = 0x129fa30,
.open_plt = 0x12a09e0,
.pread_plt = 0x12a0ad0,
.mount_ppr_pkg_plt = 0x12a26c0,
.getpid_plt = 0x129f700,
};
static struct shellcore_patch shellcore_patches_230_retail[] = {
{0x8861cc, "\x31\xc0\x50\xeb\x08", 5},
{0x8861d9, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-14
View File
@@ -1,20 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_50
#define SHELLCORE_PATCHES_2_50
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_250 = {
.ppr_call = 0x4d3601,
.ppr_cave = 0x12aa7c0,
.ppr_cave_size = 0x1840,
.close_plt = 0x12a2970,
.open_plt = 0x12a3920,
.pread_plt = 0x12a3a10,
.mount_ppr_pkg_plt = 0x12a5610,
.getpid_plt = 0x12a2640,
.game_mount_calls = {0x4cff43, 0x4d2929, 0x4d2bce},
.game_umount_calls = {0x4d2ff3, 0x4d3150},
.ppr_umount_call = 0x4d3da0,
};
static struct shellcore_patch shellcore_patches_250_retail[] = {
/* ScePreorder/security wrapper: 3.00 sub_9D1CA0/sub_9D18A0. */
{0x88757c, "\x31\xc0\x50\xeb\x08", 5}, // 3.00 0x9d18b1 (selector 1): call sub_889390, force a zero return
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_2_70
#define SHELLCORE_PATCHES_2_70
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_270 = {
.ppr_call = 0x4d3601,
.ppr_cave = 0x12aa7c0,
.ppr_cave_size = 0x1840,
.close_plt = 0x12a2970,
.open_plt = 0x12a3920,
.pread_plt = 0x12a3a10,
.mount_ppr_pkg_plt = 0x12a5610,
.getpid_plt = 0x12a2640,
};
static struct shellcore_patch shellcore_patches_270_retail[] = {
{0x88757c, "\x31\xc0\x50\xeb\x08", 5},
{0x887589, "\xe8\x02\x1e\x00\x00\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_3_00
#define SHELLCORE_PATCHES_3_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_300 = {
.ppr_call = 0x52c2da,
.ppr_cave = 0x142c990,
.ppr_cave_size = 0x3670,
.close_plt = 0x1424a20,
.open_plt = 0x1425a30,
.pread_plt = 0x1425b20,
.mount_ppr_pkg_plt = 0x1427830,
.getpid_plt = 0x14246f0,
};
static struct shellcore_patch shellcore_patches_300_retail[] = {
{0x9d1cae, "\x52\xeb\x08", 3},
{0x9d1cb9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_3_10
#define SHELLCORE_PATCHES_3_10
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_310 = {
.ppr_call = 0x52c31a,
.ppr_cave = 0x142c9d0,
.ppr_cave_size = 0x3630,
.close_plt = 0x1424a60,
.open_plt = 0x1425a70,
.pread_plt = 0x1425b60,
.mount_ppr_pkg_plt = 0x1427870,
.getpid_plt = 0x1424730,
};
static struct shellcore_patch shellcore_patches_310_retail[] = {
{0x9d1cee, "\x52\xeb\x08", 3},
{0x9d1cf9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_3_20
#define SHELLCORE_PATCHES_3_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_320 = {
.ppr_call = 0x52c5ca,
.ppr_cave = 0x142ce20,
.ppr_cave_size = 0x31e0,
.close_plt = 0x1424eb0,
.open_plt = 0x1425ec0,
.pread_plt = 0x1425fb0,
.mount_ppr_pkg_plt = 0x1427cc0,
.getpid_plt = 0x1424b80,
};
static struct shellcore_patch shellcore_patches_320_retail[] = {
{0x9d1f9e, "\x52\xeb\x08", 3},
{0x9d1fa9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_3_21
#define SHELLCORE_PATCHES_3_21
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_321 = {
.ppr_call = 0x52c5ca,
.ppr_cave = 0x142ce20,
.ppr_cave_size = 0x31e0,
.close_plt = 0x1424eb0,
.open_plt = 0x1425ec0,
.pread_plt = 0x1425fb0,
.mount_ppr_pkg_plt = 0x1427cc0,
.getpid_plt = 0x1424b80,
};
static struct shellcore_patch shellcore_patches_321_retail[] = {
{0x9d1f9e, "\x52\xeb\x08", 3},
{0x9d1fa9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_4_00
#define SHELLCORE_PATCHES_4_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_400 = {
.ppr_call = 0x57dafe,
.ppr_cave = 0x13bf980,
.ppr_cave_size = 0x680,
.close_plt = 0x13b7870,
.open_plt = 0x13b88e0,
.pread_plt = 0x13b89d0,
.mount_ppr_pkg_plt = 0x13ba840,
.getpid_plt = 0x13b7530,
};
static struct shellcore_patch shellcore_patches_400_retail[] = {
{0x974fee, "\x52\xeb\x08", 3},
{0x974ff9, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_4_02
#define SHELLCORE_PATCHES_4_02
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_402 = {
.ppr_call = 0x57dafe,
.ppr_cave = 0x13bf980,
.ppr_cave_size = 0x680,
.close_plt = 0x13b7870,
.open_plt = 0x13b88e0,
.pread_plt = 0x13b89d0,
.mount_ppr_pkg_plt = 0x13ba840,
.getpid_plt = 0x13b7530,
};
static struct shellcore_patch shellcore_patches_402_retail[] = {
{0x974fee, "\x52\xeb\x08", 3},
{0x974ff9, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_4_03
#define SHELLCORE_PATCHES_4_03
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_403 = {
.ppr_call = 0x57dafe,
.ppr_cave = 0x13bf990,
.ppr_cave_size = 0x670,
.close_plt = 0x13b7880,
.open_plt = 0x13b88f0,
.pread_plt = 0x13b89e0,
.mount_ppr_pkg_plt = 0x13ba850,
.getpid_plt = 0x13b7540,
};
static struct shellcore_patch shellcore_patches_403_retail[] = {
{0x974fee, "\x52\xeb\x08", 3},
{0x974ff9, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7}, //call 0x974bd0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_4_50
#define SHELLCORE_PATCHES_4_50
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_450 = {
.ppr_call = 0x57e46e,
.ppr_cave = 0x13cb950,
.ppr_cave_size = 0x6b0,
.close_plt = 0x13c3840,
.open_plt = 0x13c48c0,
.pread_plt = 0x13c49b0,
.mount_ppr_pkg_plt = 0x13c6820,
.getpid_plt = 0x13c3500,
};
static struct shellcore_patch shellcore_patches_450_retail[] = {
{0x97595e, "\x52\xeb\x08", 3},
{0x975969, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_4_51
#define SHELLCORE_PATCHES_4_51
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_451 = {
.ppr_call = 0x57e47e,
.ppr_cave = 0x13cb950,
.ppr_cave_size = 0x6b0,
.close_plt = 0x13c3840,
.open_plt = 0x13c48c0,
.pread_plt = 0x13c49b0,
.mount_ppr_pkg_plt = 0x13c6820,
.getpid_plt = 0x13c3500,
};
static struct shellcore_patch shellcore_patches_451_retail[] = {
{0x97596e, "\x52\xeb\x08", 3},
{0x975979, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_5_00
#define SHELLCORE_PATCHES_5_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_500 = {
.ppr_call = 0x5e67cc,
.ppr_cave = 0x14893f0,
.ppr_cave_size = 0x2c10,
.close_plt = 0x14810e0,
.open_plt = 0x1482020,
.pread_plt = 0x1482110,
.mount_ppr_pkg_plt = 0x1483f80,
.getpid_plt = 0x1480df0,
};
static struct shellcore_patch shellcore_patches_500_retail[] = {
{0xa2e62e, "\x52\xeb\x08", 3},
{0xa2e639, "\xe8\x22\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_5_02
#define SHELLCORE_PATCHES_5_02
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_502 = {
.ppr_call = 0x5e67bc,
.ppr_cave = 0x14893d0,
.ppr_cave_size = 0x2c30,
.close_plt = 0x14810c0,
.open_plt = 0x1482000,
.pread_plt = 0x14820f0,
.mount_ppr_pkg_plt = 0x1483f60,
.getpid_plt = 0x1480dd0,
};
static struct shellcore_patch shellcore_patches_502_retail[] = {
{0xa2e61e, "\x52\xeb\x08", 3},
{0xa2e629, "\xe8\x22\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_5_10
#define SHELLCORE_PATCHES_5_10
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_510 = {
.ppr_call = 0x5e928c,
.ppr_cave = 0x148c510,
.ppr_cave_size = 0x3af0,
.close_plt = 0x14841f0,
.open_plt = 0x1485130,
.pread_plt = 0x1485220,
.mount_ppr_pkg_plt = 0x14870b0,
.getpid_plt = 0x1483f00,
};
static struct shellcore_patch shellcore_patches_510_retail[] = {
{0xa30fde, "\x52\xeb\x08", 3},
{0xa30fe9, "\xe8\x22\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_5_50
#define SHELLCORE_PATCHES_5_50
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_550 = {
.ppr_call = 0x5e928c,
.ppr_cave = 0x1490b70,
.ppr_cave_size = 0x3490,
.close_plt = 0x1488850,
.open_plt = 0x14897a0,
.pread_plt = 0x1489890,
.mount_ppr_pkg_plt = 0x148b720,
.getpid_plt = 0x1488560,
};
static struct shellcore_patch shellcore_patches_550_retail[] = {
{0xa319ee, "\x52\xeb\x08", 3},
{0xa319f9, "\xe8\x22\xfb\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_6_00
#define SHELLCORE_PATCHES_6_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_600 = {
.ppr_call = 0x61ca0d,
.ppr_cave = 0x1526ac0,
.ppr_cave_size = 0x1540,
.close_plt = 0x151e550,
.open_plt = 0x151f4f0,
.pread_plt = 0x151f620,
.mount_ppr_pkg_plt = 0x15215b0,
.getpid_plt = 0x151dd70,
};
static struct shellcore_patch shellcore_patches_600_retail[] = {
{0xa7d30e, "\x52\xeb\x08", 3},
{0xa7d319, "\xe8\x82\xfa\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_6_02
#define SHELLCORE_PATCHES_6_02
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_602 = {
.ppr_call = 0x61c9ad,
.ppr_cave = 0x1526ed0,
.ppr_cave_size = 0x1130,
.close_plt = 0x151e950,
.open_plt = 0x151f8f0,
.pread_plt = 0x151fa20,
.mount_ppr_pkg_plt = 0x15219b0,
.getpid_plt = 0x151e170,
};
static struct shellcore_patch shellcore_patches_602_retail[] = {
{0xa7d2ae, "\x52\xeb\x08", 3},
{0xa7d2b9, "\xe8\x82\xfa\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_6_50
#define SHELLCORE_PATCHES_6_50
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_650 = {
.ppr_call = 0x61ca1d,
.ppr_cave = 0x1527440,
.ppr_cave_size = 0xbc0,
.close_plt = 0x151eec0,
.open_plt = 0x151fe60,
.pread_plt = 0x151ff90,
.mount_ppr_pkg_plt = 0x1521f20,
.getpid_plt = 0x151e6e0,
};
static struct shellcore_patch shellcore_patches_650_retail[] = {
{0xa7dade, "\x52\xeb\x08", 3},
{0xa7dae9, "\xe8\x82\xfa\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_00
#define SHELLCORE_PATCHES_7_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_700 = {
.ppr_call = 0x6d6682,
.ppr_cave = 0x16a8350,
.ppr_cave_size = 0x3cb0,
.close_plt = 0x169fa00,
.open_plt = 0x16a0ad0,
.pread_plt = 0x16a0c40,
.mount_ppr_pkg_plt = 0x16a2c10,
.getpid_plt = 0x169f710,
};
static struct shellcore_patch shellcore_patches_700_retail[] = {
{0xb424de, "\x52\xeb\x08", 3},
{0xb424e9, "\xe8\xd2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_01
#define SHELLCORE_PATCHES_7_01
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_701 = {
.ppr_call = 0x6d6682,
.ppr_cave = 0x16a8350,
.ppr_cave_size = 0x3cb0,
.close_plt = 0x169fa00,
.open_plt = 0x16a0ad0,
.pread_plt = 0x16a0c40,
.mount_ppr_pkg_plt = 0x16a2c10,
.getpid_plt = 0x169f710,
};
static struct shellcore_patch shellcore_patches_701_retail[] = {
{0xb424de, "\x52\xeb\x08", 3},
{0xb424e9, "\xe8\xd2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_20
#define SHELLCORE_PATCHES_7_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_720 = {
.ppr_call = 0x6d66a2,
.ppr_cave = 0x16a8cf0,
.ppr_cave_size = 0x3310,
.close_plt = 0x16a03a0,
.open_plt = 0x16a1470,
.pread_plt = 0x16a15e0,
.mount_ppr_pkg_plt = 0x16a35b0,
.getpid_plt = 0x16a00b0,
};
static struct shellcore_patch shellcore_patches_720_retail[] = {
{0xb42dbe, "\x52\xeb\x08", 3},
{0xb42dc9, "\xe8\xd2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_40
#define SHELLCORE_PATCHES_7_40
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_740 = {
.ppr_call = 0x6db192,
.ppr_cave = 0x16b6790,
.ppr_cave_size = 0x1870,
.close_plt = 0x16ade40,
.open_plt = 0x16aef10,
.pread_plt = 0x16af080,
.mount_ppr_pkg_plt = 0x16b1050,
.getpid_plt = 0x16adb50,
};
static struct shellcore_patch shellcore_patches_740_retail[] = {
{0xb4e4ae, "\x52\xeb\x08", 3},
{0xb4e4b9, "\xe8\xD2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_60
#define SHELLCORE_PATCHES_7_60
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_760 = {
.ppr_call = 0x6db192,
.ppr_cave = 0x16b9d90,
.ppr_cave_size = 0x2270,
.close_plt = 0x16b1420,
.open_plt = 0x16b24f0,
.pread_plt = 0x16b2660,
.mount_ppr_pkg_plt = 0x16b4630,
.getpid_plt = 0x16b1130,
};
static struct shellcore_patch shellcore_patches_760_retail[] = {
{0xb51a8e, "\x52\xeb\x08", 3},
{0xb51a99, "\xe8\xd2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_7_61
#define SHELLCORE_PATCHES_7_61
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_761 = {
.ppr_call = 0x6db192,
.ppr_cave = 0x16b9d90,
.ppr_cave_size = 0x2270,
.close_plt = 0x16b1420,
.open_plt = 0x16b24f0,
.pread_plt = 0x16b2660,
.mount_ppr_pkg_plt = 0x16b4630,
.getpid_plt = 0x16b1130,
};
static struct shellcore_patch shellcore_patches_761_retail[] = {
{0xb51a8e, "\x52\xeb\x08", 3},
{0xb51a99, "\xe8\xd2\xf9\xff\xff\x58\xc3", 7},
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_8_00
#define SHELLCORE_PATCHES_8_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_800 = {
.ppr_call = 0x70260d,
.ppr_cave = 0x1732a90,
.ppr_cave_size = 0x1570,
.close_plt = 0x1729e80,
.open_plt = 0x172af90,
.pread_plt = 0x172b100,
.mount_ppr_pkg_plt = 0x172d2e0,
.getpid_plt = 0x1729b90,
};
static struct shellcore_patch shellcore_patches_800_retail[] = {
{0xba85ce, "\x52\xeb\x08", 3}, //push rdx; jmp 0xBA85D9
{0xba85d9, "\xe8\xe2\xf6\xff\xff\x58\xc3", 7}, //call 0xBA7CC0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_8_20
#define SHELLCORE_PATCHES_8_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_820 = {
.ppr_call = 0x70558d,
.ppr_cave = 0x173ee50,
.ppr_cave_size = 0x11b0,
.close_plt = 0x1736230,
.open_plt = 0x1737350,
.pread_plt = 0x17374c0,
.mount_ppr_pkg_plt = 0x17396a0,
.getpid_plt = 0x1735f40,
};
static struct shellcore_patch shellcore_patches_820_retail[] = {
{0xBAF83E, "\x52\xeb\x08", 3}, //push rdx; jmp 0xBAF849 **
{0xBAF849, "\xe8\xe2\xf8\xff\xff\x58\xc3", 7}, //call 0xBAF130; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_8_40
#define SHELLCORE_PATCHES_8_40
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_840 = {
.ppr_call = 0x70558d,
.ppr_cave = 0x173ee50,
.ppr_cave_size = 0x11b0,
.close_plt = 0x1736230,
.open_plt = 0x1737350,
.pread_plt = 0x17374c0,
.mount_ppr_pkg_plt = 0x17396a0,
.getpid_plt = 0x1735f40,
};
static struct shellcore_patch shellcore_patches_840_retail[] = {
{0xBAF83E, "\x52\xeb\x08", 3}, //push rdx; jmp 0xBAF849 **
{0xBAF849, "\xe8\xe2\xf8\xff\xff\x58\xc3", 7}, //call 0xBAF130; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_8_60
#define SHELLCORE_PATCHES_8_60
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_860 = {
.ppr_call = 0x70541d,
.ppr_cave = 0x17411b0,
.ppr_cave_size = 0x2e50,
.close_plt = 0x1738590,
.open_plt = 0x17396b0,
.pread_plt = 0x1739820,
.mount_ppr_pkg_plt = 0x173ba10,
.getpid_plt = 0x17382a0,
};
static struct shellcore_patch shellcore_patches_860_retail[] = {
{0xBAF84E, "\x52\xeb\x08", 3}, //push rdx; jmp 0xBAF859 **
{0xBAF859, "\xe8\xe2\xf8\xff\xff\x58\xc3", 7}, //call 0xBAF140; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_9_00
#define SHELLCORE_PATCHES_9_00
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_900 = {
.ppr_call = 0x7488fd,
.ppr_cave = 0x17ddca0,
.ppr_cave_size = 0x2360,
.close_plt = 0x17d4f40,
.open_plt = 0x17d6050,
.pread_plt = 0x17d61a0,
.mount_ppr_pkg_plt = 0x17d8430,
.getpid_plt = 0x17d4c50,
};
static struct shellcore_patch shellcore_patches_900_retail[] = {
{0xC0F813, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC0F7F8
{0xC0F7F8, "\xe8\xe3\xf8\xff\xff\x58\xc3", 7}, //call 0xC0F0E0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_9_05
#define SHELLCORE_PATCHES_9_05
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_905 = {
.ppr_call = 0x7488fd,
.ppr_cave = 0x17ddca0,
.ppr_cave_size = 0x2360,
.close_plt = 0x17d4f40,
.open_plt = 0x17d6050,
.pread_plt = 0x17d61a0,
.mount_ppr_pkg_plt = 0x17d8430,
.getpid_plt = 0x17d4c50,
};
static struct shellcore_patch shellcore_patches_905_retail[] = {
{0xC0F813, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC0F7F8
{0xC0F7F8, "\xe8\xe3\xf8\xff\xff\x58\xc3", 7}, //call 0xC0F0E0; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_9_20
#define SHELLCORE_PATCHES_9_20
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_920 = {
.ppr_call = 0x74863d,
.ppr_cave = 0x17de380,
.ppr_cave_size = 0x1c80,
.close_plt = 0x17d5620,
.open_plt = 0x17d6730,
.pread_plt = 0x17d6880,
.mount_ppr_pkg_plt = 0x17d8b10,
.getpid_plt = 0x17d5330,
};
static struct shellcore_patch shellcore_patches_920_retail[] = {
{0xC0F553, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC0F538
{0xC0F538, "\xe8\xe3\xf8\xff\xff\x58\xc3", 7}, //call 0xC0EE20; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_9_40
#define SHELLCORE_PATCHES_9_40
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_940 = {
.ppr_call = 0x748d0d,
.ppr_cave = 0x17deb50,
.ppr_cave_size = 0x14b0,
.close_plt = 0x17d5de0,
.open_plt = 0x17d6f00,
.pread_plt = 0x17d7050,
.mount_ppr_pkg_plt = 0x17d92e0,
.getpid_plt = 0x17d5af0,
};
static struct shellcore_patch shellcore_patches_940_retail[] = {
{0xC0FCA3, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC0FC88
{0xC0FC88, "\xe8\xe3\xf8\xff\xff\x58\xc3", 7}, //call 0xC0F570; pop rax; ret
-11
View File
@@ -1,17 +1,6 @@
#ifndef SHELLCORE_PATCHES_9_60
#define SHELLCORE_PATCHES_9_60
static const struct shellcore_fpkg_offsets shellcore_fpkg_offsets_960 = {
.ppr_call = 0x748d7d,
.ppr_cave = 0x17e6f20,
.ppr_cave_size = 0x10e0,
.close_plt = 0x17de1b0,
.open_plt = 0x17df2d0,
.pread_plt = 0x17df420,
.mount_ppr_pkg_plt = 0x17e16b0,
.getpid_plt = 0x17ddec0,
};
static struct shellcore_patch shellcore_patches_960_retail[] = {
{0xC18073, "\x52\xeb\xe2", 3}, //push rdx; jmp 0xC18058
{0xC18058, "\xe8\xe3\xf8\xff\xff\x58\xc3", 7}, //call 0xC17940; pop rax; ret
+7 -3
View File
@@ -703,12 +703,12 @@ int control_ppr_plaintext_request(uint64_t magic, uint64_t mode,
uint64_t* result)
{
/*
* "PPRPLAIN", protocol v8. No user pointer is dereferenced: WRITE carries
* "PPRPLAIN". No user pointer is dereferenced: WRITE carries
* 16 snapshot bytes in R8/R9. R10 is deliberately unused because the
* established kekcall fast snapshot ends at RAX and includes R8/R9.
*/
*result = 0;
if(!get_ppr_profile() || magic != 0x505052504c41494eull)
if(magic != 0x505052504c41494eull)
return EINVAL;
if(mode == PPR_CONTROL_TRACE)
{
@@ -743,6 +743,10 @@ int control_ppr_plaintext_request(uint64_t magic, uint64_t mode,
if((fpkg_scope_for_thread(td) & FPKG_SCOPE_KIND_MASK)
!= KSTUFF_FPKG_SCOPE_PPR_MOUNT)
return EPERM;
/* Mount scope tracking also covers firmware without a validated
* PLAINTEXT_NOAUTH interception profile. */
if(!get_ppr_profile())
return EINVAL;
if(mode == 0)
{
if(arg0 != PPR_PLAINTEXT_PROTOCOL_VERSION)
@@ -1471,7 +1475,7 @@ int try_handle_fpkg_mailbox(uint64_t* regs, uint64_t lr)
* and both completed read sizes. sm_pfs normally uses the vnode/FIH
* context in request qwords 10/11 to read and fill a 0x1000-byte FIH
* buffer plus a 0x5a0-byte verified superblock. Calling VFS from the
* debug exception is unsafe, so protocol v8 snapshots both file ranges
* debug exception is unsafe, so snapshots both file ranges
* before nmount and this trap supplies the same output buffers.
* registerMountKey indexes a global RB tree by handle alone. The
* emulated result therefore jumps past both key registrations and the
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env python3
"""Audit ShellCore import NIDs and GOT slots in unpacked ELF images.
This mirrors the loader's NID-to-JMP_SLOT lookup. PLT stubs and lazy GOT
initializers are checked to catch a changed import ABI before deployment.
"""
import argparse
import hashlib
import struct
from pathlib import Path
IMPORTS = {
"close": "bY-PO6JhzhQ",
"open": "wuCroIGjt2g",
"pread": "ezv-RSBNKqI",
"mount_game": "FtGP5aXKFQU",
"umount_game": "UQTSykySQ40",
"mount_ppr": "MiUxeleLYUc",
"umount_ppr": "S5+bpaH0TWk",
}
DT_PLTRELSZ = 2
DT_STRTAB = 5
DT_SYMTAB = 6
DT_RELAENT = 9
DT_STRSZ = 10
DT_SYMENT = 11
DT_PLTREL = 20
DT_JMPREL = 23
DT_RELA = 7
PT_LOAD = 1
PT_DYNAMIC = 2
R_X86_64_JUMP_SLOT = 7
def derive(path: Path):
image = path.read_bytes()
if image[:4] != b"\x7fELF" or image[4:6] != b"\x02\x01":
raise ValueError("expected an unpacked little-endian ELF64 image")
phoff = struct.unpack_from("<Q", image, 32)[0]
phentsize, phnum = struct.unpack_from("<HH", image, 54)
if phentsize != 56 or not 0 < phnum <= 64:
raise ValueError("unexpected program-header layout")
segments = [struct.unpack_from("<IIQQQQQQ", image, phoff + i * phentsize)
for i in range(phnum)]
def file_offset(vaddr, size):
for kind, _, offset, start, _, filesz, _, _ in segments:
if kind == PT_LOAD and start <= vaddr and size <= filesz - (vaddr - start):
return offset + vaddr - start
raise ValueError(f"unmapped ELF data at {vaddr:#x}, size {size:#x}")
dynamics = [segment for segment in segments if segment[0] == PT_DYNAMIC]
if len(dynamics) != 1:
raise ValueError("expected one PT_DYNAMIC")
_, _, dynoff, _, _, dynsize, _, _ = dynamics[0]
tags = {}
for off in range(dynoff, dynoff + dynsize, 16):
tag, value = struct.unpack_from("<QQ", image, off)
if tag == 0:
break
tags[tag] = value
if (tags.get(DT_PLTREL) != DT_RELA
or tags.get(DT_RELAENT) != 24
or tags.get(DT_SYMENT) != 24):
raise ValueError("unexpected relocation or symbol ABI")
size = tags[DT_PLTRELSZ]
if size % 24:
raise ValueError("JMPREL size is not a multiple of Elf64_Rela")
reloc_offset = file_offset(tags[DT_JMPREL], size)
string_offset = file_offset(tags[DT_STRTAB], tags[DT_STRSZ])
strings = image[string_offset:string_offset + tags[DT_STRSZ]]
slots = {}
for off in range(reloc_offset, reloc_offset + size, 24):
r_offset, r_info, _ = struct.unpack_from("<QQq", image, off)
if r_info & 0xffffffff != R_X86_64_JUMP_SLOT:
continue
symbol = r_info >> 32
symoff = file_offset(tags[DT_SYMTAB] + 24 * symbol, 24)
nameoff = struct.unpack_from("<I", image, symoff)[0]
if nameoff >= len(strings):
raise ValueError("symbol name outside DT_STRTAB")
name = strings[nameoff:].split(b"\0", 1)[0].decode("ascii")
for label, nid in IMPORTS.items():
if name.startswith(nid + "#"):
if label in slots:
raise ValueError(f"duplicate {label} JMP_SLOT")
slots[label] = r_offset
missing = IMPORTS.keys() - slots.keys()
if missing:
raise ValueError(f"missing JMP_SLOT imports: {', '.join(sorted(missing))}")
stubs = {label: [] for label in IMPORTS}
slots_to_names = {value: name for name, value in slots.items()}
for kind, flags, offset, start, _, filesz, _, _ in segments:
if kind != PT_LOAD or not flags & 1:
continue
code = image[offset:offset + filesz]
cursor = 0
while (cursor := code.find(b"\xff\x25", cursor)) != -1:
if cursor + 6 > len(code):
break
displacement = struct.unpack_from("<i", code, cursor + 2)[0]
target = start + cursor + 6 + displacement
if target in slots_to_names:
stubs[slots_to_names[target]].append(start + cursor)
cursor += 2
for label, addresses in stubs.items():
if len(addresses) != 1:
raise ValueError(f"{label}: expected one PLT stub, got {addresses}")
plt = {name: addresses[0] for name, addresses in stubs.items()}
for label, got in slots.items():
initial = struct.unpack_from("<Q", image, file_offset(got, 8))[0]
if initial != plt[label] + 6:
raise ValueError(f"{label}: unexpected lazy GOT initializer {initial:#x}")
return plt, slots, hashlib.sha256(image).hexdigest()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("images", type=Path, nargs="+")
args = parser.parse_args()
for path in args.images:
plt, slots, digest = derive(path)
print(f"{path.name} sha256={digest}")
for name, value in slots.items():
print(f" {name}: GOT={value:#x} lazy_PLT={plt[name]:#x}")
if __name__ == "__main__":
main()