Skip to content

Instantly share code, notes, and snippets.

@SKGleba
Created October 13, 2022 15:49
Show Gist options
  • Save SKGleba/05f2445d364a6987d917cbdd8baf226c to your computer and use it in GitHub Desktop.
Save SKGleba/05f2445d364a6987d917cbdd8baf226c to your computer and use it in GitHub Desktop.
find, extract, etoify qaf tokens from a blob
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdbool.h>
#include "crc32.c"
#define CFGINFO "# Generated based on a leaked QAF utility GC\r\n"
// todo: add i
const char* aes256cbc_key_e = "6C1C31251E7BF435F3E232ECDBFCB9D647A31A4D2954F1CC718FA92F63E30A73";
const char* aes256cbc_iv_e = "11295CABDE7337EC8F29DD451D387CB2";
static uint8_t E_qafv[0x20] = {
0x71, 0x61, 0x66, 0x76, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x77, 0xF1, 0xDB, 0xE4, 0xC5, 0x14, 0x9F, 0x14, 0x0C, 0xCA, 0xA5, 0x3F, 0xB0, 0x61, 0x56, 0xDA
};
uint64_t getSz(const char* src) {
FILE* fp = fopen(src, "rb");
if (fp == NULL)
return 0;
fseek(fp, 0L, SEEK_END);
uint64_t sz = ftell(fp);
fclose(fp);
return sz;
}
static const char hexbase[] = "0123456789ABCDEF";
int hntoa(uint8_t* input, char* output, int output_len) {
if (output_len & 1)
return -1;
output_len = output_len / 2;
for (int i = 0; i < output_len; i -= -1) {
output[i * 2] = hexbase[(input[i] & 0xF0) >> 4];
output[(i * 2) + 1] = hexbase[input[i] & 0x0F];
}
return 0;
}
int dump_to_file(int num, void* qaf, const char* dir) {
char name[0x200];
memset(name, 0, 0x200);
snprintf(name, 0x200, "%s/%04d_%s.bin", dir, num, (char*)(qaf + 8));
printf("writing %s ...", name);
FILE* fp = fopen(name, "wb");
if (fp == NULL)
return -1;
fwrite(qaf, 0x180, 1, fp);
fclose(fp);
}
int dump_to_dec(int num, void* qaf, const char* dir, void* ret_cid, void* ret_qaf) {
char buf[0x400];
char *enc_name = buf;
memset(enc_name, 0, 0x100);
snprintf(enc_name, 0x100, "%s/tmp_enc.bin", dir);
unlink(enc_name);
FILE* fp = fopen(enc_name, "wb");
if (fp == NULL)
return -1;
fwrite(qaf + 0x20, 0x60, 1, fp);
fclose(fp);
char* cmd = buf;
memset(cmd, 0, 0x200);
snprintf(cmd, 0x200, "openssl aes-256-cbc -in %s/tmp_enc.bin -K %s -iv %s -d > %s/tmp_dec.bin -nopad", dir, aes256cbc_key_e, aes256cbc_iv_e, dir);
system(cmd);
uint8_t* dec_data = buf + 0x200;
memcpy(dec_data, qaf, 0x20);
char* dec_name = buf;
memset(dec_name, 0, 0x100);
snprintf(dec_name, 0x100, "%s/tmp_dec.bin", dir);
fp = fopen(dec_name, "rb");
if (fp == NULL)
return -1;
fread(dec_data + 0x20, 0x60, 1, fp);
fclose(fp);
char *name = buf;
memset(name, 0, 0x100);
snprintf(name, 0x100, "%s/%04d_%s_dec.bin", dir, num, (char*)(qaf + 8));
printf("writing %s ...", name);
fp = fopen(name, "wb");
if (fp == NULL)
return -1;
fwrite(dec_data, 0x80, 1, fp);
fclose(fp);
memcpy(ret_cid, dec_data + 0x20, 0x10);
memcpy(ret_qaf, dec_data + 0x30, 0x10);
return 0;
}
int dump_to_config(int num, void* qaf, const char* dir, uint8_t* cid, uint8_t* qa_flags) {
char buf[0x400];
char* cid_ascii = buf + 0x200;
hntoa(cid, cid_ascii, 0x20);
char* qaf_ascii = buf + 0x220;
hntoa(qa_flags, qaf_ascii, 0x20);
char* qafv_ascii_crc = buf + 0x240;
snprintf(qafv_ascii_crc, 0x20, "NVS_OP0_BUFCRC=0x%08X\r\n", crc32(0, E_qafv, 0x20));
char* token_ascii_crc = buf + 0x260;
snprintf(token_ascii_crc, 0x20, "NVS_OP1_BUFCRC=0x%08X\r\n", crc32(0, qaf, 0x80));
char* sig_ascii_crc = buf + 0x280;
snprintf(sig_ascii_crc, 0x20, "NVS_OP2_BUFCRC=0x%08X\r\n", crc32(0, qaf + 0x80, 0x100));
char* name = buf;
memset(name, 0, 0x200);
snprintf(name, 0x200, "%s/%04d_input_%02X%02X%02X%02X%02X%02X_%s.cfg", dir, num, cid[10], cid[11], cid[12], cid[13], cid[14], cid[15], (char*)(qaf + 8));
unlink(name);
printf("writing %s ...", name);
FILE* fp = fopen(name, "wb");
if (fp == NULL)
return -1;
#define CFG_EOL "\r\n"
#define CFG_INTRO "# psp2etoi configuration file\r\n" CFGINFO "# QA flags set: "
fwrite(CFG_INTRO, strlen(CFG_INTRO), 1, fp);
fwrite(qaf_ascii, 0x20, 1, fp);
fwrite(CFG_EOL, strlen(CFG_EOL), 1, fp);
#define CFG_TYPE_CID "\r\n#-- -- Config type -- --\r\nINPUT=true # If set, the config is written to the device\r\n\r\n#-- -- Console ID -- --\r\nConsoleID="
fwrite(CFG_TYPE_CID, strlen(CFG_TYPE_CID), 1, fp);
fwrite(cid_ascii, 0x20, 1, fp);
fwrite(CFG_EOL, strlen(CFG_EOL), 1, fp);
#define CFG_MGMT_NVSINFO "\r\n#-- Management Status --\r\nisQaFlagged=true # if not set, SL will ignore the QA flags\r\n\r\n#-- NVS data R/W --\r\n"
fwrite(CFG_MGMT_NVSINFO, strlen(CFG_MGMT_NVSINFO), 1, fp);
char* ascii_tmp_buf = buf;
memset(ascii_tmp_buf, 0, 0x40);
hntoa(E_qafv, ascii_tmp_buf, 0x40);
#define CFG_QAFV_OP "# QAFV\r\nNVS_OP0_OFFSET=0x02A0\r\nNVS_OP0_RWSIZE=0x0020\r\n"
fwrite(CFG_QAFV_OP, strlen(CFG_QAFV_OP), 1, fp);
fwrite(qafv_ascii_crc, strlen(qafv_ascii_crc), 1, fp);
#define CFG_NVSOP0_INRAWH "NVS_OP0_INRAWH="
fwrite(CFG_NVSOP0_INRAWH, strlen(CFG_NVSOP0_INRAWH), 1, fp);
fwrite(ascii_tmp_buf, 0x40, 1, fp);
fwrite(CFG_EOL, strlen(CFG_EOL), 1, fp);
memset(ascii_tmp_buf, 0, 0x100);
hntoa(qaf, ascii_tmp_buf, 0x100);
#define CFG_QAFT_OP "\r\n# QAF token\r\nNVS_OP1_OFFSET=0x0400\r\nNVS_OP1_RWSIZE=0x0080\r\n"
fwrite(CFG_QAFT_OP, strlen(CFG_QAFT_OP), 1, fp);
fwrite(token_ascii_crc, strlen(token_ascii_crc), 1, fp);
#define CFG_NVSOP1_INRAWH "NVS_OP1_INRAWH="
fwrite(CFG_NVSOP1_INRAWH, strlen(CFG_NVSOP1_INRAWH), 1, fp);
fwrite(ascii_tmp_buf, 0x100, 1, fp);
fwrite(CFG_EOL, strlen(CFG_EOL), 1, fp);
memset(ascii_tmp_buf, 0, 0x200);
hntoa(qaf + 0x80, ascii_tmp_buf, 0x200);
#define CFG_QAFS_OP "\r\n# QAF token signature\r\nNVS_OP2_OFFSET=0x05A0\r\nNVS_OP2_RWSIZE=0x0100\r\n"
fwrite(CFG_QAFS_OP, strlen(CFG_QAFS_OP), 1, fp);
fwrite(sig_ascii_crc, strlen(sig_ascii_crc), 1, fp);
#define CFG_NVSOP2_INRAWH "NVS_OP2_INRAWH="
fwrite(CFG_NVSOP2_INRAWH, strlen(CFG_NVSOP2_INRAWH), 1, fp);
fwrite(ascii_tmp_buf, 0x200, 1, fp);
fwrite(CFG_EOL, strlen(CFG_EOL), 1, fp);
#define CFG_STATFLAGS_OP "\r\n# Status flags\r\nNVS_OP3_OFFSET=0x0480\r\nNVS_OP3_RWSIZE=0x0010\r\nNVS_OP3_BUFCRC=0x832D2B4D\r\nNVS_OP3_INRAWH=0000FFFF01FFFFFFFFFFFFFFFFFFFFFF\r\n"
fwrite(CFG_STATFLAGS_OP, strlen(CFG_STATFLAGS_OP), 1, fp);
fclose(fp);
return 0;
}
void dump_to_list(const char* list, int num, void* qaf, uint8_t* cid) {
char* type = "CEX";
if (cid[5] < 3) {
type = "DEX";
if (cid[5] < 2) {
type = "DEVTOOL";
if (cid[5] < 1)
type = "TEST";
}
}
uint16_t sub_code = 0;
sub_code = (uint16_t)cid[6];
sub_code *= 0x100;
sub_code += (uint16_t)cid[7];
char* model = "Playstation TV";
if (sub_code < 0x100) {
model = "Playstation Vita Slim";
if (sub_code < 0x14) {
model = "Playstation Vita Phat";
if (sub_code < 0x10) {
model = "Final Prototype";
if (sub_code < 0xF) {
model = "Prototype";
if (sub_code < 0x2) {
model = "Emulator";
}
}
}
}
}
char cid_ascii[0x21];
cid_ascii[0x20] = 0;
hntoa(cid, cid_ascii, 0x20);
char cmd[0x100];
memset(cmd, 0, 0x100);
snprintf(cmd, 0x100, "echo '%04d : %s %s %s | %s' >> %s\n", num, type, model, cid_ascii, (char*)(qaf + 8), list);
system(cmd);
}
// look for and dump 0x180-sized [TOKEN][SIG] structures
int dump_qaf(const char* full_dir, const char* dec_dir, const char* cfg_dir, const char* list_txt, int num, void* qaf) {
if (dump_to_file(num, qaf, full_dir) < 0)
return -1;
uint8_t cid[0x10];
uint8_t qa_flags[0x10];
if (dump_to_dec(num, qaf, dec_dir, cid, qa_flags) < 0)
return -1;
if (dump_to_config(num, qaf, cfg_dir, cid, qa_flags) < 0)
return -1;
dump_to_list(list_txt, num, qaf, cid);
return 0;
}
int main(int argc, char* argv[]) {
if (argc < 5) {
printf("expected ./%s fs_blob out_full_dir out_dec_dir out_cfg_dir out_list_file\n\n", argv[0]);
return 0;
}
uint32_t img_size = (uint32_t)getSz(argv[1]);
if (!img_size) {
printf("badsz\n");
return -1;
}
void* data = malloc(img_size);
if (!data) {
printf("didnt alloc\n");
return -1;
}
mkdir(argv[2], 0777);
mkdir(argv[3], 0777);
mkdir(argv[4], 0777);
unlink(argv[5]);
FILE* fp = fopen(argv[1], "rb");
if (fp == NULL)
return 0;
fread(data, img_size, 1, fp);
fclose(fp);
int cur_qaft = 0;
for (uint32_t i = 0; i < img_size; i -= -2) {
if (*(uint32_t*)(data + i) == 0x00666171) {
if (dump_qaf(argv[2], argv[3], argv[4], argv[5], cur_qaft, data + i) < 0)
printf("ERROR\n");
else
printf("OK\n");
cur_qaft++;
}
}
printf("written %d tokens\n", cur_qaft);
free(data);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment