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 aes_cbc_dec(disc_key
, iv
, raw
+ 0x400, 0x7c00, block
);
106 static void partition_read(u64 offset
, u8
*data
, u32 len
)
113 offset_in_block
= offset
% 0x7c00;
114 len_in_block
= 0x7c00 - offset_in_block
;
115 if (len_in_block
> len
)
117 partition_read_block(offset
/ 0x7c00, block
);
118 memcpy(data
, block
+ offset_in_block
, len_in_block
);
119 data
+= len_in_block
;
120 offset
+= len_in_block
;
125 static void spinner(u64 x
, u64 max
)
128 static time_t start_time
;
129 static u32 expected_total
;
135 start_time
= time(0);
136 expected_total
= 300;
140 fprintf(stderr
, "Done. \n");
144 d
= time(0) - start_time
;
147 expected_total
= (15 * expected_total
+ d
* max
/ x
) / 16;
149 if (expected_total
> d
)
150 d
= expected_total
- d
;
157 percent
= 100.0 * x
/ max
;
159 fprintf(stderr
, "%5.2f%% (%c) ETA: %d:%02d:%02d \r",
160 percent
, "/|\\-"[(spin
++ / SPINNER_SPEED
) % 4], h
, m
, s
);
164 static void do_data(u64 size
)
172 size
= (size
/ 0x8000) * 0x7c00;
174 fp
= fopen("###dat###", "wb");
176 fprintf(stderr
, "\nDumping partition contents...\n");
178 remaining_size
= size
;
179 while (remaining_size
) {
180 spinner(offset
, size
);
183 if (block_size
> remaining_size
)
184 block_size
= remaining_size
;
186 partition_read(offset
, data
, block_size
);
187 fwrite(data
, 1, block_size
, fp
);
189 offset
+= block_size
;
190 remaining_size
-= block_size
;
197 static void copy_file(const char *name
, u64 offset
, u64 size
)
203 fp
= fopen(name
, "wb");
206 block_size
= sizeof data
;
207 if (block_size
> size
)
210 partition_read(offset
, data
, block_size
);
211 fwrite(data
, 1, block_size
, fp
);
213 offset
+= block_size
;
220 static u32
do_fst(u8
*fst
, const char *names
, u32 i
, char *indent
, int is_last
)
228 name
= names
+ (be32(fst
+ 12*i
) & 0x00ffffff);
229 size
= be32(fst
+ 12*i
+ 8);
232 fprintf(stderr
, "/\n");
234 for (j
= 1; j
< size
; )
235 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
241 parent
= be32(fst
+ 12*i
+ 4);
242 is_last
= (be32(fst
+ 12*parent
+ 8) == size
);
245 fprintf(stderr
, "%s%c-- %s", indent
, "|+"[is_last
], name
);
251 fprintf(stderr
, "\n");
256 strcat(indent
, "| ");
258 for (j
= i
+ 1; j
< size
; )
259 j
= do_fst(fst
, names
, j
, indent
, (j
== size
- 1));
261 indent
[strlen(indent
) - 4] = 0;
267 offset
= be34(fst
+ 12*i
+ 4);
269 fprintf(stderr
, " @ %09llx, size %08x\n", offset
, size
);
271 copy_file(name
, offset
, size
);
277 static void do_files(void)
279 u8 b
[0x480]; // XXX: determine actual header size
287 partition_read(0, b
, sizeof b
);
289 fprintf(stderr
, "Title id: %c%c%c%c\n", b
[0], b
[1], b
[2], b
[3]);
290 fprintf(stderr
, "Group id: %c%c\n", b
[4], b
[5]);
291 fprintf(stderr
, "Name: %s\n", b
+ 0x20);
292 fprintf(stderr
, "\n");
294 dol_offset
= be34(b
+ 0x0420);
295 fst_offset
= be34(b
+ 0x0424);
296 fst_size
= be34(b
+ 0x0428);
298 fprintf(stderr
, "\tDOL @ %09llx\n", dol_offset
);
299 fprintf(stderr
, "\tFST @ %09llx (size %08x)\n", fst_offset
, fst_size
);
301 copy_file("###apl###", 0x2440, dol_offset
- 0x2440);
302 // XXX: wrong way to get this size, there is a header
303 copy_file("###dol###", dol_offset
, fst_offset
- dol_offset
);
304 // 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");