mirror of
https://github.com/ps5-payload-dev/sdk.git
synced 2026-10-19 01:51:19 -05:00
484 lines
13 KiB
C
484 lines
13 KiB
C
/* Copyright (C) 2024 John Törnblom
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 3, or (at your option) any
|
|
later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "elf.h"
|
|
#include "klog.h"
|
|
#include "kernel.h"
|
|
#include "nid.h"
|
|
#include "rtld_sprx.h"
|
|
#include "syscall.h"
|
|
|
|
|
|
/**
|
|
* Dependencies to standard libraries.
|
|
**/
|
|
static char* (*strcpy)(char*, const char*) = 0;
|
|
static int (*strcmp)(const char*, const char*) = 0;
|
|
static int (*strncmp)(const char*, const char*, unsigned long) = 0;
|
|
|
|
static void* (*calloc)(unsigned long, unsigned long) = 0;
|
|
static void* (*malloc)(unsigned long) = 0;
|
|
static void (*free)(void*) = 0;
|
|
|
|
static int (*sceKernelLoadStartModule)(const char*, unsigned long, const void*,
|
|
unsigned int, void*, int*) = 0;
|
|
static int (*sceKernelStopUnloadModule)(int, unsigned long, const void*, unsigned int,
|
|
const void*, void*) = 0;
|
|
static int (*sceSysmoduleLoadModuleInternal)(unsigned int) = 0;
|
|
|
|
|
|
/**
|
|
* Extend the rtld_lib_t type with auxiliary parameters needed by .sprx loader.
|
|
* This requires -fms-extensions.
|
|
**/
|
|
typedef struct rtld_sprx_lib {
|
|
struct rtld_lib;
|
|
|
|
int handle;
|
|
char* strtab;
|
|
Elf64_Sym* symtab;
|
|
unsigned long symtab_size;
|
|
|
|
int unload_on_close;
|
|
} rtld_sprx_lib_t;
|
|
|
|
|
|
/**
|
|
* Lookup table for sceSysmoduleLoadModuleInternal().
|
|
**/
|
|
static struct sysmodtab {
|
|
const char* name;
|
|
unsigned int handle;
|
|
} sysmodtab[] = {
|
|
{"libSceAbstractLocal.sprx", 0x8000005f},
|
|
{"libSceAbstractStorage.sprx", 0x80000058},
|
|
{"libSceAbstractTcs.sprx", 0x800000a1},
|
|
{"libSceAbstractTwitter.sprx", 0x80000062},
|
|
{"libSceAbstractYoutube.sprx", 0x80000061},
|
|
{"libSceAc3Enc.sprx", 0x80000013},
|
|
{"libSceAgc.sprx", 0x80000094},
|
|
{"libSceAgcDriver.sprx", 0x80000080},
|
|
{"libSceAgcResourceRegistration.sprx", 0x80000093},
|
|
{"libSceAgcVsh.sprx", 0x80000086},
|
|
{"libSceAgcVshDebug.sprx", 0x80000087},
|
|
{"libSceAjm.native.sprx", 0x80000023},
|
|
{"libSceAjmi.sprx", 0x8000007e},
|
|
{"libSceAmpr.sprx", 0x800000b7},
|
|
{"libSceAppChecker.sprx", 0x80000032},
|
|
{"libSceAppDbShellCoreClient.sprx", 0x800000a7},
|
|
{"libSceAppInstUtil.sprx", 0x80000014},
|
|
{"libSceAsyncStorageInternal.sprx", 0x80000077},
|
|
{"libSceAudioIn.sprx", 0x80000002},
|
|
{"libSceAudioOut.sprx", 0x80000001},
|
|
{"libSceAudioSystem.sprx", 0x80000083},
|
|
{"libSceAudiodecCpuDtsHdMa.sprx", 0x8000002d},
|
|
{"libSceAudiodecCpuLpcm.sprx", 0x8000002e},
|
|
{"libSceAudiodecCpuTrhd.sprx", 0x80000082},
|
|
{"libSceAvSetting.sprx", 0x80000021},
|
|
{"libSceAvcap2.sprx", 0x80000085},
|
|
{"libSceBackupRestoreUtil.sprx", 0x8000003f},
|
|
{"libSceBgft.sprx", 0x8000002a},
|
|
{"libSceBgsStorage.sprx", 0x800000a3},
|
|
{"libSceCamera.sprx", 0x8000001a},
|
|
{"libSceCdlgUtilServer.sprx", 0x80000007},
|
|
{"libSceCommonDialog.sprx", 0x80000018},
|
|
{"libSceComposite.sprx", 0x8000008a},
|
|
{"libSceCompositeExt.sprx", 0x8000008b},
|
|
{"libSceContentListController.sprx", 0x800000ad},
|
|
{"libSceDataTransfer.sprx", 0x80000057},
|
|
{"libSceDbg.sprx", 0x80000025},
|
|
{"libSceDipsw.sprx", 0x80000029},
|
|
{"libSceDseehx.sprx", 0x80000056},
|
|
{"libSceDtsEnc.sprx", 0x80000028},
|
|
{"libSceEmbeddedTts.sprx", 0x8000009c},
|
|
{"libSceEmbeddedTtsCoreG3.sprx", 0x8000009b},
|
|
{"libSceFsInternalForVsh.sprx", 0x80000066},
|
|
{"libSceGLSlimVSH.sprx", 0x800000a9},
|
|
{"libSceGifParser.sprx", 0x8000005e},
|
|
{"libSceGpuCapture.sprx", 0x8000007f},
|
|
{"libSceGpuTrace.sprx", 0x8000007b},
|
|
{"libSceGvMp4Parser.sprx", 0x8000005c},
|
|
{"libSceHidControl.sprx", 0x80000017},
|
|
{"libSceHttp.sprx", 0x8000000a},
|
|
{"libSceHttp2.sprx", 0x8000008c},
|
|
{"libSceHttpCache.sprx", 0x80000078},
|
|
{"libSceIcu.sprx", 0x800000a8},
|
|
{"libSceIdu.sprx", 0x800000a6},
|
|
{"libSceImageUtil.sprx", 0x80000059},
|
|
{"libSceIpmi.sprx", 0x8000001d},
|
|
{"libSceJemspace.sprx", 0x8000009e},
|
|
{"libSceJitBridge.sprx", 0x8000006f},
|
|
{"libSceJpegParser.sprx", 0x8000005b},
|
|
{"libSceJsc.sprx", 0x800000b0},
|
|
{"libSceJscCompiler.sprx", 0x80000070},
|
|
{"libSceJxr.sprx", 0x800000b4},
|
|
{"libSceJxrParser.sprx", 0x800000b5},
|
|
{"libSceKbEmulate.sprx", 0x80000031},
|
|
{"libSceLibreSsl.sprx", 0x80000065},
|
|
{"libSceLibreSsl3.sprx", 0x800000b8},
|
|
{"libSceLoginMgrServer.sprx", 0x80000045},
|
|
{"libSceMarlin.sprx", 0x80000027},
|
|
{"libSceMat.sprx", 0x80000048},
|
|
{"libSceMbus.sprx", 0x8000001e},
|
|
{"libSceMediaFrameworkInterface.sprx", 0x80000095},
|
|
{"libSceMediaFrameworkUtil.sprx", 0x800000b6},
|
|
{"libSceMetadataReaderWriter.sprx", 0x8000005a},
|
|
{"libSceNKWeb.sprx", 0x80000079},
|
|
{"libSceNKWebKit.sprx", 0x8000007a},
|
|
{"libSceNet.sprx", 0x8000001c},
|
|
{"libSceNetCtl.sprx", 0x80000009},
|
|
{"libSceNgs2.sprx", 0x80000090},
|
|
{"libSceNpCommon.sprx", 0x8000000c},
|
|
{"libSceNpGameIntent.sprx", 0x8000008d},
|
|
{"libSceNpManager.sprx", 0x8000000d},
|
|
{"libSceNpRemotePlaySessionSignaling.sprx", 0x8000009a},
|
|
{"libSceNpSns.sprx", 0x8000001b},
|
|
{"libSceNpTcs.sprx", 0x800000a0},
|
|
{"libSceNpWebApi.sprx", 0x8000000e},
|
|
{"libSceNpWebApi2.sprx", 0x8000008f},
|
|
{"libSceOpusCeltDec.sprx", 0x80000044},
|
|
{"libSceOpusCeltEnc.sprx", 0x80000043},
|
|
{"libSceOpusDec.sprx", 0x80000069},
|
|
{"libSceOpusSilkEnc.sprx", 0x80000068},
|
|
{"libSceOrbisCompat.sprx", 0x80000071},
|
|
{"libScePad.sprx", 0x80000024},
|
|
{"libScePngParser.sprx", 0x8000005d},
|
|
{"libScePosixForWebKit.sprx", 0x80000098},
|
|
{"libScePsm.sprx", 0x80000030},
|
|
{"libSceRazorCpu_debug.sprx", 0x80000075},
|
|
{"libSceRegMgr.sprx", 0x8000001f},
|
|
{"libSceRemotePlayClientIpc.sprx", 0x800000b9},
|
|
{"libSceResourceArbitrator.sprx", 0x80000092},
|
|
{"libSceRnpsAppMgr.sprx", 0x80000076},
|
|
{"libSceRtc.sprx", 0x80000020},
|
|
{"libSceSaveData.sprx", 0x8000000f},
|
|
{"libSceShareInternal.native.sprx", 0x8000008e},
|
|
{"libSceSocialScreen.sprx", 0x800000ae},
|
|
{"libSceSsl.sprx", 0x8000000b},
|
|
{"libSceSulphaDrv.sprx", 0x8000003b},
|
|
{"libSceSysCore.sprx", 0x80000004},
|
|
{"libSceSysUtil.sprx", 0x80000026},
|
|
{"libSceSystemLogger2.sprx", 0x800000b3},
|
|
{"libSceSystemLogger2Delivery.sprx", 0x80000089},
|
|
{"libSceSystemLogger2Game.sprx", 0x8000009f},
|
|
{"libSceSystemLogger2NativeQueueClient.sprx", 0x80000088},
|
|
{"libSceSystemService.sprx", 0x80000010},
|
|
{"libSceSystemTts.sprx", 0x80000097},
|
|
{"libSceTEEClient.sprx", 0x800000a2},
|
|
{"libSceUserService.sprx", 0x80000011},
|
|
{"libSceVcodec.sprx", 0x80000091},
|
|
{"libSceVdecCore.native.sprx", 0x80000015},
|
|
{"libSceVdecSavc2.native.sprx", 0x80000036},
|
|
{"libSceVdecShevc.native.sprx", 0x8000003c},
|
|
{"libSceVdecSvp9.native.sprx", 0x800000af},
|
|
{"libSceVenc.sprx", 0x80000084},
|
|
{"libSceVideoOut.sprx", 0x80000022},
|
|
{"libSceVideoOutSecondary.sprx", 0x80000046},
|
|
{"libSceVideoStreamingEngine_sys.sprx", 0x800000b2},
|
|
{"libSceVisionManager.sprx", 0x80000012},
|
|
{"libSceVnaInternal.sprx", 0x8000007c},
|
|
{"libSceVnaWebsocket.sprx", 0x8000007d},
|
|
{"libSceVoiceCommand.sprx", 0x80000099},
|
|
{"libSceWeb.sprx", 0x80000072},
|
|
{"libSceWebKit2.sprx", 0x80000073},
|
|
{"libSceWebKit2Secure.sprx", 0x80000074},
|
|
{"libSceWebmParserMdrw.sprx", 0x800000a4},
|
|
{"libcairo.sprx", 0x800000ac},
|
|
{"libcurl.sprx", 0x800000b1},
|
|
{"libicu.sprx", 0x800000aa},
|
|
{"libpng16.sprx", 0x800000ab}
|
|
};
|
|
|
|
|
|
/**
|
|
* Open up a new sprx object and initialize its members.
|
|
**/
|
|
static int
|
|
sprx_open(rtld_lib_t* ctx) {
|
|
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
|
unsigned int handle = 0;
|
|
dynlib_dynsec_t dynsec;
|
|
dynlib_obj_t obj;
|
|
char path[1024];
|
|
int unload = 0;
|
|
int error = 0;
|
|
|
|
// check if the lib is an alias for libkernel
|
|
if(!strcmp(lib->soname, "libkernel.sprx") ||
|
|
!strcmp(lib->soname, "libkernel_web.sprx") ||
|
|
!strcmp(lib->soname, "libkernel_sys.sprx")) {
|
|
if(kernel_dynlib_dlsym(-1, 0x1, "sceKernelDlsym")) {
|
|
handle = 1;
|
|
} else {
|
|
handle = 0x2001;
|
|
}
|
|
}
|
|
// check if lib is already opened
|
|
else if(kernel_dynlib_handle(-1, lib->soname, &handle) < 0) {
|
|
if(__rtld_find_file(lib->soname, path)) {
|
|
return -1;
|
|
}
|
|
|
|
for(int i=0; i<sizeof(sysmodtab)/sizeof(sysmodtab[0]); i++) {
|
|
if(!strcmp(lib->soname, sysmodtab[i].name)) {
|
|
if((error=sceSysmoduleLoadModuleInternal(sysmodtab[i].handle))) {
|
|
klog_printf("sceSysmoduleLoadModuleInternal: 0x%x\n", error);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) < 0) {
|
|
klog_printf("sceKernelLoadStartModule: 0x%x\n", handle);
|
|
return -1;
|
|
}
|
|
unload = 1;
|
|
}
|
|
|
|
if(kernel_dynlib_obj(-1, handle, &obj) < 0) {
|
|
error = 1;
|
|
}
|
|
else if(kernel_copyout(obj.path, lib->soname, 1024) < 0) {
|
|
error = 1;
|
|
}
|
|
else if(kernel_copyout(obj.dynsec, &dynsec, sizeof(dynsec)) < 0) {
|
|
error = 1;
|
|
}
|
|
else if(!(lib->strtab=malloc(dynsec.strtabsize))) {
|
|
klog_perror("malloc");
|
|
return -1;
|
|
}
|
|
else if(kernel_copyout(dynsec.strtab, lib->strtab, dynsec.strtabsize) < 0) {
|
|
error = 1;
|
|
}
|
|
else if(!(lib->symtab=malloc(dynsec.symtabsize))) {
|
|
klog_perror("malloc");
|
|
return -1;
|
|
}
|
|
else if(kernel_copyout(dynsec.symtab, lib->symtab, dynsec.symtabsize) < 0) {
|
|
error = 1;
|
|
}
|
|
|
|
if(error) {
|
|
klog_puts("Unknown kernel I/O error");
|
|
return -1;
|
|
}
|
|
|
|
lib->handle = handle;
|
|
lib->unload_on_close = unload;
|
|
lib->mapbase = (void*)obj.mapbase;
|
|
lib->mapsize = obj.mapsize;
|
|
lib->symtab_size = dynsec.symtabsize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* TODO: sprx_init
|
|
**/
|
|
static int
|
|
sprx_init(rtld_lib_t* ctx, int argc, char** argv, char** envp) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* TODO: sprx_fini
|
|
**/
|
|
static int
|
|
sprx_fini(rtld_lib_t* ctx) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Resolve the address of a symbol provided by the given sprx object-
|
|
**/
|
|
static void*
|
|
sprx_sym2addr(rtld_lib_t* ctx, const char* name) {
|
|
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
|
char nid[12];
|
|
|
|
if(!lib->symtab || !lib->strtab || !lib->mapbase) {
|
|
return 0;
|
|
}
|
|
|
|
nid_encode(name, nid);
|
|
|
|
for(unsigned long i=0; i<lib->symtab_size/sizeof(Elf64_Sym); i++) {
|
|
if(!lib->symtab[i].st_size) {
|
|
continue;
|
|
}
|
|
|
|
if(!strncmp(nid, lib->strtab + lib->symtab[i].st_name, 11) ||
|
|
!strncmp(name, lib->strtab + lib->symtab[i].st_name, 11)) {
|
|
return lib->mapbase + lib->symtab[i].st_value;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Figure out the symbol name associated with the given address.
|
|
**/
|
|
static const char*
|
|
sprx_addr2sym(rtld_lib_t* ctx, void* addr) {
|
|
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
|
|
|
if(!lib->symtab || !lib->strtab || !lib->mapbase) {
|
|
return 0;
|
|
}
|
|
|
|
if(addr < lib->mapbase ||
|
|
addr > lib->mapbase + lib->mapsize) {
|
|
return 0;
|
|
}
|
|
|
|
for(unsigned long i=0; i<lib->symtab_size/sizeof(Elf64_Sym); i++) {
|
|
if(!lib->symtab[i].st_size) {
|
|
continue;
|
|
}
|
|
|
|
if(addr >= lib->mapbase + lib->symtab[i].st_value &&
|
|
addr <= lib->mapbase + lib->symtab[i].st_value + lib->symtab[i].st_size) {
|
|
return lib->strtab + lib->symtab[i].st_name;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Close the given sprx object and free memory associated with its members.
|
|
**/
|
|
static int
|
|
sprx_close(rtld_lib_t* ctx) {
|
|
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
|
int err = 0;
|
|
|
|
if(lib->unload_on_close) {
|
|
if((err=sceKernelStopUnloadModule(lib->handle, 0, 0, 0, 0, 0))) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
if(lib->strtab) {
|
|
free(lib->strtab);
|
|
}
|
|
if(lib->symtab) {
|
|
free(lib->symtab);
|
|
}
|
|
|
|
lib->handle = -1;
|
|
lib->strtab = 0;
|
|
lib->symtab = 0;
|
|
lib->symtab_size = 0;
|
|
lib->mapbase = 0;
|
|
lib->mapsize = 0;
|
|
lib->unload_on_close = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Free all memory associated the given sprx object.
|
|
**/
|
|
static void
|
|
sprx_destroy(rtld_lib_t* ctx) {
|
|
rtld_sprx_lib_t* lib = (rtld_sprx_lib_t*)ctx;
|
|
|
|
if(sprx_close(ctx)) {
|
|
lib->unload_on_close = 0;
|
|
sprx_close(ctx);
|
|
}
|
|
|
|
free(lib);
|
|
}
|
|
|
|
|
|
rtld_lib_t*
|
|
__rtld_sprx_new(rtld_lib_t* parent, const char *soname) {
|
|
rtld_sprx_lib_t* lib = calloc(1, sizeof(rtld_sprx_lib_t));
|
|
|
|
lib->parent = parent;
|
|
lib->open = sprx_open;
|
|
lib->init = sprx_init;
|
|
lib->sym2addr = sprx_sym2addr;
|
|
lib->addr2sym = sprx_addr2sym;
|
|
lib->fini = sprx_fini;
|
|
lib->close = sprx_close;
|
|
lib->destroy = sprx_destroy;
|
|
lib->refcnt = 0;
|
|
|
|
strcpy(lib->soname, soname);
|
|
|
|
return (rtld_lib_t*)lib;
|
|
}
|
|
|
|
|
|
int
|
|
__rtld_sprx_init(void) {
|
|
unsigned int libSceSysmodule;
|
|
unsigned int libkernel = 0x1;
|
|
unsigned int libc = 0x2;
|
|
|
|
if(!kernel_dynlib_dlsym(-1, libkernel, "sceKernelDlsym")) {
|
|
libkernel = 0x2001;
|
|
}
|
|
if(!KERNEL_DLSYM(libkernel, sceKernelLoadStartModule)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libkernel, sceKernelStopUnloadModule)) {
|
|
return -1;
|
|
}
|
|
|
|
if(!KERNEL_DLSYM(libc, strcpy)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libc, strcmp)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libc, strncmp)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libc, calloc)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libc, malloc)) {
|
|
return -1;
|
|
}
|
|
if(!KERNEL_DLSYM(libc, free)) {
|
|
return -1;
|
|
}
|
|
|
|
if(kernel_dynlib_handle(-1, "libSceSysmodule.sprx", &libSceSysmodule)) {
|
|
if((libSceSysmodule=sceKernelLoadStartModule("/system/common/lib/libSceSysmodule.sprx",
|
|
0, 0, 0, 0, 0)) <= 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
if(!KERNEL_DLSYM(libSceSysmodule, sceSysmoduleLoadModuleInternal)) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|