1 // Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
15 static int just_a_partition
= 0;
16 static int dump_partition_data
= 0;
17 static u32 max_size_to_auto_analyse
= 0x1000000;
18 static int uncompress_yaz0
= 1;
19 static int unpack_rarc
= 1;
23 static u64 partition_raw_offset
;
24 static u64 partition_data_offset
;
25 static u64 partition_data_size
;
26 static u8 h3
[0x18000];
30 static u32 errors
= 0;
32 static void seek(u64 offset
)
34 if (fseeko(disc_fp
, offset
, SEEK_SET
))
35 fatal("error seeking in disc file");
38 static void disc_read(u64 offset
, u8
*data
, u32 len
)
41 if (fread(data
, len
, 1, disc_fp
) != 1)
42 fatal("error reading disc");
45 static void partition_raw_read(u64 offset
, u8
*data
, u32 len
)
47 disc_read(partition_raw_offset
+ offset
, data
, len
);
50 static void partition_read_block(u64 blockno
, u8
*block
)
60 offset
= partition_data_offset
+ 0x8000 * blockno
;
61 partition_raw_read(offset
, raw
, 0x8000);
64 memcpy(iv
, raw
+ 0x3d0, 16);
65 aes_cbc_dec(disc_key
, iv
, raw
+ 0x400, 0x7c00, block
);
69 aes_cbc_dec(disc_key
, iv
, raw
, 0x400, raw
);
75 b2
= (blockno
>> 3) & 7;
79 for (i
= 0; i
< 31; i
++) {
80 sha(block
+ 0x400*i
, 0x400, h
);
81 if (memcmp(h0
+ 20*i
, h
, 20)) {
82 fprintf(stderr
, "H0 mismatch for %llx.%02x\n",
90 if (memcmp(h1
+ 20*b1
, h
, 20)) {
91 fprintf(stderr
, "H1 mismatch for %llx\n", blockno
);
97 if (memcmp(h2
+ 20*b2
, h
, 20)) {
98 fprintf(stderr
, "H2 mismatch for %llx\n", blockno
);
104 if (memcmp(h3
+ 20*b3
, h
, 20)) {
105 fprintf(stderr
, "H3 mismatch for %llx\n", blockno
);
110 static void partition_read(u64 offset
, u8
*data
, u32 len
)
116 if (just_a_partition
)
117 disc_read(offset
, data
, len
);
119 offset_in_block
= offset
% 0x7c00;
120 len_in_block
= 0x7c00 - offset_in_block
;
121 if (len_in_block
> len
)
123 partition_read_block(offset
/ 0x7c00, block
);
124 memcpy(data
, block
+ offset_in_block
, len_in_block
);
125 data
+= len_in_block
;
126 offset
+= len_in_block
;
131 static void spinner(u64 x
, u64 max
)
134 static time_t start_time
;
135 static u32 expected_total
;
141 start_time
= time(0);
142 expected_total
= 300;
146 fprintf(stderr
, "Done. \n");
150 d
= time(0) - start_time
;
153 expected_total
= (15 * expected_total
+ d
* max
/ x
) / 16;
155 if (expected_total
> d
)
156 d
= expected_total
- d
;
163 percent
= 100.0 * x
/ max
;
165 fprintf(stderr
, "%5.2f%% (%c) ETA: %d:%02d:%02d \r",
166 percent
, "/|\\-"[(spin
++ / 64) % 4], h
, m
, s
);
170 static void do_data(u64 size
)
178 size
= (size
/ 0x8000) * 0x7c00;
180 fp
= fopen("###dat###", "wb");
182 fatal("cannot open partition output file");
184 fprintf(stderr
, "\nDumping partition contents...\n");
186 remaining_size
= size
;
187 while (remaining_size
) {
188 spinner(offset
, size
);
191 if (block_size
> remaining_size
)
192 block_size
= remaining_size
;
194 partition_read(offset
, data
, block_size
);
195 if (fwrite(data
, block_size
, 1, fp
) != 1)
196 fatal("error writing partition");
198 offset
+= block_size
;
199 remaining_size
-= block_size
;
206 static void copy_file(const char *name
, u64 offset
, u64 size
)
212 fp
= fopen(name
, "wb");
214 fatal("cannot open output file");
217 block_size
= sizeof data
;
218 if (block_size
> size
)
221 partition_read(offset
, data
, block_size
);
222 if (fwrite(data
, block_size
, 1, fp
) != 1)
223 fatal("error writing output file");
225 offset
+= block_size
;
232 static void do_fst_file(const char *name
, u64 offset
, u64 size
)
237 if (size
> max_size_to_auto_analyse
) {
238 copy_file(name
, offset
, size
);
246 partition_read(offset
, data
, size
);
248 if (uncompress_yaz0
&& size
>= 8 && memcmp(data
, "Yaz0", 4) == 0) {
252 fprintf(stderr
, " [Yaz0]");
254 dec_size
= be32(data
+ 4);
255 dec
= malloc(dec_size
);
259 do_yaz0(data
, size
, dec
, dec_size
);
266 if (unpack_rarc
&& size
>= 8 && memcmp(data
, "RARC", 4) == 0) {
267 fprintf(stderr
, " [RARC]");
270 fp
= fopen(name
, "wb");
272 fatal("cannot open output file");
273 if (fwrite(data
, size
, 1, fp
) != 1)
274 fatal("error writing output file");
280 static u32
do_fst(u8
*fst
, const char *names
, u32 i
, char *indent
, int is_last
)
288 name
= names
+ (be32(fst
+ 12*i
) & 0x00ffffff);
289 size
= be32(fst
+ 12*i
+ 8);
292 fprintf(stderr
, "/\n");
294 for (j
= 1; j
< size
; )
295 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
301 parent
= be32(fst
+ 12*i
+ 4);
302 is_last
= (be32(fst
+ 12*parent
+ 8) == size
);
305 fprintf(stderr
, "%s%c-- %s", indent
, "|+"[is_last
], name
);
308 if (mkdir(name
, 0777))
313 fprintf(stderr
, "\n");
318 strcat(indent
, "| ");
320 for (j
= i
+ 1; j
< size
; )
321 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
323 indent
[strlen(indent
) - 4] = 0;
330 offset
= be34(fst
+ 12*i
+ 4);
331 do_fst_file(name
, offset
, size
);
333 fprintf(stderr
, "\n");
339 static void do_files(void)
341 u8 b
[0x480]; // XXX: determine actual header size
352 partition_read(0, b
, sizeof b
);
354 fprintf(stderr
, "\n");
355 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
356 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
357 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
358 fprintf(stderr
, "\n");
360 dol_offset
= be34(b
+ 0x0420);
361 fst_offset
= be34(b
+ 0x0424);
362 fst_size
= be34(b
+ 0x0428);
365 partition_read(apl_offset
, apl_header
, sizeof apl_header
);
366 apl_size
= 0x20 + be32(apl_header
+ 0x14) + be32(apl_header
+ 0x18);
368 fprintf(stderr
, "\tDOL @ %09llx\n", dol_offset
);
369 fprintf(stderr
, "\tFST @ %09llx (size %08x)\n", fst_offset
, fst_size
);
370 fprintf(stderr
, "\tAPL @ %09llx (size %08x)\n", apl_offset
, apl_size
);
372 copy_file("###apl###", apl_offset
, apl_size
);
373 copy_file("###dol###", dol_offset
, fst_offset
- dol_offset
);
374 // XXX: read the header for getting the size
376 fst
= malloc(fst_size
);
379 partition_read(fst_offset
, fst
, fst_size
);
380 n_files
= be32(fst
+ 8);
382 fprintf(stderr
, "%d entries\n", n_files
);
386 do_fst(fst
, (char *)fst
+ 12*n_files
, 0, indent
, 0);
391 static void do_partition(void)
407 // read ticket, and read some offsets and sizes
408 partition_raw_read(0, tik
, sizeof tik
);
409 partition_raw_read(0x2a4, b
, sizeof b
);
412 tmd_offset
= be34(b
+ 4);
413 cert_size
= be32(b
+ 8);
414 cert_offset
= be34(b
+ 0x0c);
415 h3_offset
= be34(b
+ 0x10);
416 partition_data_offset
= be34(b
+ 0x14);
417 partition_data_size
= be34(b
+ 0x18);
419 title_id
= be64(tik
+ 0x01dc);
420 fprintf(stderr
, "\ttitle id = %016llx\n", title_id
);
422 fprintf(stderr
, "\ttmd size = %08x\n", tmd_size
);
423 fprintf(stderr
, "\ttmd offset = %09llx\n", tmd_offset
);
424 fprintf(stderr
, "\tcert size = %08x\n", cert_size
);
425 fprintf(stderr
, "\tcert offset = %09llx\n", cert_offset
);
426 fprintf(stderr
, "\tdata offset = %09llx\n", partition_data_offset
);
427 fprintf(stderr
, "\tdata size = %09llx\n", partition_data_size
);
429 tmd
= malloc(tmd_size
);
432 partition_raw_read(tmd_offset
, tmd
, tmd_size
);
434 cert
= malloc(cert_size
);
436 fatal("malloc cert");
437 partition_raw_read(cert_offset
, cert
, cert_size
);
439 ret
= check_cert_chain(tik
, sizeof tik
, cert
, cert_size
);
441 fprintf(stderr
, "ticket cert failure (%d)\n", ret
);
444 ret
= check_cert_chain(tmd
, tmd_size
, cert
, cert_size
);
446 fprintf(stderr
, "tmd cert failure (%d)\n", ret
);
450 // XXX: we should check the cert chain here
452 decrypt_title_key(tik
+ 0x01bf, tik
+ 0x01dc, disc_key
);
454 partition_raw_read(h3_offset
, h3
, 0x18000);
457 if (memcmp(tmd
+ 0x1f4, h
, 20)) {
458 fprintf(stderr
, "H4 mismatch\n");
465 snprintf(dirname
, sizeof dirname
, "%016llx", title_id
);
467 if (mkdir(dirname
, 0777))
468 fatal("mkdir partition");
470 fatal("chdir partition");
472 if (dump_partition_data
)
473 do_data(partition_data_size
);
478 fatal("chdir up out of partition");
481 static void do_disc(void)
484 u64 partition_offset
[32]; // XXX: don't know the real maximum
488 disc_read(0, b
, sizeof b
);
490 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
491 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
492 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
493 fprintf(stderr
, "\n");
495 disc_read(0x40000, b
, sizeof b
);
496 n_partitions
= be32(b
);
498 disc_read(be34(b
+ 4), b
, sizeof b
);
499 for (i
= 0; i
< n_partitions
; i
++)
500 partition_offset
[i
] = be34(b
+ 8 * i
);
502 fprintf(stderr
, "%d partitions:\n", n_partitions
);
503 for (i
= 0; i
< n_partitions
; i
++)
504 fprintf(stderr
, "\tpartition #%d @ %09llx\n", i
,
505 partition_offset
[i
]);
507 for (i
= 0; i
< n_partitions
; i
++) {
508 fprintf(stderr
, "\nDoing partition %d...\n", i
);
509 fprintf(stderr
, "--------------------------------\n");
511 partition_raw_offset
= partition_offset
[i
];
514 //break; // XXX SII: for testing
518 int main(int argc
, char **argv
)
521 fprintf(stderr
, "Usage: %s <disc file>\n", argv
[0]);
525 disc_fp
= fopen(argv
[1], "rb");
527 fatal("open disc file");
529 if (just_a_partition
)
537 fprintf(stderr
, "\n\nErrors detected:\n");
539 fprintf(stderr
, "H0 mismatch\n");
541 fprintf(stderr
, "H1 mismatch\n");
543 fprintf(stderr
, "H2 mismatch\n");
545 fprintf(stderr
, "H3 mismatch\n");
547 fprintf(stderr
, "H4 mismatch\n");
549 fprintf(stderr
, "ticket cert failure\n");
551 fprintf(stderr
, "tmd cert failure\n");