mirror of
https://github.com/EchoStretch/kstuff.git
synced 2026-10-22 19:52:21 -05:00
1070 lines
33 KiB
C
1070 lines
33 KiB
C
#define sysctl __sysctl
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/sysctl.h>
|
|
#include <signal.h>
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include "../prosper0gdb/r0gdb.h"
|
|
#include "../prosper0gdb/offsets.h"
|
|
#include "../gdb_stub/dbg.h"
|
|
#include "uelf/structs.h"
|
|
#include "uelf/parasite_desc.h"
|
|
|
|
void* dlsym(void*, const char*);
|
|
|
|
void notify(const char* s)
|
|
{
|
|
struct
|
|
{
|
|
char pad1[0x10];
|
|
int f1;
|
|
char pad2[0x19];
|
|
char msg[0xc03];
|
|
} notification = {.f1 = -1};
|
|
char* d = notification.msg;
|
|
while(*d++ = *s++);
|
|
((void(*)())dlsym((void*)0x2001, "sceKernelSendNotificationRequest"))(0, ¬ification, 0xc30, 0);
|
|
}
|
|
|
|
void die(int line)
|
|
{
|
|
char buf[64] = "problem encountered on main.c line ";
|
|
char* p = buf;
|
|
while(*p)
|
|
p++;
|
|
int q = 1;
|
|
while(line / 10 > q)
|
|
q *= 10;
|
|
while(q)
|
|
{
|
|
*p++ = '0' + (line / q) % 10;
|
|
q /= 10;
|
|
}
|
|
notify(buf);
|
|
asm volatile("ud2");
|
|
}
|
|
|
|
#define die() die(__LINE__)
|
|
|
|
extern uint64_t kdata_base;
|
|
|
|
void kmemcpy(void* dst, const void* src, size_t sz);
|
|
|
|
static void kpoke64(void* dst, uint64_t src)
|
|
{
|
|
kmemcpy(dst, &src, 8);
|
|
}
|
|
|
|
static void kmemzero(void* dst, size_t sz)
|
|
{
|
|
char* umem = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
|
|
mlock(umem, sz);
|
|
kmemcpy(dst, umem, sz);
|
|
munmap(umem, sz);
|
|
}
|
|
|
|
static int strcmp(const char* a, const char* b)
|
|
{
|
|
while(*a && *a == *b)
|
|
{
|
|
a++;
|
|
b++;
|
|
}
|
|
return *a - *b;
|
|
}
|
|
|
|
#define kmalloc my_kmalloc
|
|
|
|
static uint64_t mem_blocks[8];
|
|
|
|
static void* kmalloc(size_t sz)
|
|
{
|
|
for(int i = 0; i < 8; i += 2)
|
|
{
|
|
if(mem_blocks[i] + sz <= mem_blocks[i+1])
|
|
{
|
|
uint64_t ans = mem_blocks[i];
|
|
mem_blocks[i] += sz;
|
|
return (void*)ans;
|
|
}
|
|
}
|
|
die();
|
|
return 0;
|
|
}
|
|
|
|
#define NCPUS 16
|
|
#define IDT (offsets.idt)
|
|
#define GDT(i) (offsets.gdt_array+0x68*(i))
|
|
#define TSS(i) (offsets.tss_array+0x68*(i))
|
|
#define PCPU(i) (offsets.pcpu_array+0x900*(i))
|
|
|
|
size_t virt2file(uint64_t* phdr, uint16_t phnum, uintptr_t addr)
|
|
{
|
|
for(size_t i = 0; i < phnum; i++)
|
|
{
|
|
uint64_t* h = phdr + 7*i;
|
|
if((uint32_t)h[0] != 1)
|
|
continue;
|
|
if(h[2] <= addr && h[2] + h[4] > addr)
|
|
return addr + h[1] - h[2];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void* load_kelf(void* ehdr, const char** symbols, uint64_t* values, void** base, void** entry, uint64_t mapped_kptr)
|
|
{
|
|
uint64_t* phdr = (void*)((char*)ehdr + *(uint64_t*)((char*)ehdr + 32));
|
|
uint16_t phnum = *(uint16_t*)((char*)ehdr + 56);
|
|
uint64_t* dynamic = 0;
|
|
size_t sz_dynamic = 0;
|
|
uint64_t kernel_size = 0;
|
|
for(size_t i = 0; i < phnum; i++)
|
|
{
|
|
uint64_t* h = phdr + 7*i;
|
|
if((uint32_t)h[0] == 2)
|
|
{
|
|
dynamic = (void*)((char*)ehdr + h[1]);
|
|
sz_dynamic = h[4];
|
|
}
|
|
else if((uint32_t)h[0] == 1)
|
|
{
|
|
uint64_t limit = h[2] + h[5];
|
|
if(limit > kernel_size)
|
|
kernel_size = limit;
|
|
}
|
|
}
|
|
kernel_size = ((kernel_size + 4095) | 4095) - 4095;
|
|
char* kptr = kmalloc(kernel_size+4096);
|
|
kptr = (char*)((((uint64_t)kptr - 1) | 4095) + 1);
|
|
if(!mapped_kptr)
|
|
mapped_kptr = (uint64_t)kptr;
|
|
base[0] = kptr;
|
|
base[1] = kptr + kernel_size;
|
|
for(size_t i = 0; i < phnum; i++)
|
|
{
|
|
uint64_t* h = phdr + 7*i;
|
|
if((uint32_t)h[0] != 1)
|
|
continue;
|
|
kmemcpy(kptr+h[2], (char*)ehdr + h[1], h[4]);
|
|
kmemzero(kptr+h[2]+h[4], h[5]-h[4]);
|
|
}
|
|
char* strtab = 0;
|
|
uint64_t* symtab = 0;
|
|
uint64_t* rela = 0;
|
|
size_t relasz = 0;
|
|
for(size_t i = 0; i < sz_dynamic / 16; i++)
|
|
{
|
|
uint64_t* kv = dynamic + 2*i;
|
|
if(kv[0] == 5)
|
|
strtab = (char*)ehdr + virt2file(phdr, phnum, kv[1]);
|
|
else if(kv[0] == 6)
|
|
symtab = (void*)((char*)ehdr + virt2file(phdr, phnum, kv[1]));
|
|
else if(kv[0] == 7)
|
|
rela = (void*)((char*)ehdr + virt2file(phdr, phnum, kv[1]));
|
|
else if(kv[0] == 8)
|
|
relasz = kv[1];
|
|
}
|
|
for(size_t i = 0; i < relasz / 24; i++)
|
|
{
|
|
uint64_t* oia = rela + 3*i;
|
|
if((uint32_t)oia[1] == 1 || (uint32_t)oia[1] == 6)
|
|
{
|
|
uint64_t* sym = symtab + 3 * (oia[1] >> 32);
|
|
const char* name = strtab + (uint32_t)sym[0];
|
|
uint64_t value = sym[1];
|
|
if(!value)
|
|
{
|
|
for(size_t i = 0; symbols[i]; i++)
|
|
if(!strcmp(symbols[i], name))
|
|
sym[1] = value = values[i];
|
|
else if(symbols[i][0] == '.' && !strcmp(symbols[i]+1, name))
|
|
value = values[i];
|
|
#ifndef FIRMWARE_PORTING
|
|
if(!value)
|
|
die();
|
|
#endif
|
|
}
|
|
if((uint32_t)oia[1] == 6 && oia[2])
|
|
die();
|
|
if(oia[0] + 8 > kernel_size)
|
|
die();
|
|
kpoke64(kptr+oia[0], oia[2]+value);
|
|
}
|
|
else if((uint32_t)oia[1] == 8)
|
|
{
|
|
if(oia[0] + 8 > kernel_size)
|
|
die();
|
|
kpoke64(kptr+oia[0], (uint64_t)(mapped_kptr+oia[2]));
|
|
}
|
|
else
|
|
die();
|
|
}
|
|
*entry = kptr + *(uint64_t*)((char*)ehdr + 24);
|
|
return kptr;
|
|
}
|
|
|
|
asm(".section .data\nkek:\n.incbin \"kelf\"\nkek_end:");
|
|
extern char kek[];
|
|
extern char kek_end[];
|
|
|
|
asm(".section .data\nuek:\n.incbin \"uelf/uelf.bin\"\nuek_end:");
|
|
extern char uek[];
|
|
extern char uek_end[];
|
|
|
|
asm(".section .text\nkekcall:\nmov 8(%rsp), %rax\njmp *p_kekcall(%rip)");
|
|
|
|
uint64_t kekcall(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f, uint64_t nr);
|
|
|
|
#define KEKCALL_GETPPID 0x000000027
|
|
#define KEKCALL_READ_DR 0x100000027
|
|
#define KEKCALL_WRITE_DR 0x200000027
|
|
#define KEKCALL_RDMSR 0x300000027
|
|
#define KEKCALL_REMOTE_SYSCALL 0x500000027
|
|
#define KEKCALL_CHECK 0xffffffff00000027
|
|
|
|
void* p_kekcall;
|
|
|
|
void* malloc(size_t sz)
|
|
{
|
|
return mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
|
|
}
|
|
|
|
uint64_t get_dmap_base(void)
|
|
{
|
|
uint64_t ptrs[2];
|
|
copyout(ptrs, offsets.kernel_pmap_store+32, sizeof(ptrs));
|
|
return ptrs[0] - ptrs[1];
|
|
}
|
|
|
|
uint64_t virt2phys(uintptr_t addr)
|
|
{
|
|
uint64_t dmap = get_dmap_base();
|
|
uint64_t pml = r0gdb_read_cr3();
|
|
for(int i = 39; i >= 12; i -= 9)
|
|
{
|
|
uint64_t inner_pml;
|
|
copyout(&inner_pml, dmap+pml+((addr & (0x1ffull << i)) >> (i - 3)), 8);
|
|
if(!(inner_pml & 1)) //not present
|
|
return -1;
|
|
if((inner_pml & 128) || i == 12) //hugepage
|
|
{
|
|
inner_pml &= (1ull << 52) - (1ull << i);
|
|
inner_pml |= addr & ((1ull << i) - 1);
|
|
return inner_pml;
|
|
}
|
|
inner_pml &= (1ull << 52) - (1ull << 12);
|
|
pml = inner_pml;
|
|
}
|
|
//unreachable
|
|
}
|
|
|
|
uint64_t find_empty_pml4_index(int idx)
|
|
{
|
|
uint64_t dmap = get_dmap_base();
|
|
uint64_t cr3 = r0gdb_read_cr3();
|
|
uint64_t pml4[512];
|
|
copyout(pml4, dmap+cr3, 4096);
|
|
for(int i = 256; i < 512; i++)
|
|
if(!pml4[i] && !idx--)
|
|
return i;
|
|
}
|
|
|
|
void build_uelf_cr3(uint64_t uelf_cr3, void* uelf_base[2], uint64_t uelf_virt_base, uint64_t dmap_virt_base)
|
|
{
|
|
static char zeros[4096];
|
|
uint64_t dmap = get_dmap_base();
|
|
uint64_t cr3 = r0gdb_read_cr3();
|
|
uint64_t user_start = (uint64_t)uelf_base[0];
|
|
uint64_t user_end = (uint64_t)uelf_base[1];
|
|
if((uelf_virt_base & 0x1fffff) || (dmap_virt_base & ((1ull << 39) - 1)) || user_end - user_start > 0x200000)
|
|
die();
|
|
uint64_t pml4_virt = uelf_cr3;
|
|
copyin(pml4_virt, zeros, 4096);
|
|
kmemcpy((void*)(pml4_virt+2048), (void*)(dmap+cr3+2048), 2048);
|
|
uint64_t pml3_virt = uelf_cr3 + 4096;
|
|
uint64_t pml3_dmap = uelf_cr3 + 16384; //user-accessible direct mapping of physical memory
|
|
copyin(pml4_virt + 8 * ((uelf_virt_base >> 39) & 511), &(uint64_t[1]){virt2phys(pml3_virt) | 7}, 8);
|
|
copyin(pml4_virt + 8 * ((dmap_virt_base >> 39) & 511), &(uint64_t[1]){virt2phys(pml3_dmap) | 7}, 8);
|
|
copyin(pml3_virt, zeros, 4096);
|
|
uint64_t pml2_virt = uelf_cr3 + 8192;
|
|
copyin(pml3_virt + 8 * ((uelf_virt_base >> 30) & 511), &(uint64_t[1]){virt2phys(pml2_virt) | 7}, 8);
|
|
copyin(pml2_virt, zeros, 4096);
|
|
uint64_t pml1_virt = uelf_cr3 + 12288;
|
|
copyin(pml2_virt + 8 * ((uelf_virt_base >> 21) & 511), &(uint64_t[1]){virt2phys(pml1_virt) | 7}, 8);
|
|
copyin(pml1_virt, zeros, 4096);
|
|
for(uint64_t i = 0; i * 4096 + user_start < user_end; i++)
|
|
copyin(pml1_virt+8*i, &(uint64_t[1]){virt2phys(i*4096+user_start) | 7}, 8);
|
|
for(uint64_t i = 0; i < 512; i++)
|
|
copyin(pml3_dmap+8*i, &(uint64_t[1]){(i<<30) | 135}, 8);
|
|
}
|
|
|
|
int find_proc(const char* name)
|
|
{
|
|
for(int pid = 1; pid < 1024; pid++)
|
|
{
|
|
size_t sz = 1096;
|
|
int key[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
|
|
char buf[1097] = {0};
|
|
sysctl(key, 4, buf, &sz, 0, 0);
|
|
const char* a = buf + 447;
|
|
const char* b = name;
|
|
while(*a && *a++ == *b++);
|
|
if(!*a && !*b)
|
|
return pid;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static uint64_t remote_syscall(int pid, int nr, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, nr);
|
|
uint64_t args[6];
|
|
for(int i = 0; i < 6; i++)
|
|
args[i] = va_arg(va, uint64_t);
|
|
va_end(va);
|
|
return kekcall(pid, nr, (uint64_t)args, 0, 0, 0, KEKCALL_REMOTE_SYSCALL);
|
|
}
|
|
|
|
#define SYS_mdbg_call 573
|
|
#define SYS_dynlib_get_info_ex 608
|
|
|
|
struct module_segment
|
|
{
|
|
uint64_t addr;
|
|
uint32_t size;
|
|
uint32_t flags;
|
|
};
|
|
|
|
struct module_info_ex
|
|
{
|
|
size_t st_size;
|
|
char name[256];
|
|
int id;
|
|
uint32_t tls_index;
|
|
uint64_t tls_init_addr;
|
|
uint32_t tls_init_size;
|
|
uint32_t tls_size;
|
|
uint32_t tls_offset;
|
|
uint32_t tls_align;
|
|
uint64_t init_proc_addr;
|
|
uint64_t fini_proc_addr;
|
|
uint64_t reserved1;
|
|
uint64_t reserved2;
|
|
uint64_t eh_frame_hdr_addr;
|
|
uint64_t eh_frame_addr;
|
|
uint32_t eh_frame_hdr_size;
|
|
uint32_t eh_frame_size;
|
|
struct module_segment segments[4];
|
|
uint32_t segment_count;
|
|
uint32_t ref_count;
|
|
};
|
|
|
|
struct shellcore_patch
|
|
{
|
|
uint64_t offset;
|
|
char* data;
|
|
size_t sz;
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_300[] = {
|
|
{0x9d1cae, "\x52\xeb\x08\x66\x90", 5},
|
|
{0x9d1cb9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
|
|
{0x9d18b1, "\x31\xc0\x50\xeb\xe3", 5},
|
|
{0x9d1899, "\xe8\x22\x00\x00\x00\x58\xc3", 7},
|
|
{0x4dcfb4, "\xeb\x04", 2},
|
|
{0x2569b1, "\xeb\x04", 2},
|
|
{0x25af5a, "\xeb\x04", 2},
|
|
{0x4fafca, "\x90\x90", 2},
|
|
{0x4e335d, "\x90\xe9", 2},
|
|
{0x4fbb63, "\xeb", 1},
|
|
{0x4ff329, "\xd0\x00\x00\x00", 4},
|
|
{0x1968c1, "\xe8\x4a\xde\x42\x00\x31\xc9\xff\xc1\xe9\x12\x01\x00\x00", 14},
|
|
{0x1969e1, "\x83\xf8\x02\x0f\x43\xc1\xe9\xff\xfb\xff\xff", 11},
|
|
{0x1965c9, "\xe9\xf3\x02\x00\x00", 5},
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_310[] = {
|
|
{0x9d1cee, "\x52\xeb\x08\x66\x90", 5},
|
|
{0x9d1cf9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
|
|
{0x9d18f1, "\x31\xc0\x50\xeb\xe3", 5},
|
|
{0x9d18d9, "\xe8\x22\x00\x00\x00\x58\xc3", 7},
|
|
{0x4dcff4, "\xeb\x04", 2},
|
|
{0x2569f1, "\xeb\x04", 2},
|
|
{0x25af9a, "\xeb\x04", 2},
|
|
{0x4fb00a, "\x90\x90", 2},
|
|
{0x4e339d, "\x90\xe9", 2},
|
|
{0x4fbba3, "\xeb", 1},
|
|
{0x4ff369, "\xd0\x00\x00\x00", 4},
|
|
{0x1968c1, "\xe8\x8a\xde\x42\x00\x31\xc9\xff\xc1\xe9\x12\x01\x00\x00", 14},
|
|
{0x1969e1, "\x83\xf8\x02\x0f\x43\xc1\xe9\xff\xfb\xff\xff", 11},
|
|
{0x1965c9, "\xe9\xf3\x02\x00\x00", 5},
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_320[] = {
|
|
{0x9d1f9e, "\x52\xeb\x08\x66\x90", 5},
|
|
{0x9d1fa9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
|
|
{0x9d1ba1, "\x31\xc0\x50\xeb\xe3", 5},
|
|
{0x9d1b89, "\xe8\x22\x00\x00\x00\x58\xc3", 7},
|
|
{0x4dd284, "\xeb\x04", 2},
|
|
{0x256aa1, "\xeb\x04", 2},
|
|
{0x25b04a, "\xeb\x04", 2},
|
|
{0x4fb29a, "\x90\x90", 2},
|
|
{0x4e362d, "\x90\xe9", 2},
|
|
{0x4fbe33, "\xeb", 1},
|
|
{0x4ff5f9, "\xd0\x00\x00\x00", 4},
|
|
{0x1968c1, "\xe8\x3a\xe1\x42\x00\x31\xc9\xff\xc1\xe9\x12\x01\x00\x00", 14},
|
|
{0x1969e1, "\x83\xf8\x02\x0f\x43\xc1\xe9\xff\xfb\xff\xff", 11},
|
|
{0x1965c9, "\xe9\xf3\x02\x00\x00", 5},
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_321[] = {
|
|
{0x9d1f9e, "\x52\xeb\x08\x66\x90", 5},
|
|
{0x9d1fa9, "\xe8\x02\xfc\xff\xff\x58\xc3", 7},
|
|
{0x9d1ba1, "\x31\xc0\x50\xeb\xe3", 5},
|
|
{0x9d1b89, "\xe8\x22\x00\x00\x00\x58\xc3", 7},
|
|
{0x4dd284, "\xeb\x04", 2},
|
|
{0x256aa1, "\xeb\x04", 2},
|
|
{0x25b04a, "\xeb\x04", 2},
|
|
{0x4fb29a, "\x90\x90", 2},
|
|
{0x4e362d, "\x90\xe9", 2},
|
|
{0x4fbe33, "\xeb", 1},
|
|
{0x4ff5f9, "\xd0\x00\x00\x00", 4},
|
|
{0x1968c1, "\xe8\x3a\xe1\x42\x00\x31\xc9\xff\xc1\xe9\x12\x01\x00\x00", 14},
|
|
{0x1969e1, "\x83\xf8\x02\x0f\x43\xc1\xe9\xff\xfb\xff\xff", 11},
|
|
{0x1965c9, "\xe9\xf3\x02\x00\x00", 5},
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_400[] = {
|
|
{0x974fee, "\x52\xeb\x08\x66\x90", 5},
|
|
{0x974ff9, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7},
|
|
{0x974bc1, "\x31\xc0\x50\xeb\xe3", 5},
|
|
{0x974ba9, "\xe8\x22\x00\x00\x00\x58\xc3", 7},
|
|
{0x5307f9, "\xeb\x04", 2},
|
|
{0x26f35c, "\xeb\x04", 2},
|
|
{0x26f76c, "\xeb\x04", 2},
|
|
{0x54e1f0, "\xeb", 1},
|
|
{0x536e1d, "\x90\xe9", 2},
|
|
{0x54db8f, "\xeb", 1},
|
|
{0x55137a, "\xc8\x00\x00\x00", 4},
|
|
{0x1a12d1, "\xe8\xea\x88\x47\x00\x31\xc9\xff\xc1\xe9\xf4\x02\x00\x00", 14},
|
|
{0x1a15d3, "\x83\xf8\x02\x0f\x43\xc1\xe9\x29\xfa\xff\xff", 11},
|
|
{0x1a0fe5, "\xe9\xe7\x02\x00\x00", 5},
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_403[] = {
|
|
{0x974fee, "\x52\xeb\x08\x66\x90", 5}, //push rdx; jmp 0x974ff9; 2-byte nop
|
|
{0x974ff9, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7}, //call 0x974bd0; pop rax; ret
|
|
{0x974bc1, "\x31\xc0\x50\xeb\xe3", 5}, //xor eax, eax; push rax; jmp 0x974ba9
|
|
{0x974ba9, "\xe8\x22\x00\x00\x00\x58\xc3", 7}, //call 0x974bd0; pop rax; ret
|
|
{0x5307f9, "\xeb\x04", 2}, //jmp 0x5307ff
|
|
{0x26f35c, "\xeb\x04", 2}, //jmp 0x26f362
|
|
{0x26f76c, "\xeb\x04", 2}, //jmp 0x26f772
|
|
{0x54e1f0, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x536e1d, "\x90\xe9", 2}, //nop; jmp (destination unchanged)
|
|
{0x54db8f, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x55137a, "\xc8\x00\x00\x00", 4}, //(jmp opcode unchanged) 0x551446
|
|
{0x1a12d1, "\xe8\xea\x88\x47\x00\x31\xc9\xff\xc1\xe9\xf4\x02\x00\x00", 14}, //call 0x619bc0; xor ecx, ecx; inc ecx; jmp 0x1a15d3
|
|
{0x1a15d3, "\x83\xf8\x02\x0f\x43\xc1\xe9\x29\xfa\xff\xff", 11}, //cmp eax, 2; cmovae eax, ecx; jmp 0x1a1007
|
|
{0x1a0fe5, "\xe9\xe7\x02\x00\x00", 5}, //jmp 0x1a12d1
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_450[] = {
|
|
{0x97595e, "\x52\xeb\x08\x66\x90", 5}, //push rdx; jmp 0x975969; 2-byte nop
|
|
{0x975969, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7}, //call 0x975540; pop rax; ret
|
|
{0x975531, "\x31\xc0\x50\xeb\xe3", 5}, //xor eax, eax; push rax; jmp 0x975519
|
|
{0x975519, "\xe8\x22\x00\x00\x00\x58\xc3", 7}, //call 0x975540; pop rax; ret
|
|
{0x530f42, "\xeb\x04", 2}, //jmp 0x530f48
|
|
{0x26fa8c, "\xeb\x04", 2}, //jmp 0x26fa16
|
|
{0x54eb60, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x5376bd, "\x90\xe9", 2}, //nop; jmp (destination unchanged)
|
|
{0x54e4ff, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x551cea, "\xc8\x00\x00\x00", 4}, //(jmp opcode unchanged) 0x551db6
|
|
{0x1a12d1, "\xe8\xfa\x88\x47\x00\x31\xc9\xff\xc1\xe9\xf4\x02\x00\x00", 14}, //call 0x619bd0; xor ecx, ecx; inc ecx; jmp 0x1a15d3
|
|
{0x1a15d3, "\x83\xf8\x02\x0f\x43\xc1\xe9\x29\xfa\xff\xff", 11}, //cmp eax, 2; cmovae eax, ecx; jmp 0x1a1007
|
|
{0x1a0fe5, "\xe9\xe7\x02\x00\x00", 5}, //jmp 0x1a12d1
|
|
};
|
|
|
|
static struct shellcore_patch shellcore_patches_451[] = {
|
|
{0x97596e, "\x52\xeb\x08\x66\x90", 5}, //push rdx; jmp 0x975979; 2-byte nop
|
|
{0x975979, "\xe8\xd2\xfb\xff\xff\x58\xc3", 7}, //call 0x975550; pop rax; ret
|
|
{0x975541, "\x31\xc0\x50\xeb\xe3", 5}, //xor eax, eax; push rax; jmp 0x975529
|
|
{0x975529, "\xe8\x22\x00\x00\x00\x58\xc3", 7}, //call 0x975550; pop rax; ret
|
|
{0x530f52, "\xeb\x04", 2}, //jmp 0x530f58
|
|
{0x26fa8c, "\xeb\x04", 2}, //jmp 0x26fa16
|
|
{0x54eb70, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x5376cd, "\x90\xe9", 2}, //nop; jmp (destination unchanged)
|
|
{0x54e50f, "\xeb", 1}, //jmp (destination unchanged)
|
|
{0x551cfa, "\xc8\x00\x00\x00", 4}, //(jmp opcode unchanged) 0x551dc6
|
|
{0x1a12d1, "\xe8\x0a\x89\x47\x00\x31\xc9\xff\xc1\xe9\xf4\x02\x00\x00", 14}, //call 0x619be0; xor ecx, ecx; inc ecx; jmp 0x1a15d3
|
|
{0x1a15d3, "\x83\xf8\x02\x0f\x43\xc1\xe9\x29\xfa\xff\xff", 11}, //cmp eax, 2; cmovae eax, ecx; jmp 0x1a1007
|
|
{0x1a0fe5, "\xe9\xe7\x02\x00\x00", 5}, //jmp 0x1a12d1
|
|
};
|
|
|
|
extern char _start[];
|
|
|
|
static void relocate_shellcore_patches(struct shellcore_patch* patches, size_t n_patches)
|
|
{
|
|
static uint64_t start_nonreloc = (uint64_t)_start;
|
|
uint64_t start = (uint64_t)_start;
|
|
for(size_t i = 0; i < n_patches; i++)
|
|
patches[i].data += start - start_nonreloc;
|
|
}
|
|
|
|
uint64_t get_eh_frame_offset(const char* path)
|
|
{
|
|
int fd = open(path, O_RDONLY);
|
|
if(!fd)
|
|
return 0;
|
|
unsigned long long shit[4];
|
|
if(read(fd, shit, sizeof(shit)) != sizeof(shit))
|
|
{
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
off_t o2 = 0x20*((shit[3]&0xffff)+1);
|
|
lseek(fd, o2, SEEK_SET);
|
|
unsigned long long ehdr[8];
|
|
if(read(fd, ehdr, sizeof(ehdr)) != sizeof(ehdr))
|
|
{
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
off_t phdr_offset = o2 + ehdr[4];
|
|
int nphdr = ehdr[7] & 0xffff;
|
|
unsigned long long eh_frame = 0;
|
|
lseek(fd, phdr_offset, SEEK_SET);
|
|
for(int i = 0; i < nphdr; i++)
|
|
{
|
|
unsigned long long phdr[7];
|
|
if(read(fd, phdr, sizeof(phdr)) != sizeof(phdr))
|
|
{
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
unsigned long long addr = phdr[2];
|
|
int ptype = phdr[0] & 0xffffffff;
|
|
if(ptype == 0x6474e550)
|
|
eh_frame = addr;
|
|
}
|
|
close(fd);
|
|
return eh_frame;
|
|
}
|
|
|
|
static const struct shellcore_patch* get_shellcore_patches(size_t* n_patches)
|
|
{
|
|
#ifdef FIRMWARE_PORTING
|
|
*n_patches = 1;
|
|
return 0;
|
|
#endif
|
|
#define FW(x)\
|
|
case 0x ## x:\
|
|
*n_patches = sizeof(shellcore_patches_ ## x) / sizeof(*shellcore_patches_ ## x);\
|
|
patches = shellcore_patches_ ## x;\
|
|
break
|
|
int(*sceKernelGetProsperoSystemSwVersion)(uint32_t*) = dlsym((void*)0x2001, "sceKernelGetProsperoSystemSwVersion");
|
|
uint32_t buf[10];
|
|
sceKernelGetProsperoSystemSwVersion(buf);
|
|
uint32_t ver = buf[9] >> 16;
|
|
struct shellcore_patch* patches;
|
|
switch(ver)
|
|
{
|
|
FW(300);
|
|
FW(310);
|
|
FW(320);
|
|
FW(321);
|
|
FW(400);
|
|
FW(403);
|
|
FW(450);
|
|
FW(451);
|
|
default:
|
|
*n_patches = 1;
|
|
return 0;
|
|
}
|
|
#undef FW
|
|
relocate_shellcore_patches(patches, *n_patches);
|
|
return patches;
|
|
}
|
|
|
|
static void patch_shellcore(const struct shellcore_patch* patches, size_t n_patches, uint64_t eh_frame_offset)
|
|
{
|
|
int pid = find_proc("SceShellCore");
|
|
struct module_info_ex mod_info;
|
|
mod_info.st_size = sizeof(mod_info);
|
|
remote_syscall(pid, SYS_dynlib_get_info_ex, 0, 0, &mod_info);
|
|
uint64_t shellcore_base = mod_info.eh_frame_hdr_addr - eh_frame_offset;
|
|
for(int i = 0; i < n_patches; i++)
|
|
{
|
|
uint64_t arg1[4] = {1, 0x13};
|
|
uint64_t arg2[8] = {pid, shellcore_base + patches[i].offset, (uint64_t)patches[i].data, patches[i].sz};
|
|
uint64_t arg3[4] = {0};
|
|
kekcall((uint64_t)arg1, (uint64_t)arg2, (uint64_t)arg3, 0, 0, 0, SYS_mdbg_call);
|
|
}
|
|
}
|
|
|
|
#ifndef DEBUG
|
|
#define dbg_enter()
|
|
#define gdb_remote_syscall(...)
|
|
#endif
|
|
|
|
void patch_app_db(void);
|
|
|
|
#ifdef FIRMWARE_PORTING
|
|
static struct PARASITES(100) parasites_empty = {};
|
|
#endif
|
|
|
|
static struct PARASITES(12) parasites_300 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 12,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x7e96ad, RDI},
|
|
{-0x38214c, RSI},
|
|
{-0x38210c, RSI},
|
|
/* fself parasites */
|
|
{-0x970280, RDI},
|
|
{-0x2c922a, RAX},
|
|
{-0x2c90f0, RAX},
|
|
{-0x2c8e0e, RAX},
|
|
{-0x2c8cc6, R10},
|
|
{-0x2c8b8d, RAX},
|
|
{-0x2c881e, RDX},
|
|
{-0x2c8812, RCX},
|
|
{-0x2c86a6, RAX},
|
|
/* unsorted parasites */
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(12) parasites_310 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 12,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x7e966d, RDI},
|
|
{-0x38210c, RSI},
|
|
{-0x3820cc, RSI},
|
|
/* fself parasites */
|
|
{-0x970280, RDI},
|
|
{-0x2c91ea, RAX},
|
|
{-0x2c90b0, RAX},
|
|
{-0x2c8dce, RAX},
|
|
{-0x2c8c86, R10},
|
|
{-0x2c8b4d, RAX},
|
|
{-0x2c87de, RDX},
|
|
{-0x2c87d2, RCX},
|
|
{-0x2c8666, RAX},
|
|
/* unsorted parasites */
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(12) parasites_320 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 12,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x7e931d, RDI},
|
|
{-0x381dbc, RSI},
|
|
{-0x381d7c, RSI},
|
|
/* fself parasites */
|
|
{-0x96ff40, RDI},
|
|
{-0x2c8e9a, RAX},
|
|
{-0x2c8d60, RAX},
|
|
{-0x2c8a7e, RAX},
|
|
{-0x2c8936, R10},
|
|
{-0x2c87fd, RAX},
|
|
{-0x2c848e, RDX},
|
|
{-0x2c8482, RCX},
|
|
{-0x2c8316, RAX},
|
|
/* unsorted parasites */
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(12) parasites_321 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 12,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x7e931d, RDI},
|
|
{-0x381dbc, RSI},
|
|
{-0x381d7c, RSI},
|
|
/* fself parasites */
|
|
{-0x96ff40, RDI},
|
|
{-0x2c8e9a, RAX},
|
|
{-0x2c8d60, RAX},
|
|
{-0x2c8a7e, RAX},
|
|
{-0x2c8936, R10},
|
|
{-0x2c87fd, RAX},
|
|
{-0x2c848e, RDX},
|
|
{-0x2c8482, RCX},
|
|
{-0x2c8316, RAX},
|
|
/* unsorted parasites */
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(12) parasites_400 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 12,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x80284d, RDI},
|
|
{-0x388a8c, RSI},
|
|
{-0x388a4c, RSI},
|
|
/* fself parasites */
|
|
{-0x990b10, RDI},
|
|
{-0x2cd36a, RAX},
|
|
{-0x2cd230, RAX},
|
|
{-0x2ccf53, RAX},
|
|
{-0x2cce16, R10},
|
|
{-0x2cccdd, RAX},
|
|
{-0x2cc96e, RDX},
|
|
{-0x2cc962, RCX},
|
|
{-0x2cc7f6, RAX},
|
|
/* unsorted parasites */
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(14) parasites_403 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 14,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x80284d, RDI},
|
|
{-0x3889ac, RSI},
|
|
{-0x38896c, RSI},
|
|
/* fself parasites */
|
|
{-0x2cc716, RAX},
|
|
{-0x2cd28a, RAX},
|
|
{-0x2cd150, RAX},
|
|
{-0x2cce73, RAX},
|
|
{-0x2ccbfd, RAX},
|
|
{-0x2cc88e, RDX},
|
|
{-0x2cc882, RCX},
|
|
{-0x990b10, RDI},
|
|
{-0x2ccd36, R10},
|
|
/* unsorted parasites */
|
|
{-0x479a0e, RAX},
|
|
{-0x479a0e, R15},
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(14) parasites_450 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 14,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x80281d, RDI},
|
|
{-0x38885c, RSI},
|
|
{-0x38881c, RSI},
|
|
/* fself parasites */
|
|
{-0x2cc566, RAX},
|
|
{-0x2cd0da, RAX},
|
|
{-0x2ccfa0, RAX},
|
|
{-0x2cccc3, RAX},
|
|
{-0x2cca4d, RAX},
|
|
{-0x2cc6de, RDX},
|
|
{-0x2cc6d2, RCX},
|
|
{-0x990b10, RDI},
|
|
{-0x2ccb86, R10},
|
|
/* unsorted parasites */
|
|
{-0x4798de, RAX},
|
|
{-0x4798de, R15},
|
|
}
|
|
};
|
|
|
|
static struct PARASITES(14) parasites_451 = {
|
|
.lim_syscall = 3,
|
|
.lim_fself = 12,
|
|
.lim_total = 14,
|
|
.parasites = {
|
|
/* syscall parasites */
|
|
{-0x80281d, RDI},
|
|
{-0x3884bc, RSI},
|
|
{-0x38847c, RSI},
|
|
/* fself parasites */
|
|
{-0x2cc1c6, RAX},
|
|
{-0x2ccd3a, RAX},
|
|
{-0x2ccc00, RAX},
|
|
{-0x2cc923, RAX},
|
|
{-0x2cc6ad, RAX},
|
|
{-0x2cc33e, RDX},
|
|
{-0x2cc332, RCX},
|
|
{-0x990b10, RDI},
|
|
{-0x2cc7e6, R10},
|
|
/* unsorted parasites */
|
|
{-0x47953e, RAX},
|
|
{-0x47953e, R15},
|
|
}
|
|
};
|
|
|
|
static struct parasite_desc* get_parasites(size_t* desc_size)
|
|
{
|
|
int(*sceKernelGetProsperoSystemSwVersion)(uint32_t*) = dlsym((void*)0x2001, "sceKernelGetProsperoSystemSwVersion");
|
|
uint32_t buf[10];
|
|
sceKernelGetProsperoSystemSwVersion(buf);
|
|
uint32_t ver = buf[9] >> 16;
|
|
switch(ver)
|
|
{
|
|
#ifndef FIRMWARE_PORTING
|
|
case 0x300:
|
|
*desc_size = sizeof(parasites_300);
|
|
return (void*)¶sites_300;
|
|
case 0x310:
|
|
*desc_size = sizeof(parasites_310);
|
|
return (void*)¶sites_310;
|
|
case 0x320:
|
|
*desc_size = sizeof(parasites_320);
|
|
return (void*)¶sites_320;
|
|
case 0x321:
|
|
*desc_size = sizeof(parasites_321);
|
|
return (void*)¶sites_321;
|
|
case 0x400:
|
|
*desc_size = sizeof(parasites_400);
|
|
return (void*)¶sites_400;
|
|
case 0x403:
|
|
*desc_size = sizeof(parasites_403);
|
|
return (void*)¶sites_403;
|
|
case 0x450:
|
|
*desc_size = sizeof(parasites_450);
|
|
return (void*)¶sites_450;
|
|
case 0x451:
|
|
*desc_size = sizeof(parasites_451);
|
|
return (void*)¶sites_451;
|
|
default:
|
|
return 0;
|
|
#else
|
|
default:
|
|
*desc_size = sizeof(parasites_empty);
|
|
return (void*)¶sites_empty;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int main(void* ds, int a, int b, uintptr_t c, uintptr_t d)
|
|
{
|
|
if(r0gdb_init(ds, a, b, c, d))
|
|
{
|
|
#ifndef FIRMWARE_PORTING
|
|
notify("your firmware is not supported (prosper0gdb)");
|
|
return 1;
|
|
#endif
|
|
}
|
|
size_t desc_size = 0;
|
|
struct parasite_desc* desc = get_parasites(&desc_size);
|
|
if(!desc)
|
|
{
|
|
notify("your firmware is not supported (ps5-kstuff)");
|
|
return 1;
|
|
}
|
|
size_t n_shellcore_patches;
|
|
uint64_t shellcore_eh_frame_offset = get_eh_frame_offset("/system/vsh/SceShellCore.elf");
|
|
const struct shellcore_patch* shellcore_patches = get_shellcore_patches(&n_shellcore_patches);
|
|
if(n_shellcore_patches && !shellcore_patches)
|
|
{
|
|
#ifdef FIRMWARE_PORTING
|
|
n_shellcore_patches = 0;
|
|
#else
|
|
notify("your firmware is not supported (shellcore)");
|
|
return 1;
|
|
#endif
|
|
}
|
|
#ifdef FIRMWARE_PORTING
|
|
dbg_enter();
|
|
#endif
|
|
uint64_t percpu_ist4[NCPUS];
|
|
for(int cpu = 0; cpu < NCPUS; cpu++)
|
|
copyout(&percpu_ist4[cpu], TSS(cpu)+28+4*8, 8);
|
|
uint64_t int1_handler;
|
|
copyout(&int1_handler, IDT+16*1, 2);
|
|
copyout((char*)&int1_handler + 2, IDT+16*1+6, 6);
|
|
uint64_t int13_handler;
|
|
copyout(&int13_handler, IDT+16*13, 2);
|
|
copyout((char*)&int13_handler + 2, IDT+16*13+6, 6);
|
|
#ifndef FIRMWARE_PORTING
|
|
dbg_enter();
|
|
#endif
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"allocating kernel memory... ", (uintptr_t)28);
|
|
for(int i = 0; i < 0x300; i += 2)
|
|
r0gdb_kmalloc(0x100);
|
|
for(int i = 0; i < 2; i += 2)
|
|
{
|
|
while(!mem_blocks[i])
|
|
mem_blocks[i] = r0gdb_kmalloc(1<<23);
|
|
mem_blocks[i+1] = (mem_blocks[i] ? mem_blocks[i] + (1<<23) : 0);
|
|
}
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\n", (uintptr_t)5);
|
|
uint64_t shared_area = (uint64_t)kmalloc(8192);
|
|
shared_area = ((shared_area - 1) | 4095) + 1;
|
|
kmemzero((void*)shared_area, 4096);
|
|
uint64_t uelf_virt_base = (find_empty_pml4_index(0) << 39) | (-1ull << 48);
|
|
uint64_t dmem_virt_base = (find_empty_pml4_index(1) << 39) | (-1ull << 48);
|
|
shared_area = virt2phys(shared_area) + dmem_virt_base;
|
|
uint64_t uelf_parasite_desc = (uint64_t)kmalloc(8192);
|
|
uelf_parasite_desc = ((uelf_parasite_desc - 1) | 4095) + 1;
|
|
for(int i = 0; i < desc->lim_total; i++)
|
|
desc->parasites[i].address += kdata_base;
|
|
kmemcpy((void*)uelf_parasite_desc, desc, desc_size);
|
|
uelf_parasite_desc = virt2phys(uelf_parasite_desc) + dmem_virt_base;
|
|
volatile int zero = 0; //hack to force runtime calculation of string pointers
|
|
const char* symbols[] = {
|
|
"dmem"+zero,
|
|
"parasites"+zero,
|
|
"int1_handler"+zero,
|
|
"int13_handler"+zero,
|
|
".ist_errc"+zero,
|
|
".ist_noerrc"+zero,
|
|
".ist4"+zero,
|
|
".pcpu"+zero,
|
|
"shared_area"+zero,
|
|
".tss"+zero,
|
|
".uelf_cr3"+zero,
|
|
".uelf_entry"+zero,
|
|
#define OFFSET(x) (#x)+zero,
|
|
#include "../prosper0gdb/offset_list.txt"
|
|
#undef OFFSET
|
|
0,
|
|
};
|
|
uint64_t values[] = {
|
|
dmem_virt_base, // dmem
|
|
uelf_parasite_desc, // parasites
|
|
int1_handler, // int1_handler
|
|
int13_handler, // int13_handler
|
|
0x1237, // .ist_errc
|
|
0x1238, // .ist_noerrc
|
|
0x1239, // .ist4
|
|
0x1234, // .pcpu
|
|
shared_area, // shared_area
|
|
0x123a, // .tss
|
|
0x1235, // .uelf_cr3
|
|
0x1236, // .uelf_entry
|
|
#define OFFSET(x) offsets.x,
|
|
#include "../prosper0gdb/offset_list.txt"
|
|
#undef OFFSET
|
|
0,
|
|
};
|
|
size_t pcpu_idx, uelf_cr3_idx, uelf_entry_idx, ist_errc_idx, ist_noerrc_idx, ist4_idx, tss_idx;
|
|
for(size_t i = 0; values[i]; i++)
|
|
switch(values[i])
|
|
{
|
|
case 0x1234: pcpu_idx = i; break;
|
|
case 0x1235: uelf_cr3_idx = i; break;
|
|
case 0x1236: uelf_entry_idx = i; break;
|
|
case 0x1237: ist_errc_idx = i; break;
|
|
case 0x1238: ist_noerrc_idx = i; break;
|
|
case 0x1239: ist4_idx = i; break;
|
|
case 0x123a: tss_idx = i; break;
|
|
}
|
|
uint64_t uelf_bases[NCPUS];
|
|
uint64_t kelf_bases[NCPUS];
|
|
uint64_t kelf_entries[NCPUS];
|
|
uint64_t uelf_cr3s[NCPUS];
|
|
for(int cpu = 0; cpu < NCPUS; cpu++)
|
|
{
|
|
char buf[] = "loading on cpu ..\n";
|
|
if(cpu >= 10)
|
|
{
|
|
buf[15] = '1';
|
|
buf[16] = (cpu - 10) + '0';
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)buf, (uintptr_t)18);
|
|
}
|
|
else
|
|
{
|
|
buf[15] = cpu + '0';
|
|
buf[16] = '\n';
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)buf, (uintptr_t)17);
|
|
}
|
|
values[pcpu_idx] = PCPU(cpu);
|
|
values[uelf_cr3_idx] = 0;
|
|
values[uelf_entry_idx] = 0;
|
|
values[ist_errc_idx] = TSS(cpu)+28+3*8;
|
|
values[ist_noerrc_idx] = TSS(cpu)+28+7*8;
|
|
values[ist4_idx] = percpu_ist4[cpu];
|
|
values[tss_idx] = TSS(cpu);
|
|
void* uelf_entry = 0;
|
|
void* uelf_base[2] = {0};
|
|
char* uelf = load_kelf(uek, symbols, values, uelf_base, &uelf_entry, uelf_virt_base);
|
|
uintptr_t uelf_cr3 = (uintptr_t)kmalloc(24576);
|
|
uelf_cr3 = ((uelf_cr3 + 4095) | 4095) - 4095;
|
|
uelf_cr3s[cpu] = uelf_cr3;
|
|
values[uelf_cr3_idx] = virt2phys(uelf_cr3);
|
|
values[uelf_entry_idx] = (uintptr_t)uelf_entry - (uintptr_t)uelf_base[0] + uelf_virt_base;
|
|
void* entry = 0;
|
|
void* base[2] = {0};
|
|
char* kelf = load_kelf(kek, symbols, values, base, &entry, 0);
|
|
build_uelf_cr3(uelf_cr3, uelf_base, uelf_virt_base, dmem_virt_base);
|
|
uelf_bases[cpu] = (uintptr_t)uelf;
|
|
kelf_bases[cpu] = (uint64_t)kelf;
|
|
kelf_entries[cpu] = (uint64_t)entry;
|
|
}
|
|
r0gdb_wrmsr(0xc0000084, r0gdb_rdmsr(0xc0000084) | 0x100);
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done loading\npatching idt... ", (uintptr_t)29);
|
|
uint64_t cr3 = r0gdb_read_cr3();
|
|
for(int cpu = 0; cpu < NCPUS; cpu++)
|
|
{
|
|
uint64_t entry = kelf_entries[cpu];
|
|
kmemcpy((char*)IDT+16*13, (char*)entry, 2);
|
|
kmemcpy((char*)IDT+16*13+6, (char*)entry+2, 6);
|
|
kmemcpy((char*)IDT+16*13+4, "\x03", 1);
|
|
kmemcpy((char*)IDT+16*1, (char*)entry+16, 2);
|
|
kmemcpy((char*)IDT+16*1+6, (char*)entry+18, 6);
|
|
kmemcpy((char*)IDT+16*1+4, "\x07", 1);
|
|
kmemcpy((char*)TSS(cpu)+28+3*8, (char*)entry+8, 8);
|
|
kmemcpy((char*)TSS(cpu)+28+7*8, (char*)entry+24, 8);
|
|
}
|
|
uint64_t iret = offsets.doreti_iret;
|
|
kmemcpy((char*)(IDT+16*2), (char*)&iret, 2);
|
|
kmemcpy((char*)(IDT+16*2+6), (char*)&iret+2, 6);
|
|
//kmemzero((char*)(IDT+16*1), 16);
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\napplying kdata patches... ", (uintptr_t)31);
|
|
copyin(offsets.sysentvec + 14, &(const uint16_t[1]){0xdeb7}, 2); //native sysentvec
|
|
copyin(offsets.sysentvec_ps4 + 14, &(const uint16_t[1]){0xdeb7}, 2); //ps4 sysentvec
|
|
copyin(offsets.crypt_singleton_array + 11*8 + 2*8 + 6, &(const uint16_t[1]){0xdeb7}, 2); //crypt xts
|
|
copyin(offsets.crypt_singleton_array + 11*8 + 9*8 + 6, &(const uint16_t[1]){0xdeb7}, 2); //crypt hmac
|
|
{
|
|
//enable debug settings & spoof target
|
|
uint32_t q = 0;
|
|
copyout(&q, offsets.security_flags, 4);
|
|
q |= 0x14;
|
|
copyin(offsets.security_flags, &q, 4);
|
|
copyin(offsets.targetid, "\x82", 1);
|
|
copyout(&q, offsets.qa_flags, 4);
|
|
q |= 0x1030300;
|
|
copyin(offsets.qa_flags, &q, 4);
|
|
copyout(&q, offsets.utoken, 4);
|
|
q |= 1;
|
|
copyin(offsets.utoken, &q, 4);
|
|
}
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\npatching shellcore... ", (uintptr_t)27);
|
|
p_kekcall = (char*)dlsym((void*)0x2001, "getpid") + 7;
|
|
//restore the gdb_stub's SIGTRAP handler
|
|
struct sigaction sa;
|
|
sigaction(SIGBUS, 0, &sa);
|
|
sigaction(SIGTRAP, &sa, 0);
|
|
#ifndef FIRMWARE_PORTING
|
|
sigaction(SIGPIPE, &sa, 0);
|
|
#endif
|
|
copyin(IDT+16*9+5, "\x8e", 1);
|
|
copyin(IDT+16*179+5, "\x8e", 1);
|
|
patch_shellcore(shellcore_patches, n_shellcore_patches, shellcore_eh_frame_offset);
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\npatching app.db... ", (uintptr_t)24);
|
|
#ifndef FIRMWARE_PORTING
|
|
patch_app_db();
|
|
#endif
|
|
gdb_remote_syscall("write", 3, 0, (uintptr_t)1, (uintptr_t)"done\n", (uintptr_t)5);
|
|
#ifndef DEBUG
|
|
notify("ps5-kstuff successfully loaded");
|
|
return 0;
|
|
#endif
|
|
asm volatile("ud2");
|
|
return 0;
|
|
}
|