diff --git a/crt/kernel.c b/crt/kernel.c index 6e05556..47bb99b 100644 --- a/crt/kernel.c +++ b/crt/kernel.c @@ -149,7 +149,7 @@ typedef struct { static void* (*malloc)(unsigned long) = 0; static void (*free)(void*) = 0; static int (*strncmp)(const char*, const char*, unsigned long) = 0; - +static int (*strlen)(const char*) = 0; /** * public constants. @@ -218,6 +218,10 @@ __kernel_init(payload_args_t* args) { klog_perror("Unable to resolve 'free'"); return error; } + if((error=args->sceKernelDlsym(0x2, "strlen", &strlen))) { + klog_perror("Unable to resolve 'strlen'"); + return error; + } if((error=args->sceKernelDlsym(0x2, "strncmp", &strncmp))) { klog_perror("Unable to resolve 'strncmp'"); return error; @@ -482,6 +486,63 @@ kernel_dynlib_obj(int pid, unsigned int handle, dynlib_obj_t* obj) { } +int +kernel_dynlib_handle(int pid, const char* basename, unsigned int *handle) { + unsigned long kproc; + unsigned long kaddr; + unsigned long kpath; + unsigned long blen; + unsigned long plen; + char path[1024]; + long temphandle; + + if(!(kproc=kernel_get_proc(pid))) { + return -1; + } + + if(kernel_copyout(kproc + 0x3e8, &kaddr, sizeof(kaddr)) < 0) { + return -1; + } + + blen = strlen(basename); + do { + if(kernel_copyout(kaddr, &kaddr, sizeof(kaddr)) < 0) { + return -1; + } + if(!kaddr) { + return -1; + } + if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, path), + &kpath, sizeof(kpath)) < 0) { + return -1; + } + if(kernel_copyout(kpath, path, sizeof(path)) < 0) { + return -1; + } + + if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, handle), + &temphandle, sizeof(temphandle)) < 0) { + return -1; + } + + plen = strlen(path); + if(plen <= blen) { + continue; + } + if(path[plen-blen-1] != '/') { + continue; + } + if(strncmp(path + plen - blen, basename, blen)) { + continue; + } + + + *handle = (unsigned int)temphandle; + return 0; + } while(1); +} + + unsigned long kernel_dynlib_fini_addr(int pid, unsigned int handle) { dynlib_obj_t obj; diff --git a/crt/kernel.h b/crt/kernel.h index edba04e..5c4a854 100644 --- a/crt/kernel.h +++ b/crt/kernel.h @@ -30,3 +30,4 @@ unsigned long kernel_get_proc_rootdir(int pid); int kernel_set_proc_rootdir(int pid, unsigned long vnode); unsigned long kernel_dynlib_entry_addr(int pid, unsigned int handle); +int kernel_dynlib_handle(int pid, const char* basename, unsigned int *handle); diff --git a/crt/rtld.c b/crt/rtld.c index f263c99..024fa78 100644 --- a/crt/rtld.c +++ b/crt/rtld.c @@ -546,31 +546,17 @@ rtld_load(void) { **/ static int rtld_load_sysmodule(payload_args_t *args) { - unsigned long nb_handles = 0; - int handles[256]; - int handle; - - // get handles for loaded modules - if(syscall(0x250, handles, sizeof(handles), &nb_handles)) { - return -1; - } + int pid = syscall(SYS_getpid); + unsigned int handle; - // try to load sceSysmoduleLoadModuleInternal from all of the handles - for(int i=0; isceKernelDlsym(handle, "sceSysmoduleLoadModuleInternal", - &sceSysmoduleLoadModuleInternal)) { - return 0; + if(kernel_dynlib_handle(pid, "libSceSysmodule.sprx", &handle)) { + if((handle=sceKernelLoadStartModule("/system/common/lib/libSceSysmodule.sprx", + 0, 0, 0, 0, 0)) <= 0) { + klog_libload_error("libSceSysmodule.sprx"); + return -1; } } - // load libSceSysmodule - if((handle=sceKernelLoadStartModule("/system/common/lib/libSceSysmodule.sprx", - 0, 0, 0, 0, 0)) <= 0) { - klog_libload_error("libSceSysmodule.sprx"); - return -1; - } - // resolve sceSysmoduleLoadModuleInternal return args->sceKernelDlsym(handle, "sceSysmoduleLoadModuleInternal", &sceSysmoduleLoadModuleInternal); diff --git a/include/ps5/kernel.h b/include/ps5/kernel.h index f641fea..d88818f 100644 --- a/include/ps5/kernel.h +++ b/include/ps5/kernel.h @@ -60,6 +60,7 @@ intptr_t kernel_get_proc_file(pid_t pid, int fd); int kernel_overlap_sockets(pid_t pid, int master_sock, int victim_sock); +int kernel_dynlib_handle(pid_t pid, const char* basename, uint32_t *handle); intptr_t kernel_dynlib_resolve(pid_t pid, uint32_t handle, const char *nid); intptr_t kernel_dynlib_entry_addr(pid_t pid, uint32_t handle); intptr_t kernel_dynlib_init_addr(pid_t pid, uint32_t handle);