mirror of
https://github.com/ps5-payload-dev/elfldr.git
synced 2026-10-19 02:19:52 -05:00
add support for payload arguments when deployed as an URI
This commit is contained in:
1 parent
8e575ad9d4
commit
96b225f7c6
8 files changed
+300
-74
No files matched your search
+7
-1
@@ -28,6 +28,12 @@ along with this program; see the file COPYING. If not, see
|
||||
#include "socksrv_elf.c"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static char* const argv[] = {"elfldr.elf", 0};
|
||||
|
||||
|
||||
/**
|
||||
* We are running inside SceRedisServer, spawn socksrv.elf.
|
||||
**/
|
||||
@@ -67,7 +73,7 @@ main() {
|
||||
ret = -1;
|
||||
} else {
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
ret = elfldr_spawn("elfldr.elf", -1, socksrv_elf, socksrv_elf_len);
|
||||
ret = elfldr_spawn(-1, argv, socksrv_elf, socksrv_elf_len);
|
||||
}
|
||||
|
||||
// restore my privileges
|
||||
|
||||
@@ -567,9 +567,7 @@ sys_budget_set(long budget) {
|
||||
|
||||
|
||||
static int
|
||||
elfldr_rfork_entry(void* progname) {
|
||||
char* const argv[] = {(char*)progname, 0};
|
||||
|
||||
elfldr_rfork_entry(void* argv) {
|
||||
if(sys_budget_set(0)) {
|
||||
klog_perror("sys_budget_set");
|
||||
return -1;
|
||||
@@ -602,7 +600,7 @@ elfldr_rfork_entry(void* progname) {
|
||||
* Execute an ELF inside a new process.
|
||||
**/
|
||||
pid_t
|
||||
elfldr_spawn(const char* progname, int stdio, uint8_t* elf, size_t payload_size) {
|
||||
elfldr_spawn(int stdio, char* const argv[], uint8_t* elf, size_t payload_size) {
|
||||
uint8_t int3instr = 0xcc;
|
||||
struct kevent evt;
|
||||
intptr_t brkpoint;
|
||||
@@ -623,7 +621,7 @@ elfldr_spawn(const char* progname, int stdio, uint8_t* elf, size_t payload_size)
|
||||
}
|
||||
|
||||
if((pid=rfork_thread(RFPROC | RFCFDG | RFMEM, stack+PAGE_SIZE-8,
|
||||
elfldr_rfork_entry, (void*)progname)) < 0) {
|
||||
elfldr_rfork_entry, (void*)argv)) < 0) {
|
||||
LOG_PERROR("rfork_thread");
|
||||
free(stack);
|
||||
close(kq);
|
||||
@@ -703,7 +701,7 @@ elfldr_spawn(const char* progname, int stdio, uint8_t* elf, size_t payload_size)
|
||||
}
|
||||
|
||||
// Execute the ELF
|
||||
elfldr_set_procname(pid, progname);
|
||||
elfldr_set_procname(pid, argv[0]);
|
||||
if(elfldr_exec(pid, stdio, elf)) {
|
||||
kill(pid, SIGKILL);
|
||||
return -1;
|
||||
|
||||
@@ -28,7 +28,7 @@ pid_t elfldr_find_pid(const char* name);
|
||||
/**
|
||||
* Spawn a new process that executes the given ELF file.
|
||||
**/
|
||||
pid_t elfldr_spawn(const char* progname, int stdio, uint8_t *elf, size_t elf_size);
|
||||
pid_t elfldr_spawn(int stdio, char* const argv[], uint8_t *elf, size_t elf_size);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef struct self_spawn_args {
|
||||
int stdio;
|
||||
uint8_t *self;
|
||||
size_t self_size;
|
||||
char* const* argv;
|
||||
} self_spawn_args_t;
|
||||
|
||||
|
||||
@@ -83,7 +84,6 @@ rdup(pid_t pid, int fd) {
|
||||
static int
|
||||
selfldr_rfork_entry(void *ctx) {
|
||||
self_spawn_args_t *args = (self_spawn_args_t *)ctx;
|
||||
char *const argv[] = {0};
|
||||
char *const envp[] = {0};
|
||||
pid_t ppid = getppid();
|
||||
char path[PATH_MAX];
|
||||
@@ -118,7 +118,7 @@ selfldr_rfork_entry(void *ctx) {
|
||||
}
|
||||
close(fd);
|
||||
|
||||
execve(path, argv, envp);
|
||||
execve(path, args->argv, envp);
|
||||
perror("execve");
|
||||
|
||||
return 0;
|
||||
@@ -126,8 +126,8 @@ selfldr_rfork_entry(void *ctx) {
|
||||
|
||||
|
||||
pid_t
|
||||
selfldr_spawn(int stdio, uint8_t *self, size_t self_size) {
|
||||
self_spawn_args_t args = {stdio, self, self_size};
|
||||
selfldr_spawn(int stdio, char* const argv[], uint8_t *self, size_t self_size) {
|
||||
self_spawn_args_t args = {stdio, self, self_size, argv};
|
||||
struct kevent evt;
|
||||
void *stack;
|
||||
pid_t pid;
|
||||
|
||||
@@ -28,4 +28,5 @@ int selfldr_read(int fd, uint8_t **self, size_t *self_size);
|
||||
/**
|
||||
* Spawn a new process that executes the given SELF file.
|
||||
**/
|
||||
pid_t selfldr_spawn(int stdio, uint8_t *self, size_t self_size);
|
||||
pid_t selfldr_spawn(int stdio, char* const argv[],
|
||||
uint8_t *self, size_t self_size);
|
||||
@@ -46,42 +46,26 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
|
||||
/**
|
||||
* Spawn an ELF or a SELF payload.
|
||||
* Decode an escaped argument.
|
||||
**/
|
||||
static int
|
||||
payload_spawn(int fd, const char* progname, uint8_t* payload, size_t payload_size) {
|
||||
int magic = *((int*)payload);
|
||||
static char*
|
||||
args_decode(const char* s) {
|
||||
size_t length = strlen(s);
|
||||
char *arg = malloc(length+1);
|
||||
size_t off = 0;
|
||||
int escape = 0;
|
||||
|
||||
if(magic == PAYLOAD_MAGIC_ELF) {
|
||||
return elfldr_spawn(progname, fd, payload, payload_size);
|
||||
}
|
||||
|
||||
if(magic == PAYLOAD_MAGIC_PS4_SELF || magic == PAYLOAD_MAGIC_PS5_SELF) {
|
||||
return selfldr_spawn(fd, payload, payload_size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the progname from an URI.
|
||||
**/
|
||||
static const char*
|
||||
payload_progname(const char* uri) {
|
||||
const char* progname = "payload.elf";
|
||||
size_t len = strlen(uri);
|
||||
|
||||
for(int i=0; i<len; i++) {
|
||||
if(uri[i] == '/' && uri[i+1]) {
|
||||
progname = uri+i+1;
|
||||
}
|
||||
else if(uri[i] == '?') {
|
||||
break;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(s[i] == '\\' && !escape) {
|
||||
escape = 1;
|
||||
} else {
|
||||
arg[off++] = s[i];
|
||||
escape = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return progname;
|
||||
arg[off] = 0;
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,17 +73,101 @@ payload_progname(const char* uri) {
|
||||
*
|
||||
**/
|
||||
static int
|
||||
read_uri(int fd, char* uri, size_t size) {
|
||||
int c;
|
||||
args_split(const char* args, char** argv, size_t size) {
|
||||
char* buf = strdup(args);
|
||||
size_t len = strlen(buf);
|
||||
int escape = 0;
|
||||
int argc = 0;
|
||||
|
||||
memset(argv, 0, size*sizeof(char*));
|
||||
for(int i=0; i<len && argc<size; i++) {
|
||||
if(escape) {
|
||||
escape = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(buf[i] == '\\') {
|
||||
escape = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(buf[i] == ' ') {
|
||||
buf[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(buf[i] && !i) {
|
||||
argv[argc++] = buf+i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(buf[i] && !buf[i-1]) {
|
||||
argv[argc++] = buf+i;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<argc; i++) {
|
||||
argv[i] = args_decode(argv[i]);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Spawn an ELF or a SELF payload.
|
||||
**/
|
||||
static pid_t
|
||||
payload_spawn(char* filename, char* args, int fd,
|
||||
uint8_t* payload, size_t payload_size) {
|
||||
int magic = *((int*)payload);
|
||||
char* argv[255+2] = {0};
|
||||
pid_t pid = -1;
|
||||
|
||||
argv[0] = filename;
|
||||
args_split(args, argv+1, 255);
|
||||
|
||||
if(magic == PAYLOAD_MAGIC_ELF) {
|
||||
pid = elfldr_spawn(fd, argv, payload, payload_size);
|
||||
|
||||
} else if(magic == PAYLOAD_MAGIC_PS4_SELF || magic == PAYLOAD_MAGIC_PS5_SELF) {
|
||||
pid = selfldr_spawn(fd, argv, payload, payload_size);
|
||||
}
|
||||
|
||||
for(int i=1; argv[i]; i++) {
|
||||
free(argv[i]);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
static int
|
||||
payload_readuri(int fd, char* uri, size_t size) {
|
||||
char c;
|
||||
int n;
|
||||
|
||||
for(int i=0; i<size; i++) {
|
||||
if(read(fd, &c, 1) != 1) {
|
||||
if((n=read(fd, &c, 1)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(n == 0) {
|
||||
uri[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
if(c == '\r') {
|
||||
continue;
|
||||
}
|
||||
if(c == '\n') {
|
||||
uri[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uri[i] = c;
|
||||
}
|
||||
|
||||
@@ -112,11 +180,12 @@ read_uri(int fd, char* uri, size_t size) {
|
||||
**/
|
||||
static void
|
||||
on_connection(int fd) {
|
||||
char* filename = "payload.elf";
|
||||
char uri[PATH_MAX+1] = {0};
|
||||
const char* progname;
|
||||
uint8_t* buf = 0;
|
||||
size_t len = 0;
|
||||
int optval = 1;
|
||||
char* args = "";
|
||||
int magic = 0;
|
||||
|
||||
if(setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) {
|
||||
@@ -131,7 +200,7 @@ on_connection(int fd) {
|
||||
}
|
||||
|
||||
if(magic == PAYLOAD_MAGIC_FILE || magic == PAYLOAD_MAGIC_HTTP) {
|
||||
if(read_uri(fd, uri, PATH_MAX) < 0 || uri_read(uri, &buf, &len)) {
|
||||
if(payload_readuri(fd, uri, PATH_MAX) || uri_get_content(uri, &buf, &len)) {
|
||||
LOG_PERROR("read_uri");
|
||||
write(fd, "[elfldr.elf] Error reading URI payload\n\r\0", 41);
|
||||
}
|
||||
@@ -152,10 +221,17 @@ on_connection(int fd) {
|
||||
}
|
||||
|
||||
if(buf) {
|
||||
progname = payload_progname(uri);
|
||||
if(payload_spawn(fd, progname, buf, len) < 0) {
|
||||
if(!(filename=uri_get_filename(uri))) {
|
||||
filename = strdup("payload.elf");
|
||||
}
|
||||
if(!(args=uri_get_param(uri, "args"))) {
|
||||
args = strdup("");
|
||||
}
|
||||
if(payload_spawn(filename, args, fd, buf, len) < 0) {
|
||||
write(fd, "[elfldr.elf] Error spawning payload\n\r\0", 38);
|
||||
}
|
||||
free(filename);
|
||||
free(args);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,53 +209,186 @@ url_read(const char* url, uint8_t** payload, size_t* payload_size) {
|
||||
* Read a payload from given path.
|
||||
**/
|
||||
static int
|
||||
path_read(const char* path, uint8_t** payload, size_t* payload_size) {
|
||||
path_read(const char* path, uint8_t** content, size_t* content_size) {
|
||||
uint8_t* buf;
|
||||
ssize_t len;
|
||||
FILE* file;
|
||||
ssize_t size;
|
||||
FILE* f;
|
||||
|
||||
if(!(file=fopen(path, "rb"))) {
|
||||
if(!(f=fopen(path, "rb"))) {
|
||||
return -1;
|
||||
}
|
||||
if(fseek(file, 0, SEEK_END)) {
|
||||
if(fseek(f, 0, SEEK_END)) {
|
||||
return -1;
|
||||
}
|
||||
if((len=ftell(file)) < 0) {
|
||||
if((size=ftell(f)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(fseek(file, 0, SEEK_SET)) {
|
||||
if(fseek(f, 0, SEEK_SET)) {
|
||||
return -1;
|
||||
}
|
||||
if(!(buf=malloc(len))) {
|
||||
if(!(buf=malloc(size))) {
|
||||
return -1;
|
||||
}
|
||||
if(fread(buf, 1, len, file) != len) {
|
||||
if(fread(buf, 1, size, f) != size) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
if(fclose(file)) {
|
||||
if(fclose(f)) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*payload = buf;
|
||||
*payload_size = len;
|
||||
*content = buf;
|
||||
*content_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
uri_read(const char* uri, uint8_t** payload, size_t* payload_size) {
|
||||
if(!strncmp(uri, "file:/", 6)) {
|
||||
return path_read(uri+6, payload, payload_size);
|
||||
static int
|
||||
hexval(char c) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
|
||||
if(!strncmp(uri, "http:/", 6) ||
|
||||
!strncmp(uri, "https:/", 7)) {
|
||||
return url_read(uri, payload, payload_size);
|
||||
if(c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
if(c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
uri_decode(const char* src, size_t len) {
|
||||
char* out;
|
||||
char* dst;
|
||||
int lo;
|
||||
int hi;
|
||||
|
||||
if(!(out=malloc(len+1))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dst = out;
|
||||
for(size_t i=0; i<len; i++) {
|
||||
if(src[i] == '%' && i+2 < len) {
|
||||
hi = hexval(src[i+1]);
|
||||
lo = hexval(src[i+2]);
|
||||
if(hi >= 0 && lo >= 0) {
|
||||
*dst++ = (char)((hi << 4) | lo);
|
||||
i += 2;
|
||||
} else {
|
||||
*dst++ = src[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
*dst++ = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
uri_get_path(const char* uri) {
|
||||
size_t len = strlen(uri);
|
||||
const char* begin = 0;
|
||||
const char* end = 0;
|
||||
|
||||
end = uri + len;
|
||||
for(int i=0; i<len; i++) {
|
||||
if(!begin && uri[i] == ':' && uri[i+1] == '/') {
|
||||
begin = uri + i + 1;
|
||||
}
|
||||
else if(uri[i] == '?' || uri[i] == '#' || uri[i] == '\0') {
|
||||
end = uri + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return uri_decode(begin, end-begin);
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
uri_get_filename(const char* uri) {
|
||||
size_t len = strlen(uri);
|
||||
const char* begin = 0;
|
||||
const char* end = 0;
|
||||
|
||||
end = uri + len;
|
||||
for(int i=0; i<len; i++) {
|
||||
if(uri[i] == '/') {
|
||||
begin = uri + i + 1;
|
||||
}
|
||||
else if(uri[i] == '?' || uri[i] == '#' || uri[i] == '\0') {
|
||||
end = uri + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return uri_decode(begin, end-begin);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
uri_get_content(const char* uri, uint8_t** content, size_t* content_size) {
|
||||
int err = -1;
|
||||
char *path;
|
||||
|
||||
if(!strncmp(uri, "file:/", 6)) {
|
||||
if((path=uri_get_path(uri))) {
|
||||
err = path_read(path, content, content_size);
|
||||
free(path);
|
||||
}
|
||||
} else if(!strncmp(uri, "http:/", 6) || !strncmp(uri, "https:/", 7)) {
|
||||
err = url_read(uri, content, content_size);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
uri_get_param(const char* uri, const char* name) {
|
||||
const char* begin;
|
||||
const char* end;
|
||||
const char* p;
|
||||
size_t len;
|
||||
|
||||
if(!(p=strchr(uri, '?'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p++;
|
||||
len = strlen(name);
|
||||
|
||||
while(*p && *p != '#') {
|
||||
if(!strncmp(p, name, len) && p[len] == '=') {
|
||||
begin = p + len + 1;
|
||||
|
||||
if(!(end=strchr(begin, '&'))) {
|
||||
if(!(end=strchr(begin, '#'))) {
|
||||
end = begin + strlen(begin);
|
||||
}
|
||||
}
|
||||
|
||||
return uri_decode(begin, end-begin);
|
||||
}
|
||||
|
||||
while(*p && *p != '&' && *p != '#') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if(*p == '&') {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -20,9 +20,21 @@ along with this program; see the file COPYING. If not, see
|
||||
|
||||
|
||||
/**
|
||||
* Read a payload from the given URI. Supported protocols are:
|
||||
* Read the content from the given URI. Supported protocols are:
|
||||
* - file://
|
||||
* - http://
|
||||
* - https://
|
||||
**/
|
||||
int uri_read(const char* uri, uint8_t** payload, size_t* payload_size);
|
||||
int uri_get_content(const char* uri, uint8_t** content, size_t* content_size);
|
||||
|
||||
|
||||
/**
|
||||
* Get the value of a named parameter associated with the given URI.
|
||||
**/
|
||||
char* uri_get_param(const char* uri, const char* name);
|
||||
|
||||
|
||||
/**
|
||||
* Get the filename associated with the given URI.
|
||||
**/
|
||||
char* uri_get_filename(const char* uri);
|
||||
Reference in new issue
Block a user