2008-04-09 11:53:28 +00:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
* __________ __ ___.
|
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
|
* $Id$
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2008 by Maurus Cuelenaere
|
|
|
|
|
*
|
|
|
|
|
* 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 <stdbool.h>
|
2008-04-09 12:08:24 +00:00
|
|
|
|
#include <stdlib.h>
|
2008-04-09 12:32:25 +00:00
|
|
|
|
#include <string.h>
|
2008-04-09 11:53:28 +00:00
|
|
|
|
|
2008-04-09 13:07:50 +00:00
|
|
|
|
#include "creative.h"
|
|
|
|
|
#include "hmac-sha1.h"
|
|
|
|
|
|
|
|
|
|
static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN.";
|
|
|
|
|
static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP.";
|
|
|
|
|
static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP.";
|
|
|
|
|
static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP.";
|
|
|
|
|
|
2008-04-24 15:54:49 +00:00
|
|
|
|
static const unsigned char bootloader_v1[] =
|
2008-04-09 13:07:50 +00:00
|
|
|
|
{
|
2008-04-24 15:54:49 +00:00
|
|
|
|
0xD3, 0xF0, 0x29, 0xE3, /* MSR CPSR_cf, #0xD3 */
|
|
|
|
|
0x09, 0xF6, 0xA0, 0xE3 /* MOV PC, #0x900000 */
|
2008-04-09 13:07:50 +00:00
|
|
|
|
};
|
|
|
|
|
|
2008-04-24 15:54:49 +00:00
|
|
|
|
static const unsigned char bootloader_v2[] =
|
|
|
|
|
{
|
|
|
|
|
0xD3, 0xF0, 0x29, 0xE3, /* MSR CPSR_cf, #0xD3 */
|
|
|
|
|
0x09, 0xF6, 0xA0, 0xE3 /* MOV PC, #0x40000000 */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const unsigned char bootloader_v3[] =
|
|
|
|
|
{
|
|
|
|
|
0 /* Unknown */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct device_info devices[] =
|
|
|
|
|
{
|
2008-05-05 15:22:43 +00:00
|
|
|
|
/* Creative Zen Vision:M */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000},
|
2008-05-05 15:22:43 +00:00
|
|
|
|
/* Creative Zen Vision:M Go! */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000},
|
2008-05-05 15:22:43 +00:00
|
|
|
|
/* Creative Zen Vision <20> TL */
|
|
|
|
|
/* The "<22>" should be ANSI encoded or the device won't accept the firmware package. */
|
2008-05-12 20:57:00 +00:00
|
|
|
|
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0<EFBFBD>\0T\0L", 47, null_key_v2, bootloader_v1, sizeof(bootloader_v1), 0x00900000},
|
2008-05-05 15:22:43 +00:00
|
|
|
|
/* Creative ZEN V */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4, bootloader_v3, sizeof(bootloader_v3), 0x00000000},
|
2008-05-05 15:22:43 +00:00
|
|
|
|
/* Creative ZEN */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N", 48, null_key_v3, bootloader_v2, sizeof(bootloader_v2), 0x40000000}
|
|
|
|
|
};
|
2008-04-09 13:07:50 +00:00
|
|
|
|
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/*
|
|
|
|
|
Create a Zen Vision:M FRESCUE structure file
|
|
|
|
|
*/
|
2008-04-09 13:07:50 +00:00
|
|
|
|
extern void int2le(unsigned int val, unsigned char* addr);
|
|
|
|
|
extern unsigned int le2int(unsigned char* buf);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
|
|
|
|
|
|
2008-04-24 15:54:49 +00:00
|
|
|
|
static int make_ciff_file(unsigned char *inbuf, unsigned int length,
|
2008-04-09 13:07:50 +00:00
|
|
|
|
unsigned char *outbuf, int device)
|
2008-04-09 11:53:28 +00:00
|
|
|
|
{
|
2008-04-09 14:04:39 +00:00
|
|
|
|
unsigned char key[20];
|
2008-04-09 11:53:28 +00:00
|
|
|
|
memcpy(outbuf, "FFIC", 4);
|
|
|
|
|
int2le(length+90, &outbuf[4]);
|
|
|
|
|
memcpy(&outbuf[8], "FNIC", 4);
|
|
|
|
|
int2le(96, &outbuf[0xC]);
|
|
|
|
|
memcpy(&outbuf[0x10], devices[device].cinf, devices[device].cinf_size);
|
2008-04-09 13:07:50 +00:00
|
|
|
|
memset(&outbuf[0x10+devices[device].cinf_size], 0,
|
|
|
|
|
96 - devices[device].cinf_size);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
memcpy(&outbuf[0x70], "ATAD", 4);
|
|
|
|
|
int2le(length+32, &outbuf[0x74]);
|
2008-04-09 13:07:50 +00:00
|
|
|
|
memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m",
|
|
|
|
|
32); /*Unicode encoded*/
|
2008-04-09 11:53:28 +00:00
|
|
|
|
memcpy(&outbuf[0x98], inbuf, length);
|
|
|
|
|
memcpy(&outbuf[0x98+length], "LLUN", 4);
|
|
|
|
|
int2le(20, &outbuf[0x98+length+4]);
|
|
|
|
|
/* Do checksum */
|
2008-04-09 16:29:05 +00:00
|
|
|
|
hmac_sha1((unsigned char *)devices[device].null, strlen(devices[device].null),
|
|
|
|
|
outbuf, 0x98+length, key);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
memcpy(&outbuf[0x98+length+8], key, 20);
|
|
|
|
|
return length+0x90+0x1C+8;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-24 15:54:49 +00:00
|
|
|
|
static int make_jrm_file(unsigned char *inbuf, unsigned int length,
|
|
|
|
|
unsigned char *outbuf, int device)
|
2008-04-09 11:53:28 +00:00
|
|
|
|
{
|
2008-04-24 15:54:49 +00:00
|
|
|
|
unsigned int i;
|
2008-04-09 11:53:28 +00:00
|
|
|
|
unsigned int sum = 0;
|
|
|
|
|
|
|
|
|
|
/* Clear the header area to zero */
|
|
|
|
|
memset(outbuf, 0, 0x18);
|
|
|
|
|
|
|
|
|
|
/* Header (EDOC) */
|
|
|
|
|
memcpy(outbuf, "EDOC", 4);
|
|
|
|
|
/* Total Size */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
#define SIZEOF_BOOTLOADER_CODE devices[device].bootloader_size
|
|
|
|
|
int2le(4+0xC+SIZEOF_BOOTLOADER_CODE+0xC+length, &outbuf[0x4]);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* 4 bytes of zero */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
memset(&outbuf[0x8], 0, 0x4);
|
|
|
|
|
|
|
|
|
|
/* First block starts here ... */
|
|
|
|
|
/* Address = 0x0 */
|
|
|
|
|
memset(&outbuf[0xC], 0, 0x4);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* Size */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
int2le(SIZEOF_BOOTLOADER_CODE, &outbuf[0x10]);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* Checksum */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
for(i=0; i<SIZEOF_BOOTLOADER_CODE; i+= 4)
|
|
|
|
|
sum += le2int((unsigned char*)&devices[device].bootloader[i]) + (le2int((unsigned char*)&devices[device].bootloader[i])>>16);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
int2le(sum, &outbuf[0x14]);
|
|
|
|
|
outbuf[0x16] = 0;
|
|
|
|
|
outbuf[0x17] = 0;
|
2008-04-24 15:54:49 +00:00
|
|
|
|
/*Data */
|
|
|
|
|
memcpy(&outbuf[0x18], devices[device].bootloader, SIZEOF_BOOTLOADER_CODE);
|
|
|
|
|
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* Second block starts here ... */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
/* Address = depends on target */
|
|
|
|
|
#define SB_START (0x18+SIZEOF_BOOTLOADER_CODE)
|
|
|
|
|
int2le(devices[device].memory_address, &outbuf[SB_START]);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* Size */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
int2le(length, &outbuf[SB_START+0x4]);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
/* Checksum */
|
2008-04-24 15:54:49 +00:00
|
|
|
|
sum = 0;
|
|
|
|
|
for(i=0; i<length; i+= 4)
|
|
|
|
|
sum += le2int(&inbuf[i]) + (le2int(&inbuf[i])>>16);
|
|
|
|
|
int2le(sum, &outbuf[SB_START+0x8]);
|
|
|
|
|
outbuf[SB_START+0xA] = 0;
|
|
|
|
|
outbuf[SB_START+0xB] = 0;
|
|
|
|
|
/* Data */
|
|
|
|
|
memcpy(&outbuf[SB_START+0xC], inbuf, length);
|
|
|
|
|
|
|
|
|
|
return SB_START+0xC+length;
|
2008-04-09 11:53:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int zvm_encode(char *iname, char *oname, int device)
|
|
|
|
|
{
|
|
|
|
|
size_t len;
|
|
|
|
|
int length;
|
|
|
|
|
FILE *file;
|
|
|
|
|
unsigned char *outbuf;
|
|
|
|
|
unsigned char *buf;
|
|
|
|
|
|
|
|
|
|
file = fopen(iname, "rb");
|
|
|
|
|
if (!file) {
|
|
|
|
|
perror(iname);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
|
length = ftell(file);
|
|
|
|
|
|
|
|
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
|
|
|
|
|
|
buf = (unsigned char*)malloc(length);
|
|
|
|
|
if ( !buf ) {
|
|
|
|
|
printf("out of memory!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = fread(buf, 1, length, file);
|
2008-04-09 13:07:50 +00:00
|
|
|
|
if(len < (size_t)length) {
|
2008-04-09 11:53:28 +00:00
|
|
|
|
perror(iname);
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
|
|
outbuf = (unsigned char*)malloc(length+0x300);
|
|
|
|
|
if ( !outbuf ) {
|
|
|
|
|
free(buf);
|
|
|
|
|
printf("out of memory!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2008-04-24 15:54:49 +00:00
|
|
|
|
length = make_jrm_file(buf, len, outbuf, device);
|
2008-04-09 11:53:28 +00:00
|
|
|
|
free(buf);
|
|
|
|
|
buf = (unsigned char*)malloc(length+0x200);
|
|
|
|
|
memset(buf, 0, length+0x200);
|
|
|
|
|
length = make_ciff_file(outbuf, length, buf, device);
|
|
|
|
|
free(outbuf);
|
|
|
|
|
|
|
|
|
|
file = fopen(oname, "wb");
|
|
|
|
|
if (!file) {
|
|
|
|
|
free(buf);
|
|
|
|
|
perror(oname);
|
|
|
|
|
return -3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = fwrite(buf, 1, length, file);
|
2008-04-09 13:07:50 +00:00
|
|
|
|
if(len < (size_t)length) {
|
2008-04-09 11:53:28 +00:00
|
|
|
|
free(buf);
|
|
|
|
|
perror(oname);
|
|
|
|
|
return -4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(buf);
|
|
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|