Files
sdk/kernel.c
T
2023-01-05 01:07:36 +01:00

243 lines
4.9 KiB
C

#include "payload.h"
/**
* standard macros.
**/
#define IPPROTO_IPV6 41
#define IPV6_PKTINFO 46
/**
* libkernel symbols
**/
static long (*_read)(int, void*, unsigned long);
static long (*_write)(int, const void*, unsigned long);
static int (*_getsockopt)(int, int, int, void *, unsigned int *);
static int (*_setsockopt)(int, int, int, const void*, unsigned int);
static int (*sysctlbyname)(const char *, void *, unsigned long*,
const void *, unsigned long);
/**
* public constants.
**/
unsigned long KERNEL_ADDRESS_DATA_BASE = 0;
unsigned long KERNEL_ADDRESS_ALLPROC = 0;
const unsigned long KERNEL_OFFSET_PROC_P_UCRED = 0x40;
const unsigned long KERNEL_OFFSET_PROC_P_PID = 0xBC;
const unsigned long KERNEL_OFFSET_UCRED_CR_UID = 0x04;
const unsigned long KERNEL_OFFSET_UCRED_CR_RUID = 0x08;
const unsigned long KERNEL_OFFSET_UCRED_CR_SVUID = 0x0C;
const unsigned long KERNEL_OFFSET_UCRED_CR_RGID = 0x14;
/**
* private global variables.
**/
static int master_sock = -1;
static int victim_sock = -1;
static int rw_pipe[2] = {-1, -1};
static unsigned long pipe_addr = 0;
static unsigned long kdata_base = 0;
/**
*
**/
unsigned int
kernel_get_fw_version(void) {
unsigned int version = 0;
unsigned long size = sizeof(version);
if(sysctlbyname("kern.sdk_version", &version, &size, 0, 0)) {
return 0;
}
return version;
}
/**
*
**/
__attribute__((constructor(101))) static int
kernel_init_rw(const payload_args_t *args) {
int error = 0;
if((error=args->sceKernelDlsym(0x2001, "_read", &_read))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "_write", &_write))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "_setsockopt", &_setsockopt))) {
return error;
}
if((error=args->sceKernelDlsym(0x2001, "_getsockopt", &_getsockopt))) {
return error;
}
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(!(KERNEL_ADDRESS_DATA_BASE=args->kdata_base_addr)) {
return -1;
}
switch(kernel_get_fw_version() & 0xffff0000) {
case 0x3000000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x276DC58;
break;
case 0x3100000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x276DC58;
break;
case 0x3200000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x276DC58;
break;
case 0x3210000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x276DC58;
break;
case 0x4020000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x27EDCB8;
break;
case 0x4030000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x27EDCB8;
break;
case 0x4500000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x27EDCB8;
break;
case 0x4510000:
KERNEL_ADDRESS_ALLPROC = KERNEL_ADDRESS_DATA_BASE + 0x27EDCB8;
break;
default:
return -1;
}
return 0;
}
/**
*
**/
static int
kwrite(unsigned long addr, unsigned long *data) {
unsigned long victim_buf[3];
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
kernel_copyin(const void *udaddr, void* kaddr, unsigned long len) {
unsigned long write_buf[3];
// Set pipe flags
write_buf[0] = 0;
write_buf[1] = 0x4000000000000000;
write_buf[2] = 0;
if(kwrite(pipe_addr, (unsigned long *) &write_buf)) {
return -1;
}
// Set pipe data addr
write_buf[0] = (unsigned long)kaddr;
write_buf[1] = 0;
write_buf[2] = 0;
if(kwrite(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
kernel_copyout(const void *kaddr, void *udaddr, unsigned long len) {
unsigned long write_buf[3];
// Set pipe flags
write_buf[0] = 0x4000000040000000;
write_buf[1] = 0x4000000000000000;
write_buf[2] = 0;
if(kwrite(pipe_addr, (unsigned long *) &write_buf)) {
return -1;
}
// Set pipe data addr
write_buf[0] = (unsigned long)kaddr;
write_buf[1] = 0;
write_buf[2] = 0;
if(kwrite(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;
}