mirror of
https://github.com/ps5-payload-dev/sdk.git
synced 2026-10-22 03:14:55 -05:00
dynamically link sprx libs
This commit is contained in:
1 parent
564ce5e2ca
commit
b4cebf24cd
58 files changed
+15292
-46413
No files matched your search
@@ -38,20 +38,14 @@ jobs:
|
||||
run: |
|
||||
make -C samples/arbitrary_syscall
|
||||
make -C samples/browser
|
||||
make -C samples/elf_loader
|
||||
make -C samples/hello_sprx
|
||||
make -C samples/hello_stdio
|
||||
make -C samples/hello_world
|
||||
make -C samples/hwinfo
|
||||
make -C samples/kernel_data_dump
|
||||
make -C samples/klog
|
||||
make -C samples/launch_app
|
||||
make -C samples/list_files
|
||||
make -C samples/mntinfo
|
||||
make -C samples/pipe_pirate
|
||||
make -C samples/procpatch
|
||||
make -C samples/ps
|
||||
make -C samples/ptrace_elfldr
|
||||
make -C samples/remount
|
||||
bash samples/hello_cmake/build.sh
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
*~
|
||||
*.a
|
||||
*.so
|
||||
*.o
|
||||
*.sprx
|
||||
nid_db.xml
|
||||
|
||||
@@ -22,20 +22,14 @@ make clean install || exit 1
|
||||
|
||||
MAKE_SAMPLES=("arbitrary_syscall"
|
||||
"browser"
|
||||
"elf_loader"
|
||||
"hello_sprx"
|
||||
"hello_stdio"
|
||||
"hello_world"
|
||||
"hwinfo"
|
||||
"kernel_data_dump"
|
||||
"klog"
|
||||
"launch_app"
|
||||
"list_files"
|
||||
"mntinfo"
|
||||
"pipe_pirate"
|
||||
"procpatch"
|
||||
"ps"
|
||||
"ptrace_elfldr"
|
||||
"remount")
|
||||
|
||||
CMAKE_SAMPLES=("hello_cmake"
|
||||
|
||||
+3
-4
@@ -19,13 +19,12 @@ DESTDIR ?= /opt/ps5-payload-sdk
|
||||
CC := clang
|
||||
LD := ld.lld
|
||||
|
||||
CFLAGS := -ffreestanding -fno-builtin -nostdlib -O2
|
||||
CFLAGS += -fPIE -target x86_64-pc-none
|
||||
|
||||
CFLAGS := -ffreestanding -fno-builtin -nostdlib
|
||||
CFLAGS += -target x86_64-sie-ps5 -fno-stack-protector
|
||||
|
||||
all: crt1.o
|
||||
|
||||
crt1.o: crt.o kernel.o sprx.o syscall.o
|
||||
crt1.o: crt.o syscall.o kernel.o rtld.o mdbg.o payload.o
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -15,7 +15,6 @@ along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "payload.h"
|
||||
#include "syscall.h"
|
||||
|
||||
|
||||
/**
|
||||
@@ -24,8 +23,8 @@ along with this program; see the file COPYING. If not, see
|
||||
extern void (*__init_array_start[])(payload_args_t*) __attribute__((weak));
|
||||
extern void (*__init_array_end[])(payload_args_t*) __attribute__((weak));
|
||||
|
||||
extern void (*__fini_array_start[])(void) __attribute__((weak));
|
||||
extern void (*__fini_array_end[])(void) __attribute__((weak));
|
||||
extern void (*__fini_array_start[])(payload_args_t*) __attribute__((weak));
|
||||
extern void (*__fini_array_end[])(payload_args_t*) __attribute__((weak));
|
||||
|
||||
extern unsigned char __bss_start[] __attribute__((weak));
|
||||
extern unsigned char __bss_end[] __attribute__((weak));
|
||||
@@ -37,59 +36,44 @@ extern unsigned char __bss_end[] __attribute__((weak));
|
||||
extern int main(int argc, char* argv[], char *envp[]);
|
||||
|
||||
|
||||
/**
|
||||
* For error reporting to /dev/klog and /dev/stdout
|
||||
**/
|
||||
static char* (*strerror)(int) = 0;
|
||||
static void (*printf)(const char*, ...) = 0;
|
||||
static void
|
||||
kerror(const char *s, int error) {
|
||||
printf("%s: %s\n", s, strerror(error));
|
||||
|
||||
syscall(0x259, 7, "<118>[homebrew] ", 0);
|
||||
syscall(0x259, 7, s, 0);
|
||||
syscall(0x259, 7, ": ", 0);
|
||||
syscall(0x259, 7, strerror(error), 0);
|
||||
syscall(0x259, 7, "\n", 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entry-point used by the ELF loader.
|
||||
**/
|
||||
void
|
||||
_start(payload_args_t *args) {
|
||||
unsigned long count;
|
||||
unsigned long count = 0;
|
||||
int exit_code = 0;
|
||||
int *error;
|
||||
|
||||
for(unsigned char* bss=__bss_start; bss<__bss_end; bss++) {
|
||||
*bss = 0;
|
||||
}
|
||||
|
||||
if((*args->payloadout=args->sceKernelDlsym(0x2, "strerror", &strerror))) {
|
||||
return;
|
||||
if(args) {
|
||||
error = args->payloadout;
|
||||
} else {
|
||||
error = &exit_code;
|
||||
}
|
||||
|
||||
if((*args->payloadout=args->sceKernelDlsym(0x2, "printf", &printf))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// run module constructors
|
||||
*error = 0;
|
||||
count = __init_array_end - __init_array_start;
|
||||
for(int i=0; i<count; i++) {
|
||||
__init_array_start[i](args);
|
||||
if(*args->payloadout) {
|
||||
kerror("Unable to initialize payload", *args->payloadout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!*args->payloadout) {
|
||||
*args->payloadout = main(0, 0, 0);
|
||||
if(!*error) {
|
||||
exit_code = main(0, 0, 0);
|
||||
} else {
|
||||
exit_code = *error;
|
||||
}
|
||||
|
||||
// run module destructors
|
||||
*error = 0;
|
||||
count = __fini_array_end - __fini_array_start;
|
||||
for(int i=0; i<count; i++) {
|
||||
__fini_array_start[count-i-1]();
|
||||
__fini_array_start[count-i-1](args);
|
||||
}
|
||||
|
||||
if(!*error) {
|
||||
*error = exit_code;
|
||||
}
|
||||
}
|
||||
+264
-68
@@ -15,7 +15,7 @@ along with this program; see the file COPYING. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "payload.h"
|
||||
|
||||
#include "syscall.h"
|
||||
|
||||
/**
|
||||
* standard macros.
|
||||
@@ -143,17 +143,11 @@ typedef struct {
|
||||
|
||||
|
||||
/**
|
||||
* libkernel and libc symbols
|
||||
* external dependencies.
|
||||
**/
|
||||
static long (*_read)(int, void*, unsigned long);
|
||||
static long (*_write)(int, const void*, unsigned long);
|
||||
static int (*_getsockopt)(int, int, int, void *, unsigned int *);
|
||||
static int (*_setsockopt)(int, int, int, const void*, unsigned int);
|
||||
static int (*sysctlbyname)(const char *, void *, unsigned long*,
|
||||
const void *, unsigned long);
|
||||
static void* (*malloc)(unsigned long);
|
||||
static void (*free)(void*);
|
||||
static int (*strncmp)(const char*, const char*, unsigned long);
|
||||
static void* (*malloc)(unsigned long) = 0;
|
||||
static void (*free)(void*) = 0;
|
||||
static int (*strncmp)(const char*, const char*, unsigned long) = 0;
|
||||
|
||||
|
||||
/**
|
||||
@@ -193,19 +187,15 @@ static int master_sock = -1;
|
||||
static int victim_sock = -1;
|
||||
static int rw_pipe[2] = {-1, -1};
|
||||
static unsigned long pipe_addr = 0;
|
||||
static unsigned long kdata_base = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned int
|
||||
kernel_get_fw_version(void) {
|
||||
int mib[2] = {1, 46};
|
||||
unsigned long size = sizeof(mib);
|
||||
unsigned int version = 0;
|
||||
unsigned long size = sizeof(version);
|
||||
|
||||
if(sysctlbyname("kern.sdk_version", &version, &size, 0, 0)) {
|
||||
if(syscall(SYS_sysctl, mib, 2, &version, &size, 0, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,32 +203,11 @@ kernel_get_fw_version(void) {
|
||||
}
|
||||
|
||||
|
||||
__attribute__((constructor(101))) static void
|
||||
kernel_constructor(const payload_args_t *args) {
|
||||
__attribute__((constructor(102))) static void
|
||||
kernel_constructor(payload_args_t* args) {
|
||||
int error = 0;
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "_read", &_read))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "_write", &_write))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "_setsockopt", &_setsockopt))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "_getsockopt", &_getsockopt))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "sysctlbyname", &sysctlbyname))) {
|
||||
*args->payloadout = error;
|
||||
if(!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,11 +316,13 @@ kernel_write(unsigned long addr, unsigned long *data) {
|
||||
victim_buf[1] = 0;
|
||||
victim_buf[2] = 0;
|
||||
|
||||
if(_setsockopt(master_sock, IPPROTO_IPV6, IPV6_PKTINFO, victim_buf, 0x14)) {
|
||||
if(syscall(SYS_setsockopt, master_sock, IPPROTO_IPV6, IPV6_PKTINFO,
|
||||
victim_buf, 0x14)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(_setsockopt(victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, data, 0x14)) {
|
||||
if(syscall(SYS_setsockopt, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO,
|
||||
data, 0x14)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -363,9 +334,13 @@ kernel_write(unsigned long addr, unsigned long *data) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_copyin(const void *udaddr, unsigned long kaddr, unsigned long len) {
|
||||
kernel_copyin(const void *uaddr, unsigned long kaddr, unsigned long len) {
|
||||
unsigned long write_buf[3];
|
||||
|
||||
if(!kaddr || !uaddr || !len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set pipe flags
|
||||
write_buf[0] = 0;
|
||||
write_buf[1] = 0x4000000000000000;
|
||||
@@ -383,7 +358,7 @@ kernel_copyin(const void *udaddr, unsigned long kaddr, unsigned long len) {
|
||||
}
|
||||
|
||||
// Perform write across pipe
|
||||
if(_write(rw_pipe[1], udaddr, len) < 0) {
|
||||
if(syscall(SYS_write, rw_pipe[1], uaddr, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -395,9 +370,13 @@ kernel_copyin(const void *udaddr, unsigned long kaddr, unsigned long len) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_copyout(unsigned long kaddr, void *udaddr, unsigned long len) {
|
||||
kernel_copyout(unsigned long kaddr, void *uaddr, unsigned long len) {
|
||||
unsigned long write_buf[3];
|
||||
|
||||
if(!kaddr || !uaddr || !len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set pipe flags
|
||||
write_buf[0] = 0x4000000040000000;
|
||||
write_buf[1] = 0x4000000000000000;
|
||||
@@ -415,7 +394,7 @@ kernel_copyout(unsigned long kaddr, void *udaddr, unsigned long len) {
|
||||
}
|
||||
|
||||
// Perform read across pipe
|
||||
if(_read(rw_pipe[0], udaddr, len) < 0) {
|
||||
if(syscall(SYS_read, rw_pipe[0], uaddr, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -455,11 +434,12 @@ kernel_get_root_vnode(void) {
|
||||
return vnode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc(unsigned int pid) {
|
||||
kernel_get_proc(int pid) {
|
||||
unsigned int other_pid = 0;
|
||||
unsigned long addr = 0;
|
||||
unsigned long next = 0;
|
||||
@@ -489,8 +469,91 @@ kernel_get_proc(unsigned int pid) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_dynlib_entry_addr(unsigned int pid, unsigned int handle) {
|
||||
kernel_dynlib_fini_addr(int pid, unsigned int handle) {
|
||||
unsigned long kproc = kernel_get_proc(pid);
|
||||
unsigned long kaddr;
|
||||
dynlib_obj_t obj;
|
||||
|
||||
if(!(kproc=kernel_get_proc(pid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kproc + 0x3e8, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if(kernel_copyout(kaddr, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
if(!kaddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, handle),
|
||||
&obj.handle, sizeof(obj.handle)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
} while(obj.handle != handle);
|
||||
|
||||
if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, fini),
|
||||
&obj.fini, sizeof(obj.fini)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return obj.fini;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_dynlib_init_addr(int pid, unsigned int handle) {
|
||||
unsigned long kproc = kernel_get_proc(pid);
|
||||
unsigned long kaddr;
|
||||
dynlib_obj_t obj;
|
||||
|
||||
if(!(kproc=kernel_get_proc(pid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kproc + 0x3e8, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if(kernel_copyout(kaddr, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
if(!kaddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, handle),
|
||||
&obj.handle, sizeof(obj.handle)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
} while(obj.handle != handle);
|
||||
|
||||
if(kernel_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, init),
|
||||
&obj.init, sizeof(obj.init)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return obj.init;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_dynlib_entry_addr(int pid, unsigned int handle) {
|
||||
unsigned long kproc = kernel_get_proc(pid);
|
||||
unsigned long kaddr;
|
||||
dynlib_obj_t obj;
|
||||
@@ -525,8 +588,11 @@ kernel_dynlib_entry_addr(unsigned int pid, unsigned int handle) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_dynlib_resolve(unsigned int pid, int handle, const char *nid) {
|
||||
kernel_dynlib_resolve(int pid, int handle, const char *nid) {
|
||||
unsigned long kproc = kernel_get_proc(pid);
|
||||
dynlib_dynsec_t dynsec;
|
||||
unsigned long kaddr;
|
||||
@@ -604,7 +670,7 @@ kernel_dynlib_resolve(unsigned int pid, int handle, const char *nid) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc_ucred(unsigned int pid) {
|
||||
kernel_get_proc_ucred(int pid) {
|
||||
unsigned long proc = 0;
|
||||
unsigned long ucred = 0;
|
||||
|
||||
@@ -625,7 +691,7 @@ kernel_get_proc_ucred(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_ucred_authid(unsigned int pid) {
|
||||
kernel_get_ucred_authid(int pid) {
|
||||
unsigned long authid = 0;
|
||||
unsigned long ucred = 0;
|
||||
|
||||
@@ -646,7 +712,7 @@ kernel_get_ucred_authid(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_authid(unsigned int pid, unsigned long authid) {
|
||||
kernel_set_ucred_authid(int pid, unsigned long authid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -666,7 +732,7 @@ kernel_set_ucred_authid(unsigned int pid, unsigned long authid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_get_ucred_caps(unsigned int pid, unsigned char caps[16]) {
|
||||
kernel_get_ucred_caps(int pid, unsigned char caps[16]) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -685,7 +751,7 @@ kernel_get_ucred_caps(unsigned int pid, unsigned char caps[16]) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_caps(unsigned int pid, unsigned char caps[16]) {
|
||||
kernel_set_ucred_caps(int pid, unsigned char caps[16]) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -704,7 +770,7 @@ kernel_set_ucred_caps(unsigned int pid, unsigned char caps[16]) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_ucred_attrs(unsigned int pid) {
|
||||
kernel_get_ucred_attrs(int pid) {
|
||||
unsigned long ucred = 0;
|
||||
unsigned long attrs = 0;
|
||||
|
||||
@@ -725,7 +791,7 @@ kernel_get_ucred_attrs(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_attrs(unsigned int pid, unsigned long attrs) {
|
||||
kernel_set_ucred_attrs(int pid, unsigned long attrs) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -745,7 +811,7 @@ kernel_set_ucred_attrs(unsigned int pid, unsigned long attrs) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_uid(unsigned int pid, unsigned int uid) {
|
||||
kernel_set_ucred_uid(int pid, unsigned int uid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -765,7 +831,7 @@ kernel_set_ucred_uid(unsigned int pid, unsigned int uid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_ruid(unsigned int pid, unsigned int ruid) {
|
||||
kernel_set_ucred_ruid(int pid, unsigned int ruid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -785,7 +851,7 @@ kernel_set_ucred_ruid(unsigned int pid, unsigned int ruid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_svuid(unsigned int pid, unsigned int svuid) {
|
||||
kernel_set_ucred_svuid(int pid, unsigned int svuid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -806,7 +872,7 @@ kernel_set_ucred_svuid(unsigned int pid, unsigned int svuid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_rgid(unsigned int pid, unsigned int rgid) {
|
||||
kernel_set_ucred_rgid(int pid, unsigned int rgid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -826,7 +892,7 @@ kernel_set_ucred_rgid(unsigned int pid, unsigned int rgid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_ucred_svgid(unsigned int pid, unsigned int svgid) {
|
||||
kernel_set_ucred_svgid(int pid, unsigned int svgid) {
|
||||
unsigned long ucred = 0;
|
||||
|
||||
if(!(ucred=kernel_get_proc_ucred(pid))) {
|
||||
@@ -846,7 +912,7 @@ kernel_set_ucred_svgid(unsigned int pid, unsigned int svgid) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc_filedesc(unsigned int pid) {
|
||||
kernel_get_proc_filedesc(int pid) {
|
||||
unsigned long filedesc = 0;
|
||||
unsigned long proc = 0;
|
||||
|
||||
@@ -867,7 +933,137 @@ kernel_get_proc_filedesc(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc_rootdir(unsigned int pid) {
|
||||
kernel_get_proc_file(int pid, int fd) {
|
||||
unsigned long fd_files;
|
||||
unsigned long fde_file;
|
||||
unsigned long file;
|
||||
unsigned long proc;
|
||||
unsigned long p_fd;
|
||||
|
||||
if(!(proc=kernel_get_proc(pid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(proc + 0x48, &p_fd, sizeof(p_fd))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(p_fd, &fd_files, sizeof(fd_files))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(fd_files + 8 + (0x30 * fd),
|
||||
&fde_file, sizeof(fde_file))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(fde_file, &file, sizeof(file))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static unsigned long
|
||||
kernel_get_proc_inp6_outputopts(int pid, int fd) {
|
||||
unsigned long inp6_outputopts;
|
||||
unsigned long so_pcb;
|
||||
unsigned long file;
|
||||
|
||||
if(!(file=kernel_get_proc_file(pid, fd))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(file + 0x18, &so_pcb, sizeof(so_pcb))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(so_pcb + 0x120, &inp6_outputopts,
|
||||
sizeof(inp6_outputopts))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return inp6_outputopts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static int
|
||||
kernel_inc_so_count(int pid, int fd) {
|
||||
unsigned long file;
|
||||
int so_count;
|
||||
|
||||
if(!(file=kernel_get_proc_file(pid, fd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_copyout(file, &so_count, sizeof(so_count))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
so_count++;
|
||||
if(kernel_copyin(&so_count, file, sizeof(so_count))) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_overlap_sockets(int pid, int master_sock, int victim_sock) {
|
||||
unsigned long master_inp6_outputopts;
|
||||
unsigned long victim_inp6_outputopts;
|
||||
unsigned long pktinfo;
|
||||
unsigned int tclass;
|
||||
|
||||
if(kernel_inc_so_count(pid, master_sock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(master_inp6_outputopts=kernel_get_proc_inp6_outputopts(pid,
|
||||
master_sock))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_inc_so_count(pid, victim_sock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(victim_inp6_outputopts=kernel_get_proc_inp6_outputopts(pid,
|
||||
victim_sock))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pktinfo = victim_inp6_outputopts + 0x10;
|
||||
if(kernel_copyin(&pktinfo, master_inp6_outputopts + 0x10,
|
||||
sizeof(pktinfo))) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
tclass = 0x13370000;
|
||||
if(kernel_copyin(&tclass, master_inp6_outputopts + 0xc0, sizeof(tclass))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc_rootdir(int pid) {
|
||||
unsigned long filedesc = 0;
|
||||
unsigned long vnode = 0;
|
||||
|
||||
@@ -888,7 +1084,7 @@ kernel_get_proc_rootdir(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
unsigned long
|
||||
kernel_get_proc_jaildir(unsigned int pid) {
|
||||
kernel_get_proc_jaildir(int pid) {
|
||||
unsigned long filedesc = 0;
|
||||
unsigned long vnode = 0;
|
||||
|
||||
@@ -909,7 +1105,7 @@ kernel_get_proc_jaildir(unsigned int pid) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_proc_rootdir(unsigned int pid, unsigned long vnode) {
|
||||
kernel_set_proc_rootdir(int pid, unsigned long vnode) {
|
||||
unsigned long filedesc = 0;
|
||||
|
||||
if(!(filedesc=kernel_get_proc_filedesc(pid))) {
|
||||
@@ -929,7 +1125,7 @@ kernel_set_proc_rootdir(unsigned int pid, unsigned long vnode) {
|
||||
*
|
||||
**/
|
||||
int
|
||||
kernel_set_proc_jaildir(unsigned int pid, unsigned long vnode) {
|
||||
kernel_set_proc_jaildir(int pid, unsigned long vnode) {
|
||||
unsigned long filedesc = 0;
|
||||
|
||||
if(!(filedesc=kernel_get_proc_filedesc(pid))) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -16,23 +16,10 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ptrace.h>
|
||||
unsigned long kernel_get_ucred_authid(int pid);
|
||||
int kernel_set_ucred_authid(int pid, unsigned long authid);
|
||||
|
||||
unsigned long kernel_get_root_vnode(void);
|
||||
unsigned long kernel_get_proc_rootdir(int pid);
|
||||
int kernel_set_proc_rootdir(int pid, unsigned long vnode);
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int pt_attach(pid_t pid);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int pt_detach(pid_t pid);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int pt_vm_entry(pid_t pid, struct ptrace_vm_entry *ve);
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -14,12 +14,9 @@ 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
#include "kernel.h"
|
||||
#include "mdbg.h"
|
||||
#include "syscall.h"
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,8 +30,8 @@ along with this program; see the file COPYING. If not, see
|
||||
*
|
||||
**/
|
||||
typedef struct mdbg_cmd {
|
||||
uint64_t type;
|
||||
uint64_t cmd;
|
||||
unsigned long type;
|
||||
unsigned long cmd;
|
||||
} mdbg_cmd_t;
|
||||
|
||||
|
||||
@@ -42,10 +39,10 @@ typedef struct mdbg_cmd {
|
||||
*
|
||||
**/
|
||||
typedef struct mdbg_memop_args {
|
||||
pid_t pid;
|
||||
intptr_t src;
|
||||
intptr_t dst;
|
||||
size_t len;
|
||||
int pid;
|
||||
unsigned long src;
|
||||
unsigned long dst;
|
||||
unsigned long len;
|
||||
} mdbg_memop_args_t;
|
||||
|
||||
|
||||
@@ -54,7 +51,7 @@ typedef struct mdbg_memop_args {
|
||||
**/
|
||||
typedef struct mdbg_res {
|
||||
int status;
|
||||
size_t len;
|
||||
unsigned long len;
|
||||
} mdbg_res_t;
|
||||
|
||||
|
||||
@@ -64,9 +61,9 @@ typedef struct mdbg_res {
|
||||
**/
|
||||
static int
|
||||
mdbg_memop(int memop, mdbg_memop_args_t *args) {
|
||||
int pid = (int)syscall(SYS_getpid);
|
||||
mdbg_cmd_t cmd = {1, memop};
|
||||
pid_t pid = getpid();
|
||||
uint64_t authid;
|
||||
unsigned long authid;
|
||||
mdbg_res_t res;
|
||||
long err;
|
||||
|
||||
@@ -79,9 +76,8 @@ mdbg_memop(int memop, mdbg_memop_args_t *args) {
|
||||
}
|
||||
|
||||
do {
|
||||
memset(&res, 0, sizeof(res));
|
||||
if((err=syscall(573, &cmd, args, &res)) == -1) {
|
||||
perror("mdbg");
|
||||
res.len = res.status = 0;
|
||||
if((err=syscall(SYS_mdbg_call, &cmd, args, &res)) == -1) {
|
||||
break;
|
||||
}
|
||||
args->src += res.len;
|
||||
@@ -98,16 +94,16 @@ mdbg_memop(int memop, mdbg_memop_args_t *args) {
|
||||
|
||||
|
||||
int
|
||||
mdbg_copyout(pid_t pid, intptr_t addr, void *buf, size_t len) {
|
||||
mdbg_memop_args_t args = {pid, addr, (intptr_t)buf, len};
|
||||
mdbg_copyout(int pid, unsigned long addr, void *buf, unsigned long len) {
|
||||
mdbg_memop_args_t args = {pid, addr, (unsigned long)buf, len};
|
||||
|
||||
return mdbg_memop(MDBG_MEMOP_READ, &args);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mdbg_copyin(pid_t pid, const void* buf, intptr_t addr, size_t len) {
|
||||
mdbg_memop_args_t args = {pid, (intptr_t)buf, addr, len};
|
||||
mdbg_copyin(int pid, const void* buf, unsigned long addr, unsigned long len) {
|
||||
mdbg_memop_args_t args = {pid, addr, (unsigned long)buf, len};
|
||||
|
||||
return mdbg_memop(MDBG_MEMOP_WRITE, &args);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -16,17 +16,14 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int mdbg_copyout(int pid, unsigned long addr, void *buf, unsigned long len);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int mdbg_copyout(pid_t pid, intptr_t addr, void *buf, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int mdbg_copyin(pid_t pid, const void *buf, intptr_t addr, size_t len);
|
||||
int mdbg_copyin(int pid, const void *buf, unsigned long addr, unsigned long len);
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -14,11 +14,15 @@ 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 "elfldr.h"
|
||||
#include "payload_elf.c"
|
||||
#include "payload.h"
|
||||
|
||||
payload_args_t* __payload_args = 0;
|
||||
|
||||
|
||||
int
|
||||
main() {
|
||||
return elfldr_exec(payload_elf, payload_elf_len);
|
||||
__attribute__((constructor(101))) static void
|
||||
payload_constructor(payload_args_t* args) {
|
||||
if(args) {
|
||||
__payload_args = args;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,7 @@ typedef struct payload_args {
|
||||
} payload_args_t;
|
||||
|
||||
|
||||
extern payload_args_t* __payload_args;
|
||||
|
||||
|
||||
#endif // PS5SDK_PAYLOAD_H
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
/* Copyright (C) 2023 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 "kernel.h"
|
||||
#include "mdbg.h"
|
||||
#include "payload.h"
|
||||
#include "syscall.h"
|
||||
|
||||
|
||||
#define ELF64_R_SYM(info) ((info) >> 32)
|
||||
|
||||
#define DT_NULL 0
|
||||
#define DT_NEEDED 1
|
||||
#define DT_STRTAB 5
|
||||
#define DT_SYMTAB 6
|
||||
#define DT_RELA 7
|
||||
#define DT_RELASZ 8
|
||||
|
||||
#define R_X86_64_GLOB_DAT 6
|
||||
#define R_X86_64_JMP_SLOT 7
|
||||
#define R_X86_64_RELATIVE 8
|
||||
|
||||
|
||||
typedef struct {
|
||||
long d_tag;
|
||||
union {
|
||||
unsigned long d_val;
|
||||
unsigned long d_ptr;
|
||||
} d_un;
|
||||
} Elf64_Dyn;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
unsigned short st_shndx;
|
||||
unsigned long st_value;
|
||||
unsigned long st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned long r_offset;
|
||||
unsigned long r_info;
|
||||
long r_addend;
|
||||
} Elf64_Rela;
|
||||
|
||||
|
||||
typedef struct rtld_lib {
|
||||
int handle;
|
||||
struct rtld_lib* next;
|
||||
} rtld_lib_t;
|
||||
|
||||
|
||||
/**
|
||||
* dependencies provided by the ELF linker.
|
||||
**/
|
||||
extern unsigned char __text_start[] __attribute__((weak));
|
||||
extern unsigned char __text_end[] __attribute__((weak));
|
||||
|
||||
extern Elf64_Dyn _DYNAMIC[];
|
||||
|
||||
|
||||
/**
|
||||
* global private variables.
|
||||
**/
|
||||
static rtld_lib_t* libhead = 0;
|
||||
static Elf64_Sym* symtab = 0;
|
||||
static char* strtab = 0;
|
||||
static unsigned long base_addr = 0;
|
||||
|
||||
|
||||
/**
|
||||
* external dependencies.
|
||||
**/
|
||||
static void* (*malloc)(unsigned long) = 0;
|
||||
static void (*free)(void*) = 0;
|
||||
static char* (*strcat)(char*, const char*);
|
||||
static int (*strcmp)(const char*, const char*) = 0;
|
||||
static int (*strlen)(const char*) = 0;
|
||||
static int (*printf)(const char*, ...) = 0;
|
||||
static int (*sprintf)(char*, const char*, ...) = 0;
|
||||
static int (*sceKernelLoadStartModule)(const char*, unsigned long, const void*,
|
||||
unsigned int, void*, int*);
|
||||
static int (*sceKernelStopUnloadModule)(int, unsigned long, const void*, unsigned int,
|
||||
const void*, void*);
|
||||
|
||||
static const char*
|
||||
LD_LIBRARY_PATH[] = {
|
||||
"/system/priv_ex/lib",
|
||||
"/system/common_ex/lib",
|
||||
"/system/priv/lib",
|
||||
"/system/common/lib"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static rtld_lib_t*
|
||||
rtld_open(const char* basename) {
|
||||
rtld_lib_t *lib = 0;
|
||||
char filename[255];
|
||||
int handle = 0;
|
||||
|
||||
if(!strcmp(basename, "libkernel.so") ||
|
||||
!strcmp(basename, "libkernel_web.so") ||
|
||||
!strcmp(basename, "libkernel_sys.so")) {
|
||||
lib = malloc(sizeof(rtld_lib_t));
|
||||
lib->handle = 0x2001;
|
||||
lib->next = 0;
|
||||
return lib;
|
||||
}
|
||||
|
||||
if(!strcmp(basename, "libSceLibcInternal.so")) {
|
||||
lib = malloc(sizeof(rtld_lib_t));
|
||||
lib->handle = 0x2;
|
||||
lib->next = 0;
|
||||
return lib;
|
||||
}
|
||||
|
||||
for(int i=0; i<sizeof(LD_LIBRARY_PATH)/sizeof(LD_LIBRARY_PATH[0]); i++) {
|
||||
sprintf(filename, "%s/%s", LD_LIBRARY_PATH[i], basename);
|
||||
filename[strlen(filename)-2] = 0;
|
||||
strcat(filename, "sprx");
|
||||
if(syscall(SYS_access, filename, 0) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if((handle=sceKernelLoadStartModule(filename, 0, 0, 0, 0, 0)) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(handle <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lib = malloc(sizeof(rtld_lib_t));
|
||||
lib->handle = handle;
|
||||
lib->next = 0;
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static unsigned long
|
||||
rtld_sym(rtld_lib_t* lib, const char* name) {
|
||||
unsigned long addr = 0;
|
||||
|
||||
syscall(SYS_sprx_dlsym, lib->handle, name, &addr);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rtld_close(rtld_lib_t* lib) {
|
||||
int handle = lib->handle;
|
||||
|
||||
free(lib);
|
||||
|
||||
return sceKernelStopUnloadModule(handle, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dt_needed(const char* basename) {
|
||||
rtld_lib_t* lib;
|
||||
|
||||
if((lib=rtld_open(basename))) {
|
||||
lib->next = libhead;
|
||||
libhead = lib;
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Unable to find %s\n", basename);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
r_glob_dat(Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = symtab + ELF64_R_SYM(rela->r_info);
|
||||
unsigned long loc = base_addr + rela->r_offset;
|
||||
const char* name = strtab + sym->st_name;
|
||||
int pid = syscall(SYS_getpid);
|
||||
unsigned long val = 0;
|
||||
|
||||
for(rtld_lib_t *lib=libhead; lib!=0; lib=lib->next) {
|
||||
if((val=rtld_sym(lib, name))) {
|
||||
return mdbg_copyin(pid, &val, loc, sizeof(val));
|
||||
}
|
||||
}
|
||||
|
||||
printf("Unable to resolve %s\n", name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
r_jmp_slot(Elf64_Rela* rela) {
|
||||
Elf64_Sym* sym = symtab + ELF64_R_SYM(rela->r_info);
|
||||
unsigned long loc = base_addr + rela->r_offset;
|
||||
const char* name = strtab + sym->st_name;
|
||||
int pid = syscall(SYS_getpid);
|
||||
unsigned long val = 0;
|
||||
|
||||
for(rtld_lib_t *lib=libhead; lib!=0; lib=lib->next) {
|
||||
if((val=rtld_sym(lib, name))) {
|
||||
return mdbg_copyin(pid, &val, loc, sizeof(val));
|
||||
}
|
||||
}
|
||||
|
||||
printf("Unable to resolve %s\n", name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
rtld_load(void) {
|
||||
Elf64_Rela* rela = 0;
|
||||
long relasz = 0;
|
||||
|
||||
// find lookup tables
|
||||
for(int i=0; _DYNAMIC[i].d_tag!=DT_NULL; i++) {
|
||||
switch(_DYNAMIC[i].d_tag) {
|
||||
case DT_SYMTAB:
|
||||
symtab = (Elf64_Sym*)(__text_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_STRTAB:
|
||||
strtab = (char*)(__text_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELA:
|
||||
rela = (Elf64_Rela*)(__text_start + _DYNAMIC[i].d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELASZ:
|
||||
relasz = _DYNAMIC[i].d_un.d_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// load needed libraries
|
||||
for(int i=0; _DYNAMIC[i].d_tag!=DT_NULL; i++) {
|
||||
switch(_DYNAMIC[i].d_tag) {
|
||||
case DT_NEEDED:
|
||||
if(dt_needed(strtab + _DYNAMIC[i].d_un.d_val)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply relocations.
|
||||
for(int i=0; i<relasz/sizeof(Elf64_Rela); i++) {
|
||||
switch(rela[i].r_info & 0xffffffffl) {
|
||||
case R_X86_64_JMP_SLOT:
|
||||
if(r_jmp_slot(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_GLOB_DAT:
|
||||
if(r_glob_dat(&rela[i])) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((constructor(104))) static void
|
||||
rtld_constructor(const payload_args_t *args) {
|
||||
int pid = syscall(SYS_getpid);
|
||||
unsigned long rootdir = 0;
|
||||
int error = 0;
|
||||
|
||||
if(!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "malloc", &malloc))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "free", &free))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "strcat", &strcat))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "strcmp", &strcmp))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "strlen", &strlen))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "printf", &printf))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2, "sprintf", &sprintf))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "sceKernelLoadStartModule",
|
||||
&sceKernelLoadStartModule))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
if((error=args->sceKernelDlsym(0x2001, "sceKernelStopUnloadModule",
|
||||
&sceKernelStopUnloadModule))) {
|
||||
*args->payloadout = error;
|
||||
return;
|
||||
}
|
||||
|
||||
base_addr = (long)__text_start;
|
||||
rootdir = kernel_get_proc_rootdir(pid);
|
||||
kernel_set_proc_rootdir(pid, kernel_get_root_vnode());
|
||||
*args->payloadout = rtld_load();
|
||||
kernel_set_proc_rootdir(pid, rootdir);
|
||||
}
|
||||
|
||||
|
||||
__attribute__((destructor(104))) static void
|
||||
rtld_destructor(const payload_args_t *args) {
|
||||
while(libhead) {
|
||||
rtld_lib_t *next = libhead->next;
|
||||
if(rtld_close(libhead)) {
|
||||
*args->payloadout = -1;
|
||||
}
|
||||
libhead = next;
|
||||
}
|
||||
}
|
||||
-181
@@ -1,181 +0,0 @@
|
||||
/* Copyright (C) 2023 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 "payload.h"
|
||||
|
||||
|
||||
/**
|
||||
* External dependencies.
|
||||
**/
|
||||
static int (*sceKernelDlsym)(int, const char*, void*) = 0;
|
||||
static int (*sceKernelStopUnloadModule)(int, unsigned long, const void*,
|
||||
unsigned int, const void*, void*) = 0;
|
||||
static int (*sceKernelLoadStartModule)(const char*, unsigned long,
|
||||
const void*, unsigned int,
|
||||
void*, int*) = 0;
|
||||
static const char* (*sceKernelGetFsSandboxRandomWord)(void) = 0;
|
||||
static int (*snprintf)(char *, unsigned long, const char *, ...) = 0;
|
||||
static int (*access)(const char*, int) = 0;
|
||||
static int (*getpid)(void) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* See include_ps5/kernel.h
|
||||
**/
|
||||
unsigned long kernel_dynlib_resolve(unsigned int pid, unsigned int handle,
|
||||
const char *nid);
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of errors.
|
||||
**/
|
||||
static int *sprx_error = 0;
|
||||
|
||||
|
||||
/**
|
||||
* process id used to resolve symbols.
|
||||
**/
|
||||
static unsigned int pid = -1;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
__attribute__((constructor(103))) static void
|
||||
sprx_constructor(const payload_args_t *args) {
|
||||
int error;
|
||||
|
||||
sceKernelDlsym = args->sceKernelDlsym;
|
||||
sprx_error = args->payloadout;
|
||||
|
||||
if((error=sceKernelDlsym(0x2001, "sceKernelStopUnloadModule",
|
||||
&sceKernelStopUnloadModule))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
if((error=sceKernelDlsym(0x2001, "sceKernelLoadStartModule",
|
||||
&sceKernelLoadStartModule))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
if((error=sceKernelDlsym(0x2001, "sceKernelGetFsSandboxRandomWord",
|
||||
&sceKernelGetFsSandboxRandomWord))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
if((error=sceKernelDlsym(0x2001, "getpid", &getpid))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
if((error=sceKernelDlsym(0x2001, "access", &access))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
if((error=sceKernelDlsym(0x2, "snprintf", &snprintf))) {
|
||||
*sprx_error = error;
|
||||
return;
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve the address of symbol from a module.
|
||||
**/
|
||||
int
|
||||
sprx_dlsym(unsigned int handle, const char *nid, void **ptr) {
|
||||
unsigned long addr;
|
||||
int error = -1;
|
||||
|
||||
if((addr=kernel_dynlib_resolve(pid, handle, nid))) {
|
||||
*ptr = (void*)addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sprx_error = error;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open a module with a given libname.
|
||||
**/
|
||||
int
|
||||
sprx_dlopen(const char* libname, unsigned int *handle) {
|
||||
const char *sandbox_path = sceKernelGetFsSandboxRandomWord();
|
||||
char path[0x100];
|
||||
|
||||
if(sandbox_path) {
|
||||
snprintf(path, sizeof(path), "/%s/priv_ex/lib/%s.sprx", sandbox_path, libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path),"/%s/common_ex/lib/%s.sprx", sandbox_path, libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), "/%s/priv/lib/%s.sprx", sandbox_path, libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
snprintf(path, sizeof(path), "/%s/common/lib/%s.sprx", sandbox_path, libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path),"/system_ex/priv_ex/lib/%s.sprx", libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path),"/system_ex/common_ex/lib/%s.sprx", libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path),"/system/priv/lib/%s.sprx", libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, 0)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path),"/system/common/lib/%s.sprx", libname);
|
||||
if(!access(path, 0) && (*handle=sceKernelLoadStartModule(path, 0, 0, 0, 0, sprx_error)) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close a module with a give handle.
|
||||
**/
|
||||
int
|
||||
sprx_dlclose(unsigned int handle) {
|
||||
int error = 0;
|
||||
|
||||
if((error=sceKernelStopUnloadModule(handle, 0, 0, 0, 0, 0))) {
|
||||
*sprx_error = error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
+11
-6
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -18,8 +18,6 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
|
||||
static __attribute__ ((used)) long ptr_syscall;
|
||||
|
||||
|
||||
asm(".intel_syntax noprefix\n"
|
||||
".global syscall\n"
|
||||
".type syscall @function\n"
|
||||
@@ -37,7 +35,14 @@ asm(".intel_syntax noprefix\n"
|
||||
|
||||
|
||||
__attribute__((constructor(101))) static void
|
||||
constructor(const payload_args_t *args) {
|
||||
*args->payloadout = args->sceKernelDlsym(0x2001, "getpid", &ptr_syscall);
|
||||
ptr_syscall += 0xa; // jump directly to syscall instruction
|
||||
syscall_constructor(const payload_args_t *args) {
|
||||
if(!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(args->sceKernelDlsym(0x2001, "getpid", &ptr_syscall)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptr_syscall += 0xa;
|
||||
}
|
||||
+15
-2
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -14,5 +14,18 @@ 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/>. */
|
||||
|
||||
long syscall(int sysno, ...);
|
||||
#pragma once
|
||||
|
||||
#define SYS_read 3
|
||||
#define SYS_write 4
|
||||
#define SYS_getpid 20
|
||||
#define SYS_access 33
|
||||
#define SYS_setsockopt 105
|
||||
#define SYS_sysctl 202
|
||||
#define SYS_mdbg_call 573
|
||||
#define SYS_sprx_dlsym 591
|
||||
#define SYS_sprx_load 594
|
||||
#define SYS_sprx_unload 595
|
||||
|
||||
|
||||
long syscall(long sysno, ...);
|
||||
+31
-17
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 John Törnblom
|
||||
/* 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
|
||||
@@ -19,32 +19,46 @@ OUTPUT_ARCH(i386:x86-64)
|
||||
ENTRY(_start)
|
||||
|
||||
PHDRS {
|
||||
ph_text PT_LOAD FLAGS (0x1 | 0x4);
|
||||
ph_text PT_LOAD FLAGS (0x5);
|
||||
ph_rodata PT_LOAD FLAGS (0x4);
|
||||
ph_data PT_LOAD FLAGS (0x2 | 0x4);
|
||||
ph_data PT_LOAD FLAGS (0x6);
|
||||
ph_dyn PT_DYNAMIC;
|
||||
}
|
||||
|
||||
SECTIONS {
|
||||
.text : { *(.text .text.*) } : ph_text
|
||||
. = ALIGN(0x4000);
|
||||
.rodata : { *(.rodata .rodata.*) } : ph_rodata
|
||||
. = ALIGN(0x4000);
|
||||
.data : { *(.data .data.*) } : ph_data
|
||||
.bss : {
|
||||
PROVIDE_HIDDEN(__bss_start = .);
|
||||
*(.bss .bss.*) *(COMMON)
|
||||
PROVIDE_HIDDEN(__bss_end = .);
|
||||
}
|
||||
.init_array : {
|
||||
.text : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
PROVIDE_HIDDEN (__text_start = .);
|
||||
*(.text .text.*)
|
||||
PROVIDE_HIDDEN (__text_end = .);
|
||||
} : ph_text
|
||||
|
||||
.rodata : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
*(.rodata .rodata.*)
|
||||
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP(*(.init_array .ctors))
|
||||
PROVIDE_HIDDEN(__init_array_end = .);
|
||||
}
|
||||
.fini_array : {
|
||||
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array .dtors))
|
||||
PROVIDE_HIDDEN(__fini_array_end = .);
|
||||
}
|
||||
} : ph_rodata
|
||||
|
||||
.data : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
*(.data .data.*)
|
||||
} : ph_data
|
||||
|
||||
.dynamic : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
PROVIDE_HIDDEN (_DYNAMIC = .);
|
||||
*(.dynamic)
|
||||
} : ph_data : ph_dyn
|
||||
|
||||
.bss (NOLOAD) : ALIGN(CONSTANT(MAXPAGESIZE)) {
|
||||
PROVIDE_HIDDEN (__bss_start = .);
|
||||
*(.bss .bss.*);
|
||||
*(COMMON)
|
||||
PROVIDE_HIDDEN (__bss_end = .);
|
||||
} : ph_data
|
||||
}
|
||||
@@ -32,7 +32,7 @@ for CC in "${CANDIDATES[@]}"; do
|
||||
exec $CC \
|
||||
-target $PS5_TARGET_TRIPLE \
|
||||
-isystem ${PS5_PAYLOAD_SDK}/usr/include \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-protector -fno-plt \
|
||||
$*
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -32,7 +32,7 @@ for CXX in "${CANDIDATES[@]}"; do
|
||||
exec $CXX \
|
||||
-target $PS5_TARGET_TRIPLE \
|
||||
-isystem ${PS5_PAYLOAD_SDK}/usr/include \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-protector -fno-plt \
|
||||
$*
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -21,12 +21,15 @@ PS5_PAYLOAD_SDK="${PS5_PAYLOAD_SDK}/.."
|
||||
|
||||
CANDIDATES=("ld.lld-17"
|
||||
"ld.lld-16"
|
||||
"ld.lld-15")
|
||||
"ld.lld-15"
|
||||
"gold"
|
||||
"ld")
|
||||
|
||||
for LD in "${CANDIDATES[@]}"; do
|
||||
if [ -x "$(command -v $LD)" ]; then
|
||||
exec $LD \
|
||||
-pie --whole-archive \
|
||||
-pie \
|
||||
-z max-page-size=0x4000 \
|
||||
-T "${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x" \
|
||||
-L "${PS5_PAYLOAD_SDK}/usr/lib" \
|
||||
$* \
|
||||
|
||||
@@ -56,9 +56,14 @@ int32_t kernel_copyout(const intptr_t kaddr, void *udaddr, size_t len);
|
||||
intptr_t kernel_get_proc(pid_t pid);
|
||||
intptr_t kernel_get_proc_ucred(pid_t pid);
|
||||
intptr_t kernel_get_proc_filedesc(pid_t pid);
|
||||
intptr_t kernel_get_proc_file(pid_t pid, int fd);
|
||||
|
||||
int kernel_overlap_sockets(pid_t pid, int master_sock, int victim_sock);
|
||||
|
||||
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);
|
||||
intptr_t kernel_dynlib_fini_addr(pid_t pid, uint32_t handle);
|
||||
|
||||
uint64_t kernel_get_ucred_authid(pid_t pid);
|
||||
int32_t kernel_set_ucred_authid(pid_t pid, uint64_t authid);
|
||||
@@ -87,5 +92,4 @@ int32_t kernel_set_ucred_svuid(pid_t pid, uid_t svuid);
|
||||
int32_t kernel_set_ucred_rgid(pid_t pid, gid_t rgid);
|
||||
int32_t kernel_set_ucred_svgid(pid_t pid, gid_t svgid);
|
||||
|
||||
|
||||
#endif // PS5SDK_KERNEL_H
|
||||
@@ -1,24 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
#ifndef PS5SDK_SPRX_H
|
||||
#define PS5SDK_SPRX_H
|
||||
|
||||
int sprx_dlopen(const char* libname, unsigned short *handle);
|
||||
int sprx_dlsym(unsigned short handle, const char *symname, void *addr);
|
||||
int sprx_dlclose(unsigned short handle);
|
||||
|
||||
#endif // PS5SDK_SPRX_H
|
||||
@@ -1,5 +0,0 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
payload_elf.c
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# Copyright (C) 2023 John Törnblom
|
||||
#
|
||||
# This file 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 of the License, 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/>.
|
||||
|
||||
ifndef PS5_PAYLOAD_SDK
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9021
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
|
||||
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
|
||||
|
||||
CFLAGS := -O2
|
||||
LDADD := -lkernel_sys -lSceLibcInternal
|
||||
|
||||
# Build the payload for a bare-metal runtime environment
|
||||
CC_BM := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-baremetal-cc
|
||||
LD_BM := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-baremetal-ld
|
||||
|
||||
|
||||
all: loader.elf
|
||||
|
||||
loader.elf: elfldr.o main.o
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
elfldr.o: elfldr.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
main.o: main.c payload_elf.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
payload_elf.c: payload.elf
|
||||
xxd -i $< > $@
|
||||
|
||||
payload.elf: payload.o
|
||||
$(LD_BM) $< -o $@
|
||||
|
||||
payload.o: payload.c
|
||||
$(CC_BM) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf payload_elf.c
|
||||
|
||||
test: loader.elf
|
||||
nc -q0 $(PS5_HOST) $(PS5_PORT) < $^
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/user.h>
|
||||
#include <elf.h>
|
||||
|
||||
|
||||
/**
|
||||
* Allignment macros used to map virtual memory.
|
||||
**/
|
||||
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
|
||||
#define TRUNC_PG(x) ((x) & ~(PAGE_SIZE - 1))
|
||||
|
||||
|
||||
/**
|
||||
* Map ELF protection flags to mmap() protection flags
|
||||
**/
|
||||
#define PFLAGS(x) ((((x) & PF_R) ? PROT_READ : 0) | \
|
||||
(((x) & PF_W) ? PROT_WRITE : 0) | \
|
||||
(((x) & PF_X) ? PROT_EXEC : 0))
|
||||
|
||||
|
||||
/**
|
||||
* External dependencies to libkernel.
|
||||
**/
|
||||
int sceKernelJitCreateSharedMemory(const char*, size_t, int, int*);
|
||||
int sceKernelJitCreateAliasOfSharedMemory(int, int, int*);
|
||||
int sceKernelDlsym(int, const char*, void*);
|
||||
|
||||
|
||||
/**
|
||||
* Load an ELF into memory, and jump to its entry point.
|
||||
**/
|
||||
int
|
||||
elfldr_exec(uint8_t *elf, size_t size) {
|
||||
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
|
||||
Elf64_Phdr *phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr*)(elf + ehdr->e_shoff);
|
||||
|
||||
void *base_addr = MAP_FAILED;
|
||||
size_t base_size = 0;
|
||||
|
||||
size_t min_vaddr = SIZE_MAX;
|
||||
size_t max_vaddr = 0;
|
||||
|
||||
int error = 0;
|
||||
|
||||
// Sanity check, we only support 64bit ELFs.
|
||||
if(ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
|
||||
ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Compute size of virtual memory region.
|
||||
for(int i=0; i<ehdr->e_phnum; i++) {
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(phdr[i].p_vaddr < min_vaddr) {
|
||||
min_vaddr = phdr[i].p_vaddr;
|
||||
}
|
||||
|
||||
if(max_vaddr < phdr[i].p_vaddr + phdr[i].p_memsz) {
|
||||
max_vaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
min_vaddr = TRUNC_PG(min_vaddr);
|
||||
max_vaddr = ROUND_PG(max_vaddr);
|
||||
base_size = max_vaddr - min_vaddr;
|
||||
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
if(ehdr->e_type == ET_DYN) {
|
||||
base_addr = 0;
|
||||
} else if(ehdr->e_type == ET_EXEC) {
|
||||
base_addr = (void*)min_vaddr;
|
||||
flags |= MAP_FIXED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Reserve an address space of sufficient size.
|
||||
if((base_addr=mmap(base_addr, base_size, PROT_NONE,
|
||||
flags, -1, 0)) == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Commit segments to reserved address space.
|
||||
for(int i=0; i<ehdr->e_phnum; i++) {
|
||||
size_t aligned_memsz = ROUND_PG(phdr[i].p_memsz);
|
||||
void *addr = base_addr + phdr[i].p_vaddr;
|
||||
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(phdr[i].p_flags & PF_X) {
|
||||
int alias_fd = -1;
|
||||
int shm_fd = -1;
|
||||
|
||||
// Create shm with executable permissions.
|
||||
if(sceKernelJitCreateSharedMemory(0, aligned_memsz,
|
||||
PROT_WRITE | PFLAGS(phdr[i].p_flags),
|
||||
&shm_fd)) {
|
||||
perror("sceKernelJitCreateSharedMemory");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Map shm into an executable address space.
|
||||
if((addr=mmap(addr, aligned_memsz, PFLAGS(phdr[i].p_flags),
|
||||
MAP_FIXED | MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create an shm alias fd with write permissions.
|
||||
if(sceKernelJitCreateAliasOfSharedMemory(shm_fd, PROT_WRITE,
|
||||
&alias_fd) != 0) {
|
||||
perror("sceKernelJitCreateAliasOfSharedMemory");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Map shm alias into a writable address space.
|
||||
if((addr=mmap(0, aligned_memsz, PROT_WRITE, MAP_SHARED,
|
||||
alias_fd, 0)) == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Copy segment data.
|
||||
memcpy(addr, elf + phdr[i].p_offset, phdr[i].p_memsz);
|
||||
|
||||
// Cleanup resources.
|
||||
munmap(addr, aligned_memsz);
|
||||
close(alias_fd);
|
||||
close(shm_fd);
|
||||
|
||||
} else {
|
||||
// Map segment into a writable address space.
|
||||
if((addr=mmap(addr, aligned_memsz, PROT_WRITE,
|
||||
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0)) == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Copy segment data.
|
||||
memcpy(addr, elf + phdr[i].p_offset, phdr[i].p_memsz);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate positional independent symbols.
|
||||
for(int i=0; i<ehdr->e_shnum && !error; i++) {
|
||||
if(shdr[i].sh_type != SHT_RELA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Elf64_Rela* rela = (Elf64_Rela*)(elf + shdr[i].sh_offset);
|
||||
|
||||
for(int j=0; j<shdr[i].sh_size/sizeof(Elf64_Rela); j++) {
|
||||
if(ELF64_R_TYPE(rela[j].r_info) == R_X86_64_RELATIVE) {
|
||||
Elf64_Addr* value_addr = (base_addr + rela[j].r_offset);
|
||||
*value_addr = (Elf64_Addr)base_addr + rela[j].r_addend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set protection bits on mapped segments.
|
||||
for(int i=0; i<ehdr->e_phnum && !error; i++) {
|
||||
size_t aligned_memsz = ROUND_PG(phdr[i].p_memsz);
|
||||
void *addr = base_addr + phdr[i].p_vaddr;
|
||||
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(mprotect(addr, aligned_memsz, PFLAGS(phdr[i].p_flags))) {
|
||||
perror("mprotect");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Jump to entry point if ELF was loaded into memory correctly.
|
||||
if(!error) {
|
||||
void (*_start)(void*) = base_addr + ehdr->e_entry;
|
||||
_start(&sceKernelDlsym);
|
||||
}
|
||||
|
||||
munmap(base_addr, base_size);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
int elfldr_exec(unsigned char *elf, unsigned int size);
|
||||
@@ -1,29 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
/**
|
||||
* Assume argument to _start() is a function pointer to sceKernelDlsym,
|
||||
* load puts() from libSceLibcInternal, and print "Hello world!" to stdout.
|
||||
**/
|
||||
void
|
||||
_start(void* args) {
|
||||
int (*sceKernelDlsym)(int, const char*, void*) = (void*)args;
|
||||
void (*puts)(const char*);
|
||||
|
||||
if(!sceKernelDlsym(0x2, "puts", &puts)) {
|
||||
puts("Hello, world!");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
*.elf
|
||||
*.o
|
||||
*.bin
|
||||
*~
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright (C) 2023 John Törnblom
|
||||
#
|
||||
# This file 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 of the License, 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/>.
|
||||
|
||||
ifndef PS5_PAYLOAD_SDK
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9021
|
||||
|
||||
ELF := kernel_data_dump.elf
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
|
||||
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
|
||||
|
||||
CFLAGS := -O2
|
||||
LDADD := -lkernel -lSceLibcInternal
|
||||
|
||||
all: $(ELF)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
$(ELF): main.o
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o $(ELF)
|
||||
|
||||
test: $(ELF)
|
||||
@nc -q0 $(PS5_HOST) $(PS5_PORT) < $^ > kernel-data.bin
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
|
||||
#ifndef PHYS_PAGE_SIZE
|
||||
#define PHYS_PAGE_SIZE 0x1000
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NB_PAGES
|
||||
#define NB_PAGES 0x40000
|
||||
#endif
|
||||
|
||||
|
||||
int main() {
|
||||
uint8_t buf[PHYS_PAGE_SIZE];
|
||||
|
||||
for(int i=0; i<NB_PAGES; i++) {
|
||||
off_t offset = sizeof(buf) * i;
|
||||
if(kernel_copyout(KERNEL_ADDRESS_DATA_BASE + offset, buf, sizeof(buf))) {
|
||||
perror("kernel_copyout");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf)) {
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright (C) 2023 John Törnblom
|
||||
#
|
||||
# This file 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 of the License, 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/>.
|
||||
|
||||
ifndef PS5_PAYLOAD_SDK
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9021
|
||||
|
||||
ELF := pipe_pirate.elf
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
|
||||
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
|
||||
|
||||
CFLAGS := -O2
|
||||
LDADD := -lkernel_web -lSceLibcInternal
|
||||
|
||||
all: $(ELF)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
$(ELF): main.o
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o $(ELF)
|
||||
|
||||
test: $(ELF)
|
||||
nc -q0 $(PS5_HOST) $(PS5_PORT) < $^
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
|
||||
/**
|
||||
* Set uid of the running process to 0x1337.
|
||||
**/
|
||||
int main(void) {
|
||||
uint64_t ucred = kernel_get_proc_ucred(getpid());
|
||||
uint32_t uid = 0x1337;
|
||||
|
||||
printf("[+] UID = 0x%x\n", getuid());
|
||||
|
||||
kernel_copyin(&uid, ucred + KERNEL_OFFSET_UCRED_CR_UID, sizeof(uid));
|
||||
kernel_copyin(&uid, ucred + KERNEL_OFFSET_UCRED_CR_RUID, sizeof(uid));
|
||||
kernel_copyin(&uid, ucred + KERNEL_OFFSET_UCRED_CR_SVUID, sizeof(uid));
|
||||
kernel_copyin(&uid, ucred + KERNEL_OFFSET_UCRED_CR_RGID, sizeof(uid));
|
||||
|
||||
printf("[+] UID = 0x%x\n", getuid());
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Copyright (C) 2023 John Törnblom
|
||||
#
|
||||
# This file 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 of the License, 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/>.
|
||||
|
||||
ifndef PS5_PAYLOAD_SDK
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9021
|
||||
|
||||
ELF := procpatch.elf
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
|
||||
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
|
||||
|
||||
CFLAGS := -O2
|
||||
LDADD := -lSceLibcInternal -lkernel_web
|
||||
|
||||
all: $(ELF)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
$(ELF): pt.o mdbg.o patch.o main.o
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o $(ELF)
|
||||
|
||||
test: $(ELF)
|
||||
nc -q0 $(PS5_HOST) $(PS5_PORT) < $^
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/event.h>
|
||||
|
||||
#include "patch.h"
|
||||
#include "pt.h"
|
||||
|
||||
|
||||
#define TEST_RUN_ONCE 1
|
||||
|
||||
|
||||
typedef struct app_info {
|
||||
uint32_t app_id;
|
||||
uint64_t unknown1;
|
||||
char title_id[10];
|
||||
char unknown2[0x40];
|
||||
} app_info_t;
|
||||
|
||||
|
||||
int sceKernelGetAppInfo(pid_t pid, app_info_t *info);
|
||||
|
||||
|
||||
static pid_t
|
||||
await_child(void) {
|
||||
struct kevent evt;
|
||||
pid_t pid = -1;
|
||||
int kq;
|
||||
|
||||
if((kq=kqueue()) < 0) {
|
||||
perror("kqueue");
|
||||
return -1;
|
||||
}
|
||||
|
||||
EV_SET(&evt, getppid(), EVFILT_PROC, EV_ADD, NOTE_FORK | NOTE_TRACK, 0, NULL);
|
||||
if(kevent(kq, &evt, 1, NULL, 0, NULL) < 0) {
|
||||
perror("kevent");
|
||||
close(kq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(kevent(kq, NULL, 0, &evt, 1, NULL) < 0) {
|
||||
perror("kevent");
|
||||
break;
|
||||
}
|
||||
|
||||
if(evt.fflags & NOTE_CHILD) {
|
||||
pid = evt.ident;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close(kq);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
app_info_t info;
|
||||
pid_t child;
|
||||
|
||||
while(1) {
|
||||
if((child=await_child()) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(pt_attach(child) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
if(!sceKernelGetAppInfo(child, &info)) {
|
||||
patch_app(child, info.app_id, info.title_id);
|
||||
} else {
|
||||
perror("sceKernelGetAppInfo");
|
||||
}
|
||||
|
||||
if(pt_detach(child) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef TEST_RUN_ONCE
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include "mdbg.h"
|
||||
#include "patch.h"
|
||||
#include "pt.h"
|
||||
|
||||
|
||||
int
|
||||
patch_app(pid_t pid, uint32_t app_id, const char* title_id) {
|
||||
struct ptrace_vm_entry ve;
|
||||
uint8_t *buf;
|
||||
size_t len;
|
||||
|
||||
printf("New application launched:\n"
|
||||
"------------------------\n"
|
||||
" title_id = %s\n"
|
||||
" app_id = 0x%x\n"
|
||||
" pid = %d\n",
|
||||
title_id, app_id, pid);
|
||||
|
||||
// TODO: something useful. For now, just sanity test mdbg
|
||||
memset(&ve, 0, sizeof(ve));
|
||||
if(pt_vm_entry(pid, &ve)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ve.pve_end - ve.pve_start;
|
||||
if(!(buf=malloc(len))){
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf(" pid %d vm entry 0 starts at: 0x%lx\n", pid, ve.pve_start);
|
||||
|
||||
if(mdbg_copyout(pid, ve.pve_start, buf, len)) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(mdbg_copyin(pid, buf, ve.pve_start, len)) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
int patch_app(pid_t pid, uint32_t app_id, const char* title_id);
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
#include "pt.h"
|
||||
|
||||
|
||||
static int
|
||||
sys_ptrace(int request, pid_t pid, caddr_t addr, int data) {
|
||||
pid_t mypid = getpid();
|
||||
uint64_t authid;
|
||||
long ret;
|
||||
|
||||
if(!(authid=kernel_get_ucred_authid(mypid))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_set_ucred_authid(mypid, 0x4800000000010003l)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = syscall(SYS_ptrace, request, pid, addr, data);
|
||||
|
||||
if(kernel_set_ucred_authid(mypid, authid)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_attach(pid_t pid) {
|
||||
if(sys_ptrace(PT_ATTACH, pid, NULL, 0) == -1) {
|
||||
perror("PT_ATTACH");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(waitpid(pid, NULL, 0) == -1) {
|
||||
perror("waitpid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_detach(pid_t pid) {
|
||||
if(sys_ptrace(PT_DETACH, pid, NULL, 0) == -1) {
|
||||
perror("PT_DETACH");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_vm_entry(pid_t pid, struct ptrace_vm_entry *ve) {
|
||||
if(sys_ptrace(PT_VM_ENTRY, pid, (caddr_t)ve, 0) == -1) {
|
||||
perror("PT_VM_ENTRY");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
elfldr-socksever_elf.c
|
||||
@@ -1,56 +0,0 @@
|
||||
# Copyright (C) 2023 John Törnblom
|
||||
#
|
||||
# This file 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 of the License, 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/>.
|
||||
|
||||
ifndef PS5_PAYLOAD_SDK
|
||||
$(error PS5_PAYLOAD_SDK is undefined)
|
||||
endif
|
||||
|
||||
PS5_HOST ?= ps5
|
||||
PS5_PORT ?= 9020
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
|
||||
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
|
||||
|
||||
CFLAGS := -O2
|
||||
LDADD := -lkernel_web -lSceLibcInternal
|
||||
OBJS := elfldr.o ptrace.o dynlib.o
|
||||
|
||||
|
||||
all: elfldr-bootstrap.elf
|
||||
|
||||
elfldr-bootstrap.elf: main-bootstrap.o $(OBJS)
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
elfldr-socksever.elf: main-socksever.o $(OBJS)
|
||||
$(LD) $^ $(LDADD) -o $@
|
||||
|
||||
main-bootstrap.o: main.c elfldr-socksever_elf.c
|
||||
$(CC) -DELFLDR_BOOTSRTAP -c $(CFLAGS) -o $@ $<
|
||||
|
||||
main-socksever.o: main.c
|
||||
$(CC) -DSOCKET_PORT=9021 -c $(CFLAGS) -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
elfldr-socksever_elf.c: elfldr-socksever.elf
|
||||
xxd -i $< > $@
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf elfldr-socksever_elf.c
|
||||
|
||||
test: elfldr-bootstrap.elf
|
||||
nc -q0 $(PS5_HOST) $(PS5_PORT) < $^
|
||||
@@ -1,211 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
#include "dynlib.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
typedef struct dynlib_dynsec {
|
||||
struct {
|
||||
intptr_t le_next;
|
||||
intptr_t le_prev;
|
||||
} list_entry;
|
||||
|
||||
intptr_t sysvec;
|
||||
uint32_t refcount;
|
||||
size_t size;
|
||||
|
||||
intptr_t symtab;
|
||||
size_t symtabsize;
|
||||
|
||||
intptr_t strtab;
|
||||
size_t strtabsize;
|
||||
|
||||
intptr_t pltrela;
|
||||
size_t pltrelasize;
|
||||
|
||||
intptr_t rela;
|
||||
size_t relasize;
|
||||
|
||||
intptr_t hash;
|
||||
size_t hashsize;
|
||||
|
||||
intptr_t dynamic;
|
||||
size_t dynamicsize;
|
||||
|
||||
intptr_t sce_comment;
|
||||
size_t sce_commentsize;
|
||||
|
||||
intptr_t sce_dynlib;
|
||||
size_t sce_dynlibsize;
|
||||
|
||||
intptr_t unknown1; // execpath?
|
||||
size_t unknown1size;
|
||||
|
||||
intptr_t buckets;
|
||||
size_t bucketssize;
|
||||
uint32_t nbuckets;
|
||||
|
||||
intptr_t chains;
|
||||
uint64_t chainssize;
|
||||
uint32_t nchains;
|
||||
|
||||
uint64_t unknown2[7];
|
||||
} dynlib_dynsec_t;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
typedef struct dynlib_obj {
|
||||
intptr_t next;
|
||||
intptr_t path;
|
||||
uint64_t unknown0[2];
|
||||
uint32_t refcount;
|
||||
uint64_t handle;
|
||||
|
||||
uint64_t mapbase;
|
||||
size_t mapsize;
|
||||
size_t textsize;
|
||||
|
||||
intptr_t database;
|
||||
size_t datasize;
|
||||
|
||||
intptr_t unknown1;
|
||||
size_t unknown1size;
|
||||
|
||||
uint64_t vaddrbase;
|
||||
uint64_t relocbase;
|
||||
uint64_t entry;
|
||||
|
||||
uint32_t tlsindex;
|
||||
intptr_t tlsinit;
|
||||
size_t tlsinitsize;
|
||||
size_t tlssize;
|
||||
off_t tlsoffset;
|
||||
uint64_t tlsalign;
|
||||
|
||||
intptr_t pltgot;
|
||||
|
||||
uint64_t unknown2[6];
|
||||
|
||||
intptr_t init;
|
||||
intptr_t fini;
|
||||
|
||||
intptr_t eh_frame_hdr;
|
||||
size_t eh_frame_hdr_size;
|
||||
|
||||
intptr_t eh_frame;
|
||||
size_t eh_frame_size;
|
||||
|
||||
int status;
|
||||
int flags;
|
||||
|
||||
uint64_t unknown5[5];
|
||||
intptr_t dynsec;
|
||||
uint64_t unknown6[6]; //fingerprint?
|
||||
} dynlib_obj_t;
|
||||
|
||||
|
||||
intptr_t
|
||||
dynlib_resolve(pid_t pid, uint32_t handle, const char *nid) {
|
||||
intptr_t kproc = kernel_get_proc(pid);
|
||||
dynlib_dynsec_t dynsec;
|
||||
dynlib_obj_t obj;
|
||||
Elf64_Sym *symtab;
|
||||
intptr_t kaddr;
|
||||
intptr_t vaddr;
|
||||
char *strtab;
|
||||
|
||||
if(!(kproc=kernel_get_proc(pid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kproc + 0x3e8, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if(kernel_copyout(kaddr, &kaddr, sizeof(kaddr)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!kaddr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(kaddr + offsetof(dynlib_obj_t, handle),
|
||||
&obj.handle, sizeof(obj.handle)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
} while(obj.handle != handle);
|
||||
|
||||
if(kernel_copyout(kaddr, &obj, sizeof(obj)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(obj.dynsec, &dynsec, sizeof(dynsec)) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(symtab=malloc(dynsec.symtabsize))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(dynsec.symtab, symtab, dynsec.symtabsize) < 0) {
|
||||
free(symtab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(strtab=malloc(dynsec.strtabsize))) {
|
||||
free(symtab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(dynsec.strtab, strtab, dynsec.strtabsize) < 0) {
|
||||
free(symtab);
|
||||
free(strtab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vaddr = 0;
|
||||
for(size_t i=0; i<dynsec.symtabsize / sizeof(Elf64_Sym); i++) {
|
||||
if(!strncmp(nid, strtab + symtab[i].st_name, 11)) {
|
||||
vaddr = obj.mapbase + symtab[i].st_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(symtab);
|
||||
free(strtab);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
|
||||
intptr_t
|
||||
dynlib_resolve_sceKernelDlsym(pid_t pid) {
|
||||
return dynlib_resolve(pid, 0x2001, "LwG8g3niqwA");
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/**
|
||||
* Resolve a symbol with the given *nid* from an sprx with the given *handle*
|
||||
* that is loaded in a process with the given pid.
|
||||
**/
|
||||
intptr_t dynlib_resolve(pid_t pid, uint32_t handle, const char *nid);
|
||||
|
||||
|
||||
/**
|
||||
* Resolve sceKernelDlsym() loaded in a process with the given pid.
|
||||
**/
|
||||
intptr_t dynlib_resolve_sceKernelDlsym(pid_t pid);
|
||||
@@ -1,703 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <elf.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
#include "dynlib.h"
|
||||
#include "ptrace.h"
|
||||
|
||||
|
||||
/**
|
||||
* Allignment macros used to map virtual memory.
|
||||
**/
|
||||
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
|
||||
#define TRUNC_PG(x) ((x) & ~(PAGE_SIZE - 1))
|
||||
|
||||
|
||||
/**
|
||||
* Map ELF protection flags to mmap() protection flags
|
||||
**/
|
||||
#define PFLAGS(x) ((((x) & PF_R) ? PROT_READ : 0) | \
|
||||
(((x) & PF_W) ? PROT_WRITE : 0) | \
|
||||
(((x) & PF_X) ? PROT_EXEC : 0))
|
||||
|
||||
|
||||
/**
|
||||
* IPv6 constants used to obtain kernel RW primitves.
|
||||
**/
|
||||
#ifndef IPV6_2292PKTOPTIONS
|
||||
#define IPV6_2292PKTOPTIONS 25
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Data structure used to send UI notifications.
|
||||
**/
|
||||
typedef struct notify_request {
|
||||
char useless1[45];
|
||||
char message[3075];
|
||||
} notify_request_t;
|
||||
|
||||
|
||||
/**
|
||||
* Send a UI notification request.
|
||||
**/
|
||||
int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int);
|
||||
|
||||
|
||||
/**
|
||||
* Get the kernel address of the given file descriptor.
|
||||
**/
|
||||
static intptr_t
|
||||
kernel_get_file(pid_t pid, int fd) {
|
||||
intptr_t fd_files;
|
||||
intptr_t fde_file;
|
||||
intptr_t file;
|
||||
intptr_t proc;
|
||||
intptr_t p_fd;
|
||||
|
||||
if(!(proc=kernel_get_proc(pid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(proc + offsetof(struct proc, p_fd),
|
||||
&p_fd, sizeof(p_fd))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(p_fd, &fd_files, sizeof(fd_files))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(fd_files + 8 + (0x30 * fd),
|
||||
&fde_file, sizeof(fde_file))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(fde_file, &file, sizeof(file))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increase the kernel refcount of an IPv6 UDP socket.
|
||||
**/
|
||||
static int
|
||||
kernel_inc_so_count(pid_t pid, int fd) {
|
||||
intptr_t file;
|
||||
int so_count;
|
||||
|
||||
if(!(file=kernel_get_file(pid, fd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_copyout(file, &so_count, sizeof(so_count))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
so_count++;
|
||||
so_count = 0x100;
|
||||
if(kernel_copyin(&so_count, file, sizeof(so_count))) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static intptr_t
|
||||
kernel_get_inp6_outputopts(pid_t pid, int fd) {
|
||||
intptr_t inp6_outputopts;
|
||||
intptr_t so_pcb;
|
||||
intptr_t file;
|
||||
|
||||
if(!(file=kernel_get_file(pid, fd))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(file + 0x18, &so_pcb, sizeof(so_pcb))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_copyout(so_pcb + 0x120, &inp6_outputopts,
|
||||
sizeof(inp6_outputopts))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return inp6_outputopts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overlap IPv6 sockets to obtain kernel RW primtives just like the
|
||||
* original PS5 kernel exploit.
|
||||
**/
|
||||
static int
|
||||
kernel_overlap_sockets(pid_t pid, int master_sock, int victim_sock) {
|
||||
intptr_t master_inp6_outputopts;
|
||||
intptr_t victim_inp6_outputopts;
|
||||
intptr_t pktinfo;
|
||||
uint32_t tclass;
|
||||
|
||||
if(kernel_inc_so_count(pid, master_sock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(master_inp6_outputopts=kernel_get_inp6_outputopts(pid, master_sock))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_inc_so_count(pid, victim_sock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(victim_inp6_outputopts=kernel_get_inp6_outputopts(pid, victim_sock))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pktinfo = victim_inp6_outputopts + 0x10;
|
||||
if(kernel_copyin(&pktinfo, master_inp6_outputopts + 0x10,
|
||||
sizeof(pktinfo))) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
tclass = 0x13370000;
|
||||
if(kernel_copyin(&tclass, master_inp6_outputopts + 0xc0, sizeof(tclass))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of a process with the given pid.
|
||||
**/
|
||||
static int
|
||||
get_procname(pid_t pid, char name[COMMLEN+1]) {
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
|
||||
struct kinfo_proc *ki;
|
||||
size_t ki_size = 1096;
|
||||
char buf[ki_size];
|
||||
|
||||
if(sysctl(mib, 4, buf, &ki_size, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ki = (struct kinfo_proc*)buf;
|
||||
strncpy(name, ki->ki_comm, COMMLEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the pid of a process with the given name.
|
||||
**/
|
||||
static pid_t
|
||||
kernel_getpid_byname(const char *name) {
|
||||
char other_name[MAXCOMLEN+1];
|
||||
intptr_t p_comm;
|
||||
intptr_t addr;
|
||||
intptr_t next;
|
||||
pid_t pid;
|
||||
|
||||
if(kernel_copyout(KERNEL_ADDRESS_ALLPROC, &addr, sizeof(addr))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(kernel_copyout(addr + offsetof(struct proc, p_pid),
|
||||
&pid, sizeof(pid))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(get_procname(pid, other_name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!strcmp(name, other_name)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(kernel_copyout(addr, &next, sizeof(next))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(addr=next)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a UI notification.
|
||||
**/
|
||||
static void
|
||||
elfldr_notify(const char *fmt, ...) {
|
||||
notify_request_t req;
|
||||
va_list args;
|
||||
|
||||
bzero(&req, sizeof req);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(req.message, sizeof req.message, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
sceKernelSendNotificationRequest(0, &req, sizeof req, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load an ELF into memory, and jump to its entry point.
|
||||
**/
|
||||
static intptr_t
|
||||
elfldr_load(pid_t pid, uint8_t *elf, size_t size) {
|
||||
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
|
||||
Elf64_Phdr *phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr*)(elf + ehdr->e_shoff);
|
||||
|
||||
intptr_t base_addr = -1;
|
||||
size_t base_size = 0;
|
||||
|
||||
size_t min_vaddr = SIZE_MAX;
|
||||
size_t max_vaddr = 0;
|
||||
|
||||
int error = 0;
|
||||
|
||||
// Sanity check, we only support 64bit ELFs.
|
||||
if(ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
|
||||
ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Compute size of virtual memory region.
|
||||
for(int i=0; i<ehdr->e_phnum; i++) {
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(phdr[i].p_vaddr < min_vaddr) {
|
||||
min_vaddr = phdr[i].p_vaddr;
|
||||
}
|
||||
|
||||
if(max_vaddr < phdr[i].p_vaddr + phdr[i].p_memsz) {
|
||||
max_vaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
|
||||
}
|
||||
}
|
||||
|
||||
min_vaddr = TRUNC_PG(min_vaddr);
|
||||
max_vaddr = ROUND_PG(max_vaddr);
|
||||
base_size = max_vaddr - min_vaddr;
|
||||
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
if(ehdr->e_type == ET_DYN) {
|
||||
base_addr = 0;
|
||||
} else if(ehdr->e_type == ET_EXEC) {
|
||||
base_addr = min_vaddr;
|
||||
flags |= MAP_FIXED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Reserve an address space of sufficient size.
|
||||
if((base_addr=pt_mmap(pid, base_addr, base_size, PROT_NONE,
|
||||
flags, -1, 0)) == -1) {
|
||||
pt_perror(pid, "mmap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Commit segments to reserved address space.
|
||||
for(int i=0; i<ehdr->e_phnum; i++) {
|
||||
size_t aligned_memsz = ROUND_PG(phdr[i].p_memsz);
|
||||
intptr_t addr = base_addr + phdr[i].p_vaddr;
|
||||
int alias_fd = -1;
|
||||
int shm_fd = -1;
|
||||
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(phdr[i].p_flags & PF_X) {
|
||||
if((shm_fd=pt_jitshm_create(pid, 0, aligned_memsz,
|
||||
PROT_WRITE | PFLAGS(phdr[i].p_flags))) < 0) {
|
||||
pt_perror(pid, "jitshm_create");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if((addr=pt_mmap(pid, addr, aligned_memsz, PFLAGS(phdr[i].p_flags),
|
||||
MAP_FIXED | MAP_SHARED, shm_fd, 0)) == -1) {
|
||||
pt_perror(pid, "mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if((alias_fd=pt_jitshm_alias(pid, shm_fd, PROT_WRITE | PROT_READ)) < 0) {
|
||||
pt_perror(pid, "jitshm_alias");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if((addr=pt_mmap(pid, 0, aligned_memsz, PROT_WRITE | PROT_READ, MAP_SHARED,
|
||||
alias_fd, 0)) == -1) {
|
||||
pt_perror(pid, "mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(pt_copyin(pid, elf + phdr[i].p_offset, addr, phdr[i].p_memsz)) {
|
||||
perror("pt_copyin");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
pt_munmap(pid, addr, aligned_memsz);
|
||||
pt_close(pid, alias_fd);
|
||||
pt_close(pid, shm_fd);
|
||||
} else {
|
||||
if((addr=pt_mmap(pid, addr, aligned_memsz, PROT_WRITE,
|
||||
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1, 0)) == -1) {
|
||||
pt_perror(pid, "mmap");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if(pt_copyin(pid, elf + phdr[i].p_offset, addr, phdr[i].p_memsz)) {
|
||||
perror("pt_copyin");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate positional independent symbols.
|
||||
for(int i=0; i<ehdr->e_shnum && !error; i++) {
|
||||
if(shdr[i].sh_type != SHT_RELA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Elf64_Rela* rela = (Elf64_Rela*)(elf + shdr[i].sh_offset);
|
||||
for(int j=0; j<shdr[i].sh_size/sizeof(Elf64_Rela); j++) {
|
||||
if(ELF64_R_TYPE(rela[j].r_info) == R_X86_64_RELATIVE) {
|
||||
intptr_t value_addr = (base_addr + rela[j].r_offset);
|
||||
intptr_t value = base_addr + rela[j].r_addend;
|
||||
if(pt_copyin(pid, &value, value_addr, sizeof(Elf64_Addr))) {
|
||||
perror("pt_copyin");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set protection bits on mapped segments.
|
||||
for(int i=0; i<ehdr->e_phnum && !error; i++) {
|
||||
size_t aligned_memsz = ROUND_PG(phdr[i].p_memsz);
|
||||
intptr_t addr = base_addr + phdr[i].p_vaddr;
|
||||
|
||||
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(pt_mprotect(pid, addr, aligned_memsz, PFLAGS(phdr[i].p_flags))) {
|
||||
pt_perror(pid, "mprotect");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(error) {
|
||||
return -1;
|
||||
} else {
|
||||
return base_addr + ehdr->e_entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create payload args for a process with the given pid.
|
||||
**/
|
||||
static intptr_t
|
||||
elfldr_args(pid_t pid) {
|
||||
int victim_sock;
|
||||
int master_sock;
|
||||
intptr_t buf;
|
||||
int pipe0;
|
||||
int pipe1;
|
||||
|
||||
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
|
||||
pt_perror(pid, "mmap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((master_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
||||
pt_perror(pid, "socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pt_setint(pid, buf+0x00, 20);
|
||||
pt_setint(pid, buf+0x04, IPPROTO_IPV6);
|
||||
pt_setint(pid, buf+0x08, IPV6_TCLASS);
|
||||
pt_setint(pid, buf+0x0c, 0);
|
||||
pt_setint(pid, buf+0x10, 0);
|
||||
pt_setint(pid, buf+0x14, 0);
|
||||
if(pt_setsockopt(pid, master_sock, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, 24)) {
|
||||
pt_perror(pid, "setsockopt");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((victim_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
||||
pt_perror(pid, "socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pt_setint(pid, buf+0x00, 0);
|
||||
pt_setint(pid, buf+0x04, 0);
|
||||
pt_setint(pid, buf+0x08, 0);
|
||||
pt_setint(pid, buf+0x0c, 0);
|
||||
pt_setint(pid, buf+0x10, 0);
|
||||
if(pt_setsockopt(pid, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20)) {
|
||||
pt_perror(pid, "setsockopt");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kernel_overlap_sockets(pid, master_sock, victim_sock)) {
|
||||
perror("overlap");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(pt_pipe(pid, buf)) {
|
||||
pt_perror(pid, "pipe");
|
||||
return 0;
|
||||
}
|
||||
pipe0 = pt_getint(pid, buf);
|
||||
pipe1 = pt_getint(pid, buf+4);
|
||||
|
||||
intptr_t args = buf;
|
||||
intptr_t dlsym = dynlib_resolve_sceKernelDlsym(pid);
|
||||
intptr_t rwpipe = buf + 0x100;
|
||||
intptr_t rwpair = buf + 0x200;
|
||||
intptr_t kpipe_addr = kernel_get_file(pid, pipe0);
|
||||
intptr_t payloadout = buf + 0x300;
|
||||
|
||||
pt_setlong(pid, args + 0x00, dlsym);
|
||||
pt_setlong(pid, args + 0x08, rwpipe);
|
||||
pt_setlong(pid, args + 0x10, rwpair);
|
||||
pt_setlong(pid, args + 0x18, kpipe_addr);
|
||||
pt_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
|
||||
pt_setlong(pid, args + 0x28, payloadout);
|
||||
pt_setint(pid, rwpipe + 0, pipe0);
|
||||
pt_setint(pid, rwpipe + 4, pipe1);
|
||||
pt_setint(pid, rwpair + 0, master_sock);
|
||||
pt_setint(pid, rwpair + 4, victim_sock);
|
||||
pt_setint(pid, payloadout, 0);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
elfldr_exec(const char* procname, uint8_t *elf, size_t size) {
|
||||
uint8_t caps[16];
|
||||
uint8_t buf[16];
|
||||
struct reg r;
|
||||
pid_t pid;
|
||||
|
||||
if((pid=kernel_getpid_byname(procname)) < 0) {
|
||||
printf("%s is not running\n", procname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(kernel_get_ucred_caps(pid, caps)) {
|
||||
perror("kernel_get_ucred_caps");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
if(kernel_set_ucred_caps(pid, buf)) {
|
||||
perror("kernel_set_ucred_caps");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pt_attach(pid)) {
|
||||
perror("pt_attach");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pt_getregs(pid, &r)) {
|
||||
perror("pt_getregs");
|
||||
pt_detach(pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(r.r_rdi=elfldr_args(pid))) {
|
||||
pt_detach(pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(r.r_rip=elfldr_load(pid, elf, size))) {
|
||||
pt_detach(pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kernel_set_ucred_caps(pid, caps);
|
||||
|
||||
if(pt_setregs(pid, &r)) {
|
||||
perror("pt_setregs");
|
||||
pt_detach(pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pt_detach(pid)) {
|
||||
perror("pt_detach");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an ELF file from socket.
|
||||
**/
|
||||
static size_t
|
||||
elfldr_read(int connfd, uint8_t **data) {
|
||||
uint8_t buf[0x4000];
|
||||
off_t offset = 0;
|
||||
ssize_t len;
|
||||
|
||||
*data = 0;
|
||||
while((len=read(connfd, buf, sizeof(buf)))) {
|
||||
*data = realloc(*data, offset + len);
|
||||
if(*data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(*data + offset, buf, len);
|
||||
offset += len;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
elfldr_serve(const char* procname, uint16_t port) {
|
||||
struct sockaddr_in server_addr;
|
||||
struct sockaddr_in client_addr;
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
struct ifaddrs *ifaddr;
|
||||
socklen_t addr_len;
|
||||
uint8_t *elf;
|
||||
size_t size;
|
||||
int connfd;
|
||||
int srvfd;
|
||||
|
||||
if(getifaddrs(&ifaddr) == -1) {
|
||||
perror("getifaddrs");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Enumerate all AF_INET IPs
|
||||
for(struct ifaddrs *ifa=ifaddr; ifa!=NULL; ifa=ifa->ifa_next) {
|
||||
if(ifa->ifa_addr == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ifa->ifa_addr->sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in *in = (struct sockaddr_in*)ifa->ifa_addr;
|
||||
inet_ntop(AF_INET, &(in->sin_addr), ip, sizeof(ip));
|
||||
elfldr_notify("Serving ELF loader on %s:%d (%s)", ip, port, ifa->ifa_name);
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
if((srvfd=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
|
||||
perror("setsockopt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
server_addr.sin_port = htons(port);
|
||||
|
||||
if(bind(srvfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(srvfd, 5) != 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_len = sizeof(client_addr);
|
||||
while(1) {
|
||||
if((connfd=accept(srvfd, (struct sockaddr*)&client_addr, &addr_len)) < 0) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
|
||||
if((size=elfldr_read(connfd, &elf))) {
|
||||
elfldr_exec(procname, elf, size);
|
||||
free(elf);
|
||||
}
|
||||
close(connfd);
|
||||
}
|
||||
close(srvfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* Launch a socket server on the given port that execute ELFs
|
||||
* within inside process with the given name.
|
||||
**/
|
||||
int elfldr_serve(const char* procname, uint16_t port);
|
||||
|
||||
|
||||
/**
|
||||
* Execute an ELF inside the process with the given name.
|
||||
**/
|
||||
int elfldr_exec(const char* procname, uint8_t *elf, size_t size);
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <ps5/kernel.h>
|
||||
|
||||
#include "elfldr.h"
|
||||
|
||||
|
||||
/**
|
||||
* Embed the ELF socket server into the bootstrap ELF.
|
||||
**/
|
||||
#ifdef ELFLDR_BOOTSRTAP
|
||||
#include "elfldr-socksever_elf.c"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Launch and ELF in its own thread.
|
||||
**/
|
||||
static void*
|
||||
main_thread(void *args) {
|
||||
pid_t pid = getpid();
|
||||
uint64_t authid;
|
||||
|
||||
if(!(authid=kernel_get_ucred_authid(pid))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(kernel_set_ucred_authid(getpid(), 0x4800000000010003l)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ELFLDR_BOOTSRTAP
|
||||
elfldr_exec("ScePartyDaemon", elfldr_socksever_elf, elfldr_socksever_elf_len);
|
||||
#else
|
||||
elfldr_serve("SceRedisServer", SOCKET_PORT);
|
||||
#endif
|
||||
|
||||
kernel_set_ucred_authid(getpid(), authid);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entry point of the payload.
|
||||
**/
|
||||
int
|
||||
main() {
|
||||
pthread_t trd;
|
||||
|
||||
pthread_create(&trd, NULL, main_thread, NULL);
|
||||
|
||||
#ifdef ELFLDR_BOOTSRTAP
|
||||
pthread_join(trd, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
/* Copyright (C) 2023 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ptrace.h"
|
||||
#include "dynlib.h"
|
||||
|
||||
|
||||
int
|
||||
pt_attach(pid_t pid) {
|
||||
if(syscall(SYS_ptrace, PT_ATTACH, pid, 0, 0)) {
|
||||
return -1;
|
||||
}
|
||||
if(waitpid(pid, 0, 0) < 0) {
|
||||
pt_detach(pid);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_detach(pid_t pid) {
|
||||
return syscall(SYS_ptrace, PT_DETACH, pid, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_getregs(pid_t pid, struct reg *r) {
|
||||
return syscall(SYS_ptrace, PT_GETREGS, pid, (caddr_t)r, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_setregs(pid_t pid, const struct reg *r) {
|
||||
return syscall(SYS_ptrace, PT_SETREGS, pid, (caddr_t)r, 0);
|
||||
}
|
||||
|
||||
|
||||
int pt_getint(pid_t pid, intptr_t addr) {
|
||||
return syscall(SYS_ptrace, PT_READ_D, pid, (caddr_t)addr, 0);
|
||||
}
|
||||
|
||||
|
||||
int pt_setint(pid_t pid, intptr_t addr, int val) {
|
||||
return(int)syscall(SYS_ptrace, PT_WRITE_D, pid, (caddr_t)addr, val);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_copyin(pid_t pid, void* buf, intptr_t addr, size_t len) {
|
||||
size_t rem = len % sizeof(int);
|
||||
int val;
|
||||
|
||||
for(size_t i=0; i<len-rem; i+=sizeof(int)) {
|
||||
memcpy(&val, buf, sizeof(val));
|
||||
if(pt_setint(pid, addr, val)) {
|
||||
return -1;
|
||||
}
|
||||
buf += sizeof(int);
|
||||
addr += sizeof(int);
|
||||
}
|
||||
|
||||
if(rem) {
|
||||
val = pt_getint(pid, addr);
|
||||
memcpy(&val, buf, rem);
|
||||
if(pt_setint(pid, addr, val)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pt_setlong(pid_t pid, intptr_t addr, long val) {
|
||||
return pt_copyin(pid, &val, addr, sizeof(val));
|
||||
}
|
||||
|
||||
|
||||
int pt_setshort(pid_t pid, intptr_t addr, short val) {
|
||||
return pt_copyin(pid, &val, addr, sizeof(val));
|
||||
}
|
||||
|
||||
|
||||
int pt_setchar(pid_t pid, intptr_t addr, char val) {
|
||||
return pt_copyin(pid, &val, addr, sizeof(val));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len) {
|
||||
size_t rem = len % sizeof(int);
|
||||
int val;
|
||||
|
||||
for(int i=0; i<len-rem; i+=sizeof(int)) {
|
||||
val = pt_getint(pid, addr);
|
||||
memcpy(buf, &val, sizeof(val));
|
||||
buf += sizeof(int);
|
||||
addr += sizeof(int);
|
||||
}
|
||||
|
||||
if(rem) {
|
||||
val = pt_getint(pid, addr);
|
||||
memcpy(buf, &val, rem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pt_step(int pid) {
|
||||
if(syscall(SYS_ptrace, PT_STEP, pid, (caddr_t)1, 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(waitpid(pid, 0, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
pt_call(pid_t pid, intptr_t addr, ...) {
|
||||
struct reg jmp_reg;
|
||||
struct reg bak_reg;
|
||||
va_list ap;
|
||||
|
||||
if(pt_getregs(pid, &bak_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
|
||||
jmp_reg.r_rip = addr;
|
||||
|
||||
va_start(ap, addr);
|
||||
jmp_reg.r_rdi = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_rsi = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_rdx = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_rcx = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_r8 = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_r9 = va_arg(ap, uint64_t);
|
||||
va_end(ap);
|
||||
|
||||
if(pt_setregs(pid, &jmp_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// single step until the function returns
|
||||
while(jmp_reg.r_rsp <= bak_reg.r_rsp) {
|
||||
if(pt_step(pid)) {
|
||||
return -1;
|
||||
}
|
||||
if(pt_getregs(pid, &jmp_reg)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// restore registers
|
||||
if(pt_setregs(pid, &bak_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return jmp_reg.r_rax;
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
pt_syscall(pid_t pid, int sysno, ...) {
|
||||
intptr_t addr = dynlib_resolve(pid, 0x2001, "HoLVWNanBBc") + 0xa;
|
||||
struct reg jmp_reg;
|
||||
struct reg bak_reg;
|
||||
va_list ap;
|
||||
|
||||
if(pt_getregs(pid, &bak_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
|
||||
jmp_reg.r_rip = addr;
|
||||
jmp_reg.r_rax = sysno;
|
||||
|
||||
va_start(ap, sysno);
|
||||
jmp_reg.r_rdi = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_rsi = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_rdx = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_r10 = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_r8 = va_arg(ap, uint64_t);
|
||||
jmp_reg.r_r9 = va_arg(ap, uint64_t);
|
||||
va_end(ap);
|
||||
|
||||
if(pt_setregs(pid, &jmp_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// single step until the function returns
|
||||
while(jmp_reg.r_rsp <= bak_reg.r_rsp) {
|
||||
if(pt_step(pid)) {
|
||||
return -1;
|
||||
}
|
||||
if(pt_getregs(pid, &jmp_reg)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// restore registers
|
||||
if(pt_setregs(pid, &bak_reg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return jmp_reg.r_rax;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags) {
|
||||
return (int)pt_syscall(pid, 0x215, name, size, flags);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_jitshm_alias(pid_t pid, int fd, int flags) {
|
||||
return (int)pt_syscall(pid, 0x216, fd, flags);
|
||||
}
|
||||
|
||||
|
||||
intptr_t
|
||||
pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
|
||||
int fd, off_t off) {
|
||||
return pt_syscall(pid, SYS_mmap, addr, len, prot, flags, fd, off);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_munmap(pid_t pid, intptr_t addr, size_t len) {
|
||||
return pt_syscall(pid, SYS_munmap, addr, len);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot) {
|
||||
return pt_syscall(pid, SYS_mprotect, addr, len, prot);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_close(pid_t pid, int fd) {
|
||||
return (int)pt_syscall(pid, SYS_close, fd);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_socket(pid_t pid, int domain, int type, int protocol) {
|
||||
return (int)pt_syscall(pid, SYS_socket, domain, type, protocol);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
|
||||
socklen_t optlen) {
|
||||
return (int)pt_syscall(pid, SYS_setsockopt, fd, level, optname, optval,
|
||||
optlen);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pt_pipe(pid_t pid, intptr_t pipefd) {
|
||||
intptr_t faddr = dynlib_resolve(pid, 0x2001, "-Jp7F+pXxNg");
|
||||
return (int)pt_call(pid, faddr, pipefd);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pt_perror(pid_t pid, const char *s) {
|
||||
intptr_t faddr = dynlib_resolve(pid, 0x2001, "9BcDykPmo1I"); //__error
|
||||
intptr_t addr;
|
||||
int err = 0;
|
||||
|
||||
addr = pt_call(pid, faddr);
|
||||
pt_copyout(pid, addr, &err, sizeof(err));
|
||||
printf("%s: %s\n", s, strerror(err));
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/* Copyright (C) 2023 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/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
|
||||
/**
|
||||
* Attach to the process with the given pid.
|
||||
**/
|
||||
int pt_attach(pid_t pid);
|
||||
|
||||
|
||||
/**
|
||||
* Detach from the process with the given pid.
|
||||
**/
|
||||
int pt_detach(pid_t pid);
|
||||
|
||||
|
||||
/**
|
||||
* Set register values of the process with the given pid.
|
||||
**/
|
||||
int pt_setregs(pid_t pid, const struct reg *r);
|
||||
|
||||
|
||||
/**
|
||||
* Get register values of the process with the given pid.
|
||||
**/
|
||||
int pt_getregs(pid_t pid, struct reg *r);
|
||||
|
||||
|
||||
/**
|
||||
* Copy memory into the virtual address space of the process with
|
||||
* the given pid.
|
||||
**/
|
||||
int pt_copyin(pid_t pid, void* buf, intptr_t addr, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Copy memory out from the virtual address space of the process with
|
||||
* the given pid.
|
||||
**/
|
||||
void pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Read 1 byte from a remote process.
|
||||
**/
|
||||
char pt_getchar(pid_t pid, intptr_t addr);
|
||||
|
||||
|
||||
/**
|
||||
* Write 1 byte to a remote process.
|
||||
**/
|
||||
int pt_setchar(pid_t pid, intptr_t addr, char val);
|
||||
|
||||
|
||||
/**
|
||||
* Read 2 bytes from a remote process.
|
||||
**/
|
||||
short pt_getshort(pid_t pid, intptr_t addr);
|
||||
|
||||
|
||||
/**
|
||||
* Write 2 bytes to a remote process.
|
||||
**/
|
||||
int pt_setshort(pid_t pid, intptr_t addr, short val);
|
||||
|
||||
|
||||
/**
|
||||
* Read 4 bytes from a remote process.
|
||||
**/
|
||||
int pt_getint(pid_t pid, intptr_t addr);
|
||||
|
||||
|
||||
/**
|
||||
* Write 4 bytes to a remote process.
|
||||
**/
|
||||
int pt_setint(pid_t pid, intptr_t addr, int val);
|
||||
|
||||
|
||||
/**
|
||||
* Read 8 byte from a remote process.
|
||||
**/
|
||||
long pt_getlong(pid_t pid, intptr_t addr);
|
||||
|
||||
|
||||
/**
|
||||
* Write 8 bytes to a remote process.
|
||||
**/
|
||||
int pt_setlong(pid_t pid, intptr_t addr, long val);
|
||||
|
||||
|
||||
/**
|
||||
* Invoke a a function in a process with the given pid.
|
||||
**/
|
||||
uint64_t pt_call(pid_t pid, intptr_t addr, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Make a system call in the process with the given pid.
|
||||
**/
|
||||
uint64_t pt_syscall(pid_t pid, int sysno, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Allocate shared memory address space for JIT in the process with the
|
||||
* given pid.
|
||||
**/
|
||||
int pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Create an alias address space for JIT in the process with the given pid.
|
||||
**/
|
||||
int pt_jitshm_alias(pid_t pid, int fd, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Create a new mapping in the virtual address space in the process
|
||||
* with the given pid.
|
||||
**/
|
||||
intptr_t pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
|
||||
int fd, off_t off);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a mapping in the virtual address space in the process with the
|
||||
* given pid.
|
||||
**/
|
||||
int pt_munmap(pid_t pid, intptr_t addr, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Set protection on a region of memory in the process with the given pid.
|
||||
**/
|
||||
int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot);
|
||||
|
||||
|
||||
/**
|
||||
* print a system error message form the process with the given pid.
|
||||
**/
|
||||
void pt_perror(pid_t pid, const char *s);
|
||||
|
||||
|
||||
/**
|
||||
* close a file descriptor in the process with the given pid.
|
||||
**/
|
||||
int pt_close(pid_t pid, int fd);
|
||||
|
||||
|
||||
/**
|
||||
* Create a socket in the process with the given pid.
|
||||
**/
|
||||
int pt_socket(pid_t pid, int domain, int type, int protocol);
|
||||
|
||||
|
||||
/**
|
||||
* Set the options of a socket in the remote process with the given pid.
|
||||
**/
|
||||
int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
|
||||
socklen_t optlen);
|
||||
|
||||
|
||||
/**
|
||||
* Create a pipe in the process with the given pid.
|
||||
**/
|
||||
int pt_pipe(pid_t pid, intptr_t pipefd);
|
||||
|
||||
+9
-11
@@ -19,21 +19,19 @@ DESTDIR ?= /opt/ps5-payload-sdk
|
||||
|
||||
CC := clang
|
||||
LD := ld.lld
|
||||
AR := ar
|
||||
|
||||
CFLAGS := -ffreestanding -fno-builtin -nostdlib -O2
|
||||
CFLAGS += -fPIE -target x86_64-pc-none
|
||||
CFLAGS += -fPIC -target x86_64-pc-none
|
||||
|
||||
SPRXS := $(wildcard *.sprx)
|
||||
STUBS := $(SPRXS:.sprx=.c)
|
||||
|
||||
SOURCES := $(wildcard *.c)
|
||||
ARCHIVES := $(SOURCES:.c=.a)
|
||||
SHARED := $(SOURCES:.c=.so)
|
||||
|
||||
NID_DB_URL := https://raw.githubusercontent.com/astrelsky/GhidraOrbis/master/data/nid_db.xml
|
||||
|
||||
|
||||
all: $(SOURCES) $(ARCHIVES)
|
||||
all: $(SOURCES) $(SHARED)
|
||||
|
||||
stubs: nid_db.xml $(STUBS)
|
||||
|
||||
@@ -41,17 +39,17 @@ nid_db.xml:
|
||||
wget -O $@ $(NID_DB_URL)
|
||||
|
||||
%.c: %.sprx
|
||||
$(PYTHON) genstub.py $*.sprx > $@
|
||||
$(PYTHON) genstub.py $^ > $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
%.a: %.o
|
||||
$(AR) rcs $@ $^
|
||||
%.so: %.o
|
||||
$(LD) -shared -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a nid_db.xml
|
||||
rm -f *.o *.so nid_db.xml
|
||||
|
||||
install: $(ARCHIVES)
|
||||
install: $(SHARED)
|
||||
install -d $(DESTDIR)/usr/lib
|
||||
install $(ARCHIVES) $(DESTDIR)/usr/lib
|
||||
install $(SHARED) $(DESTDIR)/usr/lib
|
||||
+20
-57
@@ -28,7 +28,19 @@ from pathlib import Path
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
|
||||
logger = logging.getLogger('trampgen')
|
||||
logger = logging.getLogger('genstub')
|
||||
|
||||
|
||||
tmpl_func = string.Template('''
|
||||
asm(".global $name\\n"
|
||||
".type $name @function\\n"
|
||||
"$name:\\n");''')
|
||||
|
||||
|
||||
tmpl_obj = string.Template('''
|
||||
asm(".global $name\\n"
|
||||
".type $name, @object\\n"
|
||||
"$name:\\n");''')
|
||||
|
||||
|
||||
# read NIDs from nid_db.xml
|
||||
@@ -37,29 +49,6 @@ nid_map = {entry.get('obf'): entry.get('sym')
|
||||
for entry in ET.parse(NID_DB).getroot()}
|
||||
|
||||
|
||||
# Header template
|
||||
tmpl_head = string.Template('''/*
|
||||
This file was generated by genstub.py, do not edit manually!
|
||||
*/''')
|
||||
|
||||
|
||||
# Dependencies template
|
||||
tmpl_deps = string.Template('''
|
||||
int sprx_dlsym(unsigned int handle, const char *nid, void *addr);
|
||||
int sprx_dlopen(const char* libname, unsigned short *handle);
|
||||
int sprx_dlclose(unsigned int handle);''')
|
||||
|
||||
|
||||
# Function template
|
||||
tmpl_func = string.Template('''
|
||||
static __attribute__ ((used)) void* __ptr_$name;
|
||||
asm(".intel_syntax noprefix\\n"
|
||||
".global $name\\n"
|
||||
".type $name @function\\n"
|
||||
"$name:\\n"
|
||||
"jmp qword ptr [rip + __ptr_$name]\\n");''')
|
||||
|
||||
|
||||
def symbols(sym_type, filename):
|
||||
'''
|
||||
yield symbol names in PT_DYNAMIC segments using the NID lookup table
|
||||
@@ -87,7 +76,7 @@ def symbols(sym_type, filename):
|
||||
logger.warning(f'skipping unknown NID {nid}')
|
||||
continue
|
||||
|
||||
yield nid_map[nid], nid
|
||||
yield nid_map[nid]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -97,38 +86,12 @@ if __name__ == '__main__':
|
||||
parser.add_argument('SPRX_FILE')
|
||||
cli_args = parser.parse_args()
|
||||
|
||||
libname = Path(cli_args.SPRX_FILE).stem
|
||||
filename = cli_args.SPRX_FILE
|
||||
funcs = sorted(set(symbols('STT_FUNC', cli_args.SPRX_FILE)))
|
||||
gvars = sorted(set(symbols('STT_OBJECT', cli_args.SPRX_FILE)))
|
||||
|
||||
funcs = sorted(set(symbols('STT_FUNC', filename)))
|
||||
gvars = sorted(set(symbols('STT_OBJECT', filename)))
|
||||
for name in sorted(funcs):
|
||||
print(tmpl_func.substitute(name=name))
|
||||
|
||||
if not funcs: # and not gvars:
|
||||
sys.exit(0)
|
||||
for name in sorted(gvars):
|
||||
print(tmpl_obj.substitute(name=name))
|
||||
|
||||
print(tmpl_head.substitute())
|
||||
print(tmpl_deps.substitute())
|
||||
|
||||
for name, nid in funcs:
|
||||
print(tmpl_func.substitute(name=name))
|
||||
|
||||
print('')
|
||||
print('static unsigned short __handle = 0;')
|
||||
print('static void __attribute__((constructor(104)))')
|
||||
print('__constructor(void) {')
|
||||
if libname in ('libkernel', 'libkernel_sys', 'libkernel_web'):
|
||||
print(' __handle = 0x2001;')
|
||||
elif libname == 'libSceLibcInternal':
|
||||
print(' __handle = 0x2;')
|
||||
else:
|
||||
print(f' if(sprx_dlopen("{libname}", &__handle)) return;')
|
||||
for name, nid in funcs:
|
||||
print(f' if(sprx_dlsym(__handle, "{nid}", &__ptr_{name})) return;')
|
||||
print('}')
|
||||
|
||||
if not libname in ('libkernel', 'libkernel_sys', 'libkernel_web', 'libSceLibcInternal'):
|
||||
print('')
|
||||
print('static void __attribute__((destructor(104)))')
|
||||
print('__destructor(void) {')
|
||||
print(f' sprx_dlclose(__handle);')
|
||||
print('}')
|
||||
+7517
-13638
File diff suppressed because it is too large.
Load diff
@@ -1,26 +1,4 @@
|
||||
/*
|
||||
This file was generated by genstub.py, do not edit manually!
|
||||
*/
|
||||
|
||||
int sprx_dlsym(unsigned int handle, const char *nid, void *addr);
|
||||
int sprx_dlopen(const char* libname, unsigned short *handle);
|
||||
int sprx_dlclose(unsigned int handle);
|
||||
|
||||
static __attribute__ ((used)) void* __ptr_sceRandomGetRandomNumber;
|
||||
asm(".intel_syntax noprefix\n"
|
||||
".global sceRandomGetRandomNumber\n"
|
||||
asm(".global sceRandomGetRandomNumber\n"
|
||||
".type sceRandomGetRandomNumber @function\n"
|
||||
"sceRandomGetRandomNumber:\n"
|
||||
"jmp qword ptr [rip + __ptr_sceRandomGetRandomNumber]\n");
|
||||
|
||||
static unsigned short __handle = 0;
|
||||
static void __attribute__((constructor(104)))
|
||||
__constructor(void) {
|
||||
if(sprx_dlopen("libSceRandom", &__handle)) return;
|
||||
if(sprx_dlsym(__handle, "PI7jIZj4pcE", &__ptr_sceRandomGetRandomNumber)) return;
|
||||
}
|
||||
|
||||
static void __attribute__((destructor(104)))
|
||||
__destructor(void) {
|
||||
sprx_dlclose(__handle);
|
||||
}
|
||||
"sceRandomGetRandomNumber:\n");
|
||||
+1008
-3042
File diff suppressed because it is too large.
Load diff
+912
-2754
File diff suppressed because it is too large.
Load diff
+328
-1002
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+2517
-7506
File diff suppressed because it is too large.
Load diff
+2199
-6552
File diff suppressed because it is too large.
Load diff
+6
-6
@@ -57,7 +57,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
#
|
||||
set(CMAKE_ASM_FLAGS_INIT "-target ${PS5_TARGET_TRIPLE}")
|
||||
set(CMAKE_ASM_LINK_EXECUTABLE
|
||||
"<CMAKE_LINKER> -pie -o <TARGET> <CMAKE_ASM_LINK_FLAGS> \
|
||||
"<CMAKE_LINKER> -pie -z max-page-size=0x4000 -o <TARGET> <CMAKE_ASM_LINK_FLAGS> \
|
||||
-T${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x \
|
||||
-L${PS5_PAYLOAD_SDK}/usr/lib \
|
||||
--start-group \
|
||||
@@ -68,15 +68,15 @@ set(CMAKE_ASM_LINK_EXECUTABLE
|
||||
#
|
||||
# Set flags for C programs
|
||||
#
|
||||
set(CMAKE_C_FLAGS_INIT "${CMAKE_ASM_FLAGS_INIT} -fno-stack-protector -isystem ${PS5_PAYLOAD_SDK}/usr/include")
|
||||
set(CMAKE_C_FLAGS_INIT "${CMAKE_ASM_FLAGS_INIT} -fno-plt -fno-stack-protector -isystem ${PS5_PAYLOAD_SDK}/usr/include")
|
||||
set(CMAKE_C_STANDARD_LIBRARIES "-lSceLibcInternal -l${PS5_KERNEL_LIBRARY}")
|
||||
set(CMAKE_C_LINK_EXECUTABLE
|
||||
"<CMAKE_LINKER> -pie -o <TARGET> <CMAKE_C_LINK_FLAGS> \
|
||||
"<CMAKE_LINKER> -pie -z max-page-size=0x4000 -o <TARGET> <CMAKE_C_LINK_FLAGS> \
|
||||
-T${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x \
|
||||
-L${PS5_PAYLOAD_SDK}/usr/lib \
|
||||
--start-group \
|
||||
${PS5_PAYLOAD_SDK}/usr/lib/crt1.o \
|
||||
<OBJECTS> <LINK_LIBRARIES> \
|
||||
${PS5_PAYLOAD_SDK}/usr/lib/crt1.o \
|
||||
--end-group \
|
||||
")
|
||||
|
||||
@@ -86,11 +86,11 @@ set(CMAKE_C_LINK_EXECUTABLE
|
||||
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_C_FLAGS_INIT}")
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE
|
||||
"<CMAKE_LINKER> -pie -o <TARGET> <CMAKE_CXX_LINK_FLAGS> \
|
||||
"<CMAKE_LINKER> -pie -z max-page-size=0x4000 -o <TARGET> <CMAKE_CXX_LINK_FLAGS> \
|
||||
-T${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x \
|
||||
-L${PS5_PAYLOAD_SDK}/usr/lib \
|
||||
--start-group \
|
||||
${PS5_PAYLOAD_SDK}/usr/lib/crt1.o \
|
||||
<OBJECTS> <LINK_LIBRARIES> \
|
||||
${PS5_PAYLOAD_SDK}/usr/lib/crt1.o \
|
||||
--end-group \
|
||||
")
|
||||
Reference in new issue
Block a user