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
This commit is contained in:
parent
8af1a65cae
commit
d07ea9a48e
6 changed files with 858 additions and 5 deletions
|
@ -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 $@
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
2
tools/configure
vendored
2
tools/configure
vendored
|
@ -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"
|
||||
|
|
322
tools/mk500boot.c
Normal file
322
tools/mk500boot.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
457
tools/mr500.c
Normal file
457
tools/mr500.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
56
tools/mr500.h
Normal file
56
tools/mr500.h
Normal file
|
@ -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);
|
||||
|
Loading…
Reference in a new issue