]> FriiDump Source - friidump.git/blob - libfriidump/unscrambler.c
FriiDump 0.5.3.16: finalize release identity and documentation
[friidump.git] / libfriidump / unscrambler.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Arep                                            *
3  *   Support is provided through the forums at                             *
4  *   http://wii.console-tribe.com                                          *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20  ***************************************************************************/
21
22 /*! \file
23  * \brief Unscrambler for Nintendo GameCube/Wii discs.
24  *
25  * As Nintendo GameCube/Wii discs use the standars DVD-ROM scrambling algorithm, but with different, unknown, seeds, the actual seeds have to be brute-forced.
26  * The functions in this file take care of the brute-forcing and of the actual unscrambling of the read sectors.
27  *
28  * The code in this file has been derived from unscrambler 0.4, Copyright (C) 2006 Victor Mu�oz (xt5@ingenieria-inversa.cl), GPL v2+,
29  * http://www.ingenieria-inversa.cl/?lp_lang_pref=en .
30  */
31
32 #include "misc.h"
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include "constants.h"
38 #include "byteorder.h"
39 #include "ecma-267.h"
40 #include "unscrambler.h"
41
42 // #define unscramblerdebug(...) debug (__VA_ARGS__);
43 #define unscramblerdebug(...)
44
45 /*! \brief Size of the seeds cache (Do not touch) */
46 #define MAX_SEEDS 4
47
48 /*! \brief Number of bytes of a sector on which the EDC is calculated */
49 #define EDC_LENGTH (RAW_SECTOR_SIZE - 4)                /* The EDC value is contained in the bottom 4 bytes of a frame */
50
51 u_int8_t disctype;
52
53 /*! \brief A structure that represents a seed
54  */
55 typedef struct t_seed {
56     int seed;                                           //!< The seed, in numeric format.
57     unsigned char streamcipher[SECTOR_SIZE];            //!< The stream cipher generated from the seed through the LFSR.
58 } t_seed;
59
60
61 /*! \brief A structure that represents an unscrambler
62  */
63 struct unscrambler_s {
64         t_seed seeds[(MAX_SEEDS + 1) * 16];             //!< The seeds cache.
65         bool bruteforce_seeds;                          //!< If true, whenever a seed for a sector is not cached, it will be found via a bruteforce attack, otherwise an error will be returned.
66 };
67
68 void unscrambler_set_disctype (u_int8_t disc_type){
69         disctype = disc_type;
70 //      fprintf (stdout,"%d",disctype);
71 }
72
73 /**
74  * Adds a seed to the cache, calculating its streamcipher.
75  * @param seeds The seed cache.
76  * @param seed The seed to add.
77  * @return A structure representing the added seed, or NULL if it could not be added.
78  */
79 static t_seed *add_seed (t_seed *seeds, unsigned short seed) {
80         int i;
81         t_seed *out;
82
83         unscramblerdebug ("Caching seed %04x\n", seed);
84
85         if (seeds -> seed == -2) {
86                 out = NULL;
87         } else {
88                 seeds -> seed = seed;
89
90                 LFSR_init (seed);
91                 for (i = 0; i < SECTOR_SIZE; i++)
92                         seeds -> streamcipher[i] = LFSR_byte ();
93
94                 out = seeds;
95         }
96
97         return (out);
98 }
99
100
101 /**
102  * Tests if the specified seed is the one used for the specified sector block: the check is done comparing the generated EDC with the one at the bottom of each
103  * sector. Sectors are processed in blocks, as the same seed is used for 16 consecutive sectors.
104  * @param buf The sector.
105  * @param j The seed.
106  * @return true if the seed is correct, false otherwise.
107  */
108 static bool test_seed (u_int8_t *buf, int j) {
109         int i;
110         u_int8_t tmp[RAW_SECTOR_SIZE];
111         u_int32_t edc_calculated, edc_correct;
112         bool out;
113
114         memcpy (tmp, buf, RAW_SECTOR_SIZE);
115
116         LFSR_init (j);
117         for (i = 12; i < EDC_LENGTH; i++)
118                 tmp[i] ^= LFSR_byte ();
119
120         edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH);
121         edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH])));
122         if (edc_calculated == edc_correct)
123                 out = true;
124         else
125                 out = false;
126
127         return (out);
128 }
129
130
131 /**
132  * Unscramble a complete block, using an already-cached seed.
133  * @param seed The seed to use for the unscrambling.
134  * @param _bin The 16-sector block to unscramble (RAW_BLOCK_SIZE).
135  * @param _bout The unscrambled 16-sector block (BLOCK_SIZE).
136  * @return True if the unscrambling was successful, false otherwise.
137  */
138 static bool unscramble_frame (t_seed *seed, u_int8_t *_bin, u_int8_t *_bout) {
139         int i, j;
140         u_int8_t tmp[RAW_SECTOR_SIZE], *bin, *bout;
141         u_int32_t *_4bin, *_4cipher, edc_calculated, edc_correct;
142         bool out;
143
144         out = true;
145         for(j = 0; j < 16; j++) {
146                 bin = &_bin[RAW_SECTOR_SIZE * j];
147                 bout = &_bout[SECTOR_SIZE * j];
148
149                 memcpy (tmp, bin, RAW_SECTOR_SIZE);
150                 _4bin = (u_int32_t *) &tmp[12];         /* Scrambled data begin at byte 12 */
151                 _4cipher = (u_int32_t *) seed -> streamcipher;
152                 for (i = 0; i < 512; i++)               /* Well, the scrambling algorithm is just a bitwise XOR... */
153                         _4bin[i] ^= _4cipher[i];
154
155                 //memcpy (bout, tmp + 6, SECTOR_SIZE); // copy CPR_MAI bytes
156
157                 if (disctype==3) { //Regular
158                         memcpy (bout, tmp + 12, SECTOR_SIZE); // DVD: copy 2048 bytes (starting from CPR_MAI)
159                 }
160                 else { //Nintendo
161                         memcpy (bout, tmp + 6, SECTOR_SIZE);  // Nintendo: copy 2048 bytes (up to CPR_MAI)
162                         memcpy (&_bin[(RAW_SECTOR_SIZE * j)+2054], &tmp[2054], 6);
163                 }
164
165                 edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH);
166                 edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH])));
167                 if (edc_calculated != edc_correct) {
168                         debug ("Bad EDC (%08x), must be %08x (sector = %d)", edc_calculated, edc_correct, j);
169                         out = false;
170                 }
171         }
172
173         return (out);
174 }
175
176
177 /**
178  * Initializes the seed cache.
179  * @param u The unscrambler structure.
180  */
181 static void unscrambler_init_seeds (unscrambler *u) {
182         int i, j;
183
184         for (i = 0; i < 16; i++) {
185                 for (j = 0; j < MAX_SEEDS; j++)
186                         u -> seeds[i * MAX_SEEDS + j].seed = -1;
187
188                 u -> seeds[i * MAX_SEEDS + j].seed = -2;        // TODO Check what this does
189         }
190
191         return;
192 }
193
194
195 /**
196  * Creates a new structure representing an unscrambler.
197  * @return The newly-created structure, to be used with the other commands.
198  */
199 unscrambler *unscrambler_new (void) {
200         unscrambler *u;
201
202         u = (unscrambler *) malloc (sizeof (unscrambler));
203         unscrambler_init_seeds (u);
204         u -> bruteforce_seeds = true;
205
206         return (u);
207 }
208
209
210 /**
211  * Frees resources used by an unscrambler structure and destroys it.
212  * @param u The unscrambler structure.
213  * @return NULL.
214  */
215 void *unscrambler_destroy (unscrambler *u) {
216         my_free (u);
217
218         return (NULL);
219 }
220
221
222 void unscrambler_set_bruteforce (unscrambler *u, bool b) {
223         u -> bruteforce_seeds = b;
224         debug ("Seed bruteforcing %s", b ? "enabled" : "disabled");
225
226         return;
227 }
228
229
230 /**
231  * Unscrambles a 16-sector block.
232  * @param u The unscrambler structure.
233  * @param sector_no The number of the first sector in the block.
234  * @param inbuf The 16-sector block to unscramble. Each block must be RAW_SECTOR_SIZE bytes long, so that the total size is RAW_BLOCK_SIZE.
235  * @param outbuf The unscrambled 16-sector block. Each block will be SECTOR_SIZE bytes long, so that the total size is BLOCK_SIZE.
236  * @return True if the unscrambling was successful, false otherwise.
237  */
238 bool unscrambler_unscramble_16sectors (unscrambler *u, u_int32_t sector_no, u_int8_t *inbuf, u_int8_t *outbuf) {
239         t_seed *seeds;
240         t_seed *current_seed;
241         int j;
242         bool out;
243
244         out = true;
245
246         seeds = &(u -> seeds[((sector_no / 16) & 0x0F) * MAX_SEEDS]);
247
248         /* Try to find the seed used for this sector */
249         current_seed = NULL;
250         while (!current_seed && (seeds -> seed) >= 0) {
251                 if (test_seed (inbuf, seeds -> seed))
252                         current_seed = seeds;
253                 else
254                         seeds++;
255         }
256
257         if (!current_seed && u -> bruteforce_seeds) {
258                 /* The seed is not cached, yet. Try to find it with brute force... */
259                 unscramblerdebug ("Brute-forcing seed for sector %d...", sector_no);
260
261                 for (j = 0; !current_seed && j < 0x7FFF; j++) {
262                         if (test_seed (inbuf, j)) {
263                                 if (!(current_seed = add_seed (seeds, j))) {
264                                         error ("No enough cache space for caching seed");
265                                         out = false;
266                                 }
267                         }
268                 }
269
270                 if (current_seed)
271                         unscramblerdebug ("Seed found: %04x", --j);
272         }
273
274         if (current_seed) {
275                 /* OK, somehow seed was found: unscramble frame, write it and go on */
276                 if (!unscramble_frame (current_seed, inbuf, outbuf)) {
277                         error ("Error unscrambling frame %u\n", sector_no);
278                         out = false;
279                 } else {
280                         out = true;
281                 }
282         } else {
283                 /* Well, we only get here if there are read errors */
284                 error ("Cannot find seed for frame %u", sector_no);
285                 out = false;
286         }
287
288         return (out);
289 }
290
291
292 /**
293  * Unscrambles a complete file.
294  * @param u The unscrambler structure.
295  * @param infile The input file name.
296  * @param outfile The output file name.
297  * @param progress A function to be called repeatedly during the operation, useful to report progress data/statistics.
298  * @param progress_data Data to be passed as-is to the progress function.
299  * @return True if the unscrambling was successful, false otherwise.
300  */
301 bool unscrambler_unscramble_file (unscrambler *u, char *infile, char *outfile, unscrambler_progress_func progress, void *progress_data, u_int32_t *current_sector) {
302         FILE *in, *outfp;
303         bool out;
304         u_int8_t b_in[RAW_BLOCK_SIZE], b_out[BLOCK_SIZE];
305         size_t r;
306         my_off_t filesize;
307         int s;
308         u_int32_t total_sectors;
309
310         out = false;
311         if(!(in = fopen (infile ? infile : "", "rb"))) {
312                 error ("Cannot open input file \"%s\"", infile);
313         } else if (!(outfp = fopen (outfile ? outfile : "", "wb"))) {
314                 error ("Cannot open output file \"%s\"", outfile);
315                 fclose (in);
316         } else {
317                 /* Find out how many sectors we need to process */
318                 my_fseek (in, 0, SEEK_END);
319                 filesize = my_ftell (in);
320                 total_sectors = (u_int32_t) (filesize / RAW_SECTOR_SIZE);
321                 rewind (in);
322
323                 /* First call to progress function */
324                 if (progress)
325                         progress (true, 0, total_sectors, progress_data);
326
327                 s = 0, out = true;
328                 while ((r = fread (b_in, 1, RAW_BLOCK_SIZE, in)) > 0 && out) {
329                         if (r < RAW_BLOCK_SIZE) {
330                                 warning ("Short block read (%u bytes), padding with zeroes!", r);
331                                 memset (b_in + r, 0, sizeof (b_in) - r);
332                         }
333
334                         if (unscrambler_unscramble_16sectors (u, s, b_in, b_out)) {
335                                 clearerr (outfp);
336
337                                 if (!b_out) {
338                                         error ("NULL buffer");
339                                         out = false;
340                                         *(current_sector) = s;
341                                 }
342                                 else fwrite (b_out, SECTOR_SIZE, SECTORS_PER_BLOCK, outfp);
343                                 if (ferror (outfp)) {
344                                         error ("fwrite() to ISO output file failed");
345                                         out = false;
346                                         *(current_sector) = s;
347                                 }
348                         } else {
349                                 debug ("unscrambler_unscramble_16sectors() failed");
350                                 out = false;
351                                 *(current_sector) = s;
352                         }
353
354                         s += 16;
355
356                         if ((s % 320 == 0) || (s == total_sectors)) { //speedhack
357                                 if (progress)
358                                         progress (false, s, total_sectors, progress_data);
359                         }
360                 }
361
362                 if (out) {
363                         debug ("Image successfully unscrambled");
364                 }
365
366                 fclose (in);
367                 fclose (outfp);
368         }
369
370         return (out);
371 }