1 #include <openssl/aes.h>
10 static int dump_partition_data
= 0;
12 #define SPINNER_SPEED 64
14 typedef unsigned char u8
;
15 typedef unsigned short u16
;
16 typedef unsigned int u32
;
17 typedef unsigned long long u64
;
21 u64 partition_raw_offset
;
22 u64 partition_data_offset
;
23 u64 partition_data_size
;
28 static void print_bytes(u8
*x
, u32 n
)
32 for (i
= 0; i
< n
; i
++)
33 fprintf(stderr
, "%02x", x
[i
]);
36 static void aes_cbc_dec(u8
*key
, u8
*iv
, u8
*in
, u32 len
, u8
*out
)
40 AES_set_decrypt_key(key
, 128, &aes_key
);
41 AES_cbc_encrypt(in
, out
, len
, &aes_key
, iv
, AES_DECRYPT
);
44 static void decrypt_title_key(u8
*title_key
, u8
*title_id
)
50 fp
= fopen("common-key", "rb");
51 fread(common_key
, 1, 16, fp
);
54 memset(iv
, 0, sizeof iv
);
55 memcpy(iv
, title_id
, 8);
57 aes_cbc_dec(common_key
, iv
, title_key
, 16, disc_key
);
60 static u32
be32(u8
*p
)
62 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
65 static u64
be64(u8
*p
)
67 return ((u64
)be32(p
) << 32) | be32(p
+ 4);
70 static u64
be34(u8
*p
)
72 return 4 * (u64
)be32(p
);
75 static void seek(u64 offset
)
77 fseeko(disc_fp
, offset
, SEEK_SET
);
80 static void disc_read(u64 offset
, u8
*data
, u32 len
)
83 fread(data
, 1, len
, disc_fp
);
86 static void partition_raw_read(u64 offset
, u8
*data
, u32 len
)
88 disc_read(partition_raw_offset
+ offset
, data
, len
);
91 static void partition_read_block(u64 blockno
, u8
*block
)
97 offset
= partition_data_offset
+ 0x8000 * blockno
;
98 partition_raw_read(offset
, raw
, 0x8000);
100 // XXX: check H0, H1, H2 here
102 memcpy(iv
, raw
+ 0x3d0, 16);
103 //fprintf(stderr, "ky: "); print_bytes(disc_key, 16); fprintf(stderr, "\n");
104 //fprintf(stderr, "iv: "); print_bytes(iv, 16); fprintf(stderr, "\n");
105 aes_cbc_dec(disc_key
, iv
, raw
+ 0x400, 0x7c00, block
);
108 static void partition_read(u64 offset
, u8
*data
, u32 len
)
115 offset_in_block
= offset
% 0x7c00;
116 len_in_block
= 0x7c00 - offset_in_block
;
117 if (len_in_block
> len
)
119 partition_read_block(offset
/ 0x7c00, block
);
120 memcpy(data
, block
+ offset_in_block
, len_in_block
);
121 data
+= len_in_block
;
122 offset
+= len_in_block
;
127 static void spinner(u64 x
, u64 max
)
130 static time_t start_time
;
131 static u32 expected_total
;
137 start_time
= time(0);
138 expected_total
= 300;
142 fprintf(stderr
, "Done. \n");
146 d
= time(0) - start_time
;
149 expected_total
= (15 * expected_total
+ d
* max
/ x
) / 16;
151 if (expected_total
> d
)
152 d
= expected_total
- d
;
159 percent
= 100.0 * x
/ max
;
161 fprintf(stderr
, "%5.2f%% (%c) ETA: %d:%02d:%02d \r",
162 percent
, "/|\\-"[(spin
++ / SPINNER_SPEED
) % 4], h
, m
, s
);
166 static void do_data(u64 size
)
174 size
= (size
/ 0x8000) * 0x7c00;
176 fp
= fopen("###dat###", "wb");
178 fprintf(stderr
, "\nDumping partition contents...\n");
180 remaining_size
= size
;
181 while (remaining_size
) {
182 spinner(offset
, size
);
185 if (block_size
> remaining_size
)
186 block_size
= remaining_size
;
188 partition_read(offset
, data
, block_size
);
189 fwrite(data
, 1, block_size
, fp
);
191 offset
+= block_size
;
192 remaining_size
-= block_size
;
199 static void copy_file(const char *name
, u64 offset
, u64 size
)
205 fp
= fopen(name
, "wb");
208 block_size
= sizeof data
;
209 if (block_size
> size
)
212 partition_read(offset
, data
, block_size
);
213 fwrite(data
, 1, block_size
, fp
);
215 offset
+= block_size
;
222 static u32
do_fst(u8
*fst
, const char *names
, u32 i
, char *indent
, int is_last
)
230 name
= names
+ (be32(fst
+ 12*i
) & 0x00ffffff);
231 size
= be32(fst
+ 12*i
+ 8);
234 fprintf(stderr
, "/\n");
236 for (j
= 1; j
< size
; )
237 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
243 parent
= be32(fst
+ 12*i
+ 4);
244 is_last
= (be32(fst
+ 12*parent
+ 8) == size
);
247 fprintf(stderr
, "%s%c-- %s", indent
, "|+"[is_last
], name
);
253 fprintf(stderr
, "\n");
258 strcat(indent
, "| ");
260 for (j
= i
+ 1; j
< size
; )
261 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
263 indent
[strlen(indent
) - 4] = 0;
269 offset
= be34(fst
+ 12*i
+ 4);
271 fprintf(stderr
, " @ %09llx, size %08x\n", offset
, size
);
273 copy_file(name
, offset
, size
);
279 static void do_files(void)
281 u8 b
[0x480]; // XXX: determine actual header size
289 partition_read(0, b
, sizeof b
);
291 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
292 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
293 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
294 fprintf(stderr
, "\n");
296 dol_offset
= be34(b
+ 0x0420);
297 fst_offset
= be34(b
+ 0x0424);
298 fst_size
= be34(b
+ 0x0428);
300 fprintf(stderr
, "\tDOL @ %09llx\n", dol_offset
);
301 fprintf(stderr
, "\tFST @ %09llx (size %08x)\n", fst_offset
, fst_size
);
303 copy_file("###apl###", 0x2440, dol_offset
- 0x2440); // XXX: wrong way to get this size, there is a header
304 copy_file("###dol###", dol_offset
, fst_offset
- dol_offset
); // XXX: similar, perhaps
306 fst
= malloc(fst_size
);
307 partition_read(fst_offset
, fst
, fst_size
);
308 n_files
= be32(fst
+ 8);
310 fprintf(stderr
, "%d entries\n", n_files
);
314 do_fst(fst
, (char *)fst
+ 12*n_files
, 0, indent
, 0);
319 static void do_partition(void)
328 char dirname
[] = "title-0000000000000000";
330 partition_raw_read(0, b
, 0x02c0);
332 decrypt_title_key(b
+ 0x01bf, b
+ 0x01dc);
334 title_id
= be64(b
+ 0x01dc);
336 fprintf(stderr
, "\ttitle id = %016llx\n", title_id
);
338 // XXX: we should check the cert chain here, and read the tmd
340 tmd_offset
= be32(b
+ 0x02a4);
341 tmd_size
= be34(b
+ 0x02a8);
342 cert_size
= be32(b
+ 0x02ac);
343 cert_offset
= be34(b
+ 0x02b0);
344 h3_offset
= be34(b
+ 0x02b4);
345 partition_data_offset
= be34(b
+ 0x02b8);
346 partition_data_size
= be34(b
+ 0x02bc);
348 fprintf(stderr
, "\ttmd offset = %08x\n", tmd_offset
);
349 fprintf(stderr
, "\ttmd size = %09llx\n", tmd_size
);
350 fprintf(stderr
, "\tcert size = %08x\n", cert_size
);
351 fprintf(stderr
, "\tcert offset = %09llx\n", cert_offset
);
352 fprintf(stderr
, "\tdata offset = %09llx\n", partition_data_offset
);
353 fprintf(stderr
, "\tdata size = %09llx\n", partition_data_size
);
355 partition_raw_read(h3_offset
, h3
, 0x18000);
357 // XXX: check h3 against h4 here
359 snprintf(dirname
, sizeof dirname
, "%016llx", title_id
);
361 mkdir(dirname
, 0777);
364 if (dump_partition_data
)
365 do_data(partition_data_size
);
372 static void do_disc(void)
375 u64 partition_offset
[32]; // XXX: don't know the real maximum
379 disc_read(0, b
, sizeof b
);
381 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
382 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
383 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
384 fprintf(stderr
, "\n");
386 disc_read(0x40000, b
, sizeof b
);
387 n_partitions
= be32(b
);
389 disc_read(be34(b
+ 4), b
, sizeof b
);
390 for (i
= 0; i
< n_partitions
; i
++)
391 partition_offset
[i
] = be34(b
+ 8 * i
);
393 fprintf(stderr
, "%d partitions:\n", n_partitions
);
394 for (i
= 0; i
< n_partitions
; i
++)
395 fprintf(stderr
, "\tpartition #%d @ %09llx\n", i
,
396 partition_offset
[i
]);
398 for (i
= 0; i
< n_partitions
; i
++) {
399 fprintf(stderr
, "\nDoing partition %d...\n", i
);
400 fprintf(stderr
, "--------------------------------\n");
402 partition_raw_offset
= partition_offset
[i
];
405 //break; // XXX SII: for testing
409 int main(int argc
, char **argv
)
412 fprintf(stderr
, "Usage: %s <disc file>\n", argv
[0]);
416 disc_fp
= fopen(argv
[1], "rb");