Correct order of odd and even row colours in the rowcolors command, and set colours...
[kugel-rb.git] / rbutil / ipodpatcher / ipodpatcher.c
blob1a5268bb6dfbd04dd5d39b004ee799bbaec446c7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006-2007 Dave Chapman
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <inttypes.h>
28 #include <stdbool.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
32 #include "parttypes.h"
33 #include "ipodio.h"
34 #include "ipodpatcher.h"
36 #ifdef WITH_BOOTOBJS
37 #include "ipod1g2g.h"
38 #include "ipod3g.h"
39 #include "ipod4g.h"
40 #include "ipodmini.h"
41 #include "ipodmini2g.h"
42 #include "ipodcolor.h"
43 #include "ipodnano.h"
44 #include "ipodvideo.h"
45 #endif
47 #ifndef RBUTIL
48 #include "arc4.h"
49 #endif
51 int ipod_verbose = 0;
53 unsigned char* ipod_sectorbuf = NULL;
55 /* The following string appears at the start of the firmware partition */
56 static const char *apple_stop_sign = "{{~~ /-----\\ "\
57 "{{~~ / \\ "\
58 "{{~~| | "\
59 "{{~~| S T O P | "\
60 "{{~~| | "\
61 "{{~~ \\ / "\
62 "{{~~ \\-----/ "\
63 "Copyright(C) 200"\
64 "1 Apple Computer"\
65 ", Inc.----------"\
66 "----------------"\
67 "----------------"\
68 "----------------"\
69 "----------------"\
70 "----------------"\
71 "---------------";
73 /* Windows requires the buffer for disk I/O to be aligned in memory on a
74 multiple of the disk volume size - so we use a single global variable
75 and initialise it with ipod_alloc_buf()
78 char* get_parttype(int pt)
80 int i;
81 static char unknown[]="Unknown";
83 if (pt == PARTTYPE_HFS) {
84 return "HFS/HFS+";
87 i=0;
88 while (parttypes[i].name != NULL) {
89 if (parttypes[i].type == pt) {
90 return (parttypes[i].name);
92 i++;
95 return unknown;
98 off_t filesize(int fd) {
99 struct stat buf;
101 if (fstat(fd,&buf) < 0) {
102 perror("[ERR] Checking filesize of input file");
103 return -1;
104 } else {
105 return(buf.st_size);
109 /* Partition table parsing code taken from Rockbox */
111 #define MAX_SECTOR_SIZE 2048
112 #define SECTOR_SIZE 512
114 static inline unsigned short le2ushort(unsigned char* buf)
116 unsigned short res = (buf[1] << 8) | buf[0];
118 return res;
121 static inline int le2int(unsigned char* buf)
123 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
125 return res;
128 static inline int be2int(unsigned char* buf)
130 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
132 return res;
135 static inline int getint16le(char* buf)
137 int16_t res = (buf[1] << 8) | buf[0];
139 return res;
142 static inline void short2le(unsigned short val, unsigned char* addr)
144 addr[0] = val & 0xFF;
145 addr[1] = (val >> 8) & 0xff;
148 static inline void int2le(unsigned int val, unsigned char* addr)
150 addr[0] = val & 0xFF;
151 addr[1] = (val >> 8) & 0xff;
152 addr[2] = (val >> 16) & 0xff;
153 addr[3] = (val >> 24) & 0xff;
156 static inline void int2be(unsigned int val, unsigned char* addr)
158 addr[0] = (val >> 24) & 0xff;
159 addr[1] = (val >> 16) & 0xff;
160 addr[2] = (val >> 8) & 0xff;
161 addr[3] = val & 0xFF;
165 #define BYTES2INT32(array,pos)\
166 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
167 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
169 int read_partinfo(struct ipod_t* ipod, int silent)
171 int i;
172 unsigned long count;
174 count = ipod_read(ipod,ipod_sectorbuf, ipod->sector_size);
176 if (count <= 0) {
177 print_error(" Error reading from disk: ");
178 return -1;
181 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
183 if ((ipod_sectorbuf[510] == 0x55) && (ipod_sectorbuf[511] == 0xaa)) {
184 /* DOS partition table */
185 ipod->macpod = 0;
186 /* parse partitions */
187 for ( i = 0; i < 4; i++ ) {
188 unsigned char* ptr = ipod_sectorbuf + 0x1be + 16*i;
189 ipod->pinfo[i].type = ptr[4];
190 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
191 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
193 /* extended? */
194 if ( ipod->pinfo[i].type == 5 ) {
195 /* not handled yet */
198 } else if ((ipod_sectorbuf[0] == 'E') && (ipod_sectorbuf[1] == 'R')) {
199 /* Apple Partition Map */
201 /* APM parsing code based on the check_mac_partitions() function in
202 ipodloader2 - written by Thomas Tempelmann and released
203 under the GPL. */
205 int blkNo = 1;
206 int partBlkCount = 1;
207 int partBlkSizMul = ipod_sectorbuf[2] / 2;
209 int pmMapBlkCnt; /* # of blks in partition map */
210 int pmPyPartStart; /* physical start blk of partition */
211 int pmPartBlkCnt; /* # of blks in this partition */
212 int i = 0;
214 ipod->macpod = 1;
216 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
218 while (blkNo <= partBlkCount) {
219 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
220 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
221 return -1;
224 count = ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
226 if (count <= 0) {
227 print_error(" Error reading from disk: ");
228 return -1;
231 /* see if it's a partition entry */
232 if ((ipod_sectorbuf[0] != 'P') || (ipod_sectorbuf[1] != 'M')) {
233 /* end of partition table -> leave the loop */
234 break;
237 /* Extract the interesting entries */
238 pmMapBlkCnt = be2int(ipod_sectorbuf + 4);
239 pmPyPartStart = be2int(ipod_sectorbuf + 8);
240 pmPartBlkCnt = be2int(ipod_sectorbuf + 12);
242 /* update the number of part map blocks */
243 partBlkCount = pmMapBlkCnt;
245 if (strncmp((char*)(ipod_sectorbuf + 48), "Apple_MDFW", 32)==0) {
246 /* A Firmware partition */
247 ipod->pinfo[i].start = pmPyPartStart;
248 ipod->pinfo[i].size = pmPartBlkCnt;
249 ipod->pinfo[i].type = 0;
250 i++;
251 } else if (strncmp((char*)(ipod_sectorbuf + 48), "Apple_HFS", 32)==0) {
252 /* A HFS partition */
253 ipod->pinfo[i].start = pmPyPartStart;
254 ipod->pinfo[i].size = pmPartBlkCnt;
255 ipod->pinfo[i].type = PARTTYPE_HFS;
256 i++;
259 blkNo++; /* read next partition map entry */
261 } else {
262 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
263 return -1;
266 /* Check that the partition table looks like an ipod:
267 1) Partition 1 is of type 0 (Empty) but isn't empty.
268 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
270 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
271 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
272 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
273 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
274 return -1;
277 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
278 return 0;
281 int read_partition(struct ipod_t* ipod, int outfile)
283 int res;
284 ssize_t n;
285 int bytesleft;
286 int chunksize;
287 int count = ipod->pinfo[0].size;
289 if (ipod_seek(ipod, ipod->start) < 0) {
290 return -1;
293 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
295 bytesleft = count * ipod->sector_size;
296 while (bytesleft > 0) {
297 if (bytesleft > BUFFER_SIZE) {
298 chunksize = BUFFER_SIZE;
299 } else {
300 chunksize = bytesleft;
303 n = ipod_read(ipod, ipod_sectorbuf, chunksize);
305 if (n < 0) {
306 return -1;
309 if (n < chunksize) {
310 fprintf(stderr,
311 "[ERR] Short read in disk_read() - requested %d, got %d\n",
312 chunksize,(int)n);
313 return -1;
316 bytesleft -= n;
318 res = write(outfile,ipod_sectorbuf,n);
320 if (res < 0) {
321 perror("[ERR] write in disk_read");
322 return -1;
325 if (res != n) {
326 fprintf(stderr,
327 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
328 return -1;
332 fprintf(stderr,"[INFO] Done.\n");
333 return 0;
336 int write_partition(struct ipod_t* ipod, int infile)
338 ssize_t res;
339 int n;
340 int bytesread;
341 int byteswritten = 0;
342 int eof;
343 int padding = 0;
345 if (ipod_seek(ipod, ipod->start) < 0) {
346 return -1;
349 fprintf(stderr,"[INFO] Writing input file to device\n");
350 bytesread = 0;
351 eof = 0;
352 while (!eof) {
353 n = read(infile,ipod_sectorbuf,BUFFER_SIZE);
355 if (n < 0) {
356 perror("[ERR] read in disk_write");
357 return -1;
360 if (n < BUFFER_SIZE) {
361 eof = 1;
362 /* We need to pad the last write to a multiple of SECTOR_SIZE */
363 if ((n % ipod->sector_size) != 0) {
364 padding = (ipod->sector_size-(n % ipod->sector_size));
365 n += padding;
369 bytesread += n;
371 res = ipod_write(ipod, ipod_sectorbuf, n);
373 if (res < 0) {
374 print_error(" Error writing to disk: ");
375 fprintf(stderr,"Bytes written: %d\n",byteswritten);
376 return -1;
379 if (res != n) {
380 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
381 return -1;
384 byteswritten += res;
387 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
388 byteswritten-padding,padding);
389 return 0;
392 char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" };
394 int diskmove(struct ipod_t* ipod, int delta)
396 int src_start;
397 int src_end;
398 int bytesleft;
399 int chunksize;
400 int n;
402 src_start = ipod->ipod_directory[1].devOffset;
403 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
404 ipod->ipod_directory[ipod->nimages-1].len +
405 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
406 bytesleft = src_end - src_start;
408 if (ipod_verbose) {
409 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
410 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
411 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
412 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
413 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
414 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
417 while (bytesleft > 0) {
418 if (bytesleft <= BUFFER_SIZE) {
419 chunksize = bytesleft;
420 } else {
421 chunksize = BUFFER_SIZE;
424 if (ipod_verbose) {
425 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
426 chunksize,
427 src_end-chunksize,
428 src_end-chunksize+delta,
429 (unsigned int)(ipod->start+src_end-chunksize),
430 (unsigned int)(ipod->start+src_end-chunksize+delta));
434 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
435 fprintf(stderr,"[ERR] Seek failed\n");
436 return -1;
439 if ((n = ipod_read(ipod,ipod_sectorbuf,chunksize)) < 0) {
440 perror("[ERR] Write failed\n");
441 return -1;
444 if (n < chunksize) {
445 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
446 chunksize,n);
447 return -1;
450 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
451 fprintf(stderr,"[ERR] Seek failed\n");
452 return -1;
455 if ((n = ipod_write(ipod,ipod_sectorbuf,chunksize)) < 0) {
456 perror("[ERR] Write failed\n");
457 return -1;
460 if (n < chunksize) {
461 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
462 ,chunksize,n);
463 return -1;
466 src_end -= chunksize;
467 bytesleft -= chunksize;
470 return 0;
473 int add_bootloader(struct ipod_t* ipod, char* filename, int type)
475 int length;
476 int i;
477 int x;
478 int n;
479 int infile;
480 int paddedlength;
481 int entryOffset;
482 int delta = 0;
483 unsigned long chksum=0;
484 unsigned long filechksum=0;
485 unsigned char header[8]; /* Header for .ipod file */
486 unsigned char* bootloader_buf;
488 /* Calculate the position in the OSOS image where our bootloader will go. */
489 if (ipod->ipod_directory[0].entryOffset>0) {
490 /* Keep the same entryOffset */
491 entryOffset = ipod->ipod_directory[0].entryOffset;
492 } else {
493 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
496 #ifdef WITH_BOOTOBJS
497 if (type == FILETYPE_INTERNAL) {
498 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
499 memcpy(ipod_sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
500 length = ipod->bootloader_len;
501 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
503 else
504 #endif
506 infile=open(filename,O_RDONLY);
507 if (infile < 0) {
508 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
509 return -1;
512 if (type==FILETYPE_DOT_IPOD) {
513 /* First check that the input file is the correct type for this ipod. */
514 n = read(infile,header,8);
515 if (n < 8) {
516 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
517 close(infile);
518 return -1;
521 if (memcmp(header+4, ipod->modelname,4)!=0) {
522 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
523 header[4],header[5],header[6],header[7], ipod->modelname);
524 close(infile);
525 return -1;
528 filechksum = be2int(header);
530 length=filesize(infile)-8;
531 } else {
532 length=filesize(infile);
534 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
536 bootloader_buf = malloc(length);
537 if (bootloader_buf == NULL) {
538 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
539 return -1;
541 /* Now read our bootloader - we need to check it before modifying the partition*/
542 n = read(infile,bootloader_buf,length);
543 close(infile);
545 if (n < 0) {
546 fprintf(stderr,"[ERR] Couldn't read input file\n");
547 return -1;
550 if (type==FILETYPE_DOT_IPOD) {
551 /* Calculate and confirm bootloader checksum */
552 chksum = ipod->modelnum;
553 for (i = 0; i < length; i++) {
554 /* add 8 unsigned bits but keep a 32 bit sum */
555 chksum += bootloader_buf[i];
558 if (chksum == filechksum) {
559 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
560 } else {
561 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
562 return -1;
567 if (entryOffset+paddedlength > BUFFER_SIZE) {
568 fprintf(stderr,"[ERR] Input file too big for buffer\n");
569 return -1;
572 if (ipod_verbose) {
573 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
574 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
575 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
578 /* Check if we have enough space */
579 /* TODO: Check the size of the partition. */
580 if (ipod->nimages > 1) {
581 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
582 ipod->ipod_directory[1].devOffset) {
583 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
584 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
585 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
587 if (diskmove(ipod, delta) < 0) {
588 fprintf(stderr,"[ERR] Image movement failed.\n");
589 return -1;
595 /* We have moved the partitions, now we can write our bootloader */
597 /* Firstly read the original firmware into ipod_sectorbuf */
598 fprintf(stderr,"[INFO] Reading original firmware...\n");
599 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
600 fprintf(stderr,"[ERR] Seek failed\n");
601 return -1;
604 if ((n = ipod_read(ipod,ipod_sectorbuf,entryOffset)) < 0) {
605 perror("[ERR] Read failed\n");
606 return -1;
609 if (n < entryOffset) {
610 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
611 ,entryOffset,n);
612 return -1;
615 #ifdef WITH_BOOTOBJS
616 if (type == FILETYPE_INTERNAL) {
617 memcpy(ipod_sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
619 else
620 #endif
622 memcpy(ipod_sectorbuf+entryOffset,bootloader_buf,length);
623 free(bootloader_buf);
626 /* Calculate new checksum for combined image */
627 chksum = 0;
628 for (i=0;i<entryOffset + length; i++) {
629 chksum += ipod_sectorbuf[i];
632 /* Now write the combined firmware image to the disk */
634 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
635 fprintf(stderr,"[ERR] Seek failed\n");
636 return -1;
639 if ((n = ipod_write(ipod,ipod_sectorbuf,entryOffset+paddedlength)) < 0) {
640 perror("[ERR] Write failed\n");
641 return -1;
644 if (n < (entryOffset+paddedlength)) {
645 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
646 ,entryOffset+paddedlength,n);
647 return -1;
650 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
652 x = ipod->diroffset % ipod->sector_size;
654 /* Read directory */
655 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
656 fprintf(stderr,"[ERR] Seek failed\n");
657 return -1;
660 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
661 if (n < 0) {
662 fprintf(stderr,"[ERR] Directory read failed\n");
663 return -1;
666 /* Update entries for image 0 */
667 int2le(entryOffset+length,ipod_sectorbuf+x+16);
668 int2le(entryOffset,ipod_sectorbuf+x+24);
669 int2le(chksum,ipod_sectorbuf+x+28);
670 int2le(0xffffffff,ipod_sectorbuf+x+36); /* loadAddr */
672 /* Update devOffset entries for other images, if we have moved them */
673 if (delta > 0) {
674 for (i=1;i<ipod->nimages;i++) {
675 int2le(le2int(ipod_sectorbuf+x+i*40+12)+delta,ipod_sectorbuf+x+i*40+12);
679 /* Write directory */
680 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
681 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
682 return -1;
684 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
685 if (n < 0) {
686 fprintf(stderr,"[ERR] Directory write failed\n");
687 return -1;
690 return 0;
693 int delete_bootloader(struct ipod_t* ipod)
695 int length;
696 int i;
697 int x;
698 int n;
699 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
701 /* Removing the bootloader involves adjusting the "length",
702 "chksum" and "entryOffset" values in the osos image's directory
703 entry. */
705 /* Firstly check we have a bootloader... */
707 if (ipod->ipod_directory[0].entryOffset == 0) {
708 fprintf(stderr,"[ERR] No bootloader found.\n");
709 return -1;
712 length = ipod->ipod_directory[0].entryOffset;
714 /* Read the firmware so we can calculate the checksum */
715 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
717 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
718 return -1;
721 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
722 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
723 length,i);
725 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
726 return -1;
729 if (n < i) {
730 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
731 i,n);
732 return -1;
735 chksum = 0;
736 for (i = 0; i < length; i++) {
737 /* add 8 unsigned bits but keep a 32 bit sum */
738 chksum += ipod_sectorbuf[i];
741 /* Now write back the updated directory entry */
743 fprintf(stderr,"[INFO] Updating firmware checksum\n");
745 x = ipod->diroffset % ipod->sector_size;
747 /* Read directory */
748 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
750 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
751 if (n < 0) { return -1; }
753 /* Update entries for image 0 */
754 int2le(length,ipod_sectorbuf+x+16);
755 int2le(0,ipod_sectorbuf+x+24);
756 int2le(chksum,ipod_sectorbuf+x+28);
758 /* Write directory */
759 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
760 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
761 if (n < 0) { return -1; }
763 return 0;
766 int write_firmware(struct ipod_t* ipod, char* filename, int type)
768 int length;
769 int i;
770 int x;
771 int n;
772 int infile;
773 int newsize;
774 int bytesavailable;
775 unsigned long chksum=0;
776 unsigned long filechksum=0;
777 unsigned char header[8]; /* Header for .ipod file */
779 #ifdef WITH_BOOTOBJS
780 if (type == FILETYPE_INTERNAL) {
781 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
782 length = ipod->bootloader_len;
783 infile = -1;
785 else
786 #endif
788 /* First check that the input file is the correct type for this ipod. */
789 infile=open(filename,O_RDONLY);
790 if (infile < 0) {
791 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
792 return -1;
795 if (type==FILETYPE_DOT_IPOD) {
796 n = read(infile,header,8);
797 if (n < 8) {
798 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
799 close(infile);
800 return -1;
803 if (memcmp(header+4, ipod->modelname,4)!=0) {
804 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
805 header[4],header[5],header[6],header[7], ipod->modelname);
806 close(infile);
807 return -1;
810 filechksum = be2int(header);
812 length = filesize(infile)-8;
813 } else {
814 length = filesize(infile);
818 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
820 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
821 length,newsize);
823 if (newsize > BUFFER_SIZE) {
824 fprintf(stderr,"[ERR] Input file too big for buffer\n");
825 if (infile >= 0) close(infile);
826 return -1;
829 /* Check if we have enough space */
830 /* TODO: Check the size of the partition. */
831 if (ipod->nimages > 1) {
832 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
833 if (bytesavailable < newsize) {
834 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
836 /* TODO: Implement image movement */
837 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
838 close(infile);
839 return -1;
843 #ifdef WITH_BOOTOBJS
844 if (type == FILETYPE_INTERNAL) {
845 memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
847 else
848 #endif
850 fprintf(stderr,"[INFO] Reading input file...\n");
851 /* We now know we have enough space, so write it. */
852 n = read(infile,ipod_sectorbuf,length);
853 if (n < 0) {
854 fprintf(stderr,"[ERR] Couldn't read input file\n");
855 close(infile);
856 return -1;
858 close(infile);
861 /* Pad the data with zeros */
862 memset(ipod_sectorbuf+length,0,newsize-length);
864 if (type==FILETYPE_DOT_IPOD) {
865 chksum = ipod->modelnum;
866 for (i = 0; i < length; i++) {
867 /* add 8 unsigned bits but keep a 32 bit sum */
868 chksum += ipod_sectorbuf[i];
871 if (chksum == filechksum) {
872 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
873 } else {
874 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
875 return -1;
879 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
880 fprintf(stderr,"[ERR] Seek failed\n");
881 return -1;
884 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
885 perror("[ERR] Write failed\n");
886 return -1;
889 if (n < newsize) {
890 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
891 ,newsize,n);
892 return -1;
894 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
896 /* Now we need to update the "len", "entryOffset" and "chksum" fields */
897 chksum = 0;
898 for (i = 0; i < length; i++) {
899 /* add 8 unsigned bits but keep a 32 bit sum */
900 chksum += ipod_sectorbuf[i];
903 x = ipod->diroffset % ipod->sector_size;
905 /* Read directory */
906 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
908 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
909 if (n < 0) { return -1; }
911 /* Update entries for image 0 */
912 int2le(length,ipod_sectorbuf+x+16);
913 int2le(0,ipod_sectorbuf+x+24);
914 int2le(chksum,ipod_sectorbuf+x+28);
916 /* Write directory */
917 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
918 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
919 if (n < 0) { return -1; }
921 return 0;
924 int read_firmware(struct ipod_t* ipod, char* filename, int type)
926 int length;
927 int i;
928 int outfile;
929 int n;
930 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
931 unsigned char header[8]; /* Header for .ipod file */
933 if (ipod->ipod_directory[0].entryOffset != 0) {
934 /* We have a bootloader... */
935 length = ipod->ipod_directory[0].entryOffset;
936 } else {
937 length = ipod->ipod_directory[0].len;
940 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
942 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
943 return -1;
946 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
947 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
948 length,i);
950 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
951 return -1;
954 if (n < i) {
955 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
956 i,n);
957 return -1;
960 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
961 if (outfile < 0) {
962 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
963 return -1;
966 if (type == FILETYPE_DOT_IPOD) {
967 chksum = ipod->modelnum;
968 for (i = 0; i < length; i++) {
969 /* add 8 unsigned bits but keep a 32 bit sum */
970 chksum += ipod_sectorbuf[i];
973 int2be(chksum,header);
974 memcpy(header+4, ipod->modelname,4);
976 n = write(outfile,header,8);
977 if (n != 8) {
978 fprintf(stderr,"[ERR] Write error - %d\n",n);
982 n = write(outfile,ipod_sectorbuf,length);
983 if (n != length) {
984 fprintf(stderr,"[ERR] Write error - %d\n",n);
986 close(outfile);
988 return 0;
991 int read_directory(struct ipod_t* ipod)
993 int n;
994 int x;
995 unsigned char* p;
996 unsigned short version;
998 ipod->nimages=0;
1000 /* Read firmware partition header (first 512 bytes of disk - but
1001 let's read a whole sector) */
1003 if (ipod_seek(ipod, ipod->start) < 0) {
1004 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1005 (unsigned int)(ipod->start));
1006 return -1;
1009 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1010 if (n < 0) {
1011 fprintf(stderr,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod->sector_size);
1012 return -1;
1015 if (memcmp(ipod_sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
1016 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1017 return -1;
1020 if (memcmp(ipod_sectorbuf+0x100,"]ih[",4)!=0) {
1021 fprintf(stderr,"[ERR] Bad firmware directory\n");
1022 return -1;
1025 version = le2ushort(ipod_sectorbuf+0x10a);
1026 if ((version != 2) && (version != 3)) {
1027 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1028 version);
1030 ipod->diroffset=le2int(ipod_sectorbuf+0x104) + 0x200;
1032 /* diroffset may not be sector-aligned */
1033 x = ipod->diroffset % ipod->sector_size;
1035 /* Read directory */
1036 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1037 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
1038 return -1;
1041 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1042 if (n < 0) {
1043 fprintf(stderr,"[ERR] Read of directory failed.\n");
1044 return -1;
1047 p = ipod_sectorbuf + x;
1049 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1050 if (p[0] == 0)
1052 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1053 if (n < 0) {
1054 fprintf(stderr,"[ERR] Read of directory failed.\n");
1055 return -1;
1057 p = ipod_sectorbuf;
1060 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
1061 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1062 p+=4;
1063 if (memcmp(p,"soso",4)==0) {
1064 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1065 } else if (memcmp(p,"crsr",4)==0) {
1066 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1067 } else if (memcmp(p,"dpua",4)==0) {
1068 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1069 } else if (memcmp(p,"ebih",4)==0) {
1070 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1071 } else {
1072 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1073 p[0],p[1],p[2],p[3]);
1075 p+=4;
1076 ipod->ipod_directory[ipod->nimages].id=le2int(p);
1077 p+=4;
1078 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
1079 p+=4;
1080 ipod->ipod_directory[ipod->nimages].len=le2int(p);
1081 p+=4;
1082 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
1083 p+=4;
1084 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
1085 p+=4;
1086 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
1087 p+=4;
1088 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
1089 p+=4;
1090 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
1091 p+=4;
1092 ipod->nimages++;
1095 if ((ipod->nimages > 1) && (version==2)) {
1096 /* The 3g firmware image doesn't appear to have a version, so
1097 let's make one up... Note that this is never written back to the
1098 ipod, so it's OK to do. */
1100 if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; }
1102 ipod->fwoffset = ipod->start;
1103 } else {
1104 ipod->fwoffset = ipod->start + ipod->sector_size;
1107 return 0;
1110 int list_images(struct ipod_t* ipod)
1112 int i;
1114 if (ipod_verbose) {
1115 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1116 for (i = 0 ; i < ipod->nimages; i++) {
1117 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
1118 ftypename[ipod->ipod_directory[i].ftype],
1119 ipod->ipod_directory[i].id,
1120 ipod->ipod_directory[i].devOffset,
1121 ipod->ipod_directory[i].len,
1122 ipod->ipod_directory[i].addr,
1123 ipod->ipod_directory[i].entryOffset,
1124 ipod->ipod_directory[i].chksum,
1125 ipod->ipod_directory[i].vers,
1126 ipod->ipod_directory[i].loadAddr,
1127 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
1131 printf("\n");
1132 printf("Listing firmware partition contents:\n");
1133 printf("\n");
1135 for (i = 0 ; i < ipod->nimages; i++) {
1136 printf("Image %d:\n",i+1);
1137 switch(ipod->ipod_directory[i].ftype) {
1138 case FTYPE_OSOS:
1139 if (ipod->ipod_directory[i].entryOffset==0) {
1140 printf(" Main firmware - %d bytes\n",
1141 ipod->ipod_directory[i].len);
1142 } else {
1143 printf(" Main firmware - %d bytes\n",
1144 ipod->ipod_directory[i].entryOffset);
1145 printf(" Third-party bootloader - %d bytes\n",
1146 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
1148 break;
1149 default:
1150 printf(" %s - %d bytes\n",
1151 ftypename[ipod->ipod_directory[i].ftype],
1152 ipod->ipod_directory[i].len);
1155 printf("\n");
1157 return 0;
1160 int getmodel(struct ipod_t* ipod, int ipod_version)
1162 switch (ipod_version) {
1163 case 0x01:
1164 ipod->modelstr="1st or 2nd Generation";
1165 ipod->modelnum = 19;
1166 ipod->modelname = "1g2g";
1167 ipod->targetname = "ipod1g2g";
1168 #ifdef WITH_BOOTOBJS
1169 ipod->bootloader = ipod1g2g;
1170 ipod->bootloader_len = LEN_ipod1g2g;
1171 #endif
1172 break;
1173 case 0x02:
1174 ipod->modelstr="3rd Generation";
1175 ipod->modelnum = 7;
1176 ipod->modelname = "ip3g";
1177 ipod->targetname = "ipod3g";
1178 #ifdef WITH_BOOTOBJS
1179 ipod->bootloader = ipod3g;
1180 ipod->bootloader_len = LEN_ipod3g;
1181 #endif
1182 break;
1183 case 0x40:
1184 ipod->modelstr="1st Generation Mini";
1185 ipod->modelnum = 9;
1186 ipod->modelname = "mini";
1187 ipod->targetname = "ipodmini1g";
1188 #ifdef WITH_BOOTOBJS
1189 ipod->bootloader = ipodmini;
1190 ipod->bootloader_len = LEN_ipodmini;
1191 #endif
1192 break;
1193 case 0x50:
1194 ipod->modelstr="4th Generation";
1195 ipod->modelnum = 8;
1196 ipod->modelname = "ip4g";
1197 ipod->targetname = "ipod4gray";
1198 #ifdef WITH_BOOTOBJS
1199 ipod->bootloader = ipod4g;
1200 ipod->bootloader_len = LEN_ipod4g;
1201 #endif
1202 break;
1203 case 0x60:
1204 ipod->modelstr="Photo/Color";
1205 ipod->modelnum = 3;
1206 ipod->modelname = "ipco";
1207 ipod->targetname = "ipodcolor";
1208 #ifdef WITH_BOOTOBJS
1209 ipod->bootloader = ipodcolor;
1210 ipod->bootloader_len = LEN_ipodcolor;
1211 #endif
1212 break;
1213 case 0x70:
1214 ipod->modelstr="2nd Generation Mini";
1215 ipod->modelnum = 11;
1216 ipod->modelname = "mn2g";
1217 ipod->targetname = "ipodmini2g";
1218 #ifdef WITH_BOOTOBJS
1219 ipod->bootloader = ipodmini2g;
1220 ipod->bootloader_len = LEN_ipodmini2g;
1221 #endif
1222 break;
1223 case 0xc0:
1224 ipod->modelstr="1st Generation Nano";
1225 ipod->modelnum = 4;
1226 ipod->modelname = "nano";
1227 ipod->targetname = "ipodnano";
1228 #ifdef WITH_BOOTOBJS
1229 ipod->bootloader = ipodnano;
1230 ipod->bootloader_len = LEN_ipodnano;
1231 #endif
1232 break;
1233 case 0xb0:
1234 ipod->modelstr="Video (aka 5th Generation)";
1235 ipod->modelnum = 5;
1236 ipod->modelname = "ipvd";
1237 ipod->targetname = "ipodvideo";
1238 #ifdef WITH_BOOTOBJS
1239 ipod->bootloader = ipodvideo;
1240 ipod->bootloader_len = LEN_ipodvideo;
1241 #endif
1242 break;
1243 case 0x100:
1244 ipod->modelstr="2nd Generation Nano";
1245 ipod->modelnum = 0;
1246 ipod->targetname = NULL;
1247 #ifdef WITH_BOOTOBJS
1248 ipod->bootloader = NULL;
1249 ipod->bootloader_len = 0;
1250 #endif
1251 break;
1252 default:
1253 ipod->modelname = NULL;
1254 ipod->modelnum = 0;
1255 ipod->targetname = NULL;
1256 #ifdef WITH_BOOTOBJS
1257 ipod->bootloader = NULL;
1258 ipod->bootloader_len = 0;
1259 #endif
1260 return -1;
1262 return 0;
1265 /* returns number of found ipods or -1 if no ipods found and permission
1266 * for raw disc access was denied. */
1267 int ipod_scan(struct ipod_t* ipod)
1269 int i;
1270 int n = 0;
1271 int ipod_version;
1272 char last_ipod[4096];
1273 int denied = 0;
1274 int result;
1276 printf("[INFO] Scanning disk devices...\n");
1278 for (i = 0; i <= 25 ; i++) {
1279 #ifdef __WIN32__
1280 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
1281 #elif defined(linux) || defined (__linux)
1282 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
1283 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1284 || defined(__bsdi__) || defined(__DragonFly__)
1285 sprintf(ipod->diskname,"/dev/da%d",i);
1286 #elif defined(__APPLE__) && defined(__MACH__)
1287 sprintf(ipod->diskname,"/dev/disk%d",i);
1288 #else
1289 #error No disk paths defined for this platform
1290 #endif
1291 if ((result = ipod_open(ipod, 1)) < 0) {
1292 if(result == -2) {
1293 denied++;
1295 ipod_close(ipod);
1296 continue;
1299 if (read_partinfo(ipod,1) < 0) {
1300 ipod_close(ipod);
1301 continue;
1304 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
1305 ipod_close(ipod);
1306 continue;
1309 if (read_directory(ipod) < 0) {
1310 ipod_close(ipod);
1311 continue;
1314 ipod_version=(ipod->ipod_directory[0].vers>>8);
1315 if (getmodel(ipod,ipod_version) < 0) {
1316 ipod_close(ipod);
1317 continue;
1320 #ifdef __WIN32__
1321 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1322 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
1323 #else
1324 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1325 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
1326 #endif
1327 n++;
1328 strcpy(last_ipod,ipod->diskname);
1329 ipod_close(ipod);
1332 if (n==1) {
1333 /* Remember the disk name */
1334 strcpy(ipod->diskname,last_ipod);
1336 else if(n == 0 && denied) {
1337 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied);
1338 #ifdef __WIN32__
1339 printf("[ERR] You need to run this program with administrator priviledges!\n");
1340 #else
1341 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1342 #endif
1344 return (n == 0 && denied) ? -1 : n;
1347 static void put_int32le(uint32_t x, unsigned char* p)
1349 p[0] = x & 0xff;
1350 p[1] = (x >> 8) & 0xff;
1351 p[2] = (x >> 16) & 0xff;
1352 p[3] = (x >> 24) & 0xff;
1355 int write_dos_partition_table(struct ipod_t* ipod)
1357 unsigned char* p;
1358 int i, n;
1359 uint32_t type;
1361 /* Only support 512-byte sectors at the moment */
1362 if ( ipod->sector_size != 512 )
1364 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1365 return -1;
1368 /* Firstly zero the entire MBR */
1369 memset(ipod_sectorbuf, 0, ipod->sector_size);
1371 /* Now add the partition info */
1372 for (i=0; i < 4 ; i++)
1374 p = ipod_sectorbuf + 0x1be + i*16;
1376 /* Ensure first partition is type 0, and second is 0xb */
1377 if (i==0) { type = 0; }
1378 else if (i==1) { type = 0xb; }
1379 else { type = ipod->pinfo[i].type; }
1381 put_int32le(type, p + 4);
1382 put_int32le(ipod->pinfo[i].start, p + 8);
1383 put_int32le(ipod->pinfo[i].size, p + 12);
1386 /* Finally add the magic */
1387 ipod_sectorbuf[0x1fe] = 0x55;
1388 ipod_sectorbuf[0x1ff] = 0xaa;
1390 if (ipod_seek(ipod, 0) < 0) {
1391 fprintf(stderr,"[ERR] Seek failed writing MBR\n");
1392 return -1;
1395 /* Write MBR */
1396 if ((n = ipod_write(ipod, ipod_sectorbuf, ipod->sector_size)) < 0) {
1397 perror("[ERR] Write failed\n");
1398 return -1;
1401 return 0;
1404 /* Get the XML Device Information, as documented here:
1406 http://www.ipodlinux.org/wiki/Device_Information
1409 int ipod_get_xmlinfo(struct ipod_t* ipod)
1411 unsigned char hdr[255];
1412 unsigned char buf[255];
1413 char* p;
1414 int psize;
1415 int npages;
1416 int i;
1418 if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0)
1420 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1421 return -1;
1424 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1425 win32 */
1426 memcpy(hdr, buf, sizeof(hdr));
1428 npages = hdr[3];
1430 psize = npages * 0xf8; /* Hopefully this is enough. */
1432 ipod->xmlinfo = malloc(psize);
1433 ipod->xmlinfo_len = 0;
1435 if (ipod->xmlinfo == NULL) {
1436 fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n");
1437 return -1;
1440 p = ipod->xmlinfo;
1442 for (i=0; i < npages; i++) {
1443 if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) {
1444 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1445 return -1;
1448 if ((buf[3] + ipod->xmlinfo_len) > psize) {
1449 fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n");
1450 free(ipod->xmlinfo);
1451 ipod->xmlinfo = NULL;
1452 ipod->xmlinfo_len = 0;
1453 return -1;
1456 memcpy(p, buf + 4, buf[3]);
1457 p += buf[3];
1458 ipod->xmlinfo_len += buf[3];
1461 /* NULL-terminate the XML info */
1462 *p = 0;
1464 fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len);
1466 return 0;
1469 void ipod_get_ramsize(struct ipod_t* ipod)
1471 const char needle[] = "<key>RAM</key>\n<integer>";
1472 char* p;
1474 if (ipod->xmlinfo == NULL)
1475 return;
1477 p = strstr(ipod->xmlinfo, needle);
1479 if (p) {
1480 ipod->ramsize = atoi(p + sizeof(needle) - 1);
1484 #ifndef RBUTIL
1486 static inline uint32_t getuint32le(unsigned char* buf)
1488 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
1490 return res;
1493 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1494 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1498 static bool testMarker(int marker)
1500 int mask, decrypt, temp1, temp2;
1502 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
1503 decrypt = marker ^ mask;
1504 temp1=(int)((unsigned int)decrypt>>24);
1505 temp2=decrypt<<8;
1507 if (temp1==0)
1508 return false;
1510 temp2=(int)((unsigned int)temp2>>24);
1511 decrypt=decrypt<<16;
1512 decrypt=(int)((unsigned int)decrypt>>24);
1514 if ((temp1 < temp2) && (temp2 < decrypt))
1516 temp1 = temp1 & 0xf;
1517 temp2 = temp2 & 0xf;
1518 decrypt = decrypt & 0xf;
1520 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
1522 return true;
1525 return false;
1528 static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
1530 int constant = 0x54c3a298;
1531 int key=0;
1532 int nkeys = 0;
1533 int aMarker=0;
1534 int pos=0;
1535 int c, count;
1536 int temp1;
1537 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
1539 for (c = 0; c < 8; c++)
1541 pos = offset[c]*4;
1542 aMarker = getuint32le(data + pos);
1544 if (testMarker(aMarker))
1546 if (c<7)
1547 pos =(offset[c+1]*4)+4;
1548 else
1549 pos =(offset[0]*4)+4;
1551 key=0;
1553 temp1=aMarker;
1555 for (count=0;count<2;count++){
1556 int word = getuint32le(data + pos);
1557 temp1 = aMarker;
1558 temp1 = temp1^word;
1559 temp1 = temp1^constant;
1560 key = temp1;
1561 pos = pos+4;
1563 int r1=0x6f;
1564 int r2=0;
1565 int r12;
1566 int r14;
1567 unsigned int r_tmp;
1569 for (count=2;count<128;count=count+2){
1570 r2=getuint32le(data+count*4);
1571 r12=getuint32le(data+(count*4)+4);
1572 r_tmp=(unsigned int)r12>>16;
1573 r14=r2 | ((int)r_tmp);
1574 r2=r2&0xffff;
1575 r2=r2 | r12;
1576 r1=r1^r14;
1577 r1=r1+r2;
1579 key=key^r1;
1581 // Invert key, little endian
1582 this_key[0] = key & 0xff;
1583 this_key[1] = (key >> 8) & 0xff;
1584 this_key[2] = (key >> 16) & 0xff;
1585 this_key[3] = (key >> 24) & 0xff;
1586 nkeys++;
1589 return nkeys;
1592 static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
1594 int n;
1596 /* Firstly read the security block and find the RC4 key. This is
1597 in the sector preceeding the AUPD image. */
1599 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
1600 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
1601 return -1;
1604 if ((n = ipod_read(ipod, ipod_sectorbuf, 512)) < 0) {
1605 return -1;
1608 n = GetSecurityBlockKey(ipod_sectorbuf, key);
1610 if (n != 1)
1612 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
1613 return -1;
1616 return 0;
1619 int read_aupd(struct ipod_t* ipod, char* filename)
1621 int length;
1622 int i;
1623 int outfile;
1624 int n;
1625 int aupd;
1626 struct rc4_key_t rc4;
1627 unsigned char key[4];
1628 unsigned long chksum=0;
1630 aupd = 0;
1631 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
1633 aupd++;
1636 if (aupd == ipod->nimages)
1638 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
1639 return -1;
1642 length = ipod->ipod_directory[aupd].len;
1644 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1646 if (find_key(ipod, aupd, key) < 0)
1648 return -1;
1651 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
1653 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
1654 return -1;
1657 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1659 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
1660 return -1;
1663 if (n < i) {
1664 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1665 i,n);
1666 return -1;
1669 /* Perform the decryption - this is standard (A)RC4 */
1670 matrixArc4Init(&rc4, key, 4);
1671 matrixArc4(&rc4, ipod_sectorbuf, ipod_sectorbuf, length);
1673 chksum = 0;
1674 for (i = 0; i < (int)length; i++) {
1675 /* add 8 unsigned bits but keep a 32 bit sum */
1676 chksum += ipod_sectorbuf[i];
1679 if (chksum != ipod->ipod_directory[aupd].chksum)
1681 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
1682 return -1;
1684 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
1686 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
1687 if (outfile < 0) {
1688 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1689 return -1;
1692 n = write(outfile,ipod_sectorbuf,length);
1693 if (n != length) {
1694 fprintf(stderr,"[ERR] Write error - %d\n",n);
1696 close(outfile);
1698 return 0;
1701 int write_aupd(struct ipod_t* ipod, char* filename)
1703 unsigned int length;
1704 int i;
1705 int x;
1706 int n;
1707 int infile;
1708 int newsize;
1709 int aupd;
1710 unsigned long chksum=0;
1711 struct rc4_key_t rc4;
1712 unsigned char key[4];
1714 /* First check that the input file is the correct type for this ipod. */
1715 infile=open(filename,O_RDONLY);
1716 if (infile < 0) {
1717 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
1718 return -1;
1721 length = filesize(infile);
1722 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
1724 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1725 length,newsize);
1727 if (newsize > BUFFER_SIZE) {
1728 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1729 if (infile >= 0) close(infile);
1730 return -1;
1733 /* Find aupd image number */
1734 aupd = 0;
1735 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
1737 aupd++;
1740 if (aupd == ipod->nimages)
1742 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
1743 return -1;
1746 if (length != ipod->ipod_directory[aupd].len)
1748 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
1749 ipod->ipod_directory[aupd].len, filename, length);
1750 return -1;
1753 if (find_key(ipod, aupd, key) < 0)
1755 return -1;
1758 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
1760 /* We now know we have enough space, so write it. */
1762 fprintf(stderr,"[INFO] Reading input file...\n");
1763 n = read(infile,ipod_sectorbuf,length);
1764 if (n < 0) {
1765 fprintf(stderr,"[ERR] Couldn't read input file\n");
1766 close(infile);
1767 return -1;
1769 close(infile);
1771 /* Pad the data with zeros */
1772 memset(ipod_sectorbuf+length,0,newsize-length);
1774 /* Calculate the new checksum (before we encrypt) */
1775 chksum = 0;
1776 for (i = 0; i < (int)length; i++) {
1777 /* add 8 unsigned bits but keep a 32 bit sum */
1778 chksum += ipod_sectorbuf[i];
1781 /* Perform the encryption - this is standard (A)RC4 */
1782 matrixArc4Init(&rc4, key, 4);
1783 matrixArc4(&rc4, ipod_sectorbuf, ipod_sectorbuf, length);
1785 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
1786 fprintf(stderr,"[ERR] Seek failed\n");
1787 return -1;
1790 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
1791 perror("[ERR] Write failed\n");
1792 return -1;
1795 if (n < newsize) {
1796 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
1797 ,newsize,n);
1798 return -1;
1800 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1802 x = ipod->diroffset % ipod->sector_size;
1804 /* Read directory */
1805 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1807 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1808 if (n < 0) { return -1; }
1810 /* Update checksum */
1811 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod_sectorbuf + x + aupd*40 + 28));
1812 int2le(chksum,ipod_sectorbuf+x+aupd*40+28);
1814 /* Write directory */
1815 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1816 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
1817 if (n < 0) { return -1; }
1819 return 0;
1822 #endif