rendered paste body/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: scramble.c,v 1.35 2006/08/31 19:19:35 dave Exp $ * * Copyright (C) 2002 by Björn Stenberg * * 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 <stdlib.h>#include <stdbool.h>#include <string.h>int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);void short2le(unsigned short val, unsigned char* addr){ addr[0] = val & 0xFF; addr[1] = (val >> 8) & 0xff;}void int2le(unsigned int val, unsigned char* addr){ addr[0] = val & 0xFF; addr[1] = (val >> 8) & 0xff; addr[2] = (val >> 16) & 0xff; addr[3] = (val >> 24) & 0xff;}void int2be(unsigned int val, unsigned char* addr){ addr[0] = (val >> 24) & 0xff; addr[1] = (val >> 16) & 0xff; addr[2] = (val >> 8) & 0xff; addr[3] = val & 0xFF;}void usage(void){ printf("usage: scramble [options] <input file> <output file> [xor string]\n"); printf("options:\n" "\t-ipod3g ipod firmware partition format (3rd Gen)\n" "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n" "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n" "\t-add=X Rockbox generic \"add-up\" checksum format\n" "\t (X values: ipco, nano, ipvd, ip3g, ip4g, mini, mn2g)\n" "\t\t\tip3g = iPod 3G\n" "\t\t\tip4g = iPod 4G (b&w)\n" "\t\t\tipco = iPod Color/Photo \n" "\t\t\tmini = iPod Mini 1G\n" "\t\t\tmn2g = iPod Mini 2G\n" "\t\t\tnano = iPod nano 1G \n" "\t\t\tipvd = iPod Video\n"); exit(1);}int main (int argc, char** argv){ unsigned long length,i,slen; unsigned char *inbuf,*outbuf; unsigned short crc=0; unsigned long chksum=0; /* 32 bit checksum */ unsigned char header[24]; char *iname = argv[1]; char *oname = argv[2]; char *xorstring; int headerlen = 6; FILE* file; int version; unsigned long modelnum; char modelname[5]; enum { none, scramble, xor, add } method = scramble; if (argc < 3) { usage(); } if(!strncmp(argv[1], "-add=", 5)) { iname = argv[2]; oname = argv[3]; method = add; if(!strcmp(&argv[1][5], "ipco")) //iPod Color/Photo modelnum = 3; else if(!strcmp(&argv[1][5], "nano")) //iPod nano modelnum = 4; else if(!strcmp(&argv[1][5], "ipvd")) //iPod Video modelnum = 5; else if(!strcmp(&argv[1][5], "ip3g")) //iPod 3G modelnum = 7; else if(!strcmp(&argv[1][5], "ip4g")) //iPod 4G b&w modelnum = 8; else if(!strcmp(&argv[1][5], "mini")) //iPod mini modelnum = 9; else if(!strcmp(&argv[1][5], "mn2g")) //iPod mini 2G modelnum = 11; else { fprintf(stderr, "unsupported model: %s\n", &argv[1][5]); return 2; } /* we store a 4-letter model name too, for humans */ strcpy(modelname, &argv[1][5]); chksum = modelnum; /* start checksum calcs with this */ } else if(!strcmp(argv[1], "-ipod3g")) { iname = argv[2]; oname = argv[3]; return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */ } else if(!strcmp(argv[1], "-ipod4g")) { iname = argv[2]; oname = argv[3]; return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */ } else if(!strcmp(argv[1], "-ipod5g")) { iname = argv[2]; oname = argv[3]; return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */ } /* open file */ file = fopen(iname,"rb"); if (!file) { perror(iname); return -1; } fseek(file,0,SEEK_END); length = ftell(file); length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */ fseek(file,0,SEEK_SET); inbuf = malloc(length); if (method == xor) outbuf = malloc(length*2); else if(method == add) outbuf = malloc(length + 8); else outbuf = malloc(length); if ( !inbuf || !outbuf ) { printf("out of memory!\n"); return -1; } if(length> 4) { /* zero-fill the last 4 bytes to make sure there's no rubbish there when we write the size-aligned file later */ memset(outbuf+length-4, 0, 4); } /* read file */ i=fread(inbuf,1,length,file); if ( !i ) { perror(iname); return -1; } fclose(file); switch (method) { case add: for (i = 0; i < length; i++) { /* add 8 unsigned bits but keep a 32 bit sum */ chksum += inbuf[i]; } break; case scramble: slen = length/4; for (i = 0; i < length; i++) { unsigned long addr = (i >> 2) + ((i % 4) * slen); unsigned char data = inbuf[i]; data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */ outbuf[addr] = data; } break; case xor: /* "compress" */ slen = 0; for (i=0; i<length; i++) { if (!(i&7)) outbuf[slen++] = 0xff; /* all data is uncompressed */ outbuf[slen++] = inbuf[i]; } break; } if(method != add) { /* calculate checksum */ for (i=0;i<length;i++) crc += inbuf[i]; } memset(header, 0, sizeof header); switch (method) { case add: { int2be(chksum, header); /* checksum, big-endian */ memcpy(&header[4], modelname, 4); /* 4 bytes model name */ memcpy(outbuf, inbuf, length); /* the input buffer to output*/ headerlen = 8; } break; case scramble: if (headerlen == 6) { int2be(length, header); header[4] = (crc >> 8) & 0xff; header[5] = crc & 0xff; } else { header[0] = header[1] = header[2] = header[3] = 0xff; /* ??? */ header[6] = (crc >> 8) & 0xff; header[7] = crc & 0xff; header[11] = version; header[15] = headerlen; /* really? */ int2be(length, &header[20]); } break; case xor: { int xorlen = strlen(xorstring); /* xor data */ for (i=0; i<slen; i++) outbuf[i] ^= xorstring[i & (xorlen-1)]; /* calculate checksum */ for (i=0; i<slen; i++) crc += outbuf[i]; header[0] = header[2] = 'Z'; header[1] = header[3] = version; int2le(length, &header[4]); int2le(slen, &header[8]); int2le(crc, &header[12]); length = slen; break; }#define MY_FIRMWARE_TYPE "Rockbox"#define MY_HEADER_VERSION 1 default: strncpy((char *)header, MY_FIRMWARE_TYPE,9); header[9]='\0'; /*shouldn't have to, but to be SURE */ header[10]=MY_HEADER_VERSION&0xFF; header[11]=(crc>>8)&0xFF; header[12]=crc&0xFF; int2be(sizeof(header), &header[12]); break; } /* write file */ file = fopen(oname,"wb"); if ( !file ) { perror(oname); return -1; } if ( !fwrite(header,headerlen,1,file) ) { perror(oname); return -1; } if ( !fwrite(outbuf,length,1,file) ) { perror(oname); return -1; } fclose(file); free(inbuf); free(outbuf); return 0;}int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc){ static const char *apple_stop_sign = "{{~~ /-----\\ "\ "{{~~ / \\ "\ "{{~~| | "\ "{{~~| S T O P | "\ "{{~~| | "\ "{{~~ \\ / "\ "{{~~ \\-----/ "\ "Copyright(C) 200"\ "1 Apple Computer"\ ", Inc.----------"\ "----------------"\ "----------------"\ "----------------"\ "----------------"\ "----------------"\ "---------------"; size_t len; int length; int rsrclength; int rsrcoffset; FILE *file; unsigned int sum = 0; unsigned int rsrcsum = 0; unsigned char *outbuf; int bufsize; int i; file = fopen(iname, "rb"); if (!file) { perror(iname); return -1; } fseek(file,0,SEEK_END); length = ftell(file); fseek(file,0,SEEK_SET); bufsize=(length+0x4600); if (fake_rsrc) { bufsize = (bufsize + 0x400) & ~0x200; } outbuf = malloc(bufsize); if ( !outbuf ) { printf("out of memory!\n"); return -1; } len = fread(outbuf+0x4600, 1, length, file); if(len < length) { perror(iname); return -2; } fclose(file); /* Calculate checksum for later use in header */ for(i = 0x4600; i < 0x4600+length;i++) sum += outbuf[i]; /* Clear the header area to zero */ memset(outbuf, 0, 0x4600); /* APPLE STOP SIGN */ strcpy((char *)outbuf, apple_stop_sign); /* VOLUME HEADER */ memcpy(&outbuf[0x100],"]ih[",4); /* Magic */ int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */ short2le(0x10c, &outbuf[0x108]); /* Location of extended header */ short2le(fw_ver, &outbuf[0x10a]); /* Firmware Directory - "osos" entry */ memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */ int2le(0, &outbuf[0x4208]); /* id */ int2le(0x4400, &outbuf[0x420c]); /* devOffset */ int2le(length, &outbuf[0x4210]); /* Length of firmware */ int2le(0x10000000, &outbuf[0x4214]); /* Addr */ int2le(0, &outbuf[0x4218]); /* Entry Offset */ int2le(sum, &outbuf[0x421c]); /* Checksum */ int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */ int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */ /* "rsrc" entry (if applicable) */ if (fake_rsrc) { rsrcoffset=(length+0x4600+0x200) & ~0x200; rsrclength=0x200; rsrcsum=0; memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */ int2le(0, &outbuf[0x4230]); /* id */ int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */ int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */ int2le(0x10000000, &outbuf[0x423c]); /* Addr */ int2le(0, &outbuf[0x4240]); /* Entry Offset */ int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */ int2le(0x0000b000, &outbuf[0x4248]); /* vers */ int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */ } file = fopen(oname, "wb"); if (!file) { perror(oname); return -3; } len = fwrite(outbuf, 1, length+0x4600, file); if(len < length) { perror(oname); return -4; } fclose(file); return 0;}