dynamically link sprx libs

This commit is contained in:
John Törnblom committed 2024-01-28 00:50:46 +01:00
1 parent 564ce5e2ca
commit b4cebf24cd
58 files changed
+15292 -46413

No files matched your search

-6
View File
@@ -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
View File
@@ -1,5 +1,6 @@
*~
*.a
*.so
*.o
*.sprx
nid_db.xml
-6
View File
@@ -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
View File
@@ -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
+20 -36
View File
@@ -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
View File
@@ -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))) {
+6 -19
View File
@@ -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);
+18 -22
View File
@@ -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);
}
+7 -10
View File
@@ -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);
+10 -6
View File
@@ -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;
}
}
+3
View File
@@ -14,4 +14,7 @@ typedef struct payload_args {
} payload_args_t;
extern payload_args_t* __payload_args;
#endif // PS5SDK_PAYLOAD_H
+373
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+5 -2
View File
@@ -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" \
$* \
+5 -1
View File
@@ -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
-24
View File
@@ -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
-5
View File
@@ -1,5 +0,0 @@
*.elf
*.o
*~
payload_elf.c
-60
View File
@@ -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) < $^
-221
View File
@@ -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;
}
-17
View File
@@ -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);
-29
View File
@@ -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!");
}
}
-5
View File
@@ -1,5 +0,0 @@
*.elf
*.o
*.bin
*~
-45
View File
@@ -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
-51
View File
@@ -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;
}
-4
View File
@@ -1,4 +0,0 @@
*.elf
*.o
*~
-45
View File
@@ -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) < $^
-43
View File
@@ -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;
}
-4
View File
@@ -1,4 +0,0 @@
*.elf
*.o
*~
-45
View File
@@ -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) < $^
-107
View File
@@ -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;
}
-69
View File
@@ -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;
}
-27
View File
@@ -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);
-88
View File
@@ -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;
}
-4
View File
@@ -1,4 +0,0 @@
*.elf
*.o
*~
elfldr-socksever_elf.c
-56
View File
@@ -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) < $^
-211
View File
@@ -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");
}
-33
View File
@@ -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);
-703
View File
@@ -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;
}
-32
View File
@@ -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);
-75
View File
@@ -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;
}
-304
View File
@@ -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));
}
-185
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+2 -24
View File
@@ -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");
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+328 -1002
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2517 -7506
View File
File diff suppressed because it is too large. Load diff
+2199 -6552
View File
File diff suppressed because it is too large. Load diff
+6 -6
View File
@@ -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 \
")