mirror of
https://github.com/ps5-payload-dev/elfldr.git
synced 2026-10-19 02:19:52 -05:00
complete rewrite of the elf loader, which now spawns complete new processes for each ELF, amongst other things
This commit is contained in:
1 parent
2fd0a53ec1
commit
6097b737d2
23 files changed
+726
-2795
No files matched your search
@@ -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
@@ -1,5 +1,5 @@
|
||||
*~
|
||||
*.o
|
||||
*.elf
|
||||
elfldr-socksrv_elf.c
|
||||
elfldr_elf.c
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
Reference in new issue
Block a user