1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * File: irivertools.cpp
11 * Copyright (C) 2007 Dominik Wenger
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include "irivertools.h"
24 const unsigned char munge
[] = {
25 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84,
26 0x4d, 0x73, 0x74, 0x61
29 const unsigned char header_modify
[] = "* IHPFIRM-DECODED ";
31 const char * const models
[] = { "iHP-100", "iHP-120/iHP-140", "H300 series",
34 /* aligns with models array; expected min firmware size */
35 const unsigned int firmware_minsize
[] = { 0x100000, 0x100000, 0x200000 };
36 /* aligns with models array; expected max firmware size */
37 const unsigned int firmware_maxsize
[] = { 0x200000, 0x200000, 0x400000 };
39 const unsigned char header
[][16] = {
40 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
41 { 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73,
42 0x85, 0x32, 0x83, 0x22 },
43 { 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06,
44 0x30, 0x19, 0x17, 0x65 }
47 /* begin mkboot.c excerpt */
48 unsigned char image
[0x400000 + 0x220 + 0x400000/0x200];
50 bool mkboot(wxString infile
, wxString outfile
,wxString bootloader
,int origin
)
55 int actual_length
, total_length
, binary_length
, num_chksums
;
57 memset(image
, 0xff, sizeof(image
));
59 /* First, read the iriver original firmware into the image */
63 ERR_DIALOG(wxT("Could not open: ") + infile
, wxT("mkboot"));
68 ERR_DIALOG(wxT("reading header failed"), wxT("mkboot"));
72 /* This is the length of the binary image without the scrambling
73 overhead (but including the ESTFBINR header) */
74 binary_length
= image
[4] + (image
[5] << 8) +
75 (image
[6] << 16) + (image
[7] << 24);
77 /* Read the rest of the binary data, but not the checksum block */
78 len
= binary_length
+0x200-16;
79 i
= f
.Read(image
+16, len
);
81 ERR_DIALOG(wxT("reading firmware failed"),wxT("mkboot"));
86 /* Now, read the boot loader into the image */
87 if(!f
.Open(bootloader
))
89 ERR_DIALOG(wxT("Could not open: ") + bootloader
, wxT("mkboot"));
95 i
= f
.Read(image
+0x220 + origin
, bllen
);
97 ERR_DIALOG(wxT("reading bootloader failed"), wxT("mkboot"));
103 if(!f
.Open(outfile
,wxFile::write
))
105 ERR_DIALOG(wxT("Could not open: ") + outfile
, wxT("mkboot"));
109 /* Patch the reset vector to start the boot loader */
110 image
[0x220 + 4] = image
[origin
+ 0x220 + 4];
111 image
[0x220 + 5] = image
[origin
+ 0x220 + 5];
112 image
[0x220 + 6] = image
[origin
+ 0x220 + 6];
113 image
[0x220 + 7] = image
[origin
+ 0x220 + 7];
115 /* This is the actual length of the binary, excluding all headers */
116 actual_length
= origin
+ bllen
;
118 /* Patch the ESTFBINR header */
119 image
[0x20c] = (actual_length
>> 24) & 0xff;
120 image
[0x20d] = (actual_length
>> 16) & 0xff;
121 image
[0x20e] = (actual_length
>> 8) & 0xff;
122 image
[0x20f] = actual_length
& 0xff;
124 image
[0x21c] = (actual_length
>> 24) & 0xff;
125 image
[0x21d] = (actual_length
>> 16) & 0xff;
126 image
[0x21e] = (actual_length
>> 8) & 0xff;
127 image
[0x21f] = actual_length
& 0xff;
129 /* This is the length of the binary, including the ESTFBINR header and
130 rounded up to the nearest 0x200 boundary */
131 binary_length
= (actual_length
+ 0x20 + 0x1ff) & 0xfffffe00;
133 /* The number of checksums, i.e number of 0x200 byte blocks */
134 num_chksums
= binary_length
/ 0x200;
136 /* The total file length, including all headers and checksums */
137 total_length
= binary_length
+ num_chksums
+ 0x200;
139 /* Patch the scrambler header with the new length info */
140 image
[0] = total_length
& 0xff;
141 image
[1] = (total_length
>> 8) & 0xff;
142 image
[2] = (total_length
>> 16) & 0xff;
143 image
[3] = (total_length
>> 24) & 0xff;
145 image
[4] = binary_length
& 0xff;
146 image
[5] = (binary_length
>> 8) & 0xff;
147 image
[6] = (binary_length
>> 16) & 0xff;
148 image
[7] = (binary_length
>> 24) & 0xff;
150 image
[8] = num_chksums
& 0xff;
151 image
[9] = (num_chksums
>> 8) & 0xff;
152 image
[10] = (num_chksums
>> 16) & 0xff;
153 image
[11] = (num_chksums
>> 24) & 0xff;
155 i
= f
.Write(image
,total_length
);
156 if(i
< total_length
) {
157 ERR_DIALOG(wxT("writing bootloader failed"), wxT("mkboot"));
166 /* end mkboot.c excerpt */
169 int intable(char *md5
, struct sumpairs
*table
, int len
)
172 for (i
= 0; i
< len
; i
++) {
173 if (strncmp(md5
, table
[i
].unpatched
, 32) == 0) {
183 static int testheader( const unsigned char * const data
)
185 const unsigned char * const d
= data
+16;
186 const char * const * m
= models
;
190 if( memcmp( header
[ index
], d
, 16 ) == 0 )
198 static void modifyheader( unsigned char * data
)
200 const unsigned char * h
= header_modify
;
202 for( i
=0; i
<512; i
++ )
210 int iriver_decode(wxString infile_name
, wxString outfile_name
, unsigned int modify
,
211 enum striptype stripmode
)
217 unsigned char headerdata
[512];
218 unsigned long dwLength1
, dwLength2
, dwLength3
, fp
= 0;
219 unsigned char blockdata
[16+16];
220 unsigned char out
[16];
221 unsigned char newmunge
;
224 unsigned char * pChecksums
, * ppChecksums
= 0;
227 if(!infile
.Open(infile_name
))
229 ERR_DIALOG(wxT("Could not open: ") + infile_name
, wxT("iriver_decode"));
232 if(!outfile
.Open(outfile_name
,wxFile::write
))
234 ERR_DIALOG(wxT("Could not open: ") + outfile_name
,
235 wxT("iriver_decode"));
238 lenread
= infile
.Read( headerdata
, 512);
241 ERR_DIALOG(wxT("This doesn't look like a valid encrypted iHP "
242 "firmware - reason: header length\n"),wxT("iriver_decode"));
249 i
= testheader( headerdata
);
252 ERR_DIALOG( wxT( "This firmware is for an unknown model, or is not"
253 " a valid encrypted iHP firmware\n" ),wxT("iriver_decode"));
258 fprintf( stderr
, "Model %s\n", models
[ i
] );
260 dwLength1
= headerdata
[0] | (headerdata
[1]<<8) |
261 (headerdata
[2]<<16) | (headerdata
[3]<<24);
262 dwLength2
= headerdata
[4] | (headerdata
[5]<<8) |
263 (headerdata
[6]<<16) | (headerdata
[7]<<24);
264 dwLength3
= headerdata
[8] | (headerdata
[9]<<8) |
265 (headerdata
[10]<<16) | (headerdata
[11]<<24);
267 if( dwLength1
< firmware_minsize
[ i
] ||
268 dwLength1
> firmware_maxsize
[ i
] ||
269 dwLength2
< firmware_minsize
[ i
] ||
270 dwLength2
> dwLength1
||
271 dwLength3
> dwLength1
||
272 dwLength2
>>9 != dwLength3
||
273 dwLength2
+dwLength3
+512 != dwLength1
)
275 ERR_DIALOG( wxT( "This doesn't look like a valid encrypted "
276 "iHP firmware - reason: file 'length' data\n" ),wxT("iriver_decode"));
282 pChecksums
= ppChecksums
= (unsigned char *)( malloc( dwLength3
) );
286 modifyheader( headerdata
);
289 if( stripmode
== STRIP_NONE
)
290 outfile
.Write( headerdata
, 512);
292 memset( blockdata
, 0, 16 );
295 while( ( fp
< dwLength2
) &&
296 ( lenread
= infile
.Read( blockdata
+16, 16) == 16) )
300 for( i
=0; i
<16; ++i
)
302 newmunge
= blockdata
[16+i
] ^ munge
[i
];
303 out
[i
] = newmunge
^ blockdata
[i
];
304 blockdata
[i
] = newmunge
;
308 if( fp
> ESTF_SIZE
|| stripmode
!= STRIP_HEADER_CHECKSUM_ESTF
)
310 outfile
.Write( out
+4, 12);
311 outfile
.Write( out
, 4);
315 if( ESTF_SIZE
- fp
< 16 )
317 memcpy( out
+4, blockdata
+16, 12 );
318 memcpy( out
, blockdata
+28, 4 );
319 outfile
.Write( blockdata
+16+ESTF_SIZE
-fp
, ESTF_SIZE
-fp
);
327 memset( blockdata
, 0, 16 );
335 if( fp
!= dwLength2
)
337 ERR_DIALOG( wxT( "This doesn't look like a valid encrypted "
338 "iHP firmware - reason: 'length2' mismatch\n" ),wxT("iriver_decode"));
345 ppChecksums
= pChecksums
;
346 while( ( fp
< dwLength3
) &&
347 ( lenread
= infile
.Read( blockdata
, 32 ) ) > 0 )
350 if( stripmode
== STRIP_NONE
)
351 outfile
.Write( blockdata
, lenread
);
352 if( memcmp( ppChecksums
, blockdata
, lenread
) != 0 )
354 ERR_DIALOG( wxT( "This doesn't look like a valid encrypted "
355 "iHP firmware - reason: Checksum mismatch!" ),wxT("iriver_decode"));
360 ppChecksums
+= lenread
;
363 if( fp
!= dwLength3
)
365 ERR_DIALOG(wxT( "This doesn't look like a valid encrypted "
366 "iHP firmware - reason: 'length3' mismatch\n" ),wxT("iriver_decode"));
373 fprintf( stderr
, "File decoded correctly and all checksums matched!\n" );
378 fprintf(stderr
, "Output file contains all headers and "
381 case STRIP_HEADER_CHECKSUM
:
382 fprintf( stderr
, "NB: output file contains only ESTFBINR header"
383 " and decoded firmware code\n" );
385 case STRIP_HEADER_CHECKSUM_ESTF
:
386 fprintf( stderr
, "NB: output file contains only raw decoded "
397 int iriver_encode(wxString infile_name
, wxString outfile_name
, unsigned int modify
)
403 unsigned char headerdata
[512];
404 unsigned long dwLength1
, dwLength2
, dwLength3
, fp
= 0;
405 unsigned char blockdata
[16+16];
406 unsigned char out
[16];
407 unsigned char newmunge
;
410 unsigned char * pChecksums
, * ppChecksums
;
413 if(!infile
.Open(infile_name
,wxFile::read
))
415 ERR_DIALOG(wxT("Could not open: ") + infile_name
, wxT("iriver_decode"));
418 if(!outfile
.Open(outfile_name
,wxFile::write
))
420 ERR_DIALOG(wxT("Could not open: ") + outfile_name
,
421 wxT("iriver_decode"));
425 lenread
= infile
.Read( headerdata
, 512 );
428 ERR_DIALOG(wxT("This doesn't look like a valid decoded "
429 "iHP firmware - reason: header length\n"), wxT("iriver_decode"));
436 modifyheader( headerdata
); /* reversible */
439 i
= testheader( headerdata
);
442 ERR_DIALOG(wxT("This firmware is for an unknown model, or is not"
443 " a valid decoded iHP firmware\n"), wxT("iriver_decode"));
447 fprintf( stderr
, "Model %s\n", models
[ i
] );
449 dwLength1
= headerdata
[0] | (headerdata
[1]<<8) |
450 (headerdata
[2]<<16) | (headerdata
[3]<<24);
451 dwLength2
= headerdata
[4] | (headerdata
[5]<<8) |
452 (headerdata
[6]<<16) | (headerdata
[7]<<24);
453 dwLength3
= headerdata
[8] | (headerdata
[9]<<8) |
454 (headerdata
[10]<<16) | (headerdata
[11]<<24);
456 if( dwLength1
< firmware_minsize
[i
] ||
457 dwLength1
> firmware_maxsize
[i
] ||
458 dwLength2
< firmware_minsize
[i
] ||
459 dwLength2
> dwLength1
||
460 dwLength3
> dwLength1
||
461 dwLength2
+dwLength3
+512 != dwLength1
)
463 ERR_DIALOG(wxT("This doesn't look like a valid decoded iHP"
464 " firmware - reason: file 'length' data\n"), wxT("iriver_decode"));
469 pChecksums
= ppChecksums
= (unsigned char *)( malloc( dwLength3
) );
471 outfile
.Write( headerdata
, 512);
473 memset( blockdata
, 0, 16 );
475 while( ( fp
< dwLength2
) &&
476 ( lenread
= infile
.Read( blockdata
+16, 16) ) == 16 )
479 for( i
=0; i
<16; ++i
)
481 newmunge
= blockdata
[16+((12+i
)&0xf)] ^ blockdata
[i
];
482 out
[i
] = newmunge
^ munge
[i
];
483 ck
+= blockdata
[16+i
];
484 blockdata
[i
] = newmunge
;
486 outfile
.Write( out
, 16);
491 memset( blockdata
, 0, 16 );
499 if( fp
!= dwLength2
)
501 ERR_DIALOG(wxT("This doesn't look like a valid decoded "
502 "iHP firmware - reason: 'length1' mismatch\n"), wxT("iriver_decode"));
507 /* write out remainder w/out applying descrambler */
510 ppChecksums
= pChecksums
;
511 while( ( fp
< dwLength3
) &&
512 ( lenread
= outfile
.Write( ppChecksums
, lenread
) ) > 0 )
515 ppChecksums
+= lenread
;
516 lenread
= dwLength3
- fp
;
519 if( fp
!= dwLength3
)
521 ERR_DIALOG(wxT("This doesn't look like a valid decoded "
522 "iHP firmware - reason: 'length2' mismatch\n"), wxT("iriver_decode"));
527 fprintf( stderr
, "File encoded successfully and checksum table built!\n" );
535 bool PatchFirmware(wxString firmware
,wxString bootloader
,int series
, int table_entry
)
537 wxString name1
, name2
, name3
;
540 struct sumpairs
*sums
;
543 /* get pointer to the correct bootloader.bin */
546 sums
= &h100pairs
[0];
550 sums
= &h120pairs
[0];
554 sums
= &h300pairs
[0];
559 name1
= gv
->stdpaths
->GetUserDataDir()
560 + wxT("" PATH_SEP
"download" PATH_SEP
"firmware.bin"),
561 /* descrambled file */
562 name2
= gv
->stdpaths
->GetUserDataDir()
563 + wxT("" PATH_SEP
"download" PATH_SEP
"new.bin");
565 name3
= gv
->stdpaths
->GetUserDataDir()
566 + wxT("" PATH_SEP
"download" PATH_SEP
"new.hex");
567 if (iriver_decode(firmware
, name1
, FALSE
, STRIP_NONE
) == -1) {
568 ERR_DIALOG(wxT("Error in descramble"), wxT("Descramble Firmware"));
574 if (!mkboot(name1
, name2
, bootloader
, origin
)) {
575 ERR_DIALOG(wxT("Error in patching"),wxT("Patching Firmware"));
581 if (iriver_encode(name2
, name3
, FALSE
) == -1) {
582 ERR_DIALOG(wxT("Error in scramble"),wxT("Scramble Firmware"));
589 if (!FileMD5(name3
, md5sum_str
)) {
590 ERR_DIALOG(wxT("Error in checksumming"),wxT("Checksumming Firmware"));
596 if (strncmp(sums
[table_entry
].patched
, md5sum_str
, 32) == 0) {
597 /* delete temp files */