Line 21:
Line 21:
// for some unknown reason, u64s were being treated like u32s, causing tmd misalignment in my setup.
// for some unknown reason, u64s were being treated like u32s, causing tmd misalignment in my setup.
// Version 1.3 Verifies content hashes, and ecc (eliptic curve cryptography) signature.
// Version 1.3 Verifies content hashes, and ecc (eliptic curve cryptography) signature.
+
// Version 1.4 Now uses "Bk" header to determine which contents are present.
Line 36:
Line 37:
static u8 prngseed[16];
static u8 prngseed[16];
−
−
static FILE *fp;
static FILE *fp;
−
static char gamename[5];
static char gamename[5];
−
static size_t partB_size;
static size_t partB_size;
−
static u16 num_contents;
−
static size_t* content_sizes;
−
static u8* hashes;
−
static u32 total_size;
typedef struct {
typedef struct {
Line 64:
Line 57:
u32 unknown; // padding to 0x40?
u32 unknown; // padding to 0x40?
} partB_header_t;
} partB_header_t;
+
+
+
typedef struct {
+
u32 size; //Always 0x70, however, this struct made 0x80 because of align 64.
+
u32 magic; //Always 0x426B0001
+
u32 console_id;
+
u32 num_files;
+
u32 file_size;
+
u32 tmd_size;
+
u32 payload_size;
+
u32 total_size;
+
u8 contents[0x40];
+
u32 title_id_hi;
+
u32 title_id_lo;
+
u32 unknown[2];
+
u32 align_64[4];
+
} partC_header_t;
typedef struct {
typedef struct {
Line 99:
Line 109:
u8 hash [20]; // SHA1 hash content
u8 hash [20]; // SHA1 hash content
} content_record_t;
} content_record_t;
+
+
static partC_header_t bKheader;
+
static tmd_t tmd;
+
static content_record_t *rec;
static void write_part(void* data, size_t size, char* name)
static void write_part(void* data, size_t size, char* name)
Line 231:
Line 245:
data = malloc(rounded_size);
data = malloc(rounded_size);
fread(data, 1, rounded_size, fp);
fread(data, 1, rounded_size, fp);
−
+
−
memcpy(partB_iv, sd_iv, 16); //And we need the sd-iv for content decryption as well.
+
aes_cbc_dec(sd_key, sd_iv, data, rounded_size, data);
−
aes_cbc_dec(sd_key, partB_iv, data, rounded_size, data);
header = (partB_header_t*) data;
header = (partB_header_t*) data;
Line 256:
Line 269:
write_part(data,rounded_size,"02_banner");
write_part(data,rounded_size,"02_banner");
write_part(data, sizeof(partB_header_t), "02a_banner_header");
write_part(data, sizeof(partB_header_t), "02a_banner_header");
−
//write_part(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), "02b_banner_compressed");
decompressed_data = decompress_lz77(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), &decompressed_size);
decompressed_data = decompress_lz77(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), &decompressed_size);
Line 267:
Line 279:
static void do_partC_Bk_header(void)
static void do_partC_Bk_header(void)
{
{
−
u8 header[0x80];
+
fread(&bKheader, 1, sizeof bKheader, fp);
−
−
fread(header, 1, sizeof header, fp);
−
if (be32(header + 4) != 0x426b0001)
+
if (be32((u8*) &bKheader.magic) != 0x426b0001)
ERROR("no Bk header");
ERROR("no Bk header");
−
if (be32(header) != 0x70)
+
if (be32((u8*) &bKheader.size) != 0x70)
ERROR("wrong Bk header size");
ERROR("wrong Bk header size");
−
fprintf(stderr, "NG id: %08x\n", be32(header + 8));
+
fprintf(stderr, "NG id: %08x\n", be32((u8*) &bKheader.console_id));
−
−
total_size = be32(header + 0x1c);
−
write_part(header, sizeof(header), "03_bk_header");
+
write_part(&bKheader, sizeof(bKheader), "03_bk_header");
}
}
static void do_partD_tmd(void)
static void do_partD_tmd(void)
{
{
−
tmd_t tmd;
u8* data;
u8* data;
size_t tmd_size;
size_t tmd_size;
−
int i;
+
−
content_record_t* rec;
+
fread(&tmd, 1, sizeof tmd, fp);
−
+
−
fread(&tmd, 1, sizeof tmd, fp);
+
printf("Number of content files: %d\n", be16((u8*) &tmd.num_contents));
−
−
num_contents = be16((u8*) &tmd.num_contents);
−
printf("Number of content files: %d\n", num_contents);
// Now we can read the rest of the tmd.
// Now we can read the rest of the tmd.
−
tmd_size = sizeof(tmd) + num_contents*sizeof(content_record_t);
+
tmd_size = sizeof(tmd) + be16((u8*) &tmd.num_contents)*sizeof(content_record_t);
tmd_size = (tmd_size + 63) & ~63;
tmd_size = (tmd_size + 63) & ~63;
+
tmd_size = tmd_size - sizeof(tmd);
−
data = malloc(tmd_size);
+
rec = malloc(tmd_size);
+
fread(rec, 1, tmd_size, fp);
+
+
data = malloc(tmd_size+sizeof(tmd));
memcpy(data, &tmd, sizeof(tmd));
memcpy(data, &tmd, sizeof(tmd));
−
fread(&data[sizeof(tmd)], 1, tmd_size-sizeof(tmd), fp);
+
memcpy(&data[sizeof(tmd)], rec, tmd_size);
+
−
write_part(data, tmd_size, "04_tmd");
+
write_part(data, tmd_size+sizeof(tmd), "04_tmd");
−
content_sizes = calloc(1, sizeof (size_t) * num_contents);
−
hashes = calloc(20, num_contents);
−
−
rec = (content_record_t*) &data[sizeof(tmd)];
−
for (i = 0; i < num_contents; i++, rec++) {
−
u16 type = be16((u8*) &rec->type);
−
memcpy(hashes + (20*i), rec->hash, 20);
−
−
if (!(type & 0x8000)) {
−
content_sizes[i] = (size_t)be32((u8*) &rec->size_hi);
−
}
−
}
}
}
Line 326:
Line 323:
u8 hash[0x14];
u8 hash[0x14];
−
for (i=0; i < num_contents; i++) {
+
for (i=0; i < be16((u8*) &tmd.num_contents); i++) {
printf("Content index %d: ",i);
printf("Content index %d: ",i);
−
if (content_sizes[i] != 0) {
+
if(bKheader.contents[i/8] & (1 << (i % 8))) {
char name[128];
char name[128];
u8 *data;
u8 *data;
−
size_t rounded_size = (content_sizes[i] + 63) & ~63;
+
size_t rounded_size = (be32((u8*) &rec[i].size_hi) + 63) & ~63;
−
+
data = malloc(rounded_size);
data = malloc(rounded_size);
fread(data, 1, rounded_size, fp);
fread(data, 1, rounded_size, fp);
Line 339:
Line 336:
wbe16(partE_iv,i);
wbe16(partE_iv,i);
aes_cbc_dec(prngseed, partE_iv, data, rounded_size, data);
aes_cbc_dec(prngseed, partE_iv, data, rounded_size, data);
−
+
snprintf(name, 128, "05_content_%02d", i);
snprintf(name, 128, "05_content_%02d", i);
−
printf("is included. Written size: %x, ", content_sizes[i]);
+
printf("is included. Written size: %x, ", be32((u8*) &rec[i].size_hi));
−
sha(data, content_sizes[i],hash);
+
sha(data, be32((u8*) &rec[i].size_hi),hash);
−
if(memcmp(hash,hashes+(i*20),20))
+
if(memcmp(hash,&rec[i].hash[0],20))
printf("hash invalid\n");
printf("hash invalid\n");
else
else
printf("hash ok\n");
printf("hash ok\n");
−
+
write_part(data, rounded_size, name);
write_part(data, rounded_size, name);
−
+
free (data);
free (data);
}
}
else
else
{
{
−
printf("is not included (shared)\n");
+
printf("is not included\n");
}
}
}
}
Line 381:
Line 378:
rounded_size = (partB_size + 63) & ~63;
rounded_size = (partB_size + 63) & ~63;
rounded_size += 0x640;
rounded_size += 0x640;
−
data_size = total_size - 0x340;
+
data_size = be32((u8*) &bKheader.total_size) - 0x340;
data = malloc(data_size);
data = malloc(data_size);