diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 9 | ||||
-rw-r--r-- | tools/bmp2rb.c | 17 | ||||
-rwxr-xr-x | tools/configure | 2 | ||||
-rw-r--r-- | tools/mk500boot.c | 322 | ||||
-rw-r--r-- | tools/mr500.c | 457 | ||||
-rw-r--r-- | tools/mr500.h | 56 |
6 files changed, 858 insertions, 5 deletions
diff --git a/tools/Makefile b/tools/Makefile index 43f53e2569..48f4613eb4 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -6,7 +6,7 @@ | |||
6 | # \/ \/ \/ \/ \/ | 6 | # \/ \/ \/ \/ \/ |
7 | # $Id$ | 7 | # $Id$ |
8 | # | 8 | # |
9 | CFLAGS := -O -g -W -Wall -Wshadow -pedantic | 9 | CFLAGS := -g -W -Wall -Wshadow -pedantic |
10 | LDFLAGS := -g | 10 | LDFLAGS := -g |
11 | 11 | ||
12 | .PHONY: rbspeexenc uclpack | 12 | .PHONY: rbspeexenc uclpack |
@@ -16,7 +16,7 @@ CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ | |||
16 | lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot | 16 | lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot |
17 | 17 | ||
18 | all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \ | 18 | all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \ |
19 | convbdf codepages uclpack rbspeexenc voicefont | 19 | convbdf codepages uclpack rbspeexenc voicefont mk500boot |
20 | 20 | ||
21 | scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o | 21 | scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o |
22 | descramble: descramble.o iriver.o gigabeat.o | 22 | descramble: descramble.o iriver.o gigabeat.o |
@@ -47,7 +47,10 @@ mkboot: mkboot.c | |||
47 | 47 | ||
48 | mktccboot: mktccboot.c telechips.o | 48 | mktccboot: mktccboot.c telechips.o |
49 | $(SILENT)$(CC) $(CFLAGS) $+ -o $@ | 49 | $(SILENT)$(CC) $(CFLAGS) $+ -o $@ |
50 | 50 | ||
51 | mk500boot: mk500boot.c mr500.c | ||
52 | $(SILENT)$(CC) $(CFLAGS) $+ -o $@ | ||
53 | |||
51 | mknkboot: mknkboot.c | 54 | mknkboot: mknkboot.c |
52 | $(SILENT)$(CC) $(CFLAGS) $+ -o $@ | 55 | $(SILENT)$(CC) $(CFLAGS) $+ -o $@ |
53 | 56 | ||
diff --git a/tools/bmp2rb.c b/tools/bmp2rb.c index e2e02a2a50..264179a571 100644 --- a/tools/bmp2rb.c +++ b/tools/bmp2rb.c | |||
@@ -319,6 +319,7 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, | |||
319 | 319 | ||
320 | case 4: /* 16-bit packed RGB (5-6-5) */ | 320 | case 4: /* 16-bit packed RGB (5-6-5) */ |
321 | case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */ | 321 | case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */ |
322 | case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/ | ||
322 | dst_w = width; | 323 | dst_w = width; |
323 | dst_h = height; | 324 | dst_h = height; |
324 | dst_d = 16; | 325 | dst_d = 16; |
@@ -425,6 +426,19 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, | |||
425 | (*dest)[(row/8) * dst_w + col] |= data << (row & 7); | 426 | (*dest)[(row/8) * dst_w + col] |= data << (row & 7); |
426 | } | 427 | } |
427 | break; | 428 | break; |
429 | |||
430 | case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/ | ||
431 | for (row = 0; row < height; row++) | ||
432 | for (col = 0; col < width; col++) | ||
433 | { | ||
434 | unsigned short rgb = | ||
435 | (((src[row * width + col].rgbRed >> 3) << 11) | | ||
436 | ((src[row * width + col].rgbGreen >> 2) << 5) | | ||
437 | ((src[row * width + col].rgbBlue >> 3))); | ||
438 | |||
439 | (*dest)[col * dst_h + row] = rgb; | ||
440 | } | ||
441 | break; | ||
428 | } | 442 | } |
429 | 443 | ||
430 | return 0; | 444 | return 0; |
@@ -569,7 +583,8 @@ void print_usage(void) | |||
569 | "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n" | 583 | "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n" |
570 | "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n" | 584 | "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n" |
571 | "\t 6 Greyscale iPod 4-grey\n" | 585 | "\t 6 Greyscale iPod 4-grey\n" |
572 | "\t 7 Greyscale X5 remote 4-grey\n"); | 586 | "\t 7 Greyscale X5 remote 4-grey\n" |
587 | "\t 8 16-bit packed 5-6-5 RGB with a vertical stride\n"); | ||
573 | printf("build date: " __DATE__ "\n\n"); | 588 | printf("build date: " __DATE__ "\n\n"); |
574 | } | 589 | } |
575 | 590 | ||
diff --git a/tools/configure b/tools/configure index 2f96f377e5..82ff172784 100755 --- a/tools/configure +++ b/tools/configure | |||
@@ -1598,7 +1598,7 @@ fi | |||
1598 | arm926ejscc | 1598 | arm926ejscc |
1599 | tool="$rootdir/tools/scramble -add=m500" | 1599 | tool="$rootdir/tools/scramble -add=m500" |
1600 | bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" | 1600 | bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" |
1601 | bmp2rb_native="$rootdir/tools/bmp2rb -f 4" | 1601 | bmp2rb_native="$rootdir/tools/bmp2rb -f 8" |
1602 | bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" | 1602 | bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" |
1603 | bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" | 1603 | bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" |
1604 | output="rockbox.mrobe500" | 1604 | output="rockbox.mrobe500" |
diff --git a/tools/mk500boot.c b/tools/mk500boot.c new file mode 100644 index 0000000000..1187058091 --- /dev/null +++ b/tools/mk500boot.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2009 by Karl Kurbjun | ||
10 | * $Id$ | ||
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 <stdio.h> | ||
21 | #include <errno.h> | ||
22 | #include <inttypes.h> | ||
23 | #include <string.h> | ||
24 | #include "mr500.h" | ||
25 | |||
26 | /* This is the patch necessary for the SVG exploit (decrypted) */ | ||
27 | struct patch_single hack[] = { {0x29B28, 0xE12FFF30}, | ||
28 | {0x2F960, 0xE12FFF30} }; | ||
29 | |||
30 | static void usage(void) | ||
31 | { | ||
32 | printf( "Usage: mk500boot <options> <input file> [output file]\n" | ||
33 | "options:\n" | ||
34 | "\t-decrypt Decrypt the input file and save the output file\n" | ||
35 | "\t-encrypt Encrypt the input file and save the output file\n" | ||
36 | "\t-patch Patch the input file with the SVF hack\n\n"); | ||
37 | |||
38 | exit(1); | ||
39 | } | ||
40 | |||
41 | /* This is a fake flag that is used to let the tool know what's up */ | ||
42 | #define HEADER_DECRYPTED 0x8000 | ||
43 | |||
44 | void display_header(struct olympus_header *header) { | ||
45 | printf("Magic Name: \t%s\n", header->magic_name); | ||
46 | printf("Unknown: \t0x%08hX\n", header->unknown); | ||
47 | printf("Header Length: \t0x%04X\n", header->header_length); | ||
48 | printf("Flags: \t\t0x%04X\n", header->flags); | ||
49 | printf("Unknonwn Zeros: 0x%08X\n", header->unknown_zeros); | ||
50 | printf("Image Length: \t0x%08X\n", header->image_length); | ||
51 | } | ||
52 | |||
53 | /* This is a demonstration of the encryption and decryption process. | ||
54 | * It patches a FW image to include the SVG exploit. | ||
55 | */ | ||
56 | int main (int argc, char *argv[]) { | ||
57 | uint32_t checksum; | ||
58 | uint32_t stored_crc; | ||
59 | |||
60 | enum operations { | ||
61 | decrypt, | ||
62 | encrypt, | ||
63 | patch | ||
64 | } operation; | ||
65 | |||
66 | char *encrypt_file; | ||
67 | char *decrypt_file; | ||
68 | |||
69 | struct olympus_header header; | ||
70 | |||
71 | if (argc < 2) { | ||
72 | usage(); | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | if(!strcmp(argv[1], "-decrypt")) { | ||
77 | if(argc < 3) { | ||
78 | usage(); | ||
79 | return -1; | ||
80 | } | ||
81 | encrypt_file=argv[2]; | ||
82 | decrypt_file=argv[3]; | ||
83 | operation = decrypt; | ||
84 | } else if(!strcmp(argv[1], "-encrypt")) { | ||
85 | if(argc < 3) { | ||
86 | usage(); | ||
87 | return -1; | ||
88 | } | ||
89 | decrypt_file = argv[2]; | ||
90 | encrypt_file = argv[3]; | ||
91 | operation = encrypt; | ||
92 | } else if(!strcmp(argv[1], "-patch")) { | ||
93 | decrypt_file = argv[2]; | ||
94 | encrypt_file = argv[3]; | ||
95 | operation = patch; | ||
96 | } else { | ||
97 | return -1; | ||
98 | } | ||
99 | |||
100 | /* Initialize encryption/decryption routine */ | ||
101 | mr500_init(); | ||
102 | |||
103 | if(operation == decrypt) { | ||
104 | /* Read in the header of the encrypted file */ | ||
105 | if(mr500_read_header(encrypt_file, &header) < 0 ) { | ||
106 | printf("ERROR: Unable to read header: %s\n", strerror(errno)); | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | /* Read CRC of encrypted file */ | ||
111 | if(mr500_read_crc(encrypt_file, | ||
112 | header.header_length+header.image_length, &stored_crc) < 0 ) { | ||
113 | printf("ERROR: Unable to read CRC: %s\n", strerror(errno)); | ||
114 | return -1; | ||
115 | } | ||
116 | |||
117 | /* Display the header information */ | ||
118 | printf("File format:\n"); | ||
119 | |||
120 | printf("*****Header*****\n"); | ||
121 | display_header(&header); | ||
122 | printf("****************\n\n"); | ||
123 | |||
124 | printf("*****Image******\n\n"); | ||
125 | |||
126 | printf("*****Footer*****\n"); | ||
127 | printf("Checksum: \t0x%08X\n", stored_crc); | ||
128 | printf("****************\n\n"); | ||
129 | |||
130 | printf("Writing Decrypted file...\n"); | ||
131 | |||
132 | /********************************************************************* | ||
133 | * Save a decrypted file | ||
134 | **********************************************************************/ | ||
135 | |||
136 | /* Check to make sure this is a encrypted file (bogus flag not set) */ | ||
137 | if(header.flags & HEADER_DECRYPTED) { | ||
138 | printf("ERROR: This appears to be a decrypted file! Quitting\n"); | ||
139 | return -1; | ||
140 | } | ||
141 | |||
142 | /* Check to make sure MAGIC string matches expected*/ | ||
143 | if(strncmp((char *)header.magic_name, "OIMCFWUP", 8)) { | ||
144 | printf("ERROR: Magic string does not match expected! Quitting\n"); | ||
145 | return -1; | ||
146 | } | ||
147 | |||
148 | /* Set a bogus flag to let the tool know that this is a decrypted file*/ | ||
149 | header.flags |= HEADER_DECRYPTED; | ||
150 | |||
151 | /* Start by writing out the header */ | ||
152 | if(mr500_save_header(decrypt_file, &header) < 0 ) { | ||
153 | printf("ERROR: Unable to save header: %s\n", strerror(errno)); | ||
154 | return -1; | ||
155 | } | ||
156 | |||
157 | /* Read encrypted data and save decrypted data */ | ||
158 | if(mr500_save_data( encrypt_file, decrypt_file, header.header_length, | ||
159 | header.image_length, decrypt_array) < 0 ) { | ||
160 | printf("ERROR: Unable to save decrypted data: %s\n", strerror(errno)); | ||
161 | return -1; | ||
162 | } | ||
163 | |||
164 | printf("Calculating Checksum...\n"); | ||
165 | /* Calculate CRC of decrypted data */ | ||
166 | if(mr500_calculate_crc( decrypt_file, header.header_length, | ||
167 | header.image_length, &checksum) < 0 ) { | ||
168 | printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); | ||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | printf("Calculated Checksum: \n\t\t0x%08X\n", checksum); | ||
173 | |||
174 | /* Double check to make sure that the two CRCs match */ | ||
175 | if(checksum!=stored_crc) { | ||
176 | printf("\tERROR: \tCalculated checksum: \t0x%08X and\n", checksum); | ||
177 | printf("\t\tStored checksum: \t0x%08X do not match\n", stored_crc); | ||
178 | return -1; | ||
179 | } else { | ||
180 | printf("\tOK: Calculated checksum and stored checksum match.\n"); | ||
181 | } | ||
182 | |||
183 | printf("Saving Checksum...\n"); | ||
184 | /* Save the calculated CRC to the file */ | ||
185 | if(mr500_save_crc(decrypt_file, header.header_length+header.image_length, | ||
186 | &checksum) < 0 ) { | ||
187 | printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | } else if(operation == patch) { | ||
192 | |||
193 | /********************************************************************** | ||
194 | * Patch decryped file with SVG exploit | ||
195 | **********************************************************************/ | ||
196 | printf("Patching decrypted file.\n"); | ||
197 | |||
198 | /* Read in the header of the encrypted file */ | ||
199 | if(mr500_read_header(decrypt_file, &header) < 0 ) { | ||
200 | printf("ERROR: Unable to read header: %s\n", strerror(errno)); | ||
201 | return -1; | ||
202 | } | ||
203 | |||
204 | /* Check to make sure this is a decrypted file (bogus flag not set) */ | ||
205 | if(!(header.flags & HEADER_DECRYPTED)) { | ||
206 | printf("ERROR: This appears to be a encrypted file! Quitting\n"); | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | /* Check to make sure MAGIC string matches expected*/ | ||
211 | if(strncmp((char *)header.magic_name, "OIMCFWUP", 8)) { | ||
212 | printf("ERROR: Magic string does not match expected! Quitting\n"); | ||
213 | return -1; | ||
214 | } | ||
215 | |||
216 | printf("File Header:\n"); | ||
217 | display_header(&header); | ||
218 | |||
219 | if(mr500_patch_file (decrypt_file, hack, 2) < 0 ) { | ||
220 | printf("ERROR: Unable to patch file: %s\n", strerror(errno)); | ||
221 | return -1; | ||
222 | } | ||
223 | |||
224 | printf("\nCalculating new CRC\n"); | ||
225 | |||
226 | /* Calculate the 'CRC' of the patched file */ | ||
227 | if(mr500_calculate_crc( decrypt_file, header.header_length, | ||
228 | header.image_length, &checksum) < 0 ) { | ||
229 | printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); | ||
230 | return -1; | ||
231 | } | ||
232 | |||
233 | printf("Calculated CRC: \n\t\t0x%08X\n", checksum); | ||
234 | /* Store the calculated 'CRC' (not encrypted) */ | ||
235 | if(mr500_save_crc(decrypt_file, header.header_length+header.image_length, | ||
236 | &checksum) < 0 ) { | ||
237 | printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); | ||
238 | return -1; | ||
239 | } | ||
240 | |||
241 | } else if(operation == encrypt) { | ||
242 | |||
243 | /********************************************************************** | ||
244 | * Save an encrypted file | ||
245 | **********************************************************************/ | ||
246 | printf("Saving Encrypted file\n"); | ||
247 | |||
248 | /* Read in the header of the encrypted file */ | ||
249 | if(mr500_read_header(decrypt_file, &header) < 0 ) { | ||
250 | printf("ERROR: Unable to read header: %s\n", strerror(errno)); | ||
251 | return -1; | ||
252 | } | ||
253 | |||
254 | /* Check to make sure this is a decrypted file (bogus flag not set) */ | ||
255 | if(!(header.flags & HEADER_DECRYPTED)) { | ||
256 | printf("ERROR: This appears to be a encrypted file! Quitting\n"); | ||
257 | return -1; | ||
258 | } | ||
259 | |||
260 | /* Check to make sure MAGIC string matches expected*/ | ||
261 | if(strncmp((char *)header.magic_name, "OIMCFWUP", 7)) { | ||
262 | printf("ERROR: Magic string does not match expected! Quitting\n"); | ||
263 | return -1; | ||
264 | } | ||
265 | |||
266 | /* Remove the bogus flag */ | ||
267 | header.flags &= ~HEADER_DECRYPTED; | ||
268 | |||
269 | printf("File Header:\n"); | ||
270 | display_header(&header); | ||
271 | |||
272 | /* Header is not encrypted, save it */ | ||
273 | if(mr500_save_header(encrypt_file, &header) < 0 ) { | ||
274 | printf("ERROR: Unable to save header: %s\n", strerror(errno)); | ||
275 | return -1; | ||
276 | } | ||
277 | |||
278 | /* Read CRC of decrypted file */ | ||
279 | if(mr500_read_crc(decrypt_file, | ||
280 | header.header_length+header.image_length, &stored_crc) < 0 ) { | ||
281 | printf("ERROR: Unable to read CRC: %s\n", strerror(errno)); | ||
282 | return -1; | ||
283 | } | ||
284 | |||
285 | /* Calculate the 'CRC' of the decrypted data */ | ||
286 | if(mr500_calculate_crc( decrypt_file, header.header_length, | ||
287 | header.image_length, &checksum) < 0 ) { | ||
288 | printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); | ||
289 | return -1; | ||
290 | } | ||
291 | |||
292 | if(stored_crc != checksum) { | ||
293 | printf("\nERROR: Stored and calculated checksums do not match!\n" | ||
294 | "\tFile has been improperly modified. Quitting\n"); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | printf("Encrypting data...\n"); | ||
299 | |||
300 | /* Write the encrypted data to a file */ | ||
301 | if(mr500_save_data( decrypt_file, encrypt_file, header.header_length, | ||
302 | header.image_length, encrypt_array) < 0 ) { | ||
303 | printf("ERROR: Unable to save encrypted data: %s\n", strerror(errno)); | ||
304 | return -1; | ||
305 | } | ||
306 | |||
307 | printf("Saving CRC\n"); | ||
308 | |||
309 | /* Store the calculated 'CRC' (not encrypted) */ | ||
310 | if(mr500_save_crc(encrypt_file, header.header_length+header.image_length, | ||
311 | &checksum) < 0 ) { | ||
312 | printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); | ||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | printf("File sucesfully encrypted!\n"); | ||
317 | } | ||
318 | |||
319 | printf("Done\n"); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
diff --git a/tools/mr500.c b/tools/mr500.c new file mode 100644 index 0000000000..00cf17e26b --- /dev/null +++ b/tools/mr500.c | |||
@@ -0,0 +1,457 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2009 by Karl Kurbjun | ||
10 | * based on work by Shirour: | ||
11 | * http://www.mrobe.org/forum/viewtopic.php?f=6&t=2176 | ||
12 | * $Id$ | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdio.h> | ||
23 | #include <string.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <errno.h> | ||
27 | #include <unistd.h> | ||
28 | #include <inttypes.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include "mr500.h" | ||
31 | |||
32 | /* Notes about firmware: | ||
33 | * These notes are based on the work and observations of Shirour on the M:Robe | ||
34 | * forums. | ||
35 | * | ||
36 | * The firmware for the M:Robe has basic encryption on it. The data is XORed | ||
37 | * and scrambled. The mr500_save_data function provides an implemenation of the | ||
38 | * encryption/decryption. | ||
39 | * | ||
40 | * When a firmware update is done the "{#4F494D4346575550#}" folder is stored | ||
41 | * in the system folder on the player. The "{#4F494D4346575550#}" should only | ||
42 | * contain the encrypted N5002-BD.BIN file. At the end of a firmware update | ||
43 | * the "{#4F494D4346575550#}" folder and it's contents are removed from the | ||
44 | * player. | ||
45 | * | ||
46 | * An interesting note is that the name "{#4F494D4346575550#}" is actually the | ||
47 | * Hex representation of the magic text found at the beginning of the firmware | ||
48 | * image "OIMCFWUP". | ||
49 | */ | ||
50 | |||
51 | /* These two arrays are used for descrambling or scrambling the data */ | ||
52 | int decrypt_array[16]={2, 0, 3, 1, 5, 7, 4, 6, 11, 10, 9, 8, 14, 12, 13, 15}; | ||
53 | int encrypt_array[16]; | ||
54 | |||
55 | /* mr500_patch_file: This function modifies the specified file with the patches | ||
56 | * struct. | ||
57 | * | ||
58 | * Parameters: | ||
59 | * filename: text filename | ||
60 | * patches: pointer to structure array of patches | ||
61 | * num_patches: number of patches to apply (applied in reverse order) | ||
62 | * | ||
63 | * Returns: | ||
64 | * Returns 0 if there was no error, -1 if there was an error | ||
65 | */ | ||
66 | int mr500_patch_file(char *filename, struct patch_single *patches, | ||
67 | int num_patches) { | ||
68 | int fdo; | ||
69 | int ret=0; | ||
70 | uint32_t endian_int; | ||
71 | |||
72 | /* Open the file write only. */ | ||
73 | fdo = open(filename, O_WRONLY); | ||
74 | |||
75 | if(fdo<0) { | ||
76 | ret=-1; | ||
77 | } | ||
78 | |||
79 | while(num_patches--) { | ||
80 | /* seek to patch offset */ | ||
81 | if(lseek(fdo, patches[num_patches].offset, SEEK_SET) | ||
82 | != patches[num_patches].offset) { | ||
83 | ret=-1; | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | /* Make sure patch is written in little endian format */ | ||
88 | endian_int = htole32(patches[num_patches].value); | ||
89 | |||
90 | /* Write the patch value to the file */ | ||
91 | if(write(fdo, (void *) &endian_int, sizeof(endian_int)) < 0) { | ||
92 | ret = -1; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /* Close the file and check for errors */ | ||
98 | if(close (fdo) < 0) { | ||
99 | ret = -1; | ||
100 | } | ||
101 | |||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | /* mr500_save_header: This function saves the Olympus header to the firmware | ||
106 | * image. The values stored in the header are explained above. Note that this | ||
107 | * will truncate a file. The header is stored in little endian format. | ||
108 | * | ||
109 | * Parameters: | ||
110 | * filename: text filename | ||
111 | * header: pointer to header structure to be saved | ||
112 | * | ||
113 | * Returns: | ||
114 | * Returns 0 if there was no error, -1 if there was an error | ||
115 | */ | ||
116 | int mr500_save_header(char *filename, struct olympus_header *header) { | ||
117 | int fdo; | ||
118 | int ret=0; | ||
119 | |||
120 | /* Temporary header used for storing the header in little endian. */ | ||
121 | struct olympus_header save; | ||
122 | |||
123 | /* Open the file write only and truncate it. If it doesn't exist create. */ | ||
124 | fdo = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); | ||
125 | |||
126 | if(fdo<0) { | ||
127 | ret=-1; | ||
128 | } | ||
129 | |||
130 | /* Header is stored at offset 0 (Not really needed) */ | ||
131 | if(lseek(fdo, 0, SEEK_SET) != 0) { | ||
132 | ret=-1; | ||
133 | } | ||
134 | |||
135 | /* Convert header to Little Endian */ | ||
136 | memcpy(&save.magic_name, &header->magic_name, 8*sizeof(int8_t)); | ||
137 | save.unknown = htole32(header->unknown); | ||
138 | save.header_length = htole16(header->header_length); | ||
139 | save.flags = htole16(header->flags); | ||
140 | save.unknown_zeros = htole32(header->unknown_zeros); | ||
141 | save.image_length = htole32(header->image_length); | ||
142 | |||
143 | /* Write the header to the file */ | ||
144 | if(write(fdo, (void *) &save, sizeof(save)) < 0) { | ||
145 | ret = -1; | ||
146 | } | ||
147 | |||
148 | /* Close the file and check for errors */ | ||
149 | if(close (fdo) < 0) { | ||
150 | ret = -1; | ||
151 | } | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | /* mr500_read_header: This function reads the Olympus header and converts it to | ||
157 | * the host endian format. The values stored in the header are explained above. | ||
158 | * The header is stored in little endian format. | ||
159 | * | ||
160 | * Parameters: | ||
161 | * filename: text filename | ||
162 | * header: pointer to header structure to store header read from file | ||
163 | * | ||
164 | * Returns: | ||
165 | * Returns 0 if there was no error, -1 if there was an error | ||
166 | */ | ||
167 | int mr500_read_header(char *filename, struct olympus_header *header) { | ||
168 | int fdi; | ||
169 | int ret = 0; | ||
170 | |||
171 | /* Open the file read only */ | ||
172 | fdi = open(filename, O_RDONLY); | ||
173 | |||
174 | if(fdi<0) { | ||
175 | ret=-1; | ||
176 | } | ||
177 | |||
178 | /* Header is stored at offset 0 (Not really needed) */ | ||
179 | if(lseek(fdi, 0, SEEK_SET) != 0) { | ||
180 | ret=-1; | ||
181 | } | ||
182 | |||
183 | /* Read in the header */ | ||
184 | if(read(fdi, (void *) header, sizeof(*header)) < 0) { | ||
185 | ret = -1; | ||
186 | } | ||
187 | |||
188 | /* Convert header to system endian */ | ||
189 | header->unknown = le32toh(header->unknown); | ||
190 | header->header_length = le16toh(header->header_length); | ||
191 | header->flags = le16toh(header->flags); | ||
192 | header->unknown_zeros = le32toh(header->unknown_zeros); | ||
193 | header->image_length = le32toh(header->image_length); | ||
194 | |||
195 | /* Close the file and check for errors */ | ||
196 | if(close (fdi) < 0) { | ||
197 | ret = -1; | ||
198 | } | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | /* mr500_save_crc: This function saves the 'CRC' of the Olympus firmware image. | ||
204 | * Note that the 'CRC' must be calculated on the decrytped image. It is stored | ||
205 | * in little endian. | ||
206 | * | ||
207 | * Parameters: | ||
208 | * filename: text filename | ||
209 | * offset: Offset to store the 'CRC' (header size + data size) | ||
210 | * crc_value: pointer to crc value to save | ||
211 | * | ||
212 | * Returns: | ||
213 | * Returns 0 if there was no error, -1 if there was an error | ||
214 | */ | ||
215 | int mr500_save_crc(char *filename, off_t offset, uint32_t *crc_value) { | ||
216 | int fdo; | ||
217 | int ret = 0; | ||
218 | uint32_t save_crc; | ||
219 | |||
220 | /* Open the file write only */ | ||
221 | fdo = open(filename, O_WRONLY); | ||
222 | |||
223 | if(fdo<0) { | ||
224 | ret=-1; | ||
225 | } | ||
226 | |||
227 | /* Seek to offset and check for errors */ | ||
228 | if(lseek(fdo, offset, SEEK_SET) != offset) { | ||
229 | ret=-1; | ||
230 | } | ||
231 | |||
232 | /* Convert 'CRC' to little endian from system native endian */ | ||
233 | save_crc = htole32(*crc_value); | ||
234 | |||
235 | /* Write the 'CRC' and check for errors */ | ||
236 | if(write(fdo, (void *) &save_crc, sizeof(unsigned int)) < 0) { | ||
237 | ret = -1; | ||
238 | } | ||
239 | |||
240 | /* Close the file and check for errors */ | ||
241 | if(close (fdo) < 0) { | ||
242 | ret = -1; | ||
243 | } | ||
244 | |||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /* mr500_read_crc: This function reads the 'CRC' of the Olympus firmware image. | ||
249 | * Note that the 'CRC' is calculated on the decrytped values. It is stored | ||
250 | * in little endian. | ||
251 | * | ||
252 | * Parameters: | ||
253 | * filename: text filename | ||
254 | * offset: Offset to read the 'CRC' (header size + data size) | ||
255 | * crc_value: pointer to crc value to save | ||
256 | * | ||
257 | * Returns: | ||
258 | * Returns 0 if there was no error, -1 if there was an error | ||
259 | */ | ||
260 | int mr500_read_crc(char *filename, off_t offset, uint32_t *crc_value) { | ||
261 | int fdi; | ||
262 | int ret = 0; | ||
263 | |||
264 | /* Open the file read only */ | ||
265 | fdi = open(filename, O_RDONLY); | ||
266 | |||
267 | if(fdi<0) { | ||
268 | ret = -1; | ||
269 | } | ||
270 | |||
271 | /* Seek to offset and check for errors */ | ||
272 | if(lseek(fdi, offset, SEEK_SET) != offset) { | ||
273 | ret=-1; | ||
274 | } | ||
275 | |||
276 | /* Read in the 'CRC' */ | ||
277 | if(read(fdi, (void *) crc_value, sizeof(uint32_t)) < 0) { | ||
278 | ret = -1; | ||
279 | } | ||
280 | |||
281 | /* Convert the 'CRC' from little endian to system native format */ | ||
282 | *crc_value = le32toh(*crc_value); | ||
283 | |||
284 | /* Close the file and check for errors */ | ||
285 | if(close (fdi) < 0) { | ||
286 | ret = -1; | ||
287 | } | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | /* mr500_calculate_crc: This function calculates the 'CRC' of the Olympus | ||
293 | * firmware image. Note that the 'CRC' must be calculated on decrytped values. | ||
294 | * It is stored in little endian. | ||
295 | * | ||
296 | * Parameters: | ||
297 | * filename: text filename | ||
298 | * offset: Offset to the start of the data (header size) | ||
299 | * length: Length of data to calculate | ||
300 | * crc_value: pointer to crc value to save | ||
301 | * | ||
302 | * Returns: | ||
303 | * Returns 0 if there was no error, -1 if there was an error | ||
304 | */ | ||
305 | int mr500_calculate_crc( char *filename, off_t offset, unsigned int length, | ||
306 | uint32_t *crc_value){ | ||
307 | uint32_t temp; | ||
308 | int fdi; | ||
309 | int ret = 0; | ||
310 | |||
311 | /* Open the file read only */ | ||
312 | fdi = open(filename, O_RDONLY); | ||
313 | |||
314 | if(fdi<0) { | ||
315 | ret = -1; | ||
316 | } | ||
317 | |||
318 | /* Seek to offset and check for errors */ | ||
319 | if(lseek(fdi, offset, SEEK_SET) != offset) { | ||
320 | ret=-1; | ||
321 | } | ||
322 | |||
323 | /* Initialize the crc_value to make sure this starts at 0 */ | ||
324 | *crc_value = 0; | ||
325 | /* Run this loop till the entire sum is created */ | ||
326 | do { | ||
327 | /* Read an integer at a time */ | ||
328 | if(read(fdi, &temp, sizeof(uint32_t)) < 0) { | ||
329 | ret = -1; | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | /* Keep summing the values */ | ||
334 | *crc_value+=temp; | ||
335 | } while (length-=4); | ||
336 | |||
337 | /* Close the file and check for errors */ | ||
338 | if(close (fdi) < 0) { | ||
339 | ret = -1; | ||
340 | } | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | /* mr500_save_data: This function encypts or decrypts the Olympus firmware | ||
346 | * image based on the dictionary passed to it. | ||
347 | * | ||
348 | * Parameters: | ||
349 | * source_filename: text filename where data is read from | ||
350 | * dest_filename: text filename where data is written to | ||
351 | * offset: Offset to the start of the data (header size) | ||
352 | * length: Length of data to modify | ||
353 | * dictionary: pointer to dictionary used for scrambling | ||
354 | * | ||
355 | * Returns: | ||
356 | * Returns 0 if there was no error, -1 if there was an error | ||
357 | */ | ||
358 | int mr500_save_data( | ||
359 | char *source_filename, char *dest_filename, off_t offset, | ||
360 | unsigned int length, int* dictionary) { | ||
361 | int fdi, fdo; | ||
362 | int ret = 0; | ||
363 | int i; | ||
364 | |||
365 | /* read_count stores the number of bytes actually read */ | ||
366 | int read_count; | ||
367 | |||
368 | /* read_request stores the number of bytes to be requested */ | ||
369 | int read_request; | ||
370 | |||
371 | /* These two buffers are used for reading data and scrambling or | ||
372 | * descrambling | ||
373 | */ | ||
374 | int8_t buffer_original[16]; | ||
375 | int8_t buffer_modified[16]; | ||
376 | |||
377 | /* Open input read only, output write only */ | ||
378 | fdi = open(source_filename, O_RDONLY); | ||
379 | fdo = open(dest_filename, O_WRONLY); | ||
380 | |||
381 | /* If there was an error loading the files set ret appropriately */ | ||
382 | if(fdi<0 || fdo < 0) { | ||
383 | ret = -1; | ||
384 | } | ||
385 | |||
386 | /* Input file: Seek to offset and check for errors */ | ||
387 | if(lseek(fdi, offset, SEEK_SET) != offset) { | ||
388 | ret=-1; | ||
389 | } | ||
390 | |||
391 | /* Output file: Seek to offset and check for errors */ | ||
392 | if(lseek(fdo, offset, SEEK_SET) != offset) { | ||
393 | ret=-1; | ||
394 | } | ||
395 | |||
396 | /* Run this loop till size is 0 */ | ||
397 | do { | ||
398 | /* Choose the amount of data to read - normally in 16 byte chunks, but | ||
399 | * when the end of the file is near may be less. | ||
400 | */ | ||
401 | if( length > sizeof(buffer_original)){ | ||
402 | read_request = sizeof(buffer_original); | ||
403 | } else { | ||
404 | read_request = length; | ||
405 | } | ||
406 | |||
407 | /* Read in the data */ | ||
408 | read_count = read(fdi, (void *) &buffer_original, read_request); | ||
409 | |||
410 | /* If there was an error set the flag and break */ | ||
411 | if(read_count < 0) { | ||
412 | ret = -1; | ||
413 | break; | ||
414 | } | ||
415 | |||
416 | for(i=0; i<read_count; i++) { | ||
417 | /* XOR all of the bits to de/encrypt them */ | ||
418 | buffer_original[i] ^= 0xFF; | ||
419 | /* Handle byte scrambling */ | ||
420 | buffer_modified[dictionary[i]] = buffer_original[i]; | ||
421 | } | ||
422 | |||
423 | /* write the data: If there was an error set the flag and break */ | ||
424 | if(write(fdo, (void *) &buffer_modified, read_count) < 0) { | ||
425 | ret = -1; | ||
426 | break; | ||
427 | } | ||
428 | } while (length -= read_count); | ||
429 | |||
430 | /* Close the files and check for errors */ | ||
431 | if(close (fdi) < 0) { | ||
432 | ret = -1; | ||
433 | } | ||
434 | if(close (fdo) < 0) { | ||
435 | ret = -1; | ||
436 | } | ||
437 | |||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | /* mr500_init: This function initializes the encryption array | ||
442 | * | ||
443 | * Parameters: | ||
444 | * None | ||
445 | * | ||
446 | * Returns: | ||
447 | * Returns 0 | ||
448 | */ | ||
449 | int mr500_init(void) { | ||
450 | int i; | ||
451 | /* Initialize the encryption array */ | ||
452 | for(i=0; i<16; i++) { | ||
453 | encrypt_array[decrypt_array[i]]=i; | ||
454 | } | ||
455 | return 0; | ||
456 | } | ||
457 | |||
diff --git a/tools/mr500.h b/tools/mr500.h new file mode 100644 index 0000000000..f9a651f923 --- /dev/null +++ b/tools/mr500.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2009 by Karl Kurbjun | ||
10 | * $Id$ | ||
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 <stdlib.h> | ||
21 | extern int decrypt_array[]; | ||
22 | extern int encrypt_array[]; | ||
23 | |||
24 | /* Notes about the header: | ||
25 | * The magic_name should always be "OIMCFWUP" | ||
26 | * Header length is always 18 bytes | ||
27 | * The flags have the following mask: | ||
28 | * CHECK_CRC 0x01 : Tells the firmware whether or not to check CRC | ||
29 | * ENDIAN_MODE 0x02 : Tells the OF whether to re-order the bytes | ||
30 | * The rest are unknown | ||
31 | * The image length is in bytes and is always 0x007F0000 | ||
32 | */ | ||
33 | struct olympus_header { | ||
34 | int8_t magic_name[8]; | ||
35 | uint32_t unknown; | ||
36 | uint16_t header_length; | ||
37 | uint16_t flags; | ||
38 | uint32_t unknown_zeros; | ||
39 | uint32_t image_length; | ||
40 | } __attribute__((__packed__)); | ||
41 | |||
42 | /* Patch entries should be saved in little endian format */ | ||
43 | struct patch_single { | ||
44 | off_t offset; | ||
45 | uint32_t value; | ||
46 | }; | ||
47 | |||
48 | int mr500_patch_file(char *, struct patch_single *, int); | ||
49 | int mr500_save_header(char *, struct olympus_header *); | ||
50 | int mr500_read_header(char *, struct olympus_header *); | ||
51 | int mr500_save_crc(char *, off_t, uint32_t *); | ||
52 | int mr500_read_crc(char *, off_t, uint32_t *); | ||
53 | int mr500_calculate_crc(char *, off_t, unsigned int, uint32_t *); | ||
54 | int mr500_save_data(char *, char *, off_t, unsigned int, int*); | ||
55 | int mr500_init(void); | ||
56 | |||