All pastes #437009 Raw Edit

scramble for ipods

public c v1 · immutable
·published 2007-04-12 20:33 UTC
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;}