Increase MAXTHREADS
[Rockbox.git] / rbutil / ipodpatcher / ipodpatcher.c
blob08ba9263d2bf133c9f2070cafb0e9b840644b3fc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006-2007 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26 #include <stdbool.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 #include "parttypes.h"
31 #include "ipodio.h"
32 #include "ipodpatcher.h"
34 #ifdef WITH_BOOTOBJS
35 #include "ipod1g2g.h"
36 #include "ipod3g.h"
37 #include "ipod4g.h"
38 #include "ipodmini.h"
39 #include "ipodmini2g.h"
40 #include "ipodcolor.h"
41 #include "ipodnano.h"
42 #include "ipodvideo.h"
43 #endif
45 #ifndef RBUTIL
46 #include "arc4.h"
47 #endif
49 extern int verbose;
51 unsigned char* sectorbuf;
53 /* The following string appears at the start of the firmware partition */
54 static const char *apple_stop_sign = "{{~~ /-----\\ "\
55 "{{~~ / \\ "\
56 "{{~~| | "\
57 "{{~~| S T O P | "\
58 "{{~~| | "\
59 "{{~~ \\ / "\
60 "{{~~ \\-----/ "\
61 "Copyright(C) 200"\
62 "1 Apple Computer"\
63 ", Inc.----------"\
64 "----------------"\
65 "----------------"\
66 "----------------"\
67 "----------------"\
68 "----------------"\
69 "---------------";
71 /* Windows requires the buffer for disk I/O to be aligned in memory on a
72 multiple of the disk volume size - so we use a single global variable
73 and initialise it with ipod_alloc_buf()
76 char* get_parttype(int pt)
78 int i;
79 static char unknown[]="Unknown";
81 if (pt == PARTTYPE_HFS) {
82 return "HFS/HFS+";
85 i=0;
86 while (parttypes[i].name != NULL) {
87 if (parttypes[i].type == pt) {
88 return (parttypes[i].name);
90 i++;
93 return unknown;
96 off_t filesize(int fd) {
97 struct stat buf;
99 if (fstat(fd,&buf) < 0) {
100 perror("[ERR] Checking filesize of input file");
101 return -1;
102 } else {
103 return(buf.st_size);
107 /* Partition table parsing code taken from Rockbox */
109 #define MAX_SECTOR_SIZE 2048
110 #define SECTOR_SIZE 512
112 static inline unsigned short le2ushort(unsigned char* buf)
114 unsigned short res = (buf[1] << 8) | buf[0];
116 return res;
119 static inline int le2int(unsigned char* buf)
121 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
123 return res;
126 static inline int be2int(unsigned char* buf)
128 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
130 return res;
133 static inline int getint16le(char* buf)
135 int16_t res = (buf[1] << 8) | buf[0];
137 return res;
140 static inline void short2le(unsigned short val, unsigned char* addr)
142 addr[0] = val & 0xFF;
143 addr[1] = (val >> 8) & 0xff;
146 static inline void int2le(unsigned int val, unsigned char* addr)
148 addr[0] = val & 0xFF;
149 addr[1] = (val >> 8) & 0xff;
150 addr[2] = (val >> 16) & 0xff;
151 addr[3] = (val >> 24) & 0xff;
154 static inline void int2be(unsigned int val, unsigned char* addr)
156 addr[0] = (val >> 24) & 0xff;
157 addr[1] = (val >> 16) & 0xff;
158 addr[2] = (val >> 8) & 0xff;
159 addr[3] = val & 0xFF;
163 #define BYTES2INT32(array,pos)\
164 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
165 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
167 int read_partinfo(struct ipod_t* ipod, int silent)
169 int i;
170 unsigned long count;
172 count = ipod_read(ipod,sectorbuf, ipod->sector_size);
174 if (count <= 0) {
175 print_error(" Error reading from disk: ");
176 return -1;
179 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
181 if ((sectorbuf[510] == 0x55) && (sectorbuf[511] == 0xaa)) {
182 /* DOS partition table */
183 ipod->macpod = 0;
184 /* parse partitions */
185 for ( i = 0; i < 4; i++ ) {
186 unsigned char* ptr = sectorbuf + 0x1be + 16*i;
187 ipod->pinfo[i].type = ptr[4];
188 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
189 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
191 /* extended? */
192 if ( ipod->pinfo[i].type == 5 ) {
193 /* not handled yet */
196 } else if ((sectorbuf[0] == 'E') && (sectorbuf[1] == 'R')) {
197 /* Apple Partition Map */
199 /* APM parsing code based on the check_mac_partitions() function in
200 ipodloader2 - written by Thomas Tempelmann and released
201 under the GPL. */
203 int blkNo = 1;
204 int partBlkCount = 1;
205 int partBlkSizMul = sectorbuf[2] / 2;
207 int pmMapBlkCnt; /* # of blks in partition map */
208 int pmPyPartStart; /* physical start blk of partition */
209 int pmPartBlkCnt; /* # of blks in this partition */
210 int i = 0;
212 ipod->macpod = 1;
214 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
216 while (blkNo <= partBlkCount) {
217 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
218 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
219 return -1;
222 count = ipod_read(ipod, sectorbuf, ipod->sector_size);
224 if (count <= 0) {
225 print_error(" Error reading from disk: ");
226 return -1;
229 /* see if it's a partition entry */
230 if ((sectorbuf[0] != 'P') || (sectorbuf[1] != 'M')) {
231 /* end of partition table -> leave the loop */
232 break;
235 /* Extract the interesting entries */
236 pmMapBlkCnt = be2int(sectorbuf + 4);
237 pmPyPartStart = be2int(sectorbuf + 8);
238 pmPartBlkCnt = be2int(sectorbuf + 12);
240 /* update the number of part map blocks */
241 partBlkCount = pmMapBlkCnt;
243 if (strncmp((char*)(sectorbuf + 48), "Apple_MDFW", 32)==0) {
244 /* A Firmware partition */
245 ipod->pinfo[i].start = pmPyPartStart;
246 ipod->pinfo[i].size = pmPartBlkCnt;
247 ipod->pinfo[i].type = 0;
248 i++;
249 } else if (strncmp((char*)(sectorbuf + 48), "Apple_HFS", 32)==0) {
250 /* A HFS partition */
251 ipod->pinfo[i].start = pmPyPartStart;
252 ipod->pinfo[i].size = pmPartBlkCnt;
253 ipod->pinfo[i].type = PARTTYPE_HFS;
254 i++;
257 blkNo++; /* read next partition map entry */
259 } else {
260 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
261 return -1;
264 /* Check that the partition table looks like an ipod:
265 1) Partition 1 is of type 0 (Empty) but isn't empty.
266 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
268 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
269 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
270 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
271 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
272 return -1;
275 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
276 return 0;
279 int read_partition(struct ipod_t* ipod, int outfile)
281 int res;
282 ssize_t n;
283 int bytesleft;
284 int chunksize;
285 int count = ipod->pinfo[0].size;
287 if (ipod_seek(ipod, ipod->start) < 0) {
288 return -1;
291 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
293 bytesleft = count * ipod->sector_size;
294 while (bytesleft > 0) {
295 if (bytesleft > BUFFER_SIZE) {
296 chunksize = BUFFER_SIZE;
297 } else {
298 chunksize = bytesleft;
301 n = ipod_read(ipod, sectorbuf, chunksize);
303 if (n < 0) {
304 return -1;
307 if (n < chunksize) {
308 fprintf(stderr,
309 "[ERR] Short read in disk_read() - requested %d, got %d\n",
310 chunksize,(int)n);
311 return -1;
314 bytesleft -= n;
316 res = write(outfile,sectorbuf,n);
318 if (res < 0) {
319 perror("[ERR] write in disk_read");
320 return -1;
323 if (res != n) {
324 fprintf(stderr,
325 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
326 return -1;
330 fprintf(stderr,"[INFO] Done.\n");
331 return 0;
334 int write_partition(struct ipod_t* ipod, int infile)
336 ssize_t res;
337 int n;
338 int bytesread;
339 int byteswritten = 0;
340 int eof;
341 int padding = 0;
343 if (ipod_seek(ipod, ipod->start) < 0) {
344 return -1;
347 fprintf(stderr,"[INFO] Writing input file to device\n");
348 bytesread = 0;
349 eof = 0;
350 while (!eof) {
351 n = read(infile,sectorbuf,BUFFER_SIZE);
353 if (n < 0) {
354 perror("[ERR] read in disk_write");
355 return -1;
358 if (n < BUFFER_SIZE) {
359 eof = 1;
360 /* We need to pad the last write to a multiple of SECTOR_SIZE */
361 if ((n % ipod->sector_size) != 0) {
362 padding = (ipod->sector_size-(n % ipod->sector_size));
363 n += padding;
367 bytesread += n;
369 res = ipod_write(ipod, sectorbuf, n);
371 if (res < 0) {
372 print_error(" Error writing to disk: ");
373 fprintf(stderr,"Bytes written: %d\n",byteswritten);
374 return -1;
377 if (res != n) {
378 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
379 return -1;
382 byteswritten += res;
385 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
386 byteswritten-padding,padding);
387 return 0;
390 char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" };
392 int diskmove(struct ipod_t* ipod, int delta)
394 int src_start;
395 int src_end;
396 int bytesleft;
397 int chunksize;
398 int n;
400 src_start = ipod->ipod_directory[1].devOffset;
401 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
402 ipod->ipod_directory[ipod->nimages-1].len +
403 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
404 bytesleft = src_end - src_start;
406 if (verbose) {
407 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
408 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
409 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
410 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
411 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
412 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
415 while (bytesleft > 0) {
416 if (bytesleft <= BUFFER_SIZE) {
417 chunksize = bytesleft;
418 } else {
419 chunksize = BUFFER_SIZE;
422 if (verbose) {
423 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
424 chunksize,
425 src_end-chunksize,
426 src_end-chunksize+delta,
427 (unsigned int)(ipod->start+src_end-chunksize),
428 (unsigned int)(ipod->start+src_end-chunksize+delta));
432 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
433 fprintf(stderr,"[ERR] Seek failed\n");
434 return -1;
437 if ((n = ipod_read(ipod,sectorbuf,chunksize)) < 0) {
438 perror("[ERR] Write failed\n");
439 return -1;
442 if (n < chunksize) {
443 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
444 chunksize,n);
445 return -1;
448 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
449 fprintf(stderr,"[ERR] Seek failed\n");
450 return -1;
453 if ((n = ipod_write(ipod,sectorbuf,chunksize)) < 0) {
454 perror("[ERR] Write failed\n");
455 return -1;
458 if (n < chunksize) {
459 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
460 ,chunksize,n);
461 return -1;
464 src_end -= chunksize;
465 bytesleft -= chunksize;
468 return 0;
471 int add_bootloader(struct ipod_t* ipod, char* filename, int type)
473 int length;
474 int i;
475 int x;
476 int n;
477 int infile;
478 int paddedlength;
479 int entryOffset;
480 int delta = 0;
481 unsigned long chksum=0;
482 unsigned long filechksum=0;
483 unsigned char header[8]; /* Header for .ipod file */
484 unsigned char* bootloader_buf;
486 /* Calculate the position in the OSOS image where our bootloader will go. */
487 if (ipod->ipod_directory[0].entryOffset>0) {
488 /* Keep the same entryOffset */
489 entryOffset = ipod->ipod_directory[0].entryOffset;
490 } else {
491 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
494 #ifdef WITH_BOOTOBJS
495 if (type == FILETYPE_INTERNAL) {
496 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
497 memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
498 length = ipod->bootloader_len;
499 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
501 else
502 #endif
504 infile=open(filename,O_RDONLY);
505 if (infile < 0) {
506 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
507 return -1;
510 if (type==FILETYPE_DOT_IPOD) {
511 /* First check that the input file is the correct type for this ipod. */
512 n = read(infile,header,8);
513 if (n < 8) {
514 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
515 close(infile);
516 return -1;
519 if (memcmp(header+4, ipod->modelname,4)!=0) {
520 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
521 header[4],header[5],header[6],header[7], ipod->modelname);
522 close(infile);
523 return -1;
526 filechksum = be2int(header);
528 length=filesize(infile)-8;
529 } else {
530 length=filesize(infile);
532 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
534 bootloader_buf = malloc(length);
535 if (bootloader_buf == NULL) {
536 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
537 return -1;
539 /* Now read our bootloader - we need to check it before modifying the partition*/
540 n = read(infile,bootloader_buf,length);
541 close(infile);
543 if (n < 0) {
544 fprintf(stderr,"[ERR] Couldn't read input file\n");
545 return -1;
548 if (type==FILETYPE_DOT_IPOD) {
549 /* Calculate and confirm bootloader checksum */
550 chksum = ipod->modelnum;
551 for (i = 0; i < length; i++) {
552 /* add 8 unsigned bits but keep a 32 bit sum */
553 chksum += bootloader_buf[i];
556 if (chksum == filechksum) {
557 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
558 } else {
559 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
560 return -1;
565 if (entryOffset+paddedlength > BUFFER_SIZE) {
566 fprintf(stderr,"[ERR] Input file too big for buffer\n");
567 return -1;
570 if (verbose) {
571 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
572 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
573 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
576 /* Check if we have enough space */
577 /* TODO: Check the size of the partition. */
578 if (ipod->nimages > 1) {
579 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
580 ipod->ipod_directory[1].devOffset) {
581 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
582 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
583 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
585 if (diskmove(ipod, delta) < 0) {
586 fprintf(stderr,"[ERR] Image movement failed.\n");
587 return -1;
593 /* We have moved the partitions, now we can write our bootloader */
595 /* Firstly read the original firmware into sectorbuf */
596 fprintf(stderr,"[INFO] Reading original firmware...\n");
597 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
598 fprintf(stderr,"[ERR] Seek failed\n");
599 return -1;
602 if ((n = ipod_read(ipod,sectorbuf,entryOffset)) < 0) {
603 perror("[ERR] Read failed\n");
604 return -1;
607 if (n < entryOffset) {
608 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
609 ,entryOffset,n);
610 return -1;
613 #ifdef WITH_BOOTOBJS
614 if (type == FILETYPE_INTERNAL) {
615 memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
617 else
618 #endif
620 memcpy(sectorbuf+entryOffset,bootloader_buf,length);
621 free(bootloader_buf);
624 /* Calculate new checksum for combined image */
625 chksum = 0;
626 for (i=0;i<entryOffset + length; i++) {
627 chksum += sectorbuf[i];
630 /* Now write the combined firmware image to the disk */
632 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
633 fprintf(stderr,"[ERR] Seek failed\n");
634 return -1;
637 if ((n = ipod_write(ipod,sectorbuf,entryOffset+paddedlength)) < 0) {
638 perror("[ERR] Write failed\n");
639 return -1;
642 if (n < (entryOffset+paddedlength)) {
643 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
644 ,entryOffset+paddedlength,n);
645 return -1;
648 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
650 x = ipod->diroffset % ipod->sector_size;
652 /* Read directory */
653 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
654 fprintf(stderr,"[ERR] Seek failed\n");
655 return -1;
658 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
659 if (n < 0) {
660 fprintf(stderr,"[ERR] Directory read failed\n");
661 return -1;
664 /* Update entries for image 0 */
665 int2le(entryOffset+length,sectorbuf+x+16);
666 int2le(entryOffset,sectorbuf+x+24);
667 int2le(chksum,sectorbuf+x+28);
668 int2le(0xffffffff,sectorbuf+x+36); /* loadAddr */
670 /* Update devOffset entries for other images, if we have moved them */
671 if (delta > 0) {
672 for (i=1;i<ipod->nimages;i++) {
673 int2le(le2int(sectorbuf+x+i*40+12)+delta,sectorbuf+x+i*40+12);
677 /* Write directory */
678 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
679 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
680 return -1;
682 n=ipod_write(ipod, sectorbuf, ipod->sector_size);
683 if (n < 0) {
684 fprintf(stderr,"[ERR] Directory write failed\n");
685 return -1;
688 return 0;
691 int delete_bootloader(struct ipod_t* ipod)
693 int length;
694 int i;
695 int x;
696 int n;
697 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
699 /* Removing the bootloader involves adjusting the "length",
700 "chksum" and "entryOffset" values in the osos image's directory
701 entry. */
703 /* Firstly check we have a bootloader... */
705 if (ipod->ipod_directory[0].entryOffset == 0) {
706 fprintf(stderr,"[ERR] No bootloader found.\n");
707 return -1;
710 length = ipod->ipod_directory[0].entryOffset;
712 /* Read the firmware so we can calculate the checksum */
713 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
715 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
716 return -1;
719 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
720 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
721 length,i);
723 if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
724 return -1;
727 if (n < i) {
728 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
729 i,n);
730 return -1;
733 chksum = 0;
734 for (i = 0; i < length; i++) {
735 /* add 8 unsigned bits but keep a 32 bit sum */
736 chksum += sectorbuf[i];
739 /* Now write back the updated directory entry */
741 fprintf(stderr,"[INFO] Updating firmware checksum\n");
743 x = ipod->diroffset % ipod->sector_size;
745 /* Read directory */
746 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
748 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
749 if (n < 0) { return -1; }
751 /* Update entries for image 0 */
752 int2le(length,sectorbuf+x+16);
753 int2le(0,sectorbuf+x+24);
754 int2le(chksum,sectorbuf+x+28);
756 /* Write directory */
757 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
758 n=ipod_write(ipod, sectorbuf, ipod->sector_size);
759 if (n < 0) { return -1; }
761 return 0;
764 int write_firmware(struct ipod_t* ipod, char* filename, int type)
766 int length;
767 int i;
768 int x;
769 int n;
770 int infile;
771 int newsize;
772 int bytesavailable;
773 unsigned long chksum=0;
774 unsigned long filechksum=0;
775 unsigned char header[8]; /* Header for .ipod file */
777 #ifdef WITH_BOOTOBJS
778 if (type == FILETYPE_INTERNAL) {
779 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
780 length = ipod->bootloader_len;
781 infile = -1;
783 else
784 #endif
786 /* First check that the input file is the correct type for this ipod. */
787 infile=open(filename,O_RDONLY);
788 if (infile < 0) {
789 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
790 return -1;
793 if (type==FILETYPE_DOT_IPOD) {
794 n = read(infile,header,8);
795 if (n < 8) {
796 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
797 close(infile);
798 return -1;
801 if (memcmp(header+4, ipod->modelname,4)!=0) {
802 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
803 header[4],header[5],header[6],header[7], ipod->modelname);
804 close(infile);
805 return -1;
808 filechksum = be2int(header);
810 length = filesize(infile)-8;
811 } else {
812 length = filesize(infile);
816 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
818 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
819 length,newsize);
821 if (newsize > BUFFER_SIZE) {
822 fprintf(stderr,"[ERR] Input file too big for buffer\n");
823 if (infile >= 0) close(infile);
824 return -1;
827 /* Check if we have enough space */
828 /* TODO: Check the size of the partition. */
829 if (ipod->nimages > 1) {
830 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
831 if (bytesavailable < newsize) {
832 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
834 /* TODO: Implement image movement */
835 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
836 close(infile);
837 return -1;
841 #ifdef WITH_BOOTOBJS
842 if (type == FILETYPE_INTERNAL) {
843 memcpy(sectorbuf,ipod->bootloader,ipod->bootloader_len);
845 else
846 #endif
848 fprintf(stderr,"[INFO] Reading input file...\n");
849 /* We now know we have enough space, so write it. */
850 n = read(infile,sectorbuf,length);
851 if (n < 0) {
852 fprintf(stderr,"[ERR] Couldn't read input file\n");
853 close(infile);
854 return -1;
856 close(infile);
859 /* Pad the data with zeros */
860 memset(sectorbuf+length,0,newsize-length);
862 if (type==FILETYPE_DOT_IPOD) {
863 chksum = ipod->modelnum;
864 for (i = 0; i < length; i++) {
865 /* add 8 unsigned bits but keep a 32 bit sum */
866 chksum += sectorbuf[i];
869 if (chksum == filechksum) {
870 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
871 } else {
872 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
873 return -1;
877 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
878 fprintf(stderr,"[ERR] Seek failed\n");
879 return -1;
882 if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) {
883 perror("[ERR] Write failed\n");
884 return -1;
887 if (n < newsize) {
888 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
889 ,newsize,n);
890 return -1;
892 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
894 /* Now we need to update the "len", "entryOffset" and "chksum" fields */
895 chksum = 0;
896 for (i = 0; i < length; i++) {
897 /* add 8 unsigned bits but keep a 32 bit sum */
898 chksum += sectorbuf[i];
901 x = ipod->diroffset % ipod->sector_size;
903 /* Read directory */
904 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
906 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
907 if (n < 0) { return -1; }
909 /* Update entries for image 0 */
910 int2le(length,sectorbuf+x+16);
911 int2le(0,sectorbuf+x+24);
912 int2le(chksum,sectorbuf+x+28);
914 /* Write directory */
915 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
916 n=ipod_write(ipod, sectorbuf, ipod->sector_size);
917 if (n < 0) { return -1; }
919 return 0;
922 int read_firmware(struct ipod_t* ipod, char* filename, int type)
924 int length;
925 int i;
926 int outfile;
927 int n;
928 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
929 unsigned char header[8]; /* Header for .ipod file */
931 if (ipod->ipod_directory[0].entryOffset != 0) {
932 /* We have a bootloader... */
933 length = ipod->ipod_directory[0].entryOffset;
934 } else {
935 length = ipod->ipod_directory[0].len;
938 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
940 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
941 return -1;
944 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
945 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
946 length,i);
948 if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
949 return -1;
952 if (n < i) {
953 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
954 i,n);
955 return -1;
958 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
959 if (outfile < 0) {
960 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
961 return -1;
964 if (type == FILETYPE_DOT_IPOD) {
965 chksum = ipod->modelnum;
966 for (i = 0; i < length; i++) {
967 /* add 8 unsigned bits but keep a 32 bit sum */
968 chksum += sectorbuf[i];
971 int2be(chksum,header);
972 memcpy(header+4, ipod->modelname,4);
974 n = write(outfile,header,8);
975 if (n != 8) {
976 fprintf(stderr,"[ERR] Write error - %d\n",n);
980 n = write(outfile,sectorbuf,length);
981 if (n != length) {
982 fprintf(stderr,"[ERR] Write error - %d\n",n);
984 close(outfile);
986 return 0;
989 int read_directory(struct ipod_t* ipod)
991 int n;
992 int x;
993 unsigned char* p;
994 unsigned short version;
996 ipod->nimages=0;
998 /* Read firmware partition header (first 512 bytes of disk - but
999 let's read a whole sector) */
1001 if (ipod_seek(ipod, ipod->start) < 0) {
1002 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1003 (unsigned int)(ipod->start));
1004 return -1;
1007 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
1008 if (n < 0) {
1009 fprintf(stderr,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod->sector_size);
1010 return -1;
1013 if (memcmp(sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
1014 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1015 return -1;
1018 if (memcmp(sectorbuf+0x100,"]ih[",4)!=0) {
1019 fprintf(stderr,"[ERR] Bad firmware directory\n");
1020 return -1;
1023 version = le2ushort(sectorbuf+0x10a);
1024 if ((version != 2) && (version != 3)) {
1025 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1026 version);
1028 ipod->diroffset=le2int(sectorbuf+0x104) + 0x200;
1030 /* diroffset may not be sector-aligned */
1031 x = ipod->diroffset % ipod->sector_size;
1033 /* Read directory */
1034 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1035 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
1036 return -1;
1039 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
1040 if (n < 0) {
1041 fprintf(stderr,"[ERR] Read of directory failed.\n");
1042 return -1;
1045 p = sectorbuf + x;
1047 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1048 if (p[0] == 0)
1050 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
1051 if (n < 0) {
1052 fprintf(stderr,"[ERR] Read of directory failed.\n");
1053 return -1;
1055 p = sectorbuf;
1058 while ((ipod->nimages < MAX_IMAGES) && (p < (sectorbuf + x + 400)) &&
1059 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1060 p+=4;
1061 if (memcmp(p,"soso",4)==0) {
1062 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1063 } else if (memcmp(p,"crsr",4)==0) {
1064 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1065 } else if (memcmp(p,"dpua",4)==0) {
1066 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1067 } else if (memcmp(p,"ebih",4)==0) {
1068 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1069 } else {
1070 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1071 p[0],p[1],p[2],p[3]);
1073 p+=4;
1074 ipod->ipod_directory[ipod->nimages].id=le2int(p);
1075 p+=4;
1076 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
1077 p+=4;
1078 ipod->ipod_directory[ipod->nimages].len=le2int(p);
1079 p+=4;
1080 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
1081 p+=4;
1082 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
1083 p+=4;
1084 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
1085 p+=4;
1086 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
1087 p+=4;
1088 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
1089 p+=4;
1090 ipod->nimages++;
1093 if ((ipod->nimages > 1) && (version==2)) {
1094 /* The 3g firmware image doesn't appear to have a version, so
1095 let's make one up... Note that this is never written back to the
1096 ipod, so it's OK to do. */
1098 if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; }
1100 ipod->fwoffset = ipod->start;
1101 } else {
1102 ipod->fwoffset = ipod->start + ipod->sector_size;
1105 return 0;
1108 int list_images(struct ipod_t* ipod)
1110 int i;
1112 if (verbose) {
1113 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1114 for (i = 0 ; i < ipod->nimages; i++) {
1115 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
1116 ftypename[ipod->ipod_directory[i].ftype],
1117 ipod->ipod_directory[i].id,
1118 ipod->ipod_directory[i].devOffset,
1119 ipod->ipod_directory[i].len,
1120 ipod->ipod_directory[i].addr,
1121 ipod->ipod_directory[i].entryOffset,
1122 ipod->ipod_directory[i].chksum,
1123 ipod->ipod_directory[i].vers,
1124 ipod->ipod_directory[i].loadAddr,
1125 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
1129 printf("\n");
1130 printf("Listing firmware partition contents:\n");
1131 printf("\n");
1133 for (i = 0 ; i < ipod->nimages; i++) {
1134 printf("Image %d:\n",i+1);
1135 switch(ipod->ipod_directory[i].ftype) {
1136 case FTYPE_OSOS:
1137 if (ipod->ipod_directory[i].entryOffset==0) {
1138 printf(" Main firmware - %d bytes\n",
1139 ipod->ipod_directory[i].len);
1140 } else {
1141 printf(" Main firmware - %d bytes\n",
1142 ipod->ipod_directory[i].entryOffset);
1143 printf(" Third-party bootloader - %d bytes\n",
1144 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
1146 break;
1147 default:
1148 printf(" %s - %d bytes\n",
1149 ftypename[ipod->ipod_directory[i].ftype],
1150 ipod->ipod_directory[i].len);
1153 printf("\n");
1155 return 0;
1158 int getmodel(struct ipod_t* ipod, int ipod_version)
1160 switch (ipod_version) {
1161 case 0x01:
1162 ipod->modelstr="1st or 2nd Generation";
1163 ipod->modelnum = 19;
1164 ipod->modelname = "1g2g";
1165 ipod->targetname = "ipod1g2g";
1166 #ifdef WITH_BOOTOBJS
1167 ipod->bootloader = ipod1g2g;
1168 ipod->bootloader_len = LEN_ipod1g2g;
1169 #endif
1170 break;
1171 case 0x02:
1172 ipod->modelstr="3rd Generation";
1173 ipod->modelnum = 7;
1174 ipod->modelname = "ip3g";
1175 ipod->targetname = "ipod3g";
1176 #ifdef WITH_BOOTOBJS
1177 ipod->bootloader = ipod3g;
1178 ipod->bootloader_len = LEN_ipod3g;
1179 #endif
1180 break;
1181 case 0x40:
1182 ipod->modelstr="1st Generation Mini";
1183 ipod->modelnum = 9;
1184 ipod->modelname = "mini";
1185 ipod->targetname = "ipodmini1g";
1186 #ifdef WITH_BOOTOBJS
1187 ipod->bootloader = ipodmini;
1188 ipod->bootloader_len = LEN_ipodmini;
1189 #endif
1190 break;
1191 case 0x50:
1192 ipod->modelstr="4th Generation";
1193 ipod->modelnum = 8;
1194 ipod->modelname = "ip4g";
1195 ipod->targetname = "ipod4gray";
1196 #ifdef WITH_BOOTOBJS
1197 ipod->bootloader = ipod4g;
1198 ipod->bootloader_len = LEN_ipod4g;
1199 #endif
1200 break;
1201 case 0x60:
1202 ipod->modelstr="Photo/Color";
1203 ipod->modelnum = 3;
1204 ipod->modelname = "ipco";
1205 ipod->targetname = "ipodcolor";
1206 #ifdef WITH_BOOTOBJS
1207 ipod->bootloader = ipodcolor;
1208 ipod->bootloader_len = LEN_ipodcolor;
1209 #endif
1210 break;
1211 case 0x70:
1212 ipod->modelstr="2nd Generation Mini";
1213 ipod->modelnum = 11;
1214 ipod->modelname = "mn2g";
1215 ipod->targetname = "ipodmini2g";
1216 #ifdef WITH_BOOTOBJS
1217 ipod->bootloader = ipodmini2g;
1218 ipod->bootloader_len = LEN_ipodmini2g;
1219 #endif
1220 break;
1221 case 0xc0:
1222 ipod->modelstr="1st Generation Nano";
1223 ipod->modelnum = 4;
1224 ipod->modelname = "nano";
1225 ipod->targetname = "ipodnano";
1226 #ifdef WITH_BOOTOBJS
1227 ipod->bootloader = ipodnano;
1228 ipod->bootloader_len = LEN_ipodnano;
1229 #endif
1230 break;
1231 case 0xb0:
1232 ipod->modelstr="Video (aka 5th Generation)";
1233 ipod->modelnum = 5;
1234 ipod->modelname = "ipvd";
1235 ipod->targetname = "ipodvideo";
1236 #ifdef WITH_BOOTOBJS
1237 ipod->bootloader = ipodvideo;
1238 ipod->bootloader_len = LEN_ipodvideo;
1239 #endif
1240 break;
1241 case 0x100:
1242 ipod->modelstr="2nd Generation Nano";
1243 ipod->modelnum = 0;
1244 ipod->targetname = NULL;
1245 #ifdef WITH_BOOTOBJS
1246 ipod->bootloader = NULL;
1247 ipod->bootloader_len = 0;
1248 #endif
1249 break;
1250 default:
1251 ipod->modelname = NULL;
1252 ipod->modelnum = 0;
1253 ipod->targetname = NULL;
1254 #ifdef WITH_BOOTOBJS
1255 ipod->bootloader = NULL;
1256 ipod->bootloader_len = 0;
1257 #endif
1258 return -1;
1260 return 0;
1263 int ipod_scan(struct ipod_t* ipod)
1265 int i;
1266 int n = 0;
1267 int ipod_version;
1268 char last_ipod[4096];
1270 printf("[INFO] Scanning disk devices...\n");
1272 for (i = 0; i <= 25 ; i++) {
1273 #ifdef __WIN32__
1274 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
1275 #elif defined(linux) || defined (__linux)
1276 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
1277 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1278 || defined(__bsdi__) || defined(__DragonFly__)
1279 sprintf(ipod->diskname,"/dev/da%d",i);
1280 #elif defined(__APPLE__) && defined(__MACH__)
1281 sprintf(ipod->diskname,"/dev/disk%d",i);
1282 #else
1283 #error No disk paths defined for this platform
1284 #endif
1285 if (ipod_open(ipod, 1) < 0) {
1286 continue;
1289 if (read_partinfo(ipod,1) < 0) {
1290 continue;
1293 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
1294 continue;
1297 if (read_directory(ipod) < 0) {
1298 continue;
1301 ipod_version=(ipod->ipod_directory[0].vers>>8);
1302 if (getmodel(ipod,ipod_version) < 0) {
1303 continue;
1306 #ifdef __WIN32__
1307 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1308 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
1309 #else
1310 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1311 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
1312 #endif
1313 n++;
1314 strcpy(last_ipod,ipod->diskname);
1315 ipod_close(ipod);
1318 if (n==1) {
1319 /* Remember the disk name */
1320 strcpy(ipod->diskname,last_ipod);
1322 return n;
1325 static void put_int32le(uint32_t x, unsigned char* p)
1327 p[0] = x & 0xff;
1328 p[1] = (x >> 8) & 0xff;
1329 p[2] = (x >> 16) & 0xff;
1330 p[3] = (x >> 24) & 0xff;
1333 int write_dos_partition_table(struct ipod_t* ipod)
1335 unsigned char* p;
1336 int i, n;
1337 uint32_t type;
1339 /* Only support 512-byte sectors at the moment */
1340 if ( ipod->sector_size != 512 )
1342 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1343 return -1;
1346 /* Firstly zero the entire MBR */
1347 memset(sectorbuf, 0, ipod->sector_size);
1349 /* Now add the partition info */
1350 for (i=0; i < 4 ; i++)
1352 p = sectorbuf + 0x1be + i*16;
1354 /* Ensure first partition is type 0, and second is 0xb */
1355 if (i==0) { type = 0; }
1356 else if (i==1) { type = 0xb; }
1357 else { type = ipod->pinfo[i].type; }
1359 put_int32le(type, p + 4);
1360 put_int32le(ipod->pinfo[i].start, p + 8);
1361 put_int32le(ipod->pinfo[i].size, p + 12);
1364 /* Finally add the magic */
1365 sectorbuf[0x1fe] = 0x55;
1366 sectorbuf[0x1ff] = 0xaa;
1368 if (ipod_seek(ipod, 0) < 0) {
1369 fprintf(stderr,"[ERR] Seek failed writing MBR\n");
1370 return -1;
1373 /* Write MBR */
1374 if ((n = ipod_write(ipod, sectorbuf, ipod->sector_size)) < 0) {
1375 perror("[ERR] Write failed\n");
1376 return -1;
1379 return 0;
1382 #ifndef RBUTIL
1384 static inline uint32_t getuint32le(unsigned char* buf)
1386 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
1388 return res;
1391 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1392 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1396 static bool testMarker(int marker)
1398 int mask, decrypt, temp1, temp2;
1400 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
1401 decrypt = marker ^ mask;
1402 temp1=(int)((unsigned int)decrypt>>24);
1403 temp2=decrypt<<8;
1405 if (temp1==0)
1406 return false;
1408 temp2=(int)((unsigned int)temp2>>24);
1409 decrypt=decrypt<<16;
1410 decrypt=(int)((unsigned int)decrypt>>24);
1412 if ((temp1 < temp2) && (temp2 < decrypt))
1414 temp1 = temp1 & 0xf;
1415 temp2 = temp2 & 0xf;
1416 decrypt = decrypt & 0xf;
1418 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
1420 return true;
1423 return false;
1426 static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
1428 int constant = 0x54c3a298;
1429 int key=0;
1430 int nkeys = 0;
1431 int aMarker=0;
1432 int pos=0;
1433 int c, count;
1434 int temp1;
1435 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
1437 for (c = 0; c < 8; c++)
1439 pos = offset[c]*4;
1440 aMarker = getuint32le(data + pos);
1442 if (testMarker(aMarker))
1444 if (c<7)
1445 pos =(offset[c+1]*4)+4;
1446 else
1447 pos =(offset[0]*4)+4;
1449 key=0;
1451 temp1=aMarker;
1453 for (count=0;count<2;count++){
1454 int word = getuint32le(data + pos);
1455 temp1 = aMarker;
1456 temp1 = temp1^word;
1457 temp1 = temp1^constant;
1458 key = temp1;
1459 pos = pos+4;
1461 int r1=0x6f;
1462 int r2=0;
1463 int r12;
1464 int r14;
1465 unsigned int r_tmp;
1467 for (count=2;count<128;count=count+2){
1468 r2=getuint32le(data+count*4);
1469 r12=getuint32le(data+(count*4)+4);
1470 r_tmp=(unsigned int)r12>>16;
1471 r14=r2 | ((int)r_tmp);
1472 r2=r2&0xffff;
1473 r2=r2 | r12;
1474 r1=r1^r14;
1475 r1=r1+r2;
1477 key=key^r1;
1479 // Invert key, little endian
1480 this_key[0] = key & 0xff;
1481 this_key[1] = (key >> 8) & 0xff;
1482 this_key[2] = (key >> 16) & 0xff;
1483 this_key[3] = (key >> 24) & 0xff;
1484 nkeys++;
1487 return nkeys;
1490 static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
1492 int n;
1494 /* Firstly read the security block and find the RC4 key. This is
1495 in the sector preceeding the AUPD image. */
1497 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
1498 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
1499 return -1;
1502 if ((n = ipod_read(ipod, sectorbuf, 512)) < 0) {
1503 return -1;
1506 n = GetSecurityBlockKey(sectorbuf, key);
1508 if (n != 1)
1510 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
1511 return -1;
1514 return 0;
1517 int read_aupd(struct ipod_t* ipod, char* filename)
1519 int length;
1520 int i;
1521 int outfile;
1522 int n;
1523 int aupd;
1524 struct rc4_key_t rc4;
1525 unsigned char key[4];
1526 unsigned long chksum=0;
1528 aupd = 0;
1529 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
1531 aupd++;
1534 if (aupd == ipod->nimages)
1536 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
1537 return -1;
1540 length = ipod->ipod_directory[aupd].len;
1542 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1544 if (find_key(ipod, aupd, key) < 0)
1546 return -1;
1549 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
1551 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
1552 return -1;
1555 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1557 if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
1558 return -1;
1561 if (n < i) {
1562 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1563 i,n);
1564 return -1;
1567 /* Perform the decryption - this is standard (A)RC4 */
1568 matrixArc4Init(&rc4, key, 4);
1569 matrixArc4(&rc4, sectorbuf, sectorbuf, length);
1571 chksum = 0;
1572 for (i = 0; i < (int)length; i++) {
1573 /* add 8 unsigned bits but keep a 32 bit sum */
1574 chksum += sectorbuf[i];
1577 if (chksum != ipod->ipod_directory[aupd].chksum)
1579 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
1580 return -1;
1582 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
1584 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
1585 if (outfile < 0) {
1586 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1587 return -1;
1590 n = write(outfile,sectorbuf,length);
1591 if (n != length) {
1592 fprintf(stderr,"[ERR] Write error - %d\n",n);
1594 close(outfile);
1596 return 0;
1599 int write_aupd(struct ipod_t* ipod, char* filename)
1601 unsigned int length;
1602 int i;
1603 int x;
1604 int n;
1605 int infile;
1606 int newsize;
1607 int aupd;
1608 unsigned long chksum=0;
1609 struct rc4_key_t rc4;
1610 unsigned char key[4];
1612 /* First check that the input file is the correct type for this ipod. */
1613 infile=open(filename,O_RDONLY);
1614 if (infile < 0) {
1615 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
1616 return -1;
1619 length = filesize(infile);
1620 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
1622 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1623 length,newsize);
1625 if (newsize > BUFFER_SIZE) {
1626 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1627 if (infile >= 0) close(infile);
1628 return -1;
1631 /* Find aupd image number */
1632 aupd = 0;
1633 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
1635 aupd++;
1638 if (aupd == ipod->nimages)
1640 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
1641 return -1;
1644 if (length != ipod->ipod_directory[aupd].len)
1646 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
1647 ipod->ipod_directory[aupd].len, filename, length);
1648 return -1;
1651 if (find_key(ipod, aupd, key) < 0)
1653 return -1;
1656 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
1658 /* We now know we have enough space, so write it. */
1660 fprintf(stderr,"[INFO] Reading input file...\n");
1661 n = read(infile,sectorbuf,length);
1662 if (n < 0) {
1663 fprintf(stderr,"[ERR] Couldn't read input file\n");
1664 close(infile);
1665 return -1;
1667 close(infile);
1669 /* Pad the data with zeros */
1670 memset(sectorbuf+length,0,newsize-length);
1672 /* Calculate the new checksum (before we encrypt) */
1673 chksum = 0;
1674 for (i = 0; i < (int)length; i++) {
1675 /* add 8 unsigned bits but keep a 32 bit sum */
1676 chksum += sectorbuf[i];
1679 /* Perform the encryption - this is standard (A)RC4 */
1680 matrixArc4Init(&rc4, key, 4);
1681 matrixArc4(&rc4, sectorbuf, sectorbuf, length);
1683 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
1684 fprintf(stderr,"[ERR] Seek failed\n");
1685 return -1;
1688 if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) {
1689 perror("[ERR] Write failed\n");
1690 return -1;
1693 if (n < newsize) {
1694 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
1695 ,newsize,n);
1696 return -1;
1698 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1700 x = ipod->diroffset % ipod->sector_size;
1702 /* Read directory */
1703 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1705 n=ipod_read(ipod, sectorbuf, ipod->sector_size);
1706 if (n < 0) { return -1; }
1708 /* Update checksum */
1709 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(sectorbuf + x + aupd*40 + 28));
1710 int2le(chksum,sectorbuf+x+aupd*40+28);
1712 /* Write directory */
1713 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1714 n=ipod_write(ipod, sectorbuf, ipod->sector_size);
1715 if (n < 0) { return -1; }
1717 return 0;
1720 #endif