mirror of
https://github.com/EchoStretch/kstuff-lite.git
synced 2026-10-19 02:09:50 -05:00
Resolve ShellCore mount hooks from dynamic imports
This commit is contained in:
1 parent
e8f6819656
commit
47e6c23311
62 files changed
+493
-945
No files matched your search
+1
-1
@@ -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
@@ -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]},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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) $^
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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(¤t, 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(¤t, 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(¤t, 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(¤t, 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
Reference in new issue
Block a user