summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Kurbjun <kkurbjun@gmail.com>2009-08-30 23:24:22 +0000
committerKarl Kurbjun <kkurbjun@gmail.com>2009-08-30 23:24:22 +0000
commitd07ea9a48ed53f3500500a38e254db73cbc0a432 (patch)
treebd74aae290c9d375c8786f048a6c2bc0d89327a0
parent8af1a65cae553a7f2614a1a5c3e41158f9c8291a (diff)
downloadrockbox-d07ea9a48ed53f3500500a38e254db73cbc0a432.tar.gz
rockbox-d07ea9a48ed53f3500500a38e254db73cbc0a432.zip
M:Robe 500: Add firmware patcher: Can decrypt firmware updates, patch them, and re-encrypt them.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22565 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--tools/Makefile9
-rw-r--r--tools/bmp2rb.c17
-rwxr-xr-xtools/configure2
-rw-r--r--tools/mk500boot.c322
-rw-r--r--tools/mr500.c457
-rw-r--r--tools/mr500.h56
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#
9CFLAGS := -O -g -W -Wall -Wshadow -pedantic 9CFLAGS := -g -W -Wall -Wshadow -pedantic
10LDFLAGS := -g 10LDFLAGS := -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
18all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \ 18all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \
19 convbdf codepages uclpack rbspeexenc voicefont 19 convbdf codepages uclpack rbspeexenc voicefont mk500boot
20 20
21scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o 21scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o
22descramble: descramble.o iriver.o gigabeat.o 22descramble: descramble.o iriver.o gigabeat.o
@@ -47,7 +47,10 @@ mkboot: mkboot.c
47 47
48mktccboot: mktccboot.c telechips.o 48mktccboot: mktccboot.c telechips.o
49 $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 49 $(SILENT)$(CC) $(CFLAGS) $+ -o $@
50 50
51mk500boot: mk500boot.c mr500.c
52 $(SILENT)$(CC) $(CFLAGS) $+ -o $@
53
51mknkboot: mknkboot.c 54mknkboot: 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) */
27struct patch_single hack[] = { {0x29B28, 0xE12FFF30},
28 {0x2F960, 0xE12FFF30} };
29
30static 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
44void 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 */
56int 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 */
52int decrypt_array[16]={2, 0, 3, 1, 5, 7, 4, 6, 11, 10, 9, 8, 14, 12, 13, 15};
53int 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 */
66int 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 */
116int 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 */
167int 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 */
215int 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 */
260int 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 */
305int 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 */
358int 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 */
449int 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>
21extern int decrypt_array[];
22extern 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 */
33struct 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 */
43struct patch_single {
44 off_t offset;
45 uint32_t value;
46};
47
48int mr500_patch_file(char *, struct patch_single *, int);
49int mr500_save_header(char *, struct olympus_header *);
50int mr500_read_header(char *, struct olympus_header *);
51int mr500_save_crc(char *, off_t, uint32_t *);
52int mr500_read_crc(char *, off_t, uint32_t *);
53int mr500_calculate_crc(char *, off_t, unsigned int, uint32_t *);
54int mr500_save_data(char *, char *, off_t, unsigned int, int*);
55int mr500_init(void);
56