orbital/tools/dumper/source/main.c
Alexandro Sanchez Bach 583df8beb9
Filtering recycle.bin for USB drives
Signed-off-by: Alexandro Sanchez Bach <alexandro@phi.nz>
2019-06-29 14:59:00 +02:00

273 lines
6.2 KiB
C

/**
* (c) 2017-2018 Alexandro Sanchez Bach.
* Released under MIT license. Read LICENSE for more details.
*
* Based/inspired by previous tools and research by:
* flatz, m0rph3us1987, wildcard.
*/
#include "ps4.h"
#include "blob.h"
#include "debug.h"
#include "ksdk.h"
#include "gpu_dumper.h"
#include "pup_decrypter.h"
#include "self_decrypter.h"
#include "self_mapper.h"
/* kernel payloads */
int kpatch_getroot(struct thread *td)
{
/* Resolve credentials */
struct ucred *cred;
struct filedesc *fd;
fd = td->td_proc->p_fd;
cred = td->td_proc->p_ucred;
/* Escalate process to uid0 */
cred->cr_uid = 0;
cred->cr_ruid = 0;
cred->cr_rgid = 0;
cred->cr_groups[0] = 0;
/* Break out of FreeBSD jail */
cred->cr_prison = prison0[0];
/* Escalate ucred privs */
void *td_ucred = *(void **)(((char *)td) + 304);
// sceSblACMgrIsSystemUcred
uint64_t *sonyCred = (uint64_t *)(((char *)td_ucred) + 96);
*sonyCred = 0xffffffffffffffff;
// sceSblACMgrGetDeviceAccessType
uint64_t *sceProcType = (uint64_t *)(((char *)td_ucred) + 88);
*sceProcType = 0x3801000000000013;
// sceSblACMgrHasSceProcessCapability
uint64_t *sceProcCap = (uint64_t *)(((char *)td_ucred) + 104);
*sceProcCap = 0xffffffffffffffff;
/* Set vnode to real root "/" to defeat sandbox */
fd->fd_rdir = rootvnode[0];
fd->fd_jdir = rootvnode[0];
/* Return back to usermode */
return 0;
}
void kpatch_enablemapself(struct thread *td)
{
uint8_t *kmem;
cpu_disable_wp();
/* update offsets (5.00) */
uint8_t* kernel_base = &((uint8_t*)read_msr(0xC0000082))[-0x1C0];
uint8_t* map_self_patch1 = &kernel_base[0x117B0];
uint8_t* map_self_patch2 = &kernel_base[0x117C0];
#ifdef VERSION_500
uint8_t* map_self_patch3 = &kernel_base[0x13EF2F];
#elif VERSION_505
uint8_t* map_self_patch3 = &kernel_base[0x13F03F];
#else
#error "Target firmware not yet supported."
#endif
// sceSblACMgrIsAllowedToMmapSelf result
kmem = (uint8_t*)map_self_patch1;
kmem[0] = 0xB8;
kmem[1] = 0x01;
kmem[2] = 0x00;
kmem[3] = 0x00;
kmem[4] = 0x00;
kmem[5] = 0xC3;
// sceSblACMgrHasMmapSelfCapability result
kmem = (uint8_t*)map_self_patch2;
kmem[0] = 0xB8;
kmem[1] = 0x01;
kmem[2] = 0x00;
kmem[3] = 0x00;
kmem[4] = 0x00;
kmem[5] = 0xC3;
// sceSblAuthMgrIsLoadable bypass
kmem = (uint8_t*)map_self_patch3;
kmem[0] = 0x31;
kmem[1] = 0xC0;
kmem[2] = 0x90;
kmem[3] = 0x90;
kmem[4] = 0x90;
cpu_enable_wp();
}
static int traverse_dir(const char *dir, int recursive, void(*handler)(const char*))
{
void *dp;
struct dirent *entry;
char name[1024];
dp = opendir(dir);
if (!dp) {
dprintf("Invalid directory.\n");
return 1;
}
while ((entry = readdir(dp)) != NULL) {
if (entry->d_type == DT_DIR && recursive) {
if (!strcmp(entry->d_name, ".") ||
!strcmp(entry->d_name, "..") ||
!strcmp(entry->d_name, "$RECYCLE.BIN") ||
!strcmp(entry->d_name, "sandbox")) {
continue;
}
snprintf(name, sizeof(name), "%s/%s", dir, entry->d_name);
traverse_dir(name, recursive, handler);
}
if (entry->d_type == DT_REG) {
snprintf(name, sizeof(name), "%s/%s", dir, entry->d_name);
handler(name);
}
}
closedir(dp);
return 0;
}
static void decrypt_self_to_blobs(const char *file)
{
int err;
self_t *self;
const char *dot;
// Check filename and open file
dot = strrchr(file, '.');
if (!dot) return;
if (strcmp(dot, ".self") &&
strcmp(dot, ".sprx") &&
strcmp(dot, ".elf") &&
strcmp(dot, ".bin")) {
return;
}
dprintf("Decrypting %s to blobs.\n", file);
self = self_open(file);
if (!self) {
return;
}
// Decrypt SELF
err = self_verify_header(self);
if (err)
goto fail;
err = self_load_segments(self);
if (err)
goto fail;
blob_transfer_all(self->blobs, BLOB_TRANSFER_NET);
fail:
self_close(self);
return;
}
static void decrypt_self_to_elf(const char *file)
{
const char *dot;
char path[256];
uint8_t *elf_data;
size_t elf_size;
blob_t blob;
// Check filename and open file
dot = strrchr(file, '.');
if (!dot) return;
if (strcmp(dot, ".self") &&
strcmp(dot, ".sprx") &&
strcmp(dot, ".elf") &&
strcmp(dot, ".bin")) {
return;
}
dprintf("Decrypting %s to ELF.\n", file);
elf_data = self_decrypt_file(file, &elf_size);
if (!elf_data)
return;
blob.next = NULL;
blob.data = elf_data;
blob.size = elf_size;
snprintf(path, sizeof(path), "elfs/%s", file);
blob_set_path(&blob, path);
blob_transfer(&blob, BLOB_TRANSFER_NET);
free(elf_data);
}
static void decrypt_pup_to_blobs(const char *file)
{
int err;
pup_t *pup;
const char *dot;
// Check filename and open file
dot = strrchr(file, '.');
if (!dot) return;
if (strcmp(dot, ".PUP") &&
strcmp(dot, ".pup")) {
return;
}
dprintf("Decrypting %s to blobs.\n", file);
pup = pup_open(file);
if (!pup) {
return;
}
// Decrypt PUP
err = pup_verify_header(pup);
if (err)
goto fail;
err = pup_decrypt_segments(pup);
if (err)
goto fail;
blob_transfer_all(pup->blobs, BLOB_TRANSFER_NET);
fail:
pup_close(pup);
return;
}
static void decrypt_selfs(void)
{
traverse_dir("/", true, decrypt_self_to_blobs);
traverse_dir("/", true, decrypt_self_to_elf);
}
static void decrypt_pups(void)
{
traverse_dir("/mnt/usb0", true, decrypt_pup_to_blobs);
}
int _main(struct thread *td)
{
/* Prepare userland environment */
initKernel();
initLibc();
initNetwork();
debug_init();
blob_transfer_init();
dprintf("Starting dump...\n");
/* Prepare kernel environment*/
syscall(11, init_ksdk);
syscall(11, kpatch_getroot);
syscall(11, kpatch_enablemapself);
/* Dump/decrypt data */
decrypt_selfs();
decrypt_pups();
//gpu_dump_ih();
/* Return back to browser */
dprintf("Dump finished!\n");
blob_transfer_close();
debug_close();
return 0;
}