mirror of
https://github.com/AlexAltea/orbital.git
synced 2025-04-02 10:32:05 -04:00
268 lines
6.7 KiB
C
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);
|
|
}
|