Changes

no edit summary
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);
40

edits