1 // Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
2 // Licensed under the terms of the GNU GPL, version 2
4 #include <openssl/aes.h>
13 typedef unsigned char u8
;
14 typedef unsigned short u16
;
15 typedef unsigned int u32
;
16 typedef unsigned long long u64
;
18 static int dump_partition_data
= 0;
19 static u32 max_size_to_auto_analyse
= 0x1000000;
20 static int uncompress_yaz0
= 1;
21 static int unpack_rarc
= 1;
25 static u64 partition_raw_offset
;
26 static u64 partition_data_offset
;
27 static u64 partition_data_size
;
28 static u8 h3
[0x18000];
30 static u8 disc_key
[16];
32 static void print_bytes(u8
*x
, u32 n
)
36 for (i
= 0; i
< n
; i
++)
37 fprintf(stderr
, "%02x", x
[i
]);
40 static void aes_cbc_dec(u8
*key
, u8
*iv
, u8
*in
, u32 len
, u8
*out
)
44 AES_set_decrypt_key(key
, 128, &aes_key
);
45 AES_cbc_encrypt(in
, out
, len
, &aes_key
, iv
, AES_DECRYPT
);
48 static void decrypt_title_key(u8
*title_key
, u8
*title_id
)
54 fp
= fopen("common-key", "rb");
55 fread(common_key
, 1, 16, fp
);
58 memset(iv
, 0, sizeof iv
);
59 memcpy(iv
, title_id
, 8);
61 aes_cbc_dec(common_key
, iv
, title_key
, 16, disc_key
);
64 static u32
be32(u8
*p
)
66 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
69 static u64
be64(u8
*p
)
71 return ((u64
)be32(p
) << 32) | be32(p
+ 4);
74 static u64
be34(u8
*p
)
76 return 4 * (u64
)be32(p
);
79 static void seek(u64 offset
)
81 fseeko(disc_fp
, offset
, SEEK_SET
);
84 static void disc_read(u64 offset
, u8
*data
, u32 len
)
87 fread(data
, 1, len
, disc_fp
);
90 static void partition_raw_read(u64 offset
, u8
*data
, u32 len
)
92 disc_read(partition_raw_offset
+ offset
, data
, len
);
95 static void partition_read_block(u64 blockno
, u8
*block
)
101 offset
= partition_data_offset
+ 0x8000 * blockno
;
102 partition_raw_read(offset
, raw
, 0x8000);
104 // XXX: check H0, H1, H2 here
106 memcpy(iv
, raw
+ 0x3d0, 16);
107 aes_cbc_dec(disc_key
, iv
, raw
+ 0x400, 0x7c00, block
);
110 static void partition_read(u64 offset
, u8
*data
, u32 len
)
117 offset_in_block
= offset
% 0x7c00;
118 len_in_block
= 0x7c00 - offset_in_block
;
119 if (len_in_block
> len
)
121 partition_read_block(offset
/ 0x7c00, block
);
122 memcpy(data
, block
+ offset_in_block
, len_in_block
);
123 data
+= len_in_block
;
124 offset
+= len_in_block
;
129 static void spinner(u64 x
, u64 max
)
132 static time_t start_time
;
133 static u32 expected_total
;
139 start_time
= time(0);
140 expected_total
= 300;
144 fprintf(stderr
, "Done. \n");
148 d
= time(0) - start_time
;
151 expected_total
= (15 * expected_total
+ d
* max
/ x
) / 16;
153 if (expected_total
> d
)
154 d
= expected_total
- d
;
161 percent
= 100.0 * x
/ max
;
163 fprintf(stderr
, "%5.2f%% (%c) ETA: %d:%02d:%02d \r",
164 percent
, "/|\\-"[(spin
++ / 64) % 4], h
, m
, s
);
168 static void do_data(u64 size
)
176 size
= (size
/ 0x8000) * 0x7c00;
178 fp
= fopen("###dat###", "wb");
180 fprintf(stderr
, "\nDumping partition contents...\n");
182 remaining_size
= size
;
183 while (remaining_size
) {
184 spinner(offset
, size
);
187 if (block_size
> remaining_size
)
188 block_size
= remaining_size
;
190 partition_read(offset
, data
, block_size
);
191 fwrite(data
, 1, block_size
, fp
);
193 offset
+= block_size
;
194 remaining_size
-= block_size
;
201 static void copy_file(const char *name
, u64 offset
, u64 size
)
207 fp
= fopen(name
, "wb");
210 block_size
= sizeof data
;
211 if (block_size
> size
)
214 partition_read(offset
, data
, block_size
);
215 fwrite(data
, 1, block_size
, fp
);
217 offset
+= block_size
;
224 static void do_yaz0(u8
*in
, u32 in_size
, u8
*out
, u32 out_size
)
233 for (nout
= 0; nout
< out_size
; ) {
239 if ((bits
& 0x80) != 0) {
245 d
|= (n
<< 8) & 0xf00;
252 for (i
= 0; i
< n
; i
++) {
264 static void do_fst_file(const char *name
, u64 offset
, u64 size
)
269 if (size
> max_size_to_auto_analyse
) {
270 copy_file(name
, offset
, size
);
276 partition_read(offset
, data
, size
);
278 if (uncompress_yaz0
&& size
>= 8 && memcmp(data
, "Yaz0", 4) == 0) {
282 fprintf(stderr
, " [Yaz0]");
284 dec_size
= be32(data
+ 4);
285 dec
= malloc(dec_size
);
287 do_yaz0(data
, size
, dec
, dec_size
);
294 if (unpack_rarc
&& size
>= 8 && memcmp(data
, "RARC", 4) == 0) {
295 fprintf(stderr
, " [RARC]");
298 fp
= fopen(name
, "wb");
299 fwrite(data
, 1, size
, fp
);
305 static u32
do_fst(u8
*fst
, const char *names
, u32 i
, char *indent
, int is_last
)
313 name
= names
+ (be32(fst
+ 12*i
) & 0x00ffffff);
314 size
= be32(fst
+ 12*i
+ 8);
317 fprintf(stderr
, "/\n");
319 for (j
= 1; j
< size
; )
320 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
326 parent
= be32(fst
+ 12*i
+ 4);
327 is_last
= (be32(fst
+ 12*parent
+ 8) == size
);
330 fprintf(stderr
, "%s%c-- %s", indent
, "|+"[is_last
], name
);
336 fprintf(stderr
, "\n");
341 strcat(indent
, "| ");
343 for (j
= i
+ 1; j
< size
; )
344 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
346 indent
[strlen(indent
) - 4] = 0;
352 offset
= be34(fst
+ 12*i
+ 4);
353 do_fst_file(name
, offset
, size
);
355 fprintf(stderr
, "\n");
361 static void do_files(void)
363 u8 b
[0x480]; // XXX: determine actual header size
371 partition_read(0, b
, sizeof b
);
373 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
374 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
375 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
376 fprintf(stderr
, "\n");
378 dol_offset
= be34(b
+ 0x0420);
379 fst_offset
= be34(b
+ 0x0424);
380 fst_size
= be34(b
+ 0x0428);
382 fprintf(stderr
, "\tDOL @ %09llx\n", dol_offset
);
383 fprintf(stderr
, "\tFST @ %09llx (size %08x)\n", fst_offset
, fst_size
);
385 copy_file("###apl###", 0x2440, dol_offset
- 0x2440);
386 // XXX: wrong way to get this size, there is a header
387 copy_file("###dol###", dol_offset
, fst_offset
- dol_offset
);
388 // XXX: similar, perhaps
390 fst
= malloc(fst_size
);
391 partition_read(fst_offset
, fst
, fst_size
);
392 n_files
= be32(fst
+ 8);
394 fprintf(stderr
, "%d entries\n", n_files
);
398 do_fst(fst
, (char *)fst
+ 12*n_files
, 0, indent
, 0);
403 static void do_partition(void)
412 char dirname
[] = "title-0000000000000000";
414 partition_raw_read(0, b
, 0x02c0);
416 decrypt_title_key(b
+ 0x01bf, b
+ 0x01dc);
418 title_id
= be64(b
+ 0x01dc);
420 fprintf(stderr
, "\ttitle id = %016llx\n", title_id
);
422 // XXX: we should check the cert chain here, and read the tmd
424 tmd_offset
= be32(b
+ 0x02a4);
425 tmd_size
= be34(b
+ 0x02a8);
426 cert_size
= be32(b
+ 0x02ac);
427 cert_offset
= be34(b
+ 0x02b0);
428 h3_offset
= be34(b
+ 0x02b4);
429 partition_data_offset
= be34(b
+ 0x02b8);
430 partition_data_size
= be34(b
+ 0x02bc);
432 fprintf(stderr
, "\ttmd offset = %08x\n", tmd_offset
);
433 fprintf(stderr
, "\ttmd size = %09llx\n", tmd_size
);
434 fprintf(stderr
, "\tcert size = %08x\n", cert_size
);
435 fprintf(stderr
, "\tcert offset = %09llx\n", cert_offset
);
436 fprintf(stderr
, "\tdata offset = %09llx\n", partition_data_offset
);
437 fprintf(stderr
, "\tdata size = %09llx\n", partition_data_size
);
439 partition_raw_read(h3_offset
, h3
, 0x18000);
441 // XXX: check h3 against h4 here
443 snprintf(dirname
, sizeof dirname
, "%016llx", title_id
);
445 mkdir(dirname
, 0777);
448 if (dump_partition_data
)
449 do_data(partition_data_size
);
456 static void do_disc(void)
459 u64 partition_offset
[32]; // XXX: don't know the real maximum
463 disc_read(0, b
, sizeof b
);
465 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
466 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
467 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
468 fprintf(stderr
, "\n");
470 disc_read(0x40000, b
, sizeof b
);
471 n_partitions
= be32(b
);
473 disc_read(be34(b
+ 4), b
, sizeof b
);
474 for (i
= 0; i
< n_partitions
; i
++)
475 partition_offset
[i
] = be34(b
+ 8 * i
);
477 fprintf(stderr
, "%d partitions:\n", n_partitions
);
478 for (i
= 0; i
< n_partitions
; i
++)
479 fprintf(stderr
, "\tpartition #%d @ %09llx\n", i
,
480 partition_offset
[i
]);
482 for (i
= 0; i
< n_partitions
; i
++) {
483 fprintf(stderr
, "\nDoing partition %d...\n", i
);
484 fprintf(stderr
, "--------------------------------\n");
486 partition_raw_offset
= partition_offset
[i
];
489 //break; // XXX SII: for testing
493 int main(int argc
, char **argv
)
496 fprintf(stderr
, "Usage: %s <disc file>\n", argv
[0]);
500 disc_fp
= fopen(argv
[1], "rb");