orbital/tools/dumper/source/pup_decrypter.c
Alexandro Sanchez Bach 94ed646bd0
Added PUPMGR spawn/exit code
Signed-off-by: Alexandro Sanchez Bach <alexandro@phi.nz>
2019-06-29 14:55:13 +02:00

268 lines
6.7 KiB
C

/**
* (c) 2017-2018 Alexandro Sanchez Bach.
* Released under MIT license. Read LICENSE for more details.
*
* Based in previous research by: flatz.
*/
#include "pup_decrypter.h"
#include "ksdk.h"
#include "blob.h"
#include "debug.h"
/* debugging */
#define DEBUG_PUP 1
#define assert(cond) if (!(cond)) { \
dprintf("%s:%d: failed.\n", __FUNCTION__, __LINE__); \
goto error; \
}
#define kassert(cond) if (!(cond)) { \
kdprintf("%s:%d: failed.\n", __FUNCTION__, __LINE__); \
goto error; \
}
/* constants */
#define BLS_MAGIC 0x32424C53
#define PUP_MAGIC 0x1D3D154F
/* debug */
void trace_pup(pup_t *pup)
{
uint32_t i;
bls_entry_t *entry;
dprintf("pup:\n");
dprintf(" file-path: %s\n", pup->file_path);
dprintf(" file-size: 0x%llX bytes\n", pup->file_size);
dprintf(" header:\n");
dprintf(" magic: 0x%08X\n", pup->header.magic);
dprintf(" version: 0x%08X\n", pup->header.version);
dprintf(" flags: 0x%08X\n", pup->header.flags);
dprintf(" entry_count: 0x%08X\n", pup->header.entry_count);
dprintf(" block_count: 0x%08X\n", pup->header.block_count);
dprintf(" entries:\n");
for (i = 0; i < pup->header.entry_count; i++) {
entry = &pup->entries[i];
dprintf(" [%u]\n", i);
dprintf(" block_offset: 0x%08X\n", entry->block_offset);
dprintf(" file_size: 0x%08X\n", entry->file_size);
dprintf(" file_name: %s\n", entry->file_name);
}
}
/* kernel */
typedef struct pup_kdecrypt_segment_args_t {
unsigned int segment_index;
uint8_t *segment_data_user;
size_t segment_data_user_size;
} pup_kdecrypt_segment_args_t;
typedef struct pup_kmethod_uap_t {
void *kmethod;
pup_t *pup;
void *args;
} pup_kmethod_uap_t;
int pup_kpupmgr_open(
struct thread *td, struct pup_kmethod_uap_t *uap)
{
int ret;
pup_t *pup = uap->pup;
kassert(pup->svc_id == 0);
ret = sceSblServiceSpawn("80010006", 0, 0, 0, 0, &pup->svc_id);
kassert(!ret);
kassert(pup->svc_id != 0);
error:
return ret;
}
int pup_kpupmgr_close(
struct thread *td, struct pup_kmethod_uap_t *uap)
{
int ret;
char payload[0x80];
sbl_pupmgr_exit_t *cmd = (void*)&payload[0];
pup_t *pup = uap->pup;
kassert(pup->svc_id != 0);
memset(payload, 0, sizeof(payload));
cmd->function = 0xFFFF;
cmd->status = 0;
sceSblServiceMailbox_locked(ret, pup->svc_id, &payload, &payload);
kassert(ret == 0);
sceSblServiceMailbox_locked(ret, pup->svc_id, &payload, &payload);
kassert(ret == -3);
pup->svc_id = 0;
error:
return ret;
}
int pup_kdecrypt_segment(
struct thread *td, struct pup_kmethod_uap_t *uap)
{
int ret;
char payload[0x80];
size_t segment_data_size;
uint64_t segment_data_gpu_paddr = NULL;
uint64_t segment_data_gpu_desc = NULL;
uint8_t *segment_data = NULL;
uint64_t chunk_table_gpu_paddr = NULL;
uint64_t chunk_table_gpu_desc = NULL;
uint8_t *chunk_table = NULL;
pup_kdecrypt_segment_args_t *args = uap->args;
pup_t *pup = uap->pup;
ret = 1;
/* copy segment data */
segment_data_size = ALIGN_PAGE(args->segment_data_user_size);
segment_data = kmalloc(segment_data_size, M_AUTHMGR, 0x102);
kassert(segment_data);
memset(segment_data, 0, segment_data_size);
memcpy(segment_data, args->segment_data_user, args->segment_data_user_size);
/* create chunk table */
chunk_table = kmalloc(0x4000, M_AUTHMGR, 0x102);
kassert(chunk_table);
ret = make_chunk_table(
&segment_data_gpu_paddr,
&segment_data_gpu_desc,
segment_data,
segment_data_size,
chunk_table,
0x4000, 0);
kassert(!ret);
kassert(segment_data_gpu_paddr);
kassert(segment_data_gpu_desc);
ret = map_chunk_table(
&chunk_table_gpu_paddr,
&chunk_table_gpu_desc,
chunk_table);
kassert(!ret);
kassert(chunk_table_gpu_paddr);
kassert(chunk_table_gpu_desc);
/* decrypt segment */
sbl_pupmgr_decrypt_segment_t *cmd = (void*)&payload[0];
memset(payload, 0, sizeof(payload));
cmd->function = PUPMGR_CMD_DECRYPT_SEGMENT;
cmd->status = 0;
cmd->chunk_table_addr = chunk_table_gpu_paddr;
cmd->segment_index = args->segment_index;
kdprintf("Sending PUPMGR_CMD_DECRYPT_SEGMENT...\n");
sceSblServiceMailbox_locked(ret, pup->svc_id, &payload, &payload);
kassert(!ret);
kassert(!cmd->status);
kassert(cmd->function == PUPMGR_CMD_DECRYPT_SEGMENT);
memcpy(args->segment_data_user, segment_data, args->segment_data_user_size);
ret = 0;
error:
if (chunk_table_gpu_paddr)
kassert(!sceSblDriverUnmapPages(chunk_table_gpu_desc));
if (segment_data_gpu_paddr)
kassert(!sceSblDriverUnmapPages(segment_data_gpu_desc));
if (chunk_table)
kfree(chunk_table, M_AUTHMGR);
if (segment_data)
kfree(segment_data, M_AUTHMGR);
return ret;
}
pup_t* pup_open(const char* file)
{
pup_t* pup;
ssize_t size;
off_t off;
int fd;
/* allocate object */
pup = malloc(sizeof(pup_t));
assert(pup);
memset(pup, 0, sizeof(pup_t));
/* open file */
fd = open(file, O_RDONLY, 0);
assert(fd >= 0);
pup->fd = fd;
/* get pup size */
off = lseek(fd, 0, SEEK_END);
assert(off >= 0);
pup->file_size = off;
off = lseek(fd, 0, SEEK_SET);
assert(off >= 0);
/* get bls header */
size = read(fd, &pup->header, sizeof(bls_header_t));
assert(size == sizeof(bls_header_t));
assert(pup->header.magic == BLS_MAGIC);
assert(pup->header.entry_count > 0);
/* get bls entries */
pup->entries_size = pup->header.entry_count * sizeof(bls_entry_t);
pup->entries = malloc(pup->entries_size);
assert(pup->entries);
memset(pup->entries, 0, pup->entries_size);
size = read(fd, pup->entries, pup->entries_size);
assert(size == pup->entries_size);
/* open pupmgr */
syscall(11, pup_kpupmgr_open, pup);
/* return pup object */
pup->fd = fd;
pup->file_path = strdup(file);
if (DEBUG_PUP) {
trace_pup(pup);
}
return pup;
error:
pup_close(pup);
return NULL;
}
int pup_verify_header(pup_t *pup)
{
return 0;
}
int pup_decrypt_segments(pup_t *pup)
{
return 0;
}
void pup_close(pup_t *pup)
{
struct blob_t *blob;
struct blob_t *next;
if (!pup) {
return;
}
/* close pupmgr */
syscall(11, pup_kpupmgr_close, pup);
/* remove blobs */
blob = pup->blobs;
while (blob) {
next = blob->next;
free(blob->data);
free(blob);
blob = next;
}
/* close file */
if (pup->fd) {
close(pup->fd);
}
free(pup->file_path);
free(pup->entries);
free(pup);
}