diff options
author | Karl Kurbjun <kkurbjun@gmail.com> | 2009-08-30 23:24:22 +0000 |
---|---|---|
committer | Karl Kurbjun <kkurbjun@gmail.com> | 2009-08-30 23:24:22 +0000 |
commit | d07ea9a48ed53f3500500a38e254db73cbc0a432 (patch) | |
tree | bd74aae290c9d375c8786f048a6c2bc0d89327a0 /tools | |
parent | 8af1a65cae553a7f2614a1a5c3e41158f9c8291a (diff) |
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
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 @@ # \/ \/ \/ \/ \/ # $Id$ # -CFLAGS := -O -g -W -Wall -Wshadow -pedantic +CFLAGS := -g -W -Wall -Wshadow -pedantic LDFLAGS := -g .PHONY: rbspeexenc uclpack @@ -16,7 +16,7 @@ CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \ - convbdf codepages uclpack rbspeexenc voicefont + convbdf codepages uclpack rbspeexenc voicefont mk500boot scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o descramble: descramble.o iriver.o gigabeat.o @@ -47,7 +47,10 @@ mkboot: mkboot.c mktccboot: mktccboot.c telechips.o $(SILENT)$(CC) $(CFLAGS) $+ -o $@ - + +mk500boot: mk500boot.c mr500.c + $(SILENT)$(CC) $(CFLAGS) $+ -o $@ + mknkboot: mknkboot.c $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 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, case 4: /* 16-bit packed RGB (5-6-5) */ case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */ + case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/ dst_w = width; dst_h = height; dst_d = 16; @@ -425,6 +426,19 @@ int transform_bitmap(const struct RGBQUAD *src, int width, int height, (*dest)[(row/8) * dst_w + col] |= data << (row & 7); } break; + + case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/ + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) + { + unsigned short rgb = + (((src[row * width + col].rgbRed >> 3) << 11) | + ((src[row * width + col].rgbGreen >> 2) << 5) | + ((src[row * width + col].rgbBlue >> 3))); + + (*dest)[col * dst_h + row] = rgb; + } + break; } return 0; @@ -569,7 +583,8 @@ void print_usage(void) "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n" "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n" "\t 6 Greyscale iPod 4-grey\n" - "\t 7 Greyscale X5 remote 4-grey\n"); + "\t 7 Greyscale X5 remote 4-grey\n" + "\t 8 16-bit packed 5-6-5 RGB with a vertical stride\n"); printf("build date: " __DATE__ "\n\n"); } diff --git a/tools/configure b/tools/configure index 2f96f377e5..82ff172784 100755 --- a/tools/configure +++ b/tools/configure @@ -1598,7 +1598,7 @@ fi arm926ejscc tool="$rootdir/tools/scramble -add=m500" bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" - bmp2rb_native="$rootdir/tools/bmp2rb -f 4" + bmp2rb_native="$rootdir/tools/bmp2rb -f 8" bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2009 by Karl Kurbjun + * $Id$ + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include <stdio.h> +#include <errno.h> +#include <inttypes.h> +#include <string.h> +#include "mr500.h" + +/* This is the patch necessary for the SVG exploit (decrypted) */ +struct patch_single hack[] = { {0x29B28, 0xE12FFF30}, + {0x2F960, 0xE12FFF30} }; + +static void usage(void) +{ + printf( "Usage: mk500boot <options> <input file> [output file]\n" + "options:\n" + "\t-decrypt Decrypt the input file and save the output file\n" + "\t-encrypt Encrypt the input file and save the output file\n" + "\t-patch Patch the input file with the SVF hack\n\n"); + + exit(1); +} + +/* This is a fake flag that is used to let the tool know what's up */ +#define HEADER_DECRYPTED 0x8000 + +void display_header(struct olympus_header *header) { + printf("Magic Name: \t%s\n", header->magic_name); + printf("Unknown: \t0x%08hX\n", header->unknown); + printf("Header Length: \t0x%04X\n", header->header_length); + printf("Flags: \t\t0x%04X\n", header->flags); + printf("Unknonwn Zeros: 0x%08X\n", header->unknown_zeros); + printf("Image Length: \t0x%08X\n", header->image_length); +} + +/* This is a demonstration of the encryption and decryption process. + * It patches a FW image to include the SVG exploit. + */ +int main (int argc, char *argv[]) { + uint32_t checksum; + uint32_t stored_crc; + + enum operations { + decrypt, + encrypt, + patch + } operation; + + char *encrypt_file; + char *decrypt_file; + + struct olympus_header header; + + if (argc < 2) { + usage(); + return -1; + } + + if(!strcmp(argv[1], "-decrypt")) { + if(argc < 3) { + usage(); + return -1; + } + encrypt_file=argv[2]; + decrypt_file=argv[3]; + operation = decrypt; + } else if(!strcmp(argv[1], "-encrypt")) { + if(argc < 3) { + usage(); + return -1; + } + decrypt_file = argv[2]; + encrypt_file = argv[3]; + operation = encrypt; + } else if(!strcmp(argv[1], "-patch")) { + decrypt_file = argv[2]; + encrypt_file = argv[3]; + operation = patch; + } else { + return -1; + } + + /* Initialize encryption/decryption routine */ + mr500_init(); + + if(operation == decrypt) { + /* Read in the header of the encrypted file */ + if(mr500_read_header(encrypt_file, &header) < 0 ) { + printf("ERROR: Unable to read header: %s\n", strerror(errno)); + return -1; + } + + /* Read CRC of encrypted file */ + if(mr500_read_crc(encrypt_file, + header.header_length+header.image_length, &stored_crc) < 0 ) { + printf("ERROR: Unable to read CRC: %s\n", strerror(errno)); + return -1; + } + + /* Display the header information */ + printf("File format:\n"); + + printf("*****Header*****\n"); + display_header(&header); + printf("****************\n\n"); + + printf("*****Image******\n\n"); + + printf("*****Footer*****\n"); + printf("Checksum: \t0x%08X\n", stored_crc); + printf("****************\n\n"); + + printf("Writing Decrypted file...\n"); + + /********************************************************************* + * Save a decrypted file + **********************************************************************/ + + /* Check to make sure this is a encrypted file (bogus flag not set) */ + if(header.flags & HEADER_DECRYPTED) { + printf("ERROR: This appears to be a decrypted file! Quitting\n"); + return -1; + } + + /* Check to make sure MAGIC string matches expected*/ + if(strncmp((char *)header.magic_name, "OIMCFWUP", 8)) { + printf("ERROR: Magic string does not match expected! Quitting\n"); + return -1; + } + + /* Set a bogus flag to let the tool know that this is a decrypted file*/ + header.flags |= HEADER_DECRYPTED; + + /* Start by writing out the header */ + if(mr500_save_header(decrypt_file, &header) < 0 ) { + printf("ERROR: Unable to save header: %s\n", strerror(errno)); + return -1; + } + + /* Read encrypted data and save decrypted data */ + if(mr500_save_data( encrypt_file, decrypt_file, header.header_length, + header.image_length, decrypt_array) < 0 ) { + printf("ERROR: Unable to save decrypted data: %s\n", strerror(errno)); + return -1; + } + + printf("Calculating Checksum...\n"); + /* Calculate CRC of decrypted data */ + if(mr500_calculate_crc( decrypt_file, header.header_length, + header.image_length, &checksum) < 0 ) { + printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); + return -1; + } + + printf("Calculated Checksum: \n\t\t0x%08X\n", checksum); + + /* Double check to make sure that the two CRCs match */ + if(checksum!=stored_crc) { + printf("\tERROR: \tCalculated checksum: \t0x%08X and\n", checksum); + printf("\t\tStored checksum: \t0x%08X do not match\n", stored_crc); + return -1; + } else { + printf("\tOK: Calculated checksum and stored checksum match.\n"); + } + + printf("Saving Checksum...\n"); + /* Save the calculated CRC to the file */ + if(mr500_save_crc(decrypt_file, header.header_length+header.image_length, + &checksum) < 0 ) { + printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); + return -1; + } + + } else if(operation == patch) { + + /********************************************************************** + * Patch decryped file with SVG exploit + **********************************************************************/ + printf("Patching decrypted file.\n"); + + /* Read in the header of the encrypted file */ + if(mr500_read_header(decrypt_file, &header) < 0 ) { + printf("ERROR: Unable to read header: %s\n", strerror(errno)); + return -1; + } + + /* Check to make sure this is a decrypted file (bogus flag not set) */ + if(!(header.flags & HEADER_DECRYPTED)) { + printf("ERROR: This appears to be a encrypted file! Quitting\n"); + return -1; + } + + /* Check to make sure MAGIC string matches expected*/ + if(strncmp((char *)header.magic_name, "OIMCFWUP", 8)) { + printf("ERROR: Magic string does not match expected! Quitting\n"); + return -1; + } + + printf("File Header:\n"); + display_header(&header); + + if(mr500_patch_file (decrypt_file, hack, 2) < 0 ) { + printf("ERROR: Unable to patch file: %s\n", strerror(errno)); + return -1; + } + + printf("\nCalculating new CRC\n"); + + /* Calculate the 'CRC' of the patched file */ + if(mr500_calculate_crc( decrypt_file, header.header_length, + header.image_length, &checksum) < 0 ) { + printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); + return -1; + } + + printf("Calculated CRC: \n\t\t0x%08X\n", checksum); + /* Store the calculated 'CRC' (not encrypted) */ + if(mr500_save_crc(decrypt_file, header.header_length+header.image_length, + &checksum) < 0 ) { + printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); + return -1; + } + + } else if(operation == encrypt) { + + /********************************************************************** + * Save an encrypted file + **********************************************************************/ + printf("Saving Encrypted file\n"); + + /* Read in the header of the encrypted file */ + if(mr500_read_header(decrypt_file, &header) < 0 ) { + printf("ERROR: Unable to read header: %s\n", strerror(errno)); + return -1; + } + + /* Check to make sure this is a decrypted file (bogus flag not set) */ + if(!(header.flags & HEADER_DECRYPTED)) { + printf("ERROR: This appears to be a encrypted file! Quitting\n"); + return -1; + } + + /* Check to make sure MAGIC string matches expected*/ + if(strncmp((char *)header.magic_name, "OIMCFWUP", 7)) { + printf("ERROR: Magic string does not match expected! Quitting\n"); + return -1; + } + + /* Remove the bogus flag */ + header.flags &= ~HEADER_DECRYPTED; + + printf("File Header:\n"); + display_header(&header); + + /* Header is not encrypted, save it */ + if(mr500_save_header(encrypt_file, &header) < 0 ) { + printf("ERROR: Unable to save header: %s\n", strerror(errno)); + return -1; + } + + /* Read CRC of decrypted file */ + if(mr500_read_crc(decrypt_file, + header.header_length+header.image_length, &stored_crc) < 0 ) { + printf("ERROR: Unable to read CRC: %s\n", strerror(errno)); + return -1; + } + + /* Calculate the 'CRC' of the decrypted data */ + if(mr500_calculate_crc( decrypt_file, header.header_length, + header.image_length, &checksum) < 0 ) { + printf("ERROR: Unable to calculate CRC: %s\n", strerror(errno)); + return -1; + } + + if(stored_crc != checksum) { + printf("\nERROR: Stored and calculated checksums do not match!\n" + "\tFile has been improperly modified. Quitting\n"); + return -1; + } + + printf("Encrypting data...\n"); + + /* Write the encrypted data to a file */ + if(mr500_save_data( decrypt_file, encrypt_file, header.header_length, + header.image_length, encrypt_array) < 0 ) { + printf("ERROR: Unable to save encrypted data: %s\n", strerror(errno)); + return -1; + } + + printf("Saving CRC\n"); + + /* Store the calculated 'CRC' (not encrypted) */ + if(mr500_save_crc(encrypt_file, header.header_length+header.image_length, + &checksum) < 0 ) { + printf("ERROR: Unable to save CRC: %s\n", strerror(errno)); + return -1; + } + + printf("File sucesfully encrypted!\n"); + } + + printf("Done\n"); + return 0; +} + 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2009 by Karl Kurbjun + * based on work by Shirour: + * http://www.mrobe.org/forum/viewtopic.php?f=6&t=2176 + * $Id$ + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/stat.h> +#include "mr500.h" + +/* Notes about firmware: + * These notes are based on the work and observations of Shirour on the M:Robe + * forums. + * + * The firmware for the M:Robe has basic encryption on it. The data is XORed + * and scrambled. The mr500_save_data function provides an implemenation of the + * encryption/decryption. + * + * When a firmware update is done the "{#4F494D4346575550#}" folder is stored + * in the system folder on the player. The "{#4F494D4346575550#}" should only + * contain the encrypted N5002-BD.BIN file. At the end of a firmware update + * the "{#4F494D4346575550#}" folder and it's contents are removed from the + * player. + * + * An interesting note is that the name "{#4F494D4346575550#}" is actually the + * Hex representation of the magic text found at the beginning of the firmware + * image "OIMCFWUP". + */ + +/* These two arrays are used for descrambling or scrambling the data */ +int decrypt_array[16]={2, 0, 3, 1, 5, 7, 4, 6, 11, 10, 9, 8, 14, 12, 13, 15}; +int encrypt_array[16]; + +/* mr500_patch_file: This function modifies the specified file with the patches + * struct. + * + * Parameters: + * filename: text filename + * patches: pointer to structure array of patches + * num_patches: number of patches to apply (applied in reverse order) + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_patch_file(char *filename, struct patch_single *patches, + int num_patches) { + int fdo; + int ret=0; + uint32_t endian_int; + + /* Open the file write only. */ + fdo = open(filename, O_WRONLY); + + if(fdo<0) { + ret=-1; + } + + while(num_patches--) { + /* seek to patch offset */ + if(lseek(fdo, patches[num_patches].offset, SEEK_SET) + != patches[num_patches].offset) { + ret=-1; + break; + } + + /* Make sure patch is written in little endian format */ + endian_int = htole32(patches[num_patches].value); + + /* Write the patch value to the file */ + if(write(fdo, (void *) &endian_int, sizeof(endian_int)) < 0) { + ret = -1; + break; + } + } + + /* Close the file and check for errors */ + if(close (fdo) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_save_header: This function saves the Olympus header to the firmware + * image. The values stored in the header are explained above. Note that this + * will truncate a file. The header is stored in little endian format. + * + * Parameters: + * filename: text filename + * header: pointer to header structure to be saved + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_save_header(char *filename, struct olympus_header *header) { + int fdo; + int ret=0; + + /* Temporary header used for storing the header in little endian. */ + struct olympus_header save; + + /* Open the file write only and truncate it. If it doesn't exist create. */ + fdo = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + + if(fdo<0) { + ret=-1; + } + + /* Header is stored at offset 0 (Not really needed) */ + if(lseek(fdo, 0, SEEK_SET) != 0) { + ret=-1; + } + + /* Convert header to Little Endian */ + memcpy(&save.magic_name, &header->magic_name, 8*sizeof(int8_t)); + save.unknown = htole32(header->unknown); + save.header_length = htole16(header->header_length); + save.flags = htole16(header->flags); + save.unknown_zeros = htole32(header->unknown_zeros); + save.image_length = htole32(header->image_length); + + /* Write the header to the file */ + if(write(fdo, (void *) &save, sizeof(save)) < 0) { + ret = -1; + } + + /* Close the file and check for errors */ + if(close (fdo) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_read_header: This function reads the Olympus header and converts it to + * the host endian format. The values stored in the header are explained above. + * The header is stored in little endian format. + * + * Parameters: + * filename: text filename + * header: pointer to header structure to store header read from file + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_read_header(char *filename, struct olympus_header *header) { + int fdi; + int ret = 0; + + /* Open the file read only */ + fdi = open(filename, O_RDONLY); + + if(fdi<0) { + ret=-1; + } + + /* Header is stored at offset 0 (Not really needed) */ + if(lseek(fdi, 0, SEEK_SET) != 0) { + ret=-1; + } + + /* Read in the header */ + if(read(fdi, (void *) header, sizeof(*header)) < 0) { + ret = -1; + } + + /* Convert header to system endian */ + header->unknown = le32toh(header->unknown); + header->header_length = le16toh(header->header_length); + header->flags = le16toh(header->flags); + header->unknown_zeros = le32toh(header->unknown_zeros); + header->image_length = le32toh(header->image_length); + + /* Close the file and check for errors */ + if(close (fdi) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_save_crc: This function saves the 'CRC' of the Olympus firmware image. + * Note that the 'CRC' must be calculated on the decrytped image. It is stored + * in little endian. + * + * Parameters: + * filename: text filename + * offset: Offset to store the 'CRC' (header size + data size) + * crc_value: pointer to crc value to save + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_save_crc(char *filename, off_t offset, uint32_t *crc_value) { + int fdo; + int ret = 0; + uint32_t save_crc; + + /* Open the file write only */ + fdo = open(filename, O_WRONLY); + + if(fdo<0) { + ret=-1; + } + + /* Seek to offset and check for errors */ + if(lseek(fdo, offset, SEEK_SET) != offset) { + ret=-1; + } + + /* Convert 'CRC' to little endian from system native endian */ + save_crc = htole32(*crc_value); + + /* Write the 'CRC' and check for errors */ + if(write(fdo, (void *) &save_crc, sizeof(unsigned int)) < 0) { + ret = -1; + } + + /* Close the file and check for errors */ + if(close (fdo) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_read_crc: This function reads the 'CRC' of the Olympus firmware image. + * Note that the 'CRC' is calculated on the decrytped values. It is stored + * in little endian. + * + * Parameters: + * filename: text filename + * offset: Offset to read the 'CRC' (header size + data size) + * crc_value: pointer to crc value to save + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_read_crc(char *filename, off_t offset, uint32_t *crc_value) { + int fdi; + int ret = 0; + + /* Open the file read only */ + fdi = open(filename, O_RDONLY); + + if(fdi<0) { + ret = -1; + } + + /* Seek to offset and check for errors */ + if(lseek(fdi, offset, SEEK_SET) != offset) { + ret=-1; + } + + /* Read in the 'CRC' */ + if(read(fdi, (void *) crc_value, sizeof(uint32_t)) < 0) { + ret = -1; + } + + /* Convert the 'CRC' from little endian to system native format */ + *crc_value = le32toh(*crc_value); + + /* Close the file and check for errors */ + if(close (fdi) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_calculate_crc: This function calculates the 'CRC' of the Olympus + * firmware image. Note that the 'CRC' must be calculated on decrytped values. + * It is stored in little endian. + * + * Parameters: + * filename: text filename + * offset: Offset to the start of the data (header size) + * length: Length of data to calculate + * crc_value: pointer to crc value to save + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_calculate_crc( char *filename, off_t offset, unsigned int length, + uint32_t *crc_value){ + uint32_t temp; + int fdi; + int ret = 0; + + /* Open the file read only */ + fdi = open(filename, O_RDONLY); + + if(fdi<0) { + ret = -1; + } + + /* Seek to offset and check for errors */ + if(lseek(fdi, offset, SEEK_SET) != offset) { + ret=-1; + } + + /* Initialize the crc_value to make sure this starts at 0 */ + *crc_value = 0; + /* Run this loop till the entire sum is created */ + do { + /* Read an integer at a time */ + if(read(fdi, &temp, sizeof(uint32_t)) < 0) { + ret = -1; + break; + } + + /* Keep summing the values */ + *crc_value+=temp; + } while (length-=4); + + /* Close the file and check for errors */ + if(close (fdi) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_save_data: This function encypts or decrypts the Olympus firmware + * image based on the dictionary passed to it. + * + * Parameters: + * source_filename: text filename where data is read from + * dest_filename: text filename where data is written to + * offset: Offset to the start of the data (header size) + * length: Length of data to modify + * dictionary: pointer to dictionary used for scrambling + * + * Returns: + * Returns 0 if there was no error, -1 if there was an error + */ +int mr500_save_data( + char *source_filename, char *dest_filename, off_t offset, + unsigned int length, int* dictionary) { + int fdi, fdo; + int ret = 0; + int i; + + /* read_count stores the number of bytes actually read */ + int read_count; + + /* read_request stores the number of bytes to be requested */ + int read_request; + + /* These two buffers are used for reading data and scrambling or + * descrambling + */ + int8_t buffer_original[16]; + int8_t buffer_modified[16]; + + /* Open input read only, output write only */ + fdi = open(source_filename, O_RDONLY); + fdo = open(dest_filename, O_WRONLY); + + /* If there was an error loading the files set ret appropriately */ + if(fdi<0 || fdo < 0) { + ret = -1; + } + + /* Input file: Seek to offset and check for errors */ + if(lseek(fdi, offset, SEEK_SET) != offset) { + ret=-1; + } + + /* Output file: Seek to offset and check for errors */ + if(lseek(fdo, offset, SEEK_SET) != offset) { + ret=-1; + } + + /* Run this loop till size is 0 */ + do { + /* Choose the amount of data to read - normally in 16 byte chunks, but + * when the end of the file is near may be less. + */ + if( length > sizeof(buffer_original)){ + read_request = sizeof(buffer_original); + } else { + read_request = length; + } + + /* Read in the data */ + read_count = read(fdi, (void *) &buffer_original, read_request); + + /* If there was an error set the flag and break */ + if(read_count < 0) { + ret = -1; + break; + } + + for(i=0; i<read_count; i++) { + /* XOR all of the bits to de/encrypt them */ + buffer_original[i] ^= 0xFF; + /* Handle byte scrambling */ + buffer_modified[dictionary[i]] = buffer_original[i]; + } + + /* write the data: If there was an error set the flag and break */ + if(write(fdo, (void *) &buffer_modified, read_count) < 0) { + ret = -1; + break; + } + } while (length -= read_count); + + /* Close the files and check for errors */ + if(close (fdi) < 0) { + ret = -1; + } + if(close (fdo) < 0) { + ret = -1; + } + + return ret; +} + +/* mr500_init: This function initializes the encryption array + * + * Parameters: + * None + * + * Returns: + * Returns 0 + */ +int mr500_init(void) { + int i; + /* Initialize the encryption array */ + for(i=0; i<16; i++) { + encrypt_array[decrypt_array[i]]=i; + } + return 0; +} + 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2009 by Karl Kurbjun + * $Id$ + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include <stdlib.h> +extern int decrypt_array[]; +extern int encrypt_array[]; + +/* Notes about the header: + * The magic_name should always be "OIMCFWUP" + * Header length is always 18 bytes + * The flags have the following mask: + * CHECK_CRC 0x01 : Tells the firmware whether or not to check CRC + * ENDIAN_MODE 0x02 : Tells the OF whether to re-order the bytes + * The rest are unknown + * The image length is in bytes and is always 0x007F0000 + */ +struct olympus_header { + int8_t magic_name[8]; + uint32_t unknown; + uint16_t header_length; + uint16_t flags; + uint32_t unknown_zeros; + uint32_t image_length; +} __attribute__((__packed__)); + +/* Patch entries should be saved in little endian format */ +struct patch_single { + off_t offset; + uint32_t value; +}; + +int mr500_patch_file(char *, struct patch_single *, int); +int mr500_save_header(char *, struct olympus_header *); +int mr500_read_header(char *, struct olympus_header *); +int mr500_save_crc(char *, off_t, uint32_t *); +int mr500_read_crc(char *, off_t, uint32_t *); +int mr500_calculate_crc(char *, off_t, unsigned int, uint32_t *); +int mr500_save_data(char *, char *, off_t, unsigned int, int*); +int mr500_init(void); + |