complete rewrite of the elf loader, which now spawns complete new processes for each ELF, amongst other things

This commit is contained in:
John Törnblom committed 2024-02-03 22:36:25 +01:00
1 parent 2fd0a53ec1
commit 6097b737d2
23 files changed
+726 -2795

No files matched your search

+20 -5
View File
@@ -20,19 +20,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Source Code
- name: Checkout
uses: actions/checkout@v3
- name: Setup Build Env
run: sudo apt-get install build-essential clang lld
- name: Checkout
uses: actions/checkout@v3
with:
repository: john-tornblom/ps5-payload-sdk
path: ps5-payload-sdk
- name: Setup SDK
working-directory: ps5-payload-sdk
run: |
sudo apt update
sudo apt install wget build-essential clang clang-15 lld lld-15
make
make DESTDIR=${{ runner.tool_cache }}/ps5-payload-sdk install
echo PS5_PAYLOAD_SDK=${{ runner.tool_cache }}/ps5-payload-sdk >> $GITHUB_ENV
echo PS5_HOST=ps5 >> $GITHUB_ENV
echo PS5_PORT=9020 >> $GITHUB_ENV
- name: Build Payload
run: make
run: |
make clean all
- name: Upload Payload
uses: actions/upload-artifact@v3
with:
name: Payload
path: ./elfldr.elf
path: ./bootstrap.elf
if-no-files-found: error
+1 -1
View File
@@ -1,5 +1,5 @@
*~
*.o
*.elf
elfldr-socksrv_elf.c
elfldr_elf.c
+36 -40
View File
@@ -1,55 +1,51 @@
PS5_HOST ?= ps5
PS5_PORT ?= 9020
ELFLDR_PORT ?= 9021
# Copyright (C) 2024 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/>.
CC := clang
LD := ld.lld
XXD := xxd
ifndef PS5_PAYLOAD_SDK
$(error PS5_PAYLOAD_SDK is undefined)
endif
CFLAGS := -target x86_64-pc-none -fPIE -fno-stack-protector -ffreestanding \
-fno-builtin -nostdlib -nostdinc -Wall -Werror
LDFLAGS := -pie -T elf_x86_64.x
PS5_HOST ?= ps5
PS5_PORT ?= 9020
OBJS := crt.o libc.o kern.o dynlib.o pt.o elfldr.o
CC := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-cc
LD := $(PS5_PAYLOAD_SDK)/host/x86_64-ps5-payload-ld
all: elfldr.elf hello_world.elf
CFLAGS := -O2
elfldr.elf: $(OBJS) main.o
$(LD) $(LDFLAGS) -o $@ $^
all: bootstrap.elf
elfldr-socksrv.elf: $(OBJS) main-socksrv.o
$(LD) $(LDFLAGS) -o $@ $^
elfldr.elf: main.o pt.o elfldr.o
$(LD) $^ -lSceLibcInternal -lkernel_sys -o $@
payload_launchpad.elf: payload_launchpad.o
$(LD) $(LDFLAGS) -o $@ $^
bootstrap.elf: bootstrap.o pt.o elfldr.o
$(LD) $^ -lSceLibcInternal -lkernel_web -o $@
hello_world.elf: hello_world.o
$(LD) $(LDFLAGS) -o $@ $^
main.o: main.c elfldr-socksrv_elf.c
$(CC) -c $(CFLAGS) -DELFLDR_BOOTSTRAP -o $@ $<
elfldr-socksrv_elf.c: elfldr-socksrv.elf
$(XXD) -i $^ > $@
elfldr.o: elfldr.c payload_launchpad_elf.c
bootstrap.o: bootstrap.c elfldr_elf.c
$(CC) -c $(CFLAGS) -o $@ $<
payload_launchpad_elf.c: payload_launchpad.elf
$(XXD) -i $^ > $@
main-socksrv.o: main.c
$(CC) -c $(CFLAGS) -DELFLDR_PORT=$(ELFLDR_PORT) -o $@ $<
elfldr_elf.c: elfldr.elf
xxd -i $^ > $@
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
$(CC) -c $(CFLAGS) -o $@ $^
clean:
rm -f *.o *.elf elfldr-socksrv_elf.c payload_launchpad_elf.c
rm -f *.o bootstrap.elf elfldr.elf elfldr_elf.c
test: bootstrap.elf
nc -q0 $(PS5_HOST) $(PS5_PORT) < $^
test: elfldr.elf hello_world.elf
nc -q0 $(PS5_HOST) $(PS5_PORT) < elfldr.elf
@sleep 1
nc -q0 $(PS5_HOST) $(ELFLDR_PORT) < hello_world.elf
+7 -5
View File
@@ -5,14 +5,15 @@ Unlike the ELF loaders bundled with those exploits, this one uses the ptrace
syscall to load itself into the `ScePartyDaemon` process, hence will continue
running in the background even when playing games. Furthermore, this ELF loader
will also resume its execution when the PS5 returns from rest mode. Payloads that
are loaded are executed in the `SceRedisServer` process, so if the payload crashes,
are loaded are executed in induvidual processes, so if the payload crashes,
the ELF loader will keep on running.
## Building
On Debian-flavored operating systems, one can invoke the following commands to
install dependencies and build the ELF loader.
Assuming you have the [ps5-payload-sdk][sdk] installed on a POSIX machine,
the ELF loader can be compiled using the following two commands:
```console
john@localhost:ps5-payload-elfldr$ sudo apt-get install build-essential clang lld
john@localhost:ps5-payload-elfldr$ export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk
john@localhost:ps5-payload-elfldr$ make
```
@@ -20,7 +21,7 @@ john@localhost:ps5-payload-elfldr$ make
To deploy the ELF loader itself, we first bootstrap via the ELF loader bundled
with the exploit of your choice.
```console
john@localhost:ps5-payload-elfldr$ nc -q0 PS5_HOST 9020 < elfldr.elf
john@localhost:ps5-payload-elfldr$ nc -q0 PS5_HOST 9020 < bootstrap.elf
```
**Note**: recent versions of the [BD-J ps5-payload-loader][bdj] include a binary
version of this ELF loader which can be launched directly from the menu system.
@@ -38,6 +39,7 @@ please file an issue before you start to work on you changes. This will allow us
to discuss the solution properly before you commit time and effort.
[bdj]: https://github.com/john-tornblom/bdj-sdk/tree/master/samples/ps5-payload-loader
[sdk]: https://github.com/john-tornblom/ps5-payload-sdk
[webkit]: https://github.com/Cryptogenic/PS5-IPV6-Kernel-Exploit
[issues]: https://github.com/john-tornblom/ps5-payload-elfldr/issues/new
+94
View File
@@ -0,0 +1,94 @@
/* Copyright (C) 2024 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <ps5/kernel.h>
#include "elfldr.h"
#include "elfldr_elf.c"
#include "pt.h"
/**
* sceKernelSpawn() is not available in libkernel_web, which is what is used by
* the webkit exploit entry point. However, we do not actually use it during
* bootstraping, hence we just define an empty implementation to silence the
* linker.
**/
int sceKernelSpawn(pid_t* pid, int dbg, const char* binpath, const char* rootpath,
char* const argv[]) {
return -1;
}
int main() {
uint8_t privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
uint8_t qa_flags[16];
uint8_t caps[16];
int error;
pid_t pid;
if(kernel_get_qaflags(qa_flags)) {
puts("[elfldr.elf] kernel_get_qa_flags() failed");
return -1;
}
qa_flags[1] |= 0x03;
if(kernel_set_qaflags(qa_flags)) {
puts("[elfldr.elf] kernel_set_qa_flags() failed");
return -1;
}
if((pid=elfldr_find_pid("ScePartyDaemon")) < 0) {
puts("[elfldr.elf] elfldr_find_pid() failed");
return -1;
}
if(pt_attach(pid)) {
perror("[elfldr.elf] pt_attach");
return -1;
}
if(kernel_get_ucred_caps(pid, caps)) {
puts("[elfldr.elf] kern_get_ucred_caps() failed");
pt_detach(pid);
return -1;
}
if(kernel_set_ucred_caps(pid, privcaps)) {
puts("[elfldr.elf] kern_set_ucred_caps() failed");
pt_detach(pid);
return -1;
}
error = elfldr_exec(pid, elfldr_elf);
if(kernel_set_ucred_caps(pid, caps)) {
puts("[elfldr.elf] kern_set_ucred_caps() failed");
pt_detach(pid);
return -1;
}
if(pt_detach(pid)) {
perror("[elfldr.elf] pt_detach");
return -1;
}
return error;
}
-35
View File
@@ -1,35 +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"
extern int libc_init(const payload_args_t *args);
extern int kern_init(const payload_args_t *args);
extern int main(const payload_args_t *args);
void
_start(payload_args_t *args) {
if((*args->payloadout=libc_init(args))) {
return;
}
if((*args->payloadout=kern_init(args))) {
return;
}
*args->payloadout = main(args);
}
-199
View File
@@ -1,199 +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 "dynlib.h"
#include "elf.h"
#include "kern.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;
size_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;
intptr_t mapbase;
size_t mapsize;
size_t textsize;
intptr_t database;
size_t datasize;
intptr_t unknown1;
size_t unknown1size;
intptr_t vaddrbase;
intptr_t relocbase;
intptr_t entry;
uint32_t tlsindex;
intptr_t tlsinit;
size_t tlsinitsize;
size_t tlssize;
off_t tlsoffset;
size_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 = kern_get_proc(pid);
dynlib_dynsec_t dynsec;
Elf64_Sym *symtab;
dynlib_obj_t obj;
intptr_t kaddr;
intptr_t vaddr;
char *strtab;
if(!(kproc=kern_get_proc(pid))) {
return 0;
}
if(kern_copyout(kproc + 0x3e8, &kaddr, sizeof(kaddr)) < 0) {
return 0;
}
do {
if(kern_copyout(kaddr, &kaddr, sizeof(kaddr)) < 0) {
return 0;
}
if(!kaddr) {
return 0;
}
if(kern_copyout(kaddr + __builtin_offsetof(dynlib_obj_t, handle),
&obj.handle, sizeof(obj.handle)) < 0) {
return 0;
}
} while(obj.handle != handle);
if(kern_copyout(kaddr, &obj, sizeof(obj)) < 0) {
return 0;
}
if(kern_copyout(obj.dynsec, &dynsec, sizeof(dynsec)) < 0) {
return 0;
}
if(!(symtab=malloc(dynsec.symtabsize))) {
return 0;
}
if(kern_copyout(dynsec.symtab, symtab, dynsec.symtabsize) < 0) {
free(symtab);
return 0;
}
if(!(strtab=malloc(dynsec.strtabsize))) {
free(symtab);
return 0;
}
if(kern_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");
}
-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/>. */
#pragma once
#include "libc.h"
intptr_t dynlib_resolve(pid_t pid, uint32_t handle, const char *nid);
intptr_t dynlib_resolve_sceKernelDlsym(pid_t pid);
-105
View File
@@ -1,105 +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
#define ET_EXEC 2
#define ET_DYN 3
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define SHT_RELA 4
#define R_X86_64_GLOB_DAT 6
#define R_X86_64_JMP_SLOT 7
#define R_X86_64_RELATIVE 8
#define PF_X 1
#define PF_W 2
#define PF_R 4
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_STRTAB 5
#define DT_SYMTAB 6
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 char e_ident[16];
unsigned short e_type;
unsigned short e_machine;
unsigned int e_version;
unsigned long e_entry;
unsigned long e_phoff;
unsigned long e_shoff;
unsigned int e_flags;
unsigned short e_ehsize;
unsigned short e_phentsize;
unsigned short e_phnum;
unsigned short e_shentsize;
unsigned short e_shnum;
unsigned short e_shstrndx;
} Elf64_Ehdr;
typedef struct {
unsigned int p_type;
unsigned int p_flags;
unsigned long p_offset;
unsigned long p_vaddr;
unsigned long p_paddr;
unsigned long p_filesz;
unsigned long p_memsz;
unsigned long p_align;
} Elf64_Phdr;
typedef struct {
unsigned int sh_name;
unsigned int sh_type;
unsigned long sh_flags;
unsigned long sh_addr;
unsigned long sh_offset;
unsigned long sh_size;
unsigned int sh_link;
unsigned int sh_info;
unsigned long sh_addralign;
unsigned long sh_entsize;
} Elf64_Shdr;
typedef struct {
unsigned long r_offset;
unsigned long r_info;
long r_addend;
} Elf64_Rela;
-34
View File
@@ -1,34 +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/>. */
OUTPUT_FORMAT("elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
PHDRS {
ph_text PT_LOAD FLAGS (0x1 | 0x4);
ph_rodata PT_LOAD FLAGS (0x4);
ph_data PT_LOAD FLAGS (0x2 | 0x4);
}
SECTIONS {
.text : { *(.text .text.*) } : ph_text
. = ALIGN(0x4000);
.rodata : { *(.rodata .rodata.*) } : ph_rodata
. = ALIGN(0x4000);
.data : { *(.data .data.*) } : ph_data
.bss : { *(.bss .bss.*) *(COMMON) }
}
+182 -415
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,18 +14,31 @@ 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 "dynlib.h"
#include "elf.h"
#include "kern.h"
#include "libc.h"
#include <elf.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <ps5/kernel.h>
#include <ps5/mdbg.h>
#include "elfldr.h"
#include "pt.h"
#include "syscall.h"
/**
* Parameters for the ELF loader.
**/
#define ELFLDR_UNIX_SOCKET "/system_tmp/elfldr.sock"
#ifndef IPV6_2292PKTOPTIONS
#define IPV6_2292PKTOPTIONS 25
#endif
/**
@@ -50,7 +63,8 @@ typedef struct elfldr_ctx {
} elfldr_ctx_t;
#include "payload_launchpad_elf.c"
int sceKernelSpawn(pid_t* pid, int dbg, const char* binpath, const char* rootpath,
char* const argv[]);
/**
@@ -61,7 +75,7 @@ r_relative(elfldr_ctx_t *ctx, Elf64_Rela* rela) {
intptr_t loc = ctx->base_addr + rela->r_offset;
intptr_t val = ctx->base_addr + rela->r_addend;
return pt_setlong(ctx->pid, loc, val);
return mdbg_copyin(ctx->pid, &val, loc, sizeof(val));
}
@@ -80,8 +94,8 @@ pt_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
return -1;
}
if(pt_copyin(ctx->pid, ctx->elf+phdr->p_offset, addr, phdr->p_memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] pt_copyin");
if(mdbg_copyin(ctx->pid, ctx->elf+phdr->p_offset, addr, phdr->p_memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] mdbg_copyin");
return -1;
}
@@ -108,8 +122,8 @@ pt_reload(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
}
// Backup data
else if(pt_copyout(ctx->pid, addr, data, memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] pt_copyout");
else if(mdbg_copyout(ctx->pid, addr, data, memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] mdbg_copyout");
error = -1;
}
@@ -143,8 +157,8 @@ pt_reload(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
// Resore data
else {
if(pt_copyin(ctx->pid, data, addr, memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] pt_copyin");
if(mdbg_copyin(ctx->pid, data, addr, memsz)) {
pt_perror(ctx->pid, "[elfldr.elf] mdbg_copyin");
error = -1;
}
pt_munmap(ctx->pid, addr, memsz);
@@ -162,7 +176,7 @@ pt_reload(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
* Load an ELF into the address space of a process with the given pid.
**/
static intptr_t
elfldr_load(pid_t pid, uint8_t *elf, size_t size) {
elfldr_load(pid_t pid, uint8_t *elf) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
Elf64_Shdr *shdr = (Elf64_Shdr*)(elf + ehdr->e_shoff);
@@ -273,7 +287,7 @@ elfldr_load(pid_t pid, uint8_t *elf, size_t size) {
/**
* Create payload args in the address space of the process with the given pid.
**/
intptr_t
static intptr_t
elfldr_payload_args(pid_t pid) {
int victim_sock;
int master_sock;
@@ -292,12 +306,12 @@ elfldr_payload_args(pid_t pid) {
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);
mdbg_setint(pid, buf+0x00, 20);
mdbg_setint(pid, buf+0x04, IPPROTO_IPV6);
mdbg_setint(pid, buf+0x08, IPV6_TCLASS);
mdbg_setint(pid, buf+0x0c, 0);
mdbg_setint(pid, buf+0x10, 0);
mdbg_setint(pid, buf+0x14, 0);
if(pt_setsockopt(pid, master_sock, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, 24)) {
pt_perror(pid, "[elfldr.elf] pt_setsockopt");
return 0;
@@ -308,18 +322,18 @@ elfldr_payload_args(pid_t pid) {
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);
mdbg_setint(pid, buf+0x00, 0);
mdbg_setint(pid, buf+0x04, 0);
mdbg_setint(pid, buf+0x08, 0);
mdbg_setint(pid, buf+0x0c, 0);
mdbg_setint(pid, buf+0x10, 0);
if(pt_setsockopt(pid, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20)) {
pt_perror(pid, "[elfldr.elf] pt_setsockopt");
return 0;
}
if(kern_overlap_sockets(pid, master_sock, victim_sock)) {
puts("[elfldr.elf] kern_overlap_sockets() failed");
if(kernel_overlap_sockets(pid, master_sock, victim_sock)) {
puts("[elfldr.elf] kernel_overlap_sockets() failed");
return 0;
}
@@ -331,32 +345,150 @@ elfldr_payload_args(pid_t pid) {
pipe1 = pt_getint(pid, buf+4);
intptr_t args = buf;
intptr_t dlsym = dynlib_resolve_sceKernelDlsym(pid);
intptr_t dlsym = pt_resolve(pid, "LwG8g3niqwA");
intptr_t rwpipe = buf + 0x100;
intptr_t rwpair = buf + 0x200;
intptr_t kpipe_addr = kern_get_proc_file(pid, pipe0);
intptr_t kpipe_addr = kernel_get_proc_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, kern_get_data_baseaddr());
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);
mdbg_setlong(pid, args + 0x00, dlsym);
mdbg_setlong(pid, args + 0x08, rwpipe);
mdbg_setlong(pid, args + 0x10, rwpair);
mdbg_setlong(pid, args + 0x18, kpipe_addr);
mdbg_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
mdbg_setlong(pid, args + 0x28, payloadout);
mdbg_setint(pid, rwpipe + 0, pipe0);
mdbg_setint(pid, rwpipe + 4, pipe1);
mdbg_setint(pid, rwpair + 0, master_sock);
mdbg_setint(pid, rwpair + 4, victim_sock);
mdbg_setint(pid, payloadout, 0);
return args;
}
/**
* Get the pid of a process with the given name.
**/
static pid_t
static int
elfldr_raise_privileges(pid_t pid) {
uint8_t caps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
intptr_t vnode;
if(!(vnode=kernel_get_root_vnode())) {
puts("[elfldr.elf] kernel_get_root_vnode() failed");
return -1;
}
if(kernel_set_proc_rootdir(pid, vnode)) {
puts("[elfldr.elf] kernel_set_proc_rootdir() failed");
return -1;
}
if(kernel_set_ucred_uid(pid, 0)) {
puts("[elfldr.elf] kernel_set_ucred_uid() failed");
return -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
puts("[elfldr.elf] kernel_set_ucred_caps() failed");
return -1;
}
return 0;
}
int
elfldr_exec(pid_t pid, uint8_t *elf) {
intptr_t entry;
intptr_t args;
struct reg r;
if(pt_getregs(pid, &r)) {
perror("[elfldr.elf] pt_getregs");
return -1;
}
if(!(entry=elfldr_load(pid, elf))) {
puts("[elfldr.elf] elfldr_load() failed");
return -1;
}
if(!(args=elfldr_payload_args(pid))) {
puts("[elfldr.elf] elfldr_payload_args() failed");
return -1;
}
r.r_rip = entry;
r.r_rdi = args;
if(pt_setregs(pid, &r)) {
perror("[elfldr.elf] pt_setregs");
return -1;
}
return 0;
}
int
elfldr_spawn(uint8_t *elf) {
uint8_t int3instr = 0xcc;
char* argv[] = {0, 0};
struct reg r = {0};
intptr_t brkpoint;
intptr_t rootdir;
pid_t pid = -1;
// SceSpZeroConf
argv[0] = "/system/vsh/app/NPXS40112/eboot.bin";
if(sceKernelSpawn(&pid, 1, argv[0], NULL, argv)) {
perror("sceKernelSpawn");
pt_detach(pid);
return -1;
}
if(!(brkpoint=kernel_dynlib_entry_addr(pid, 0))) {
puts("[elfldr.elf] kernel_dynlib_entry_addr() failed");
pt_detach(pid);
return -1;
}
if(mdbg_copyin(pid, &int3instr, brkpoint, sizeof(int3instr))) {
perror("[elfldr.elf] mdbg_copyin");
pt_detach(pid);
return -1;
}
if(pt_continue(pid)) {
perror("[elfldr.elf] pt_continue");
pt_detach(pid);
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
perror("[elfldr.elf] waitpid");
pt_detach(pid);
return -1;
}
if(elfldr_raise_privileges(pid)) {
puts("[elfldr.elf] Unable to raise privileges");
pt_detach(pid);
return -1;
}
if(elfldr_exec(pid, elf)) {
pt_setregs(pid, &r);
}
if(pt_detach(pid)) {
perror("[elfldr.elf] pt_detach");
return -1;
}
return pid;
}
pid_t
elfldr_find_pid(const char* name) {
int mib[4] = {1, 14, 8, 0};
pid_t pid = -1;
@@ -394,368 +526,3 @@ elfldr_find_pid(const char* name) {
return pid;
}
/**
* Send a file descriptor to a process that listens on a UNIX domain socket
* with the given socket path.
**/
static int
elfldr_sendfd(const char *sockpath, int fd) {
struct sockaddr_un addr = {0};
struct msghdr msg = {0};
struct cmsghdr *cmsg;
uint8_t buf[24];
int sockfd;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, sockpath);
memset(&msg, 0, sizeof(msg));
msg.msg_name = &addr;
msg.msg_namelen = sizeof(struct sockaddr_un);
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
memset(buf, 0, sizeof(buf));
cmsg = (struct cmsghdr *)buf;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = 20;
*((int *)&buf[16]) = fd;
if((sockfd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("[elfldr.elf] socket");
return -1;
}
if(sendmsg(sockfd, &msg, 0) < 0) {
perror("[elfldr.elf] sendmsg");
close(sockfd);
return -1;
}
return close(sockfd);
}
/**
* Pipe stdout of a process with the given pid to a file descriptor, where
* communication is done via a UNIX domain socket of the given socket path.
**/
static int
elfldr_stdout(pid_t pid, const char *sockpath, int fd) {
struct sockaddr_un addr = {0};
intptr_t ptbuf;
int sockfd;
if((ptbuf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
pt_perror(pid, "[elfldr.elf] pt_mmap");
return -1;
}
if((sockfd=pt_socket(pid, AF_UNIX, SOCK_DGRAM, 0)) < 0) {
pt_perror(pid, "[elfldr.elf] pt_socket");
pt_munmap(pid, ptbuf, PAGE_SIZE);
return -1;
}
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, sockpath);
pt_copyin(pid, &addr, ptbuf, sizeof(addr));
if(pt_bind(pid, sockfd, ptbuf, sizeof(addr))) {
pt_perror(pid, "[elfldr.elf] pt_bind");
pt_munmap(pid, ptbuf, PAGE_SIZE);
pt_close(pid, sockfd);
return -1;
}
if(elfldr_sendfd(sockpath, fd)) {
pt_munmap(pid, ptbuf, PAGE_SIZE);
pt_close(pid, sockfd);
return -1;
}
intptr_t hdr = ptbuf;
intptr_t iov = ptbuf + 0x100;
intptr_t control = ptbuf + 0x200;
pt_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_name), 0);
pt_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_namelen), 0);
pt_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_iov), iov);
pt_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_iovlen), 1);
pt_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_control), control);
pt_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_controllen), 24);
if(pt_recvmsg(pid, sockfd, hdr, 0) < 0) {
pt_perror(pid, "[elfldr.elf] pt_recvmsg");
pt_munmap(pid, ptbuf, PAGE_SIZE);
pt_close(pid, sockfd);
return -1;
}
if((fd=pt_getint(pid, control+16)) < 0) {
pt_munmap(pid, ptbuf, PAGE_SIZE);
pt_close(pid, sockfd);
return -1;
}
if(pt_munmap(pid, ptbuf, PAGE_SIZE)) {
pt_perror(pid, "[elfldr.elf] pt_munmap");
pt_close(pid, sockfd);
pt_close(pid, fd);
}
if(pt_close(pid, sockfd)) {
pt_perror(pid, "[elfldr.elf] pt_close");
pt_close(pid, fd);
return -1;
}
return fd;
}
int
elfldr_exec(const char* procname, int stdout, uint8_t *elf, size_t size) {
uint8_t privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
uint8_t caps[16];
intptr_t payload_entry;
intptr_t payload_args;
intptr_t launch_entry;
struct reg jmp_reg;
struct reg bak_reg;
pid_t pid;
if((pid=elfldr_find_pid(procname)) < 0) {
puts("[elfldr.elf] elfldr_find_pid() failed");
return -1;
}
if(pt_attach(pid)) {
perror("[elfldr.elf] pt_attach");
return -1;
}
if(kern_get_ucred_caps(pid, caps)) {
puts("[elfldr.elf] kern_get_ucred_caps() failed");
pt_detach(pid);
return -1;
}
if(kern_set_ucred_caps(pid, privcaps)) {
puts("[elfldr.elf] kern_set_ucred_caps() failed");
pt_detach(pid);
return -1;
}
if(pt_getregs(pid, &bak_reg)) {
perror("[elfldr.elf] pt_getregs");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
if(stdout > 0) {
unlink(ELFLDR_UNIX_SOCKET);
if((stdout=elfldr_stdout(pid, ELFLDR_UNIX_SOCKET, stdout)) < 0) {
puts("[elfldr.elf] elfldr_stdout() failed");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
unlink(ELFLDR_UNIX_SOCKET);
}
if(!(payload_entry=elfldr_load(pid, elf, size))) {
puts("[elfldr.elf] elfldr_load() failed");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
if(!(payload_args=elfldr_payload_args(pid))) {
puts("[elfldr.elf] elfldr_args() failed");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
if(!(launch_entry=elfldr_load(pid, payload_launchpad_elf,
payload_launchpad_elf_len))) {
puts("[elfldr.elf] elfldr_load() failed");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
jmp_reg.r_rip = launch_entry;
jmp_reg.r_rsp -= 8;
jmp_reg.r_rdi = payload_entry;
jmp_reg.r_rsi = payload_args;
jmp_reg.r_rdx = stdout;
if(pt_setregs(pid, &jmp_reg)) {
perror("[elfldr.elf] pt_setregs");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
if(pt_continue(pid)) {
perror("[elfldr.elf] pt_continue");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
perror("[elfldr.elf] waitpid");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
}
if(pt_setregs(pid, &bak_reg)) {
perror("[elfldr.elf] pt_setregs");
kern_set_ucred_caps(pid, caps);
pt_detach(pid);
return -1;
}
puts("[elfldr.elf] running ELF...");
kern_set_ucred_caps(pid, caps);
if(pt_detach(pid)) {
perror("[elfldr.elf] pt_detach");
return -1;
}
return 0;
}
/**
* Read an ELF from a given socket connection.
**/
static ssize_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 == 0) {
perror("[elfldr.elf] realloc");
return -1;
}
memcpy(*data + offset, buf, len);
offset += len;
}
return offset;
}
/**
* Accept ELFs from the given port, and execute them inside the process
* with the given name.
**/
int
elfldr_serve(const char* procname, uint16_t port) {
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t addr_len;
uint8_t *elf;
size_t size;
int connfd;
int srvfd;
if((srvfd=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("[elfldr.elf] socket");
return -1;
}
if(setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
perror("[elfldr.elf] setsockopt");
close(srvfd);
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if(bind(srvfd, &server_addr, sizeof(server_addr)) != 0) {
perror("[elfldr.elf] bind");
close(srvfd);
return -1;
}
if(listen(srvfd, 5) != 0) {
perror("[elfldr.elf] listen");
close(srvfd);
return -1;
}
addr_len = sizeof(client_addr);
while(1) {
if((connfd=accept(srvfd, &client_addr, &addr_len)) < 0) {
perror("[elfldr.elf] accept");
close(connfd);
close(srvfd);
return -1;
}
// We got a connection, read ELF and launch it in the given process.
if((size=elfldr_read(connfd, &elf))) {
elfldr_exec(procname, connfd, elf, size);
free(elf);
}
close(connfd);
}
close(srvfd);
return 0;
}
int
elfldr_socksrv(const char* procname, uint16_t port) {
pid_t pid;
// kill previous instances of elfldr.elf
while((pid=elfldr_find_pid("elfldr.elf")) > 0) {
if(kill(pid, SIGKILL)) {
perror("[elfldr.elf] kill");
}
sleep(1);
}
// fork process
if((pid=syscall(SYS_rfork, RFPROC | RFNOWAIT | RFFDG)) < 0) {
perror("[elfldr.elf] rfork");
return -1;
}
// parent process should just return
if(pid) {
return pid;
}
// initialize child process
syscall(SYS_setsid); // become session leader
syscall(0x1d0, -1, "elfldr.elf"); // set proc name
dup2(open("/dev/console", 1), 1); // set stdout to /dev/klog
dup2(open("/dev/console", 1), 2); // set stderr to /dev/klog
while(1) {
puts("[elfldr.elf] Launching socket server...");
elfldr_serve(procname, port);
sleep(3);
}
// unreacheable
return syscall(SYS_exit, 0);
}
+5 -13
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,18 +16,10 @@ along with this program; see the file COPYING. If not, see
#pragma once
#include "libc.h"
#include <unistd.h>
/**
* Execute an ELF inside the process with the given name, and pipe outout
* to the given stdout file descriptor.
**/
int elfldr_exec(const char* procname, int stdout, uint8_t *elf, size_t size);
pid_t elfldr_find_pid(const char* name);
int elfldr_exec(pid_t pid, uint8_t *elf);
/**
* Launch a socket server that accapts ELF files that are executed in the
* process with given name, where stdout is piped to the connecting socket.
**/
int elfldr_socksrv(const char* procname, uint16_t port);
pid_t elfldr_spawn(uint8_t *elf);
-65
View File
@@ -1,65 +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"
static __attribute__ ((used)) long ptr_syscall;
asm(".intel_syntax noprefix\n"
".global syscall\n"
".type syscall @function\n"
"syscall:\n"
" mov rax, rdi\n" // sysno
" mov rdi, rsi\n" // arg1
" mov rsi, rdx\n" // arg2
" mov rdx, rcx\n" // arg3
" mov r10, r8\n" // arg4
" mov r8, r9\n" // arg5
" mov r9, qword ptr [rsp + 8]\n" // arg6
" jmp qword ptr [rip + ptr_syscall]\n" // syscall
" ret\n"
);
long syscall(long sysno, ...);
void
klog(const char *s) {
syscall(0x259, 7, "<118>", 0);
syscall(0x259, 7, s, 0);
syscall(0x259, 7, "\n", 0);
}
void
_start(const payload_args_t *args) {
void (*puts)(const char*);
if((args->sceKernelDlsym(0x2, "puts", &puts))) {
return;
}
if(args->sceKernelDlsym(0x2001, "getpid", &ptr_syscall)) {
return;
}
ptr_syscall += 0xa; // jump directly to syscall instruction
klog("[hello_world.elf] Hello, world!");
puts("[hello_world.elf] Hello, world!");
}
-450
View File
@@ -1,450 +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 "libc.h"
#include "kern.h"
#include "payload.h"
static int (*sysctlbyname)(const char*, void*, size_t*, const void*, size_t);
static intptr_t ADDRESS_DATA_BASE = 0;
static intptr_t ADDRESS_ALLPROC = 0;
static intptr_t ADDRESS_QA_FLAGS = 0;
static off_t OFFSET_PROC_P_UCRED = 0x40;
static off_t OFFSET_PROC_P_PID = 0xBC;
static off_t OFFSET_UCRED_CR_SCEAUTHID = 0x58;
static off_t OFFSET_UCRED_CR_SCECAPS = 0x60;
static int master_sock = -1;
static int victim_sock = -1;
static int rw_pipe[2] = {-1, -1};
static intptr_t pipe_addr = 0;
static uint32_t
kern_get_fw_version(void) {
uint32_t version = 0;
size_t size = sizeof(version);
if(sysctlbyname("kern.sdk_version", &version, &size, 0, 0)) {
return 0;
}
return version;
}
/**
*
**/
int
kern_init(const payload_args_t *args) {
int error = 0;
if((error=args->sceKernelDlsym(0x2001, "sysctlbyname", &sysctlbyname))) {
return error;
}
if((master_sock=args->rwpair[0]) < 0) {
return -1;
}
if((victim_sock=args->rwpair[1]) < 0) {
return -1;
}
if((rw_pipe[0]=args->rwpipe[0]) < 0) {
return -1;
}
if((rw_pipe[1]=args->rwpipe[1]) < 0) {
return -1;
}
if(!(pipe_addr=args->kpipe_addr)) {
return -1;
}
if(!(ADDRESS_DATA_BASE=args->kdata_base_addr)) {
return -1;
}
switch(kern_get_fw_version() & 0xffff0000) {
case 0x3000000:
case 0x3100000:
case 0x3200000:
case 0x3210000:
ADDRESS_ALLPROC = ADDRESS_DATA_BASE + 0x276DC58;
ADDRESS_QA_FLAGS = ADDRESS_DATA_BASE + 0x6466498;
break;
case 0x4020000:
ADDRESS_ALLPROC = ADDRESS_DATA_BASE + 0x27EDCB8;
ADDRESS_QA_FLAGS = ADDRESS_DATA_BASE + 0x6505498;
break;
case 0x4000000:
case 0x4030000:
case 0x4500000:
case 0x4510000:
ADDRESS_ALLPROC = ADDRESS_DATA_BASE + 0x27EDCB8;
ADDRESS_QA_FLAGS = ADDRESS_DATA_BASE + 0x6506498;
break;
default:
return -1;
}
return 0;
}
static int
kern_write(intptr_t addr, unsigned long *data) {
intptr_t victim_buf[3];
// sanity check for invalid kernel pointers
if(!(addr & 0xffff000000000000)) {
return -1;
}
victim_buf[0] = addr;
victim_buf[1] = 0;
victim_buf[2] = 0;
if(setsockopt(master_sock, IPPROTO_IPV6, IPV6_PKTINFO, victim_buf, 0x14)) {
return -1;
}
if(setsockopt(victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, data, 0x14)) {
return -1;
}
return 0;
}
int
kern_copyin(const void *udaddr, intptr_t kaddr, size_t len) {
intptr_t write_buf[3];
// Set pipe flags
write_buf[0] = 0;
write_buf[1] = 0x4000000000000000;
write_buf[2] = 0;
if(kern_write(pipe_addr, (unsigned long *) &write_buf)) {
return -1;
}
// Set pipe data addr
write_buf[0] = kaddr;
write_buf[1] = 0;
write_buf[2] = 0;
if(kern_write(pipe_addr + 0x10, (unsigned long *) &write_buf)) {
return -1;
}
// Perform write across pipe
if(write(rw_pipe[1], udaddr, len) < 0) {
return -1;
}
return 0;
}
int
kern_copyout(intptr_t kaddr, void *udaddr, size_t len) {
intptr_t write_buf[3];
// Set pipe flags
write_buf[0] = 0x4000000040000000;
write_buf[1] = 0x4000000000000000;
write_buf[2] = 0;
if(kern_write(pipe_addr, (unsigned long *) &write_buf)) {
return -1;
}
// Set pipe data addr
write_buf[0] = kaddr;
write_buf[1] = 0;
write_buf[2] = 0;
if(kern_write(pipe_addr + 0x10, (unsigned long *) &write_buf)) {
return -1;
}
// Perform read across pipe
if(read(rw_pipe[0], udaddr, len) < 0) {
return -1;
}
return 0;
}
intptr_t
kern_get_data_baseaddr(void) {
return ADDRESS_DATA_BASE;
}
int
kern_get_qa_flags(uint8_t val[16]) {
return kern_copyout(ADDRESS_QA_FLAGS, val, 16);
}
int
kern_set_qa_flags(const uint8_t val[16]) {
return kern_copyin(val, ADDRESS_QA_FLAGS, 16);
}
intptr_t
kern_get_proc(pid_t pid) {
pid_t other_pid = 0;
intptr_t addr = 0;
intptr_t next = 0;
if(kern_copyout(ADDRESS_ALLPROC, &addr, sizeof(addr))) {
return 0;
}
while(addr) {
if(kern_copyout(addr + OFFSET_PROC_P_PID, &other_pid,
sizeof(other_pid))) {
return 0;
}
if(pid == other_pid) {
break;
}
if(kern_copyout(addr, &next, sizeof(next))) {
return 0;
}
addr = next;
}
return addr;
}
static intptr_t
kern_get_proc_ucred(pid_t pid) {
intptr_t proc = 0;
intptr_t ucred = 0;
if(!(proc=kern_get_proc(pid))) {
return 0;
}
if(kern_copyout(proc + OFFSET_PROC_P_UCRED, &ucred,
sizeof(ucred))) {
return 0;
}
return ucred;
}
int
kern_get_ucred_auth_id(pid_t pid, uint64_t *val) {
intptr_t ucred = 0;
if(!(ucred=kern_get_proc_ucred(pid))) {
return -1;
}
if(kern_copyout(ucred + OFFSET_UCRED_CR_SCEAUTHID, val, 8)) {
return -1;
}
return 0;
}
int
kern_set_ucred_auth_id(pid_t pid, uint64_t val) {
intptr_t ucred = 0;
if(!(ucred=kern_get_proc_ucred(pid))) {
return -1;
}
if(kern_copyin(&val, ucred + OFFSET_UCRED_CR_SCEAUTHID, 8)) {
return -1;
}
return 0;
}
int
kern_get_ucred_caps(pid_t pid, uint8_t caps[16]) {
intptr_t ucred = 0;
if(!(ucred=kern_get_proc_ucred(pid))) {
return -1;
}
if(kern_copyout(ucred + OFFSET_UCRED_CR_SCECAPS, caps, 16)) {
return -1;
}
return 0;
}
int
kern_set_ucred_caps(pid_t pid, const uint8_t caps[16]) {
intptr_t ucred = 0;
if(!(ucred=kern_get_proc_ucred(pid))) {
return -1;
}
if(kern_copyin(caps, ucred + OFFSET_UCRED_CR_SCECAPS, 16)) {
return -1;
}
return 0;
}
intptr_t
kern_get_proc_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=kern_get_proc(pid))) {
return 0;
}
if(kern_copyout(proc + 0x48, &p_fd, sizeof(p_fd))) {
return 0;
}
if(kern_copyout(p_fd, &fd_files, sizeof(fd_files))) {
return 0;
}
if(kern_copyout(fd_files + 8 + (0x30 * fd),
&fde_file, sizeof(fde_file))) {
return 0;
}
if(kern_copyout(fde_file, &file, sizeof(file))) {
return 0;
}
return file;
}
static intptr_t
kern_get_proc_inp6_outputopts(pid_t pid, int fd) {
intptr_t inp6_outputopts;
intptr_t so_pcb;
intptr_t file;
if(!(file=kern_get_proc_file(pid, fd))) {
return 0;
}
if(kern_copyout(file + 0x18, &so_pcb, sizeof(so_pcb))) {
return 0;
}
if(kern_copyout(so_pcb + 0x120, &inp6_outputopts,
sizeof(inp6_outputopts))) {
return 0;
}
return inp6_outputopts;
}
static int
kern_inc_so_count(pid_t pid, int fd) {
intptr_t file;
int so_count;
if(!(file=kern_get_proc_file(pid, fd))) {
return -1;
}
if(kern_copyout(file, &so_count, sizeof(so_count))) {
return -1;
}
so_count++;
if(kern_copyin(&so_count, file, sizeof(so_count))) {
return -1;
}
return 0;
}
int
kern_overlap_sockets(pid_t pid, int master_sock, int victim_sock) {
intptr_t master_inp6_outputopts;
intptr_t victim_inp6_outputopts;
intptr_t pktinfo;
unsigned int tclass;
if(kern_inc_so_count(pid, master_sock)) {
return -1;
}
if(!(master_inp6_outputopts=kern_get_proc_inp6_outputopts(pid,
master_sock))) {
return -1;
}
if(kern_inc_so_count(pid, victim_sock)) {
return -1;
}
if(!(victim_inp6_outputopts=kern_get_proc_inp6_outputopts(pid,
victim_sock))) {
return -1;
}
pktinfo = victim_inp6_outputopts + 0x10;
if(kern_copyin(&pktinfo, master_inp6_outputopts + 0x10,
sizeof(pktinfo))) {
return -1;
}
tclass = 0x13370000;
if(kern_copyin(&tclass, master_inp6_outputopts + 0xc0, sizeof(tclass))) {
return -1;
}
return 0;
}
-37
View File
@@ -1,37 +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 "libc.h"
intptr_t kern_get_data_baseaddr(void);
intptr_t kern_get_proc(pid_t pid);
intptr_t kern_get_proc_file(pid_t pid, int fd);
int kern_copyin(const void *udaddr, intptr_t kaddr, size_t len);
int kern_copyout(intptr_t kaddr, void *udaddr, size_t len);
int kern_get_qa_flags(uint8_t flags[16]);
int kern_set_qa_flags(const uint8_t flags[16]);
int kern_get_ucred_auth_id(pid_t pid, uint64_t *auth_id);
int kern_set_ucred_auth_id(pid_t pid, uint64_t auth_id);
int kern_get_ucred_caps(pid_t pid, uint8_t caps[16]);
int kern_set_ucred_caps(pid_t pid, const uint8_t caps[16]);
int kern_overlap_sockets(pid_t pid, int master_sock, int victim_sock);
-364
View File
@@ -1,364 +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 "kern.h"
#include "libc.h"
#include "payload.h"
#include "syscall.h"
static int (*sce_htons)(uint16_t);
static int (*sce_sleep)(int);
static void* (*sce_malloc)(size_t);
static void* (*sce_realloc)(void*, size_t);
static void (*sce_free)(void*);
static void* (*sce_memset)(void*, int, size_t);
static void* (*sce_memcpy)(void*, const void*, size_t);
static char* (*sce_strcpy)(const char*, const char*);
static int (*sce_strcmp)(const char*, const char*);
static int (*sce_strncmp)(const char*, const char*, size_t);
static int (*sce_strcat)(char*, const char*);
static void (*sce_puts)(const char*);
static void (*sce_perror)(const char*);
static char* (*sce_strerror)(int);
static int* (*sce_errno)(void);
static intptr_t sce_syscall;
asm(".intel_syntax noprefix\n"
".global syscall\n"
".type syscall @function\n"
"syscall:\n"
" mov rax, rdi\n" // sysno
" mov rdi, rsi\n" // arg1
" mov rsi, rdx\n" // arg2
" mov rdx, rcx\n" // arg3
" mov r10, r8\n" // arg4
" mov r8, r9\n" // arg5
" mov r9, qword ptr [rsp + 8]\n" // arg6
" jmp qword ptr [rip + sce_syscall]\n" // syscall
" ret\n"
);
int
libc_init(const payload_args_t *args) {
int error;
if((error=args->sceKernelDlsym(0x2001, "htons", &sce_htons))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "sleep", &sce_sleep))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "getpid", &sce_syscall))) {
return error;
}
sce_syscall += 0xa; // jump directly to syscall instruction
if((error=args->sceKernelDlsym(0x2, "malloc", &sce_malloc))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "realloc", &sce_realloc))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "free", &sce_free))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "memset", &sce_memset))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "memcpy", &sce_memcpy))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "strcpy", &sce_strcpy))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "strcmp", &sce_strcmp))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "strncmp", &sce_strncmp))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "strcat", &sce_strcat))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "puts", &sce_puts))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "perror", &sce_perror))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "strerror", &sce_strerror))) {
return error;
}
return 0;
}
int
open(const char *path, int flags) {
return (int)syscall(SYS_open, path, flags);
}
int
unlink(const char *path) {
return (int)syscall(SYS_unlink, path);
}
ssize_t
read(int fd, void *buf, size_t cnt) {
return syscall(SYS_read, fd, buf, cnt);
}
ssize_t
write(int fd, const void *buf, size_t cnt) {
return syscall(SYS_write, fd, buf, cnt);
}
int
dup2(int oldfd, int newfd) {
return (int)syscall(SYS_dup2, oldfd, newfd);
}
int
close(int fd) {
return (int)syscall(SYS_close, fd);
}
int
socket(int dom, int ty, int proto) {
return (int)syscall(SYS_socket, dom, ty, proto);
}
int
setsockopt(int fd, int lvl, int name, const void *val, socklen_t len) {
return (int)syscall(SYS_setsockopt, fd, lvl, name, val, len);
}
int
bind(int fd, const struct sockaddr_in *addr, socklen_t addr_len) {
return (int)syscall(SYS_bind, fd, addr, addr_len);
}
int
listen(int fd, int backlog) {
return (int)syscall(SYS_listen, fd, backlog);
}
int
accept(int fd, struct sockaddr_in *addr, socklen_t *addr_len) {
return (int)syscall(SYS_accept, fd, addr, addr_len);
}
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
return (ssize_t)syscall(SYS_sendmsg, fd, msg, flags);
}
pid_t
getpid(void) {
return (pid_t)syscall(SYS_getpid);
}
int
kill(pid_t pid, int sig) {
return (int)syscall(SYS_kill, pid, sig);
}
pid_t
rfork(int flags) {
return (pid_t)syscall(SYS_rfork, flags);
}
pid_t
waitpid(pid_t pid, int *status, int opts) {
return (pid_t)syscall(SYS_wait4, pid, status, opts, 0);
}
int
ptrace(int request, pid_t pid, intptr_t addr, int data) {
uint8_t privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
pid_t mypid = getpid();
uint8_t caps[16];
uint64_t authid;
int ret;
if(kern_get_ucred_auth_id(mypid, &authid)) {
return -1;
}
if(kern_get_ucred_caps(mypid, caps)) {
return -1;
}
if(kern_set_ucred_auth_id(mypid, 0x4800000000010003l)) {
return -1;
}
if(kern_set_ucred_caps(mypid, privcaps)) {
return -1;
}
ret = (int)syscall(SYS_ptrace, request, pid, addr, data);
if(kern_set_ucred_auth_id(mypid, authid)) {
return -1;
}
if(kern_set_ucred_caps(mypid, caps)) {
return -1;
}
return ret;
}
int
sysctl(const int *name, size_t namelen, void *oldp, size_t *oldlenp,
const void *newp, size_t newlen) {
return syscall(SYS___sysctl, name, namelen, oldp, oldlenp, newp, newlen);
}
int
jitshm_create(const char* name, size_t size, int flags) {
return (int)syscall(0x215, name, size, flags);
}
int
jitshm_alias(int fd, int flags) {
return (int)syscall(0x216, fd, flags);
}
void*
mmap(void* addr, size_t len, int prot, int flags, int fd, off_t off) {
return (void*)syscall(SYS_mmap, addr, len, prot, flags, fd, off);
}
int
munmap(void* addr, size_t len) {
return (int)syscall(SYS_munmap, addr, len);
}
int
mprotect(void* addr, size_t len, int prot) {
return (int)syscall(SYS_mprotect, addr, len, prot);
}
void*
malloc(size_t len) {
return sce_malloc(len);
}
void*
realloc(void *ptr, size_t len) {
return sce_realloc(ptr, len);
}
void
free(void *ptr) {
return sce_free(ptr);
}
void*
memset(void *dst, int c, size_t len) {
return sce_memset(dst, c, len);
}
void*
memcpy(void *dst, const void* src, size_t len) {
return sce_memcpy(dst, src, len);
}
char*
strcpy(char *dst, const char *src) {
return sce_strcpy(dst, src);
}
int
strcmp(const char* s1, const char* s2) {
return sce_strcmp(s1, s2);
}
int
strncmp(const char *s1, const char *s2, size_t len) {
return sce_strncmp(s1, s2, len);
}
int
strcat(char* s1, const char* s2) {
return sce_strcat(s1, s2);
}
uint16_t
htons(uint16_t val) {
return sce_htons(val);
}
uint32_t
sleep(uint32_t seconds) {
return sce_sleep(seconds);
}
void puts(const char *s) {
sce_puts(s);
}
void
perror(const char* s) {
sce_perror(s);
}
char*
strerror(int error) {
return sce_strerror(error);
}
int* geterrno(void) {
return sce_errno();
}
-167
View File
@@ -1,167 +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
#define AF_UNIX 1
#define AF_INET 2
#define AF_INET6 28
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define IPPROTO_UDP 17
#define IPPROTO_IPV6 41
#define IPV6_2292PKTOPTIONS 25
#define IPV6_PKTINFO 46
#define IPV6_TCLASS 61
#define SOL_SOCKET 0xffff
#define SO_REUSEADDR 0x0004
#define SCM_RIGHTS 0x01
#define PAGE_SIZE 0x4000
#define PROT_NONE 0x0
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define MAP_SHARED 0x1
#define MAP_PRIVATE 0x2
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x1000
#define RFFDG (1<<2)
#define RFPROC (1<<4)
#define RFNOWAIT (1<<6)
#define RFCFDG (1<<12)
#define SIGKILL 9
#define SIGCONT 19
#define EAGAIN 35
#define errno (*geterrno())
typedef char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
typedef uint64_t intptr_t;
typedef uint64_t off_t;
typedef uint64_t size_t;
typedef int64_t ssize_t;
typedef uint32_t socklen_t;
typedef uint32_t in_addr_t;
typedef int32_t pid_t;
typedef int32_t uid_t;
typedef int32_t gid_t;
struct in_addr {
in_addr_t s_addr;
};
struct sockaddr_in {
uint8_t sin_len;
uint8_t sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
uint8_t sin_zero[8];
};
struct sockaddr_un {
uint8_t sun_len;
uint8_t sun_family;
char sun_path[104];
};
struct msghdr {
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
int msg_iovlen;
void *msg_control;
socklen_t msg_controllen;
int msg_flags;
};
struct cmsghdr {
socklen_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
long syscall(int, ...);
int open(const char *path, int flags);
int unlink(const char *pathname);
ssize_t read(int fd, void *buf, size_t cnt);
ssize_t write(int fd, const void* buf, size_t cnt);
int dup2(int oldfd, int newfd);
int close(int fd);
int socket(int dom, int ty, int proto);
int setsockopt(int fd, int lvl, int name, const void *val,
unsigned int len);
int bind(int fd, const struct sockaddr_in *addr, socklen_t addr_len);
int listen(int fd, int backlog);
int accept(int fd, struct sockaddr_in *addr, socklen_t *addr_len);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
pid_t rfork(int flags);
pid_t getpid(void);
pid_t waitpid(pid_t pid, int *status, int opts);
int kill(pid_t pid, int sig);
int ptrace(int request, pid_t pid, intptr_t addr, int data);
int sysctl(const int *name, size_t namelen, void *oldp, size_t *oldlenp,
const void *newp, size_t newlen);
int jitshm_create(const char* name, size_t size, int flags);
int jitshm_alias(int fd, int flags);
void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t off);
int munmap(void* addr, size_t len);
int mprotect(void* addr, size_t len, int prot);
uint16_t htons(uint16_t val);
uint32_t sleep(uint32_t seconds);
void* malloc(size_t len);
void* realloc(void *ptr, size_t len);
void free(void *ptr);
void* memset(void *dst, int c, size_t len);
void* memcpy(void *dst, const void* src, size_t len);
char* strcpy(char *dst, const char *src);
int strcmp(const char* s1, const char* s2);
int strncmp(const char *s1, const char *s2, size_t n);
int strcat(char* s1, const char* s2);
void puts(const char *s);
void perror(const char *s);
char *strerror(int error);
int* geterrno(void);
+244 -25
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,37 +14,256 @@ 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 <arpa/inet.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <ps5/kernel.h>
#include "elfldr.h"
#include "kern.h"
#include "libc.h"
#ifdef ELFLDR_BOOTSTRAP
#include "elfldr-socksrv_elf.c"
#endif
/**
* Name of the process.
**/
#define PROCNAME "elfldr.elf"
int
main() {
uint8_t qa_flags[16];
/**
* Data structure used to send UI notifications on the PS5.
**/
typedef struct notify_request {
char useless1[45];
char message[3075];
} notify_request_t;
if(kern_get_qa_flags(qa_flags)) {
puts("[elfldr.elf] kern_get_qa_flags() failed");
return -1;
}
qa_flags[1] |= 0x03;
if(kern_set_qa_flags(qa_flags)) {
puts("[elfldr.elf] kern_set_qa_flags() failed");
return -1;
/**
* Send a UI notification request.
**/
int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int);
/**
* Read an ELF from a given file descriptor.
**/
static uint8_t*
readsock(int fd) {
uint8_t buf[0x4000];
uint8_t* data = 0;
off_t offset = 0;
ssize_t len;
while((len=read(fd, buf, sizeof(buf)))) {
data = realloc(data, offset + len + 1);
if(data == 0) {
perror("[elfldr.elf] realloc");
return 0;
}
memcpy(data + offset, buf, len);
offset += len;
}
#ifdef ELFLDR_BOOTSTRAP
puts("[elfldr.elf] Bootstrapping");
return elfldr_exec("ScePartyDaemon", -1, elfldr_socksrv_elf,
elfldr_socksrv_elf_len);
#else
puts("[elfldr.elf] Launching socket server");
return elfldr_socksrv("SceRedisServer", ELFLDR_PORT);
#endif
data[offset] = 0;
return data;
}
/**
* Read an ELF from a given path.
**/
static uint8_t*
readfile(const char* path) {
uint8_t* buf;
FILE* file;
long len;
if(!(file=fopen(path, "rb"))) {
perror("fopen");
return 0;
}
if(fseek(file, 0, SEEK_END)) {
perror("fseek");
return 0;
}
if((len=ftell(file)) < 0) {
perror("ftell");
return 0;
}
if(fseek(file, 0, SEEK_SET)) {
perror("fseek");
return 0;
}
if(!(buf=malloc(len))) {
return 0;
}
if(fread(buf, 1, len, file) != len) {
perror("fread");
free(buf);
return 0;
}
if(fclose(file)) {
perror("fclose");
free(buf);
return 0;
}
return buf;
}
/**
*
**/
static int
serve_elfldr(uint16_t port) {
struct sockaddr_in srvaddr;
struct sockaddr_in cliaddr;
char ip[INET_ADDRSTRLEN];
struct ifaddrs *ifaddr;
notify_request_t req;
int ifaddr_wait = 1;
socklen_t socklen;
uint8_t* elf;
int connfd;
int srvfd;
if(getifaddrs(&ifaddr) == -1) {
perror("[elfldr.elf] 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;
}
// skip localhost
if(!strncmp("lo", ifa->ifa_name, 2)) {
continue;
}
struct sockaddr_in *in = (struct sockaddr_in*)ifa->ifa_addr;
inet_ntop(AF_INET, &(in->sin_addr), ip, sizeof(ip));
// skip interfaces without an ip
if(!strncmp("0.", ip, 2)) {
continue;
}
ifaddr_wait = 0;
bzero(&req, sizeof(req));
sprintf(req.message, "elfldr.elf running on %s:%d (%s)", ip, port, ifa->ifa_name);
printf("[elfldr.elf] %s\n", req.message);
}
freeifaddrs(ifaddr);
if(ifaddr_wait) {
return 0;
}
if((srvfd=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("[elfldr.elf] socket");
return -1;
}
if(setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
perror("[elfldr.elf] setsockopt");
return -1;
}
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvaddr.sin_port = htons(port);
if(bind(srvfd, (struct sockaddr*)&srvaddr, sizeof(srvaddr)) != 0) {
perror("[elfldr.elf] bind");
return -1;
}
if(listen(srvfd, 5) != 0) {
perror("[elfldr.elf] listen");
return -1;
}
while(1) {
socklen = sizeof(cliaddr);
if((connfd=accept(srvfd, (struct sockaddr*)&cliaddr, &socklen)) < 0) {
perror("[elfldr.elf] accept");
break;
}
if(!(elf=readsock(connfd))) {
close(connfd);
continue;
}
if(!memcmp(elf, "\x7f\x45\x4c\x46", 4)) {
elfldr_spawn(elf);
} else {
write(connfd, "Not an ELF file\n", 16);
}
free(elf);
close(connfd);
}
return close(srvfd);
}
int main() {
const int port = 9021;
pid_t pid;
signal(SIGCHLD, SIG_IGN);
if((pid=syscall(SYS_rfork, RFPROC | RFNOWAIT | RFFDG))) {
return pid;
}
signal(SIGCHLD, SIG_IGN);
while((pid=elfldr_find_pid(PROCNAME)) > 0) {
if(kill(pid, SIGKILL)) {
perror("[elfldr.elf] kill");
}
sleep(1);
}
syscall(SYS_setsid);
syscall(SYS_thr_set_name, -1, PROCNAME);
dup2(open("/dev/console", O_WRONLY), STDOUT_FILENO);
dup2(open("/dev/console", O_WRONLY), STDERR_FILENO);
kernel_set_proc_rootdir(getpid(), kernel_get_root_vnode());
while(1) {
serve_elfldr(port);
sleep(3);
}
return 0;
}
-30
View File
@@ -1,30 +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
typedef struct payload_args {
int (*sceKernelDlsym)(int, const char*, void*);
int *rwpipe;
int *rwpair;
long kpipe_addr;
long kdata_base_addr;
int *payloadout;
} payload_args_t;
typedef void (payload_entry_t)(const payload_args_t *args);
-115
View File
@@ -1,115 +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"
typedef void* pthread_t;
typedef void* pthread_attr_t;
typedef struct payload_ctx {
payload_entry_t *entry;
payload_args_t *args;
int stdout;
} payload_ctx_t;
static void* (*malloc)(unsigned long);
static void (*free)(void*);
static void* (*memcpy)(void*, const void*, unsigned long);
static int (*close)(int);
static int (*dup)(int);
static int (*dup2)(int, int);
static int (*pthread_create)(pthread_t*, pthread_attr_t*,
void*(*f)(void*), void*);
static void*
payload_thread(void* args) {
payload_ctx_t *ctx = (payload_ctx_t*)args;
int stdout = dup(1);
int stderr = dup(2);
dup2(ctx->stdout, 1);
dup2(ctx->stdout, 2);
ctx->entry(ctx->args);
free(args);
dup2(stdout, 1);
dup2(stderr, 2);
close(ctx->stdout);
return 0;
}
int main(payload_ctx_t *ctx) {
pthread_t trd;
void* trd_args = malloc(sizeof(payload_ctx_t));
memcpy(trd_args, ctx, sizeof(payload_ctx_t));
pthread_create(&trd, 0, payload_thread, trd_args);
return 0;
}
static int
init(payload_args_t *args) {
int error;
if((error=args->sceKernelDlsym(0x2001, "pthread_create", &pthread_create))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "dup", &dup))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "dup2", &dup2))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "close", &close))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "malloc", &malloc))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "free", &free))) {
return error;
}
if((error=args->sceKernelDlsym(0x2, "memcpy", &memcpy))) {
return error;
}
return 0;
}
void
_start(payload_entry_t *entry, payload_args_t *args, int stdout) {
payload_ctx_t ctx = {
.entry = entry,
.args = args,
.stdout = stdout
};
if(!(*args->payloadout=init(args))) {
*args->payloadout = main(&ctx);
}
__builtin_debugtrap();
}
+128 -150
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,35 +14,74 @@ 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 "libc.h"
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <ps5/kernel.h>
#include "pt.h"
#include "syscall.h"
#define PT_READ_D 2
#define PT_WRITE_D 5
#define PT_CONTINUE 7
#define PT_STEP 9
#define PT_ATTACH 10
#define PT_DETACH 11
#define PT_IO 12
#define PT_GETREGS 33
#define PT_SETREGS 34
#define PIOD_READ_D 1
#define PIOD_WRITE_D 2
struct ptrace_io_desc {
int piod_op;
void *piod_offs;
void *piod_addr;
size_t piod_len;
};
static int
sys_ptrace(int request, pid_t pid, caddr_t addr, int data) {
uint8_t privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
pid_t mypid = getpid();
uint8_t caps[16];
uint64_t authid;
int ret;
if(!(authid=kernel_get_ucred_authid(mypid))) {
return -1;
}
if(kernel_get_ucred_caps(mypid, caps)) {
return -1;
}
if(kernel_set_ucred_authid(mypid, 0x4800000000010003l)) {
return -1;
}
if(kernel_set_ucred_caps(mypid, privcaps)) {
return -1;
}
ret = (int)syscall(SYS_ptrace, request, pid, addr, data);
if(kernel_set_ucred_authid(mypid, authid)) {
return -1;
}
if(kernel_set_ucred_caps(mypid, caps)) {
return -1;
}
return ret;
}
intptr_t
pt_resolve(pid_t pid, const char* nid) {
intptr_t addr;
if((addr=kernel_dynlib_resolve(pid, 0x1, nid))) {
return addr;
}
return kernel_dynlib_resolve(pid, 0x2001, nid);
}
int
pt_attach(pid_t pid) {
if(ptrace(PT_ATTACH, pid, 0, 0) == -1) {
if(sys_ptrace(PT_ATTACH, pid, 0, 0) == -1) {
return -1;
}
@@ -56,7 +95,7 @@ pt_attach(pid_t pid) {
int
pt_detach(pid_t pid) {
if(ptrace(PT_DETACH, pid, 0, 0) == -1) {
if(sys_ptrace(PT_DETACH, pid, 0, 0) == -1) {
return -1;
}
@@ -65,82 +104,8 @@ pt_detach(pid_t pid) {
int
pt_continue(pid_t pid) {
if(ptrace(PT_CONTINUE, pid, 1, SIGCONT) == -1) {
return -1;
}
return 0;
}
int
pt_getregs(pid_t pid, struct reg *r) {
return ptrace(PT_GETREGS, pid, (intptr_t)r, 0);
}
int
pt_setregs(pid_t pid, const struct reg *r) {
return ptrace(PT_SETREGS, pid, (intptr_t)r, 0);
}
int
pt_getint(pid_t pid, intptr_t addr) {
return ptrace(PT_READ_D, pid, addr, 0);
}
int
pt_setint(pid_t pid, intptr_t addr, int val) {
return ptrace(PT_WRITE_D, pid, addr, val);
}
int
pt_copyin(pid_t pid, void* buf, intptr_t addr, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_WRITE_D,
.piod_offs = (void*)addr,
.piod_addr = buf,
.piod_len = len};
while(ptrace(PT_IO, pid, (intptr_t)&iod, 0)) {
if(errno != EAGAIN) {
return -1;
}
}
return 0;
}
int
pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len) {
struct ptrace_io_desc iod = {
.piod_op = PIOD_READ_D,
.piod_offs = (void*)addr,
.piod_addr = buf,
.piod_len = len};
return ptrace(PT_IO, pid, (intptr_t)&iod, 0);
}
int
pt_setchar(pid_t pid, intptr_t addr, char val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
int
pt_setlong(pid_t pid, intptr_t addr, long val) {
return pt_copyin(pid, &val, addr, sizeof(val));
}
static int
pt_step(int pid) {
if(ptrace(PT_STEP, pid, (intptr_t)1, 0)) {
if(sys_ptrace(PT_STEP, pid, (caddr_t)1, 0)) {
return -1;
}
@@ -152,12 +117,39 @@ pt_step(int pid) {
}
static uint64_t
pt_call(pid_t pid, intptr_t addr,
uint64_t arg1, uint64_t arg2, uint64_t arg3,
uint64_t arg4, uint64_t arg5, uint64_t arg6) {
int
pt_continue(pid_t pid) {
if(sys_ptrace(PT_CONTINUE, pid, (caddr_t)1, SIGCONT) == -1) {
return -1;
}
return 0;
}
int
pt_getint(pid_t pid, intptr_t addr) {
return sys_ptrace(PT_READ_D, pid, (caddr_t)addr, 0);
}
int
pt_getregs(pid_t pid, struct reg *r) {
return sys_ptrace(PT_GETREGS, pid, (caddr_t)r, 0);
}
int
pt_setregs(pid_t pid, const struct reg *r) {
return sys_ptrace(PT_SETREGS, pid, (caddr_t)r, 0);
}
long
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;
@@ -165,12 +157,15 @@ pt_call(pid_t pid, intptr_t addr,
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
jmp_reg.r_rip = addr;
jmp_reg.r_rdi = arg1;
jmp_reg.r_rsi = arg2;
jmp_reg.r_rdx = arg3;
jmp_reg.r_rcx = arg4;
jmp_reg.r_r8 = arg5;
jmp_reg.r_r9 = arg5;
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;
@@ -195,20 +190,19 @@ pt_call(pid_t pid, intptr_t addr,
}
static uint64_t
pt_syscall(pid_t pid, int sysno,
uint64_t arg1, uint64_t arg2, uint64_t arg3,
uint64_t arg4, uint64_t arg5, uint64_t arg6) {
intptr_t addr = dynlib_resolve(pid, 0x2001, "HoLVWNanBBc");
long
pt_syscall(pid_t pid, int sysno, ...) {
intptr_t addr = pt_resolve(pid, "HoLVWNanBBc");
struct reg jmp_reg;
struct reg bak_reg;
va_list ap;
if(!addr) {
return -1;
} else {
addr += 0xa;
}
if(pt_getregs(pid, &bak_reg)) {
return -1;
}
@@ -216,12 +210,15 @@ pt_syscall(pid_t pid, int sysno,
memcpy(&jmp_reg, &bak_reg, sizeof(jmp_reg));
jmp_reg.r_rip = addr;
jmp_reg.r_rax = sysno;
jmp_reg.r_rdi = arg1;
jmp_reg.r_rsi = arg2;
jmp_reg.r_rdx = arg3;
jmp_reg.r_r10 = arg4;
jmp_reg.r_r8 = arg5;
jmp_reg.r_r9 = arg6;
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;
@@ -248,13 +245,13 @@ pt_syscall(pid_t pid, int sysno,
int
pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags) {
return (int)pt_syscall(pid, 0x215, name, size, flags, 0, 0, 0);
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, 0, 0, 0, 0);
return (int)pt_syscall(pid, 0x216, fd, flags);
}
@@ -267,25 +264,19 @@ pt_mmap(pid_t pid, intptr_t addr, size_t len, int prot, int flags,
int
pt_munmap(pid_t pid, intptr_t addr, size_t len) {
return pt_syscall(pid, SYS_munmap, addr, len, 0, 0, 0, 0);
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, 0, 0, 0);
}
int
pt_close(pid_t pid, int fd) {
return (int)pt_syscall(pid, SYS_close, fd, 0, 0, 0, 0, 0);
return pt_syscall(pid, SYS_mprotect, addr, len, prot);
}
int
pt_socket(pid_t pid, int domain, int type, int protocol) {
return (int)pt_syscall(pid, SYS_socket, domain, type, protocol, 0, 0, 0);
return (int)pt_syscall(pid, SYS_socket, domain, type, protocol);
}
@@ -296,36 +287,23 @@ pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
optlen, 0);
}
int
pt_bind(pid_t pid, int sockfd, intptr_t addr, socklen_t addrlen) {
return (int)pt_syscall(pid, SYS_bind, sockfd, addr, addrlen, 0, 0, 0);
}
ssize_t
pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags) {
return (int)pt_syscall(pid, SYS_recvmsg, fd, msg, flags, 0, 0, 0);
}
int
pt_dup2(pid_t pid, int oldfd, int newfd) {
return (int)pt_syscall(pid, SYS_dup2, oldfd, newfd, 0, 0, 0, 0);
pt_close(pid_t pid, int fd) {
return (int)pt_syscall(pid, SYS_close, fd);
}
int
pt_pipe(pid_t pid, intptr_t pipefd) {
intptr_t faddr = dynlib_resolve(pid, 0x2001, "-Jp7F+pXxNg");
intptr_t faddr = pt_resolve(pid, "-Jp7F+pXxNg");
return (int)pt_call(pid, faddr, pipefd, 0, 0, 0, 0, 0);
}
void
pt_perror(pid_t pid, const char *s) {
intptr_t faddr = dynlib_resolve(pid, 0x2001, "9BcDykPmo1I"); //__error
intptr_t addr = pt_call(pid, faddr, 0, 0, 0, 0, 0, 0);
intptr_t faddr = pt_resolve(pid, "9BcDykPmo1I");
intptr_t addr = pt_call(pid, faddr);
int err = pt_getint(pid, addr);
char buf[255];
+9 -46
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,57 +16,24 @@ along with this program; see the file COPYING. If not, see
#pragma once
#include "dynlib.h"
#include "libc.h"
struct reg {
uint64_t r_r15;
uint64_t r_r14;
uint64_t r_r13;
uint64_t r_r12;
uint64_t r_r11;
uint64_t r_r10;
uint64_t r_r9;
uint64_t r_r8;
uint64_t r_rdi;
uint64_t r_rsi;
uint64_t r_rbp;
uint64_t r_rbx;
uint64_t r_rdx;
uint64_t r_rcx;
uint64_t r_rax;
uint32_t r_trapno;
uint16_t r_fs;
uint16_t r_gs;
uint32_t r_err;
uint16_t r_es;
uint16_t r_ds;
uint64_t r_rip;
uint64_t r_cs;
uint64_t r_rflags;
uint64_t r_rsp;
uint64_t r_ss;
};
#include <stdint.h>
#include <sys/types.h>
#include <machine/reg.h>
int pt_attach(pid_t pid);
int pt_detach(pid_t pid);
int pt_step(pid_t pid);
int pt_continue(pid_t pid);
int pt_getregs(pid_t pid, struct reg *r);
int pt_setregs(pid_t pid, const struct reg *r);
int pt_setchar(pid_t pid, intptr_t addr, char val);
int pt_setint(pid_t pid, intptr_t addr, int val);
int pt_setlong(pid_t pid, intptr_t addr, long val);
int pt_copyin(pid_t pid, void* buf, intptr_t addr, size_t len);
int pt_copyout(pid_t pid, intptr_t addr, void* buf, size_t len);
int pt_getint(pid_t pid, intptr_t addr);
long pt_syscall(pid_t pid, int sysno, ...);
intptr_t pt_resolve(pid_t pid, const char* nid);
int pt_jitshm_create(pid_t pid, intptr_t name, size_t size, int flags);
int pt_jitshm_alias(pid_t pid, int fd, int flags);
@@ -77,13 +44,9 @@ int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot);
int pt_socket(pid_t pid, int domain, int type, int protocol);
int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval,
socklen_t optlen);
int pt_bind(pid_t pid, int sockfd, intptr_t addr, socklen_t addrlen) ;
ssize_t pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags);
uint32_t optlen);
int pt_close(pid_t pid, int fd);
int pt_dup2(pid_t pid, int oldfd, int newfd);
int pt_pipe(pid_t pid, intptr_t pipefd);
void pt_perror(pid_t pid, const char *s);
-470
View File
@@ -1,470 +0,0 @@
/*
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD: releng/11.0/sys/sys/syscall.h 303858 2016-08-08 21:19:57Z bdrewery $
* created from FreeBSD: stable/11/sys/kern/syscalls.master 303854 2016-08-08 20:23:11Z bdrewery
*/
#define SYS_syscall 0
#define SYS_exit 1
#define SYS_fork 2
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_wait4 7
/* 8 is old creat */
#define SYS_link 9
#define SYS_unlink 10
/* 11 is obsolete execv */
#define SYS_chdir 12
#define SYS_fchdir 13
#define SYS_mknod 14
#define SYS_chmod 15
#define SYS_chown 16
#define SYS_break 17
/* 18 is freebsd4 getfsstat */
/* 19 is old lseek */
#define SYS_getpid 20
#define SYS_mount 21
#define SYS_unmount 22
#define SYS_setuid 23
#define SYS_getuid 24
#define SYS_geteuid 25
#define SYS_ptrace 26
#define SYS_recvmsg 27
#define SYS_sendmsg 28
#define SYS_recvfrom 29
#define SYS_accept 30
#define SYS_getpeername 31
#define SYS_getsockname 32
#define SYS_access 33
#define SYS_chflags 34
#define SYS_fchflags 35
#define SYS_sync 36
#define SYS_kill 37
/* 38 is old stat */
#define SYS_getppid 39
/* 40 is old lstat */
#define SYS_dup 41
#define SYS_freebsd10_pipe 42
#define SYS_getegid 43
#define SYS_profil 44
#define SYS_ktrace 45
/* 46 is old sigaction */
#define SYS_getgid 47
/* 48 is old sigprocmask */
#define SYS_getlogin 49
#define SYS_setlogin 50
#define SYS_acct 51
/* 52 is old sigpending */
#define SYS_sigaltstack 53
#define SYS_ioctl 54
#define SYS_reboot 55
#define SYS_revoke 56
#define SYS_symlink 57
#define SYS_readlink 58
#define SYS_execve 59
#define SYS_umask 60
#define SYS_chroot 61
/* 62 is old fstat */
/* 63 is old getkerninfo */
/* 64 is old getpagesize */
#define SYS_msync 65
#define SYS_vfork 66
/* 67 is obsolete vread */
/* 68 is obsolete vwrite */
#define SYS_sbrk 69
#define SYS_sstk 70
/* 71 is old mmap */
#define SYS_vadvise 72
#define SYS_munmap 73
#define SYS_mprotect 74
#define SYS_madvise 75
/* 76 is obsolete vhangup */
/* 77 is obsolete vlimit */
#define SYS_mincore 78
#define SYS_getgroups 79
#define SYS_setgroups 80
#define SYS_getpgrp 81
#define SYS_setpgid 82
#define SYS_setitimer 83
/* 84 is old wait */
#define SYS_swapon 85
#define SYS_getitimer 86
/* 87 is old gethostname */
/* 88 is old sethostname */
#define SYS_getdtablesize 89
#define SYS_dup2 90
#define SYS_fcntl 92
#define SYS_select 93
#define SYS_fsync 95
#define SYS_setpriority 96
#define SYS_socket 97
#define SYS_connect 98
/* 99 is old accept */
#define SYS_getpriority 100
/* 101 is old send */
/* 102 is old recv */
/* 103 is old sigreturn */
#define SYS_bind 104
#define SYS_setsockopt 105
#define SYS_listen 106
/* 107 is obsolete vtimes */
/* 108 is old sigvec */
/* 109 is old sigblock */
/* 110 is old sigsetmask */
/* 111 is old sigsuspend */
/* 112 is old sigstack */
/* 113 is old recvmsg */
/* 114 is old sendmsg */
/* 115 is obsolete vtrace */
#define SYS_gettimeofday 116
#define SYS_getrusage 117
#define SYS_getsockopt 118
#define SYS_readv 120
#define SYS_writev 121
#define SYS_settimeofday 122
#define SYS_fchown 123
#define SYS_fchmod 124
/* 125 is old recvfrom */
#define SYS_setreuid 126
#define SYS_setregid 127
#define SYS_rename 128
/* 129 is old truncate */
/* 130 is old ftruncate */
#define SYS_flock 131
#define SYS_mkfifo 132
#define SYS_sendto 133
#define SYS_shutdown 134
#define SYS_socketpair 135
#define SYS_mkdir 136
#define SYS_rmdir 137
#define SYS_utimes 138
/* 139 is obsolete 4.2 sigreturn */
#define SYS_adjtime 140
/* 141 is old getpeername */
/* 142 is old gethostid */
/* 143 is old sethostid */
/* 144 is old getrlimit */
/* 145 is old setrlimit */
/* 146 is old killpg */
#define SYS_setsid 147
#define SYS_quotactl 148
/* 149 is old quota */
/* 150 is old getsockname */
#define SYS_nlm_syscall 154
#define SYS_nfssvc 155
/* 156 is old getdirentries */
/* 157 is freebsd4 statfs */
/* 158 is freebsd4 fstatfs */
#define SYS_lgetfh 160
#define SYS_getfh 161
/* 162 is freebsd4 getdomainname */
/* 163 is freebsd4 setdomainname */
/* 164 is freebsd4 uname */
#define SYS_sysarch 165
#define SYS_rtprio 166
#define SYS_semsys 169
#define SYS_msgsys 170
#define SYS_shmsys 171
/* 173 is freebsd6 pread */
/* 174 is freebsd6 pwrite */
#define SYS_setfib 175
#define SYS_ntp_adjtime 176
#define SYS_setgid 181
#define SYS_setegid 182
#define SYS_seteuid 183
#define SYS_stat 188
#define SYS_fstat 189
#define SYS_lstat 190
#define SYS_pathconf 191
#define SYS_fpathconf 192
#define SYS_getrlimit 194
#define SYS_setrlimit 195
#define SYS_getdirentries 196
/* 197 is freebsd6 mmap */
#define SYS___syscall 198
/* 199 is freebsd6 lseek */
/* 200 is freebsd6 truncate */
/* 201 is freebsd6 ftruncate */
#define SYS___sysctl 202
#define SYS_mlock 203
#define SYS_munlock 204
#define SYS_undelete 205
#define SYS_futimes 206
#define SYS_getpgid 207
#define SYS_poll 209
#define SYS_freebsd7___semctl 220
#define SYS_semget 221
#define SYS_semop 222
#define SYS_freebsd7_msgctl 224
#define SYS_msgget 225
#define SYS_msgsnd 226
#define SYS_msgrcv 227
#define SYS_shmat 228
#define SYS_freebsd7_shmctl 229
#define SYS_shmdt 230
#define SYS_shmget 231
#define SYS_clock_gettime 232
#define SYS_clock_settime 233
#define SYS_clock_getres 234
#define SYS_ktimer_create 235
#define SYS_ktimer_delete 236
#define SYS_ktimer_settime 237
#define SYS_ktimer_gettime 238
#define SYS_ktimer_getoverrun 239
#define SYS_nanosleep 240
#define SYS_ffclock_getcounter 241
#define SYS_ffclock_setestimate 242
#define SYS_ffclock_getestimate 243
#define SYS_clock_getcpuclockid2 247
#define SYS_ntp_gettime 248
#define SYS_minherit 250
#define SYS_rfork 251
#define SYS_openbsd_poll 252
#define SYS_issetugid 253
#define SYS_lchown 254
#define SYS_aio_read 255
#define SYS_aio_write 256
#define SYS_lio_listio 257
#define SYS_getdents 272
#define SYS_lchmod 274
#define SYS_netbsd_lchown 275
#define SYS_lutimes 276
#define SYS_netbsd_msync 277
#define SYS_nstat 278
#define SYS_nfstat 279
#define SYS_nlstat 280
#define SYS_preadv 289
#define SYS_pwritev 290
/* 297 is freebsd4 fhstatfs */
#define SYS_fhopen 298
#define SYS_fhstat 299
#define SYS_modnext 300
#define SYS_modstat 301
#define SYS_modfnext 302
#define SYS_modfind 303
#define SYS_kldload 304
#define SYS_kldunload 305
#define SYS_kldfind 306
#define SYS_kldnext 307
#define SYS_kldstat 308
#define SYS_kldfirstmod 309
#define SYS_getsid 310
#define SYS_setresuid 311
#define SYS_setresgid 312
/* 313 is obsolete signanosleep */
#define SYS_aio_return 314
#define SYS_aio_suspend 315
#define SYS_aio_cancel 316
#define SYS_aio_error 317
/* 318 is freebsd6 aio_read */
/* 319 is freebsd6 aio_write */
/* 320 is freebsd6 lio_listio */
#define SYS_yield 321
/* 322 is obsolete thr_sleep */
/* 323 is obsolete thr_wakeup */
#define SYS_mlockall 324
#define SYS_munlockall 325
#define SYS___getcwd 326
#define SYS_sched_setparam 327
#define SYS_sched_getparam 328
#define SYS_sched_setscheduler 329
#define SYS_sched_getscheduler 330
#define SYS_sched_yield 331
#define SYS_sched_get_priority_max 332
#define SYS_sched_get_priority_min 333
#define SYS_sched_rr_get_interval 334
#define SYS_utrace 335
/* 336 is freebsd4 sendfile */
#define SYS_kldsym 337
#define SYS_jail 338
#define SYS_nnpfs_syscall 339
#define SYS_sigprocmask 340
#define SYS_sigsuspend 341
/* 342 is freebsd4 sigaction */
#define SYS_sigpending 343
/* 344 is freebsd4 sigreturn */
#define SYS_sigtimedwait 345
#define SYS_sigwaitinfo 346
#define SYS___acl_get_file 347
#define SYS___acl_set_file 348
#define SYS___acl_get_fd 349
#define SYS___acl_set_fd 350
#define SYS___acl_delete_file 351
#define SYS___acl_delete_fd 352
#define SYS___acl_aclcheck_file 353
#define SYS___acl_aclcheck_fd 354
#define SYS_extattrctl 355
#define SYS_extattr_set_file 356
#define SYS_extattr_get_file 357
#define SYS_extattr_delete_file 358
#define SYS_aio_waitcomplete 359
#define SYS_getresuid 360
#define SYS_getresgid 361
#define SYS_kqueue 362
#define SYS_kevent 363
#define SYS_extattr_set_fd 371
#define SYS_extattr_get_fd 372
#define SYS_extattr_delete_fd 373
#define SYS___setugid 374
#define SYS_eaccess 376
#define SYS_afs3_syscall 377
#define SYS_nmount 378
#define SYS___mac_get_proc 384
#define SYS___mac_set_proc 385
#define SYS___mac_get_fd 386
#define SYS___mac_get_file 387
#define SYS___mac_set_fd 388
#define SYS___mac_set_file 389
#define SYS_kenv 390
#define SYS_lchflags 391
#define SYS_uuidgen 392
#define SYS_sendfile 393
#define SYS_mac_syscall 394
#define SYS_getfsstat 395
#define SYS_statfs 396
#define SYS_fstatfs 397
#define SYS_fhstatfs 398
#define SYS_ksem_close 400
#define SYS_ksem_post 401
#define SYS_ksem_wait 402
#define SYS_ksem_trywait 403
#define SYS_ksem_init 404
#define SYS_ksem_open 405
#define SYS_ksem_unlink 406
#define SYS_ksem_getvalue 407
#define SYS_ksem_destroy 408
#define SYS___mac_get_pid 409
#define SYS___mac_get_link 410
#define SYS___mac_set_link 411
#define SYS_extattr_set_link 412
#define SYS_extattr_get_link 413
#define SYS_extattr_delete_link 414
#define SYS___mac_execve 415
#define SYS_sigaction 416
#define SYS_sigreturn 417
#define SYS_getcontext 421
#define SYS_setcontext 422
#define SYS_swapcontext 423
#define SYS_swapoff 424
#define SYS___acl_get_link 425
#define SYS___acl_set_link 426
#define SYS___acl_delete_link 427
#define SYS___acl_aclcheck_link 428
#define SYS_sigwait 429
#define SYS_thr_create 430
#define SYS_thr_exit 431
#define SYS_thr_self 432
#define SYS_thr_kill 433
#define SYS_jail_attach 436
#define SYS_extattr_list_fd 437
#define SYS_extattr_list_file 438
#define SYS_extattr_list_link 439
#define SYS_ksem_timedwait 441
#define SYS_thr_suspend 442
#define SYS_thr_wake 443
#define SYS_kldunloadf 444
#define SYS_audit 445
#define SYS_auditon 446
#define SYS_getauid 447
#define SYS_setauid 448
#define SYS_getaudit 449
#define SYS_setaudit 450
#define SYS_getaudit_addr 451
#define SYS_setaudit_addr 452
#define SYS_auditctl 453
#define SYS__umtx_op 454
#define SYS_thr_new 455
#define SYS_sigqueue 456
#define SYS_kmq_open 457
#define SYS_kmq_setattr 458
#define SYS_kmq_timedreceive 459
#define SYS_kmq_timedsend 460
#define SYS_kmq_notify 461
#define SYS_kmq_unlink 462
#define SYS_abort2 463
#define SYS_thr_set_name 464
#define SYS_aio_fsync 465
#define SYS_rtprio_thread 466
#define SYS_sctp_peeloff 471
#define SYS_sctp_generic_sendmsg 472
#define SYS_sctp_generic_sendmsg_iov 473
#define SYS_sctp_generic_recvmsg 474
#define SYS_pread 475
#define SYS_pwrite 476
#define SYS_mmap 477
#define SYS_lseek 478
#define SYS_truncate 479
#define SYS_ftruncate 480
#define SYS_thr_kill2 481
#define SYS_shm_open 482
#define SYS_shm_unlink 483
#define SYS_cpuset 484
#define SYS_cpuset_setid 485
#define SYS_cpuset_getid 486
#define SYS_cpuset_getaffinity 487
#define SYS_cpuset_setaffinity 488
#define SYS_faccessat 489
#define SYS_fchmodat 490
#define SYS_fchownat 491
#define SYS_fexecve 492
#define SYS_fstatat 493
#define SYS_futimesat 494
#define SYS_linkat 495
#define SYS_mkdirat 496
#define SYS_mkfifoat 497
#define SYS_mknodat 498
#define SYS_openat 499
#define SYS_readlinkat 500
#define SYS_renameat 501
#define SYS_symlinkat 502
#define SYS_unlinkat 503
#define SYS_posix_openpt 504
#define SYS_gssd_syscall 505
#define SYS_jail_get 506
#define SYS_jail_set 507
#define SYS_jail_remove 508
#define SYS_closefrom 509
#define SYS___semctl 510
#define SYS_msgctl 511
#define SYS_shmctl 512
#define SYS_lpathconf 513
/* 514 is obsolete cap_new */
#define SYS___cap_rights_get 515
#define SYS_cap_enter 516
#define SYS_cap_getmode 517
#define SYS_pdfork 518
#define SYS_pdkill 519
#define SYS_pdgetpid 520
#define SYS_pselect 522
#define SYS_getloginclass 523
#define SYS_setloginclass 524
#define SYS_rctl_get_racct 525
#define SYS_rctl_get_rules 526
#define SYS_rctl_get_limits 527
#define SYS_rctl_add_rule 528
#define SYS_rctl_remove_rule 529
#define SYS_posix_fallocate 530
#define SYS_posix_fadvise 531
#define SYS_wait6 532
#define SYS_cap_rights_limit 533
#define SYS_cap_ioctls_limit 534
#define SYS_cap_ioctls_get 535
#define SYS_cap_fcntls_limit 536
#define SYS_cap_fcntls_get 537
#define SYS_bindat 538
#define SYS_connectat 539
#define SYS_chflagsat 540
#define SYS_accept4 541
#define SYS_pipe2 542
#define SYS_aio_mlock 543
#define SYS_procctl 544
#define SYS_ppoll 545
#define SYS_futimens 546
#define SYS_utimensat 547
#define SYS_numa_getaffinity 548
#define SYS_numa_setaffinity 549
#define SYS_MAXSYSCALL 550