A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

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

+858 -5
+6 -3
tools/Makefile
··· 6 6 # \/ \/ \/ \/ \/ 7 7 # $Id$ 8 8 # 9 - CFLAGS := -O -g -W -Wall -Wshadow -pedantic 9 + CFLAGS := -g -W -Wall -Wshadow -pedantic 10 10 LDFLAGS := -g 11 11 12 12 .PHONY: rbspeexenc uclpack ··· 16 16 lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot 17 17 18 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 21 scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o 22 22 descramble: descramble.o iriver.o gigabeat.o ··· 47 47 48 48 mktccboot: mktccboot.c telechips.o 49 49 $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 50 - 50 + 51 + mk500boot: mk500boot.c mr500.c 52 + $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 53 + 51 54 mknkboot: mknkboot.c 52 55 $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 53 56
+16 -1
tools/bmp2rb.c
··· 319 319 320 320 case 4: /* 16-bit packed RGB (5-6-5) */ 321 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 323 dst_w = width; 323 324 dst_h = height; 324 325 dst_d = 16; ··· 423 424 424 425 data = (data | (data << 7)) & 0x0101; 425 426 (*dest)[(row/8) * dst_w + col] |= data << (row & 7); 427 + } 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; 426 440 } 427 441 break; 428 442 } ··· 569 583 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n" 570 584 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n" 571 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 588 printf("build date: " __DATE__ "\n\n"); 574 589 } 575 590
+1 -1
tools/configure
··· 1598 1598 arm926ejscc 1599 1599 tool="$rootdir/tools/scramble -add=m500" 1600 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 1602 bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" 1603 1603 bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" 1604 1604 output="rockbox.mrobe500"
+322
tools/mk500boot.c
··· 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 +
+457
tools/mr500.c
··· 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 +
+56
tools/mr500.h
··· 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 +