summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom Johansen <thomj@rockbox.org>2005-04-25 21:08:36 +0000
committerThom Johansen <thomj@rockbox.org>2005-04-25 21:08:36 +0000
commit8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3 (patch)
tree15a59767a56ec91c01acacf0d50b6a30f1afac4c
parent7254b9cc1506e2906ba70653fca8ad60b59437c1 (diff)
downloadrockbox-8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3.tar.gz
rockbox-8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3.zip
GUI firmware patcher for windows.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6351 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--tools/fwpatcher/checksums.h4
-rw-r--r--tools/fwpatcher/favicon.icobin0 -> 1400 bytes
-rw-r--r--tools/fwpatcher/iriver.c393
-rw-r--r--tools/fwpatcher/iriver.h40
-rw-r--r--tools/fwpatcher/main.c367
-rw-r--r--tools/fwpatcher/md5.c246
-rw-r--r--tools/fwpatcher/md5.h25
-rw-r--r--tools/fwpatcher/resource.h3
-rw-r--r--tools/fwpatcher/resource.rc4
9 files changed, 1082 insertions, 0 deletions
diff --git a/tools/fwpatcher/checksums.h b/tools/fwpatcher/checksums.h
new file mode 100644
index 0000000000..a7de794126
--- /dev/null
+++ b/tools/fwpatcher/checksums.h
@@ -0,0 +1,4 @@
1"627d5195b56ebca3b431cccb535c3bfa", /* 1.63 eu */
2"5068bf62d68fdbfcb3d8a2eaf2f4fdfe", /* 1.63 us */
3"1afe2172a4d10f69069084466f7a83ce", /* 1.63 k */
4"5802da654706239f2782510f6ab73b26" /* 1.65 eu */
diff --git a/tools/fwpatcher/favicon.ico b/tools/fwpatcher/favicon.ico
new file mode 100644
index 0000000000..c4989f558d
--- /dev/null
+++ b/tools/fwpatcher/favicon.ico
Binary files differ
diff --git a/tools/fwpatcher/iriver.c b/tools/fwpatcher/iriver.c
new file mode 100644
index 0000000000..e24df8c768
--- /dev/null
+++ b/tools/fwpatcher/iriver.c
@@ -0,0 +1,393 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Dave Hooper
11 *
12 * This particular source code file is licensed under the X11 license. See the
13 * bottom of the COPYING file for details on this license.
14 *
15 * Original code from http://www.beermex.com/@spc/ihpfirm.src.zip
16 * Details at http://www.rockbox.org/twiki/bin/view/Main/IriverToolsGuide
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "iriver.h"
24
25const unsigned char munge[] = {
26 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84,
27 0x4d, 0x73, 0x74, 0x61
28};
29
30const unsigned char header_modify[] = "* IHPFIRM-DECODED ";
31
32const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series",
33 NULL };
34
35/* aligns with models array; expected min firmware size */
36const unsigned int firmware_minsize[] = { 0x100000, 0x100000, 0x200000 };
37/* aligns with models array; expected max firmware size */
38const unsigned int firmware_maxsize[] = { 0x200000, 0x200000, 0x400000 };
39
40const unsigned char header[][16] = {
41 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
42 { 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73,
43 0x85, 0x32, 0x83, 0x22 },
44 { 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06,
45 0x30, 0x19, 0x17, 0x65 }
46};
47
48static int testheader( const unsigned char * const data )
49{
50 const unsigned char * const d = data+16;
51 const char * const * m = models;
52 int index = 0;
53 while( *m )
54 {
55 if( memcmp( header[ index ], d, 16 ) == 0 )
56 return index;
57 index++;
58 m++;
59 };
60 return -1;
61};
62
63static void modifyheader( unsigned char * data )
64{
65 const unsigned char * h = header_modify;
66 int i;
67 for( i=0; i<512; i++ )
68 {
69 if( *h == '\0' )
70 h = header_modify;
71 *data++ ^= *h++;
72 };
73};
74
75static FILE * openinfile( const TCHAR * filename )
76{
77 FILE * F = _tfopen( filename, TEXT("rb") );
78 if( F == NULL )
79 {
80 fprintf( stderr, "Couldn't open input file %s\n", filename );
81 perror( "Error was " );
82 };
83 return F;
84};
85
86static FILE * openoutfile( const TCHAR * filename )
87{
88 FILE * F = _tfopen( filename, TEXT("wb") );
89 if( F == NULL )
90 {
91 fprintf( stderr, "Couldn't open output file %s\n", filename );
92 perror( "Error was " );
93 };
94 return F;
95};
96
97int iriver_decode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify,
98 enum striptype stripmode )
99{
100 FILE * infile = NULL;
101 FILE * outfile = NULL;
102 int i = -1;
103 unsigned char headerdata[512];
104 unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
105 unsigned char blockdata[16+16];
106 unsigned char out[16];
107 unsigned char newmunge;
108 signed long lenread;
109 int s = 0;
110 unsigned char * pChecksums, * ppChecksums = 0;
111 unsigned char ck;
112
113 infile = openinfile(infile_name);
114 outfile = openoutfile(outfile_name);
115 if (!infile || !outfile) return -1;
116
117 lenread = fread( headerdata, 1, 512, infile );
118 if( lenread != 512 )
119 {
120 fprintf( stderr, "This doesn't look like a valid encrypted iHP "
121 "firmware - reason: header length\n" );
122 goto error;
123 };
124
125 i = testheader( headerdata );
126 if( i == -1 )
127 {
128 fprintf( stderr, "This firmware is for an unknown model, or is not"
129 " a valid encrypted iHP firmware\n" );
130 goto error;
131 };
132 fprintf( stderr, "Model %s\n", models[ i ] );
133
134 dwLength1 = headerdata[0] | (headerdata[1]<<8) |
135 (headerdata[2]<<16) | (headerdata[3]<<24);
136 dwLength2 = headerdata[4] | (headerdata[5]<<8) |
137 (headerdata[6]<<16) | (headerdata[7]<<24);
138 dwLength3 = headerdata[8] | (headerdata[9]<<8) |
139 (headerdata[10]<<16) | (headerdata[11]<<24);
140
141 if( dwLength1 < firmware_minsize[ i ] ||
142 dwLength1 > firmware_maxsize[ i ] ||
143 dwLength2 < firmware_minsize[ i ] ||
144 dwLength2 > dwLength1 ||
145 dwLength3 > dwLength1 ||
146 dwLength2>>9 != dwLength3 ||
147 dwLength2+dwLength3+512 != dwLength1 )
148 {
149 fprintf( stderr, "This doesn't look like a valid encrypted "
150 "iHP firmware - reason: file 'length' data\n" );
151 goto error;
152 };
153
154 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
155
156 if( modify )
157 {
158 modifyheader( headerdata );
159 };
160
161 if( stripmode == STRIP_NONE )
162 fwrite( headerdata, 512, 1, outfile );
163
164 memset( blockdata, 0, 16 );
165
166 ck = 0;
167 while( ( fp < dwLength2 ) &&
168 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
169 {
170 fp += 16;
171
172 for( i=0; i<16; ++i )
173 {
174 newmunge = blockdata[16+i] ^ munge[i];
175 out[i] = newmunge ^ blockdata[i];
176 blockdata[i] = newmunge;
177 ck += out[i];
178 }
179
180 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF )
181 {
182 fwrite( out+4, 1, 12, outfile );
183 fwrite( out, 1, 4, outfile );
184 }
185 else
186 {
187 if( ESTF_SIZE - fp < 16 )
188 {
189 memcpy( out+4, blockdata+16, 12 );
190 memcpy( out, blockdata+28, 4 );
191 fwrite( blockdata+16+ESTF_SIZE-fp, 1, ESTF_SIZE-fp, outfile );
192 }
193 }
194
195
196 if( s == 496 )
197 {
198 s = 0;
199 memset( blockdata, 0, 16 );
200 *ppChecksums++ = ck;
201 ck = 0;
202 }
203 else
204 s+=16;
205 };
206
207 if( fp != dwLength2 )
208 {
209 fprintf( stderr, "This doesn't look like a valid encrypted "
210 "iHP firmware - reason: 'length2' mismatch\n" );
211 goto error;
212 };
213
214 fp = 0;
215 ppChecksums = pChecksums;
216 while( ( fp < dwLength3 ) &&
217 ( lenread = fread( blockdata, 1, 32, infile ) ) > 0 )
218 {
219 fp += lenread;
220 if( stripmode == STRIP_NONE )
221 fwrite( blockdata, 1, lenread, outfile );
222 if( memcmp( ppChecksums, blockdata, lenread ) != 0 )
223 {
224 fprintf( stderr, "This doesn't look like a valid encrypted "
225 "iHP firmware - reason: Checksum mismatch!" );
226 goto error;
227 };
228 ppChecksums += lenread;
229 };
230
231 if( fp != dwLength3 )
232 {
233 fprintf( stderr, "This doesn't look like a valid encrypted "
234 "iHP firmware - reason: 'length3' mismatch\n" );
235 goto error;
236 };
237
238
239 fprintf( stderr, "File decoded correctly and all checksums matched!\n" );
240 switch( stripmode )
241 {
242 default:
243 case STRIP_NONE:
244 fprintf(stderr, "Output file contains all headers and "
245 "checksums\n");
246 break;
247 case STRIP_HEADER_CHECKSUM:
248 fprintf( stderr, "NB: output file contains only ESTFBINR header"
249 " and decoded firmware code\n" );
250 break;
251 case STRIP_HEADER_CHECKSUM_ESTF:
252 fprintf( stderr, "NB: output file contains only raw decoded "
253 "firmware code\n" );
254 break;
255 };
256
257 fclose(infile);
258 fclose(outfile);
259 return 0;
260error:
261 fclose(infile);
262 fclose(outfile);
263 return -1;
264};
265
266int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify )
267{
268 FILE * infile = NULL;
269 FILE * outfile = NULL;
270 int i = -1;
271 unsigned char headerdata[512];
272 unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
273 unsigned char blockdata[16+16];
274 unsigned char out[16];
275 unsigned char newmunge;
276 signed long lenread;
277 int s = 0;
278 unsigned char * pChecksums, * ppChecksums;
279 unsigned char ck;
280
281 enum striptype stripmode = STRIP_NONE;
282
283 infile = openinfile(infile_name);
284 outfile = openoutfile(outfile_name);
285 if (!infile || !outfile) return -1;
286
287 lenread = fread( headerdata, 1, 512, infile );
288 if( lenread != 512 )
289 {
290 fprintf( stderr, "This doesn't look like a valid decoded "
291 "iHP firmware - reason: header length\n" );
292 goto error;
293 };
294
295 if( modify )
296 {
297 modifyheader( headerdata ); /* reversible */
298 };
299
300 i = testheader( headerdata );
301 if( i == -1 )
302 {
303 fprintf( stderr, "This firmware is for an unknown model, or is not"
304 " a valid decoded iHP firmware\n" );
305 goto error;
306 };
307 fprintf( stderr, "Model %s\n", models[ i ] );
308
309 dwLength1 = headerdata[0] | (headerdata[1]<<8) |
310 (headerdata[2]<<16) | (headerdata[3]<<24);
311 dwLength2 = headerdata[4] | (headerdata[5]<<8) |
312 (headerdata[6]<<16) | (headerdata[7]<<24);
313 dwLength3 = headerdata[8] | (headerdata[9]<<8) |
314 (headerdata[10]<<16) | (headerdata[11]<<24);
315
316 if( dwLength1 < firmware_minsize[i] ||
317 dwLength1 > firmware_maxsize[i] ||
318 dwLength2 < firmware_minsize[i] ||
319 dwLength2 > dwLength1 ||
320 dwLength3 > dwLength1 ||
321 dwLength2+dwLength3+512 != dwLength1 )
322 {
323 fprintf( stderr, "This doesn't look like a valid decoded iHP"
324 " firmware - reason: file 'length' data\n" );
325 goto error;
326 };
327
328 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
329
330 fwrite( headerdata, 512, 1, outfile );
331
332 memset( blockdata, 0, 16 );
333 ck = 0;
334 while( ( fp < dwLength2 ) &&
335 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
336 {
337 fp += 16;
338 for( i=0; i<16; ++i )
339 {
340 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i];
341 out[i] = newmunge ^ munge[i];
342 ck += blockdata[16+i];
343 blockdata[i] = newmunge;
344 };
345 fwrite( out, 1, 16, outfile );
346
347 if( s == 496 )
348 {
349 s = 0;
350 memset( blockdata, 0, 16 );
351 *ppChecksums++ = ck;
352 ck = 0;
353 }
354 else
355 s+=16;
356 };
357
358 if( fp != dwLength2 )
359 {
360 fprintf( stderr, "This doesn't look like a valid decoded "
361 "iHP firmware - reason: 'length1' mismatch\n" );
362 goto error;
363 };
364
365 /* write out remainder w/out applying descrambler */
366 fp = 0;
367 lenread = dwLength3;
368 ppChecksums = pChecksums;
369 while( ( fp < dwLength3) &&
370 ( lenread = fwrite( ppChecksums, 1, lenread, outfile ) ) > 0 )
371 {
372 fp += lenread;
373 ppChecksums += lenread;
374 lenread = dwLength3 - fp;
375 };
376
377 if( fp != dwLength3 )
378 {
379 fprintf( stderr, "This doesn't look like a valid decoded "
380 "iHP firmware - reason: 'length2' mismatch\n" );
381 goto error;
382 };
383
384 fprintf( stderr, "File encoded successfully and checksum table built!\n" );
385
386 fclose(infile);
387 fclose(outfile);
388 return 0;
389error:
390 fclose(infile);
391 fclose(outfile);
392 return -1;
393};
diff --git a/tools/fwpatcher/iriver.h b/tools/fwpatcher/iriver.h
new file mode 100644
index 0000000000..d3d00d2eff
--- /dev/null
+++ b/tools/fwpatcher/iriver.h
@@ -0,0 +1,40 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Daniel Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <tchar.h>
21#include <windows.h>
22
23#define TRUE 1
24#define FALSE 0
25
26#define BOOL unsigned int
27
28#define ESTF_SIZE 32
29
30enum striptype
31{
32 STRIP_NONE,
33 STRIP_HEADER_CHECKSUM,
34 STRIP_HEADER_CHECKSUM_ESTF
35};
36
37/* protos for iriver.c */
38int iriver_decode(TCHAR *infile, TCHAR *outfile, BOOL modify,
39 enum striptype stripmode );
40int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, BOOL modify );
diff --git a/tools/fwpatcher/main.c b/tools/fwpatcher/main.c
new file mode 100644
index 0000000000..c8fa11ea95
--- /dev/null
+++ b/tools/fwpatcher/main.c
@@ -0,0 +1,367 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Thom Johansen
11 *
12 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
13 * KIND, either express or implied.
14 *
15 ****************************************************************************/
16
17/* TODO: integrate the iriver.c and mkboot stuff better, they're pretty much
18 * intended to be called from a command line tool, and i haven't changed that.
19 */
20
21#include <stdio.h>
22#include <string.h>
23#include <tchar.h>
24#include <windows.h>
25#include "iriver.h"
26#include "md5.h"
27#include "resource.h"
28
29#define WINDOW_WIDTH 280
30#define WINDOW_HEIGHT 130
31
32#define IDM_RESTORE 1000
33#define IDM_EXIT 1010
34
35#define LABEL_FILENAME 0
36#define EDIT_FILENAME 1
37#define BUTTON_BROWSE 2
38#define BUTTON_PATCH 3
39
40#define CTL_NUM 4
41
42/* include precalculated checksums */
43static char *checksums[] = {
44#include "checksums.h"
45};
46
47HICON rbicon;
48HFONT deffont;
49HWND controls[CTL_NUM];
50
51/* begin mkboot.c excerpt */
52
53char image[0x200000 + 0x220 + 0x200000/0x200];
54
55int mkboot(TCHAR *infile, TCHAR *outfile, unsigned char *bldata, int bllen)
56{
57 FILE *f;
58 int i;
59 int len;
60 int actual_length, total_length, binary_length, num_chksums;
61
62 memset(image, 0xff, sizeof(image));
63
64 /* First, read the iriver original firmware into the image */
65 f = _tfopen(infile, TEXT("rb"));
66 if(!f) {
67 perror(infile);
68 return 0;
69 }
70
71 i = fread(image, 1, 16, f);
72 if(i < 16) {
73 perror(infile);
74 return 0;
75 }
76
77 /* This is the length of the binary image without the scrambling
78 overhead (but including the ESTFBINR header) */
79 binary_length = image[4] + (image[5] << 8) +
80 (image[6] << 16) + (image[7] << 24);
81
82 /* Read the rest of the binary data, but not the checksum block */
83 len = binary_length+0x200-16;
84 i = fread(image+16, 1, len, f);
85 if(i < len) {
86 perror(infile);
87 return 0;
88 }
89
90 fclose(f);
91
92 memcpy(image + 0x220 + 0x1f0000, bldata, bllen);
93
94 f = _tfopen(outfile, TEXT("wb"));
95 if(!f) {
96 perror(outfile);
97 return 0;
98 }
99
100 /* Patch the reset vector to start the boot loader */
101 image[0x220 + 4] = image[0x1f0000 + 0x220 + 4];
102 image[0x220 + 5] = image[0x1f0000 + 0x220 + 5];
103 image[0x220 + 6] = image[0x1f0000 + 0x220 + 6];
104 image[0x220 + 7] = image[0x1f0000 + 0x220 + 7];
105
106 /* This is the actual length of the binary, excluding all headers */
107 actual_length = 0x1f0000 + bllen;
108
109 /* Patch the ESTFBINR header */
110 image[0x20c] = (actual_length >> 24) & 0xff;
111 image[0x20d] = (actual_length >> 16) & 0xff;
112 image[0x20e] = (actual_length >> 8) & 0xff;
113 image[0x20f] = actual_length & 0xff;
114
115 image[0x21c] = (actual_length >> 24) & 0xff;
116 image[0x21d] = (actual_length >> 16) & 0xff;
117 image[0x21e] = (actual_length >> 8) & 0xff;
118 image[0x21f] = actual_length & 0xff;
119
120 /* This is the length of the binary, including the ESTFBINR header and
121 rounded up to the nearest 0x200 boundary */
122 binary_length = (actual_length + 0x20 + 0x1ff) & 0xfffffe00;
123
124 /* The number of checksums, i.e number of 0x200 byte blocks */
125 num_chksums = binary_length / 0x200;
126
127 /* The total file length, including all headers and checksums */
128 total_length = binary_length + num_chksums + 0x200;
129
130 /* Patch the scrambler header with the new length info */
131 image[0] = total_length & 0xff;
132 image[1] = (total_length >> 8) & 0xff;
133 image[2] = (total_length >> 16) & 0xff;
134 image[3] = (total_length >> 24) & 0xff;
135
136 image[4] = binary_length & 0xff;
137 image[5] = (binary_length >> 8) & 0xff;
138 image[6] = (binary_length >> 16) & 0xff;
139 image[7] = (binary_length >> 24) & 0xff;
140
141 image[8] = num_chksums & 0xff;
142 image[9] = (num_chksums >> 8) & 0xff;
143 image[10] = (num_chksums >> 16) & 0xff;
144 image[11] = (num_chksums >> 24) & 0xff;
145
146 i = fwrite(image, 1, total_length, f);
147 if(i < total_length) {
148 perror(outfile);
149 return 0;
150 }
151
152 fclose(f);
153
154 return 1;
155}
156
157/* end mkboot.c excerpt */
158
159int FileMD5(TCHAR *name, char *md5)
160{
161 int i, read;
162 md5_context ctx;
163 unsigned char md5sum[16];
164 unsigned char block[32768];
165 FILE *file;
166
167 file = _tfopen(name, TEXT("rb"));
168 if (!file) {
169 MessageBox(NULL,
170 TEXT("Could not open patched firmware for checksum check"),
171 TEXT("Error"), MB_ICONERROR);
172 return 0;
173 }
174 md5_starts(&ctx);
175 while ((read = fread(block, 1, sizeof(block), file)) > 0) {
176 md5_update(&ctx, block, read);
177 }
178 fclose(file);
179 md5_finish(&ctx, md5sum);
180 for (i = 0; i < 16; ++i)
181 sprintf(md5 + 2*i, "%02x", md5sum[i]);
182 return 1;
183}
184
185int PatchFirmware()
186{
187 TCHAR fn[MAX_PATH];
188 TCHAR name1[MAX_PATH], name2[MAX_PATH], name3[MAX_PATH];
189 HRSRC res;
190 HGLOBAL resload;
191 unsigned char *bootloader;
192 unsigned char md5sum_str[256];
193 DWORD blsize;
194 int i;
195
196 /* get pointer to bootloader.bin */
197 res = FindResource(NULL, MAKEINTRESOURCE(IDI_BOOTLOADER), TEXT("BIN"));
198 resload = LoadResource(NULL, res);
199 bootloader = (unsigned char *)LockResource(resload);
200 blsize = SizeofResource(NULL, res);
201
202 /* get filename from edit box */
203 GetWindowText(controls[EDIT_FILENAME], fn, MAX_PATH);
204 /* store temp files in temp directory */
205 GetTempPath(MAX_PATH, name1);
206 GetTempPath(MAX_PATH, name2);
207 GetTempPath(MAX_PATH, name3);
208 _tcscat(name1, TEXT("firmware.bin")); /* descrambled file */
209 _tcscat(name2, TEXT("new.bin")); /* patched file */
210 _tcscat(name3, TEXT("new.hex")); /* patched and scrambled file */
211 if (iriver_decode(fn, name1, FALSE, STRIP_NONE) == -1) {
212 MessageBox(NULL, TEXT("Error in descramble"),
213 TEXT("Error"), MB_ICONERROR);
214 goto error;
215 }
216 if (!mkboot(name1, name2, bootloader, blsize)) {
217 MessageBox(NULL, TEXT("Error in patching"),
218 TEXT("Error"), MB_ICONERROR);
219 goto error;
220 }
221 if (iriver_encode(name2, name3, FALSE) == -1) {
222 MessageBox(NULL, TEXT("Error in scramble"),
223 TEXT("Error"), MB_ICONERROR);
224 goto error;
225 }
226 /* now md5sum it */
227 if (!FileMD5(name3, md5sum_str)) goto error;
228 for (i = 0; i < sizeof(checksums)/sizeof(char *); ++i) {
229 if (strncmp(checksums[i], md5sum_str, 32) != 0) {
230 MessageBox(NULL,
231 TEXT("Checksum doesn't match known good patched firmware.\n")
232 TEXT("Download another firmware image, then try again."),
233 TEXT("Error"), MB_ICONERROR);
234 goto error;
235 }
236 }
237 /* all is fine, rename the patched file to original name of the firmware */
238 MoveFileEx(name3, fn, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
239 /* delete temp files */
240 DeleteFile(name1);
241 DeleteFile(name2);
242 return 1;
243error:
244 /* delete all temp files, don't care if some aren't created yet */
245 DeleteFile(name1);
246 DeleteFile(name2);
247 DeleteFile(name3);
248 return 0;
249}
250
251int FileDialog(TCHAR *fn)
252{
253 OPENFILENAME ofn;
254 TCHAR filename[MAX_PATH];
255
256 ZeroMemory(&ofn, sizeof(ofn));
257 ofn.lStructSize = sizeof(ofn);
258 ofn.lpstrFile = filename;
259 ofn.lpstrFile[0] = '\0'; // no default filename
260 ofn.nMaxFile = sizeof(filename);
261 ofn.lpstrFilter = TEXT("Firmware\0*.HEX\0");
262 ofn.nFilterIndex = 1;
263 ofn.lpstrFileTitle = NULL;
264 ofn.nMaxFileTitle = 0;
265 ofn.lpstrInitialDir = NULL;
266 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
267
268 if (GetOpenFileName(&ofn) == TRUE) {
269 _tcscpy(fn, filename);
270 return 1;
271 }
272 return 0;
273}
274
275LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
276{
277 int i;
278 switch (msg) {
279 case WM_CREATE:
280 /* text label */
281 controls[LABEL_FILENAME] =
282 CreateWindowEx(0, TEXT("STATIC"), TEXT("Firmware file name:"),
283 WS_CHILD | WS_VISIBLE, 10, 14,
284 100, 32, hwnd, 0, 0, 0);
285 /* text field for inputing file name */
286 controls[EDIT_FILENAME] =
287 CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""),
288 WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL,
289 10, 35, 180, 20, hwnd, 0, 0, 0);
290 /* browse button */
291 controls[BUTTON_BROWSE] =
292 CreateWindowEx(0, TEXT("BUTTON"), TEXT("Browse"),
293 WS_CHILD | WS_TABSTOP | WS_VISIBLE, 200, 32, 70, 25,
294 hwnd, 0, 0, 0);
295 /* patch button */
296 controls[BUTTON_PATCH] =
297 CreateWindowEx(0, TEXT("BUTTON"), TEXT("Patch"),
298 WS_CHILD | WS_TABSTOP | WS_VISIBLE, 90, 70, 90, 25,
299 hwnd, 0, 0, 0);
300 /* set default font on all controls, will be ugly if we don't do this */
301 deffont = GetStockObject(DEFAULT_GUI_FONT);
302 for (i = 0; i < CTL_NUM; ++i)
303 SendMessage(controls[i], WM_SETFONT, (WPARAM)deffont,
304 MAKELPARAM(FALSE, 0));
305 break;
306 case WM_CLOSE:
307 DestroyWindow(hwnd);
308 break;
309 case WM_DESTROY:
310 PostQuitMessage(0);
311 break;
312 case WM_SIZE:
313 break;
314 case WM_COMMAND:
315 /* user pressed browse button */
316 if (((HWND)lParam == controls[BUTTON_BROWSE])) {
317 TCHAR buf[MAX_PATH];
318 if (FileDialog(buf))
319 SetWindowText(controls[EDIT_FILENAME], buf);
320 }
321 /* user pressed patch button */
322 if (((HWND)lParam == controls[BUTTON_PATCH])) {
323 if (PatchFirmware())
324 MessageBox(NULL, TEXT("Firmware patched successfully"),
325 TEXT("Success"), MB_OK);
326 }
327 break;
328 default:
329 return DefWindowProc(hwnd, msg, wParam, lParam);
330 }
331 return 0;
332}
333
334int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance,
335 LPSTR command_line, int command_show)
336{
337 HWND window;
338 WNDCLASSEX wc;
339 MSG msg;
340
341 rbicon = LoadIcon(instance, MAKEINTRESOURCE(IDI_RBICON));
342 ZeroMemory(&wc, sizeof(wc));
343 wc.cbSize = sizeof(wc);
344 wc.lpfnWndProc = WndProc;
345 wc.hInstance = instance;
346 wc.hIcon = rbicon;
347 wc.hCursor = LoadCursor(0, IDC_ARROW);
348 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
349 wc.lpszClassName = TEXT("patcher");
350 RegisterClassEx(&wc);
351
352 window = CreateWindowEx(0, TEXT("patcher"), TEXT("Rockbox firmware patcher"),
353 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
354 WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
355 WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, instance, NULL);
356 if (!window) return 0;
357
358 ShowWindow(window, command_show);
359 while (GetMessage(&msg, 0, 0, 0) > 0) {
360 if (!IsDialogMessage(window, &msg)) {
361 TranslateMessage(&msg);
362 DispatchMessage(&msg);
363 }
364 }
365 return 0;
366}
367
diff --git a/tools/fwpatcher/md5.c b/tools/fwpatcher/md5.c
new file mode 100644
index 0000000000..6c5e8127f9
--- /dev/null
+++ b/tools/fwpatcher/md5.c
@@ -0,0 +1,246 @@
1/*
2 * RFC 1321 compliant MD5 implementation
3 *
4 * Copyright (C) 2001-2003 Christophe Devine
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 Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <string.h>
22
23#include "md5.h"
24
25#define GET_UINT32(n,b,i) \
26{ \
27 (n) = ( (uint32) (b)[(i) ] ) \
28 | ( (uint32) (b)[(i) + 1] << 8 ) \
29 | ( (uint32) (b)[(i) + 2] << 16 ) \
30 | ( (uint32) (b)[(i) + 3] << 24 ); \
31}
32
33#define PUT_UINT32(n,b,i) \
34{ \
35 (b)[(i) ] = (uint8) ( (n) ); \
36 (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
37 (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
38 (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
39}
40
41void md5_starts( md5_context *ctx )
42{
43 ctx->total[0] = 0;
44 ctx->total[1] = 0;
45
46 ctx->state[0] = 0x67452301;
47 ctx->state[1] = 0xEFCDAB89;
48 ctx->state[2] = 0x98BADCFE;
49 ctx->state[3] = 0x10325476;
50}
51
52void md5_process( md5_context *ctx, uint8 data[64] )
53{
54 uint32 X[16], A, B, C, D;
55
56 GET_UINT32( X[0], data, 0 );
57 GET_UINT32( X[1], data, 4 );
58 GET_UINT32( X[2], data, 8 );
59 GET_UINT32( X[3], data, 12 );
60 GET_UINT32( X[4], data, 16 );
61 GET_UINT32( X[5], data, 20 );
62 GET_UINT32( X[6], data, 24 );
63 GET_UINT32( X[7], data, 28 );
64 GET_UINT32( X[8], data, 32 );
65 GET_UINT32( X[9], data, 36 );
66 GET_UINT32( X[10], data, 40 );
67 GET_UINT32( X[11], data, 44 );
68 GET_UINT32( X[12], data, 48 );
69 GET_UINT32( X[13], data, 52 );
70 GET_UINT32( X[14], data, 56 );
71 GET_UINT32( X[15], data, 60 );
72
73#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
74
75#define P(a,b,c,d,k,s,t) \
76{ \
77 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
78}
79
80 A = ctx->state[0];
81 B = ctx->state[1];
82 C = ctx->state[2];
83 D = ctx->state[3];
84
85#define F(x,y,z) (z ^ (x & (y ^ z)))
86
87 P( A, B, C, D, 0, 7, 0xD76AA478 );
88 P( D, A, B, C, 1, 12, 0xE8C7B756 );
89 P( C, D, A, B, 2, 17, 0x242070DB );
90 P( B, C, D, A, 3, 22, 0xC1BDCEEE );
91 P( A, B, C, D, 4, 7, 0xF57C0FAF );
92 P( D, A, B, C, 5, 12, 0x4787C62A );
93 P( C, D, A, B, 6, 17, 0xA8304613 );
94 P( B, C, D, A, 7, 22, 0xFD469501 );
95 P( A, B, C, D, 8, 7, 0x698098D8 );
96 P( D, A, B, C, 9, 12, 0x8B44F7AF );
97 P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
98 P( B, C, D, A, 11, 22, 0x895CD7BE );
99 P( A, B, C, D, 12, 7, 0x6B901122 );
100 P( D, A, B, C, 13, 12, 0xFD987193 );
101 P( C, D, A, B, 14, 17, 0xA679438E );
102 P( B, C, D, A, 15, 22, 0x49B40821 );
103
104#undef F
105
106#define F(x,y,z) (y ^ (z & (x ^ y)))
107
108 P( A, B, C, D, 1, 5, 0xF61E2562 );
109 P( D, A, B, C, 6, 9, 0xC040B340 );
110 P( C, D, A, B, 11, 14, 0x265E5A51 );
111 P( B, C, D, A, 0, 20, 0xE9B6C7AA );
112 P( A, B, C, D, 5, 5, 0xD62F105D );
113 P( D, A, B, C, 10, 9, 0x02441453 );
114 P( C, D, A, B, 15, 14, 0xD8A1E681 );
115 P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
116 P( A, B, C, D, 9, 5, 0x21E1CDE6 );
117 P( D, A, B, C, 14, 9, 0xC33707D6 );
118 P( C, D, A, B, 3, 14, 0xF4D50D87 );
119 P( B, C, D, A, 8, 20, 0x455A14ED );
120 P( A, B, C, D, 13, 5, 0xA9E3E905 );
121 P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
122 P( C, D, A, B, 7, 14, 0x676F02D9 );
123 P( B, C, D, A, 12, 20, 0x8D2A4C8A );
124
125#undef F
126
127#define F(x,y,z) (x ^ y ^ z)
128
129 P( A, B, C, D, 5, 4, 0xFFFA3942 );
130 P( D, A, B, C, 8, 11, 0x8771F681 );
131 P( C, D, A, B, 11, 16, 0x6D9D6122 );
132 P( B, C, D, A, 14, 23, 0xFDE5380C );
133 P( A, B, C, D, 1, 4, 0xA4BEEA44 );
134 P( D, A, B, C, 4, 11, 0x4BDECFA9 );
135 P( C, D, A, B, 7, 16, 0xF6BB4B60 );
136 P( B, C, D, A, 10, 23, 0xBEBFBC70 );
137 P( A, B, C, D, 13, 4, 0x289B7EC6 );
138 P( D, A, B, C, 0, 11, 0xEAA127FA );
139 P( C, D, A, B, 3, 16, 0xD4EF3085 );
140 P( B, C, D, A, 6, 23, 0x04881D05 );
141 P( A, B, C, D, 9, 4, 0xD9D4D039 );
142 P( D, A, B, C, 12, 11, 0xE6DB99E5 );
143 P( C, D, A, B, 15, 16, 0x1FA27CF8 );
144 P( B, C, D, A, 2, 23, 0xC4AC5665 );
145
146#undef F
147
148#define F(x,y,z) (y ^ (x | ~z))
149
150 P( A, B, C, D, 0, 6, 0xF4292244 );
151 P( D, A, B, C, 7, 10, 0x432AFF97 );
152 P( C, D, A, B, 14, 15, 0xAB9423A7 );
153 P( B, C, D, A, 5, 21, 0xFC93A039 );
154 P( A, B, C, D, 12, 6, 0x655B59C3 );
155 P( D, A, B, C, 3, 10, 0x8F0CCC92 );
156 P( C, D, A, B, 10, 15, 0xFFEFF47D );
157 P( B, C, D, A, 1, 21, 0x85845DD1 );
158 P( A, B, C, D, 8, 6, 0x6FA87E4F );
159 P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
160 P( C, D, A, B, 6, 15, 0xA3014314 );
161 P( B, C, D, A, 13, 21, 0x4E0811A1 );
162 P( A, B, C, D, 4, 6, 0xF7537E82 );
163 P( D, A, B, C, 11, 10, 0xBD3AF235 );
164 P( C, D, A, B, 2, 15, 0x2AD7D2BB );
165 P( B, C, D, A, 9, 21, 0xEB86D391 );
166
167#undef F
168
169 ctx->state[0] += A;
170 ctx->state[1] += B;
171 ctx->state[2] += C;
172 ctx->state[3] += D;
173}
174
175void md5_update( md5_context *ctx, uint8 *input, uint32 length )
176{
177 uint32 left, fill;
178
179 if( ! length ) return;
180
181 left = ctx->total[0] & 0x3F;
182 fill = 64 - left;
183
184 ctx->total[0] += length;
185 ctx->total[0] &= 0xFFFFFFFF;
186
187 if( ctx->total[0] < length )
188 ctx->total[1]++;
189
190 if( left && length >= fill )
191 {
192 memcpy( (void *) (ctx->buffer + left),
193 (void *) input, fill );
194 md5_process( ctx, ctx->buffer );
195 length -= fill;
196 input += fill;
197 left = 0;
198 }
199
200 while( length >= 64 )
201 {
202 md5_process( ctx, input );
203 length -= 64;
204 input += 64;
205 }
206
207 if( length )
208 {
209 memcpy( (void *) (ctx->buffer + left),
210 (void *) input, length );
211 }
212}
213
214static uint8 md5_padding[64] =
215{
216 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
220};
221
222void md5_finish( md5_context *ctx, uint8 digest[16] )
223{
224 uint32 last, padn;
225 uint32 high, low;
226 uint8 msglen[8];
227
228 high = ( ctx->total[0] >> 29 )
229 | ( ctx->total[1] << 3 );
230 low = ( ctx->total[0] << 3 );
231
232 PUT_UINT32( low, msglen, 0 );
233 PUT_UINT32( high, msglen, 4 );
234
235 last = ctx->total[0] & 0x3F;
236 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
237
238 md5_update( ctx, md5_padding, padn );
239 md5_update( ctx, msglen, 8 );
240
241 PUT_UINT32( ctx->state[0], digest, 0 );
242 PUT_UINT32( ctx->state[1], digest, 4 );
243 PUT_UINT32( ctx->state[2], digest, 8 );
244 PUT_UINT32( ctx->state[3], digest, 12 );
245}
246
diff --git a/tools/fwpatcher/md5.h b/tools/fwpatcher/md5.h
new file mode 100644
index 0000000000..71fa395548
--- /dev/null
+++ b/tools/fwpatcher/md5.h
@@ -0,0 +1,25 @@
1#ifndef _MD5_H
2#define _MD5_H
3
4#ifndef uint8
5#define uint8 unsigned char
6#endif
7
8#ifndef uint32
9#define uint32 unsigned long int
10#endif
11
12typedef struct
13{
14 uint32 total[2];
15 uint32 state[4];
16 uint8 buffer[64];
17}
18md5_context;
19
20void md5_starts( md5_context *ctx );
21void md5_update( md5_context *ctx, uint8 *input, uint32 length );
22void md5_finish( md5_context *ctx, uint8 digest[16] );
23
24#endif /* md5.h */
25
diff --git a/tools/fwpatcher/resource.h b/tools/fwpatcher/resource.h
new file mode 100644
index 0000000000..9847eee88c
--- /dev/null
+++ b/tools/fwpatcher/resource.h
@@ -0,0 +1,3 @@
1#define IDI_RBICON 101
2#define IDI_BOOTLOADER 102
3
diff --git a/tools/fwpatcher/resource.rc b/tools/fwpatcher/resource.rc
new file mode 100644
index 0000000000..eabd9e49bd
--- /dev/null
+++ b/tools/fwpatcher/resource.rc
@@ -0,0 +1,4 @@
1#include "resource.h"
2
3IDI_RBICON ICON "favicon.ico"
4IDI_BOOTLOADER BIN "bootloader.bin"