1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 #include <sys/types.h>
32 #include "parttypes.h"
34 #include "ipodpatcher.h"
40 #include "ipodmini1g.h"
41 #include "ipodmini2g.h"
42 #include "ipodcolor.h"
43 #include "ipodnano1g.h"
44 #include "ipodvideo.h"
45 #include "ipodnano2g.h"
54 unsigned char* ipod_sectorbuf
= NULL
;
56 /* The following string appears at the start of the firmware partition */
57 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
74 /* Windows requires the buffer for disk I/O to be aligned in memory on a
75 multiple of the disk volume size - so we use a single global variable
76 and initialise it with ipod_alloc_buf()
79 char* get_parttype(int pt
)
82 static char unknown
[]="Unknown";
84 if (pt
== PARTTYPE_HFS
) {
89 while (parttypes
[i
].name
!= NULL
) {
90 if (parttypes
[i
].type
== pt
) {
91 return (parttypes
[i
].name
);
99 off_t
filesize(int fd
) {
102 if (fstat(fd
,&buf
) < 0) {
103 perror("[ERR] Checking filesize of input file");
110 /* Partition table parsing code taken from Rockbox */
112 #define MAX_SECTOR_SIZE 2048
113 #define SECTOR_SIZE 512
115 static inline unsigned short le2ushort(unsigned char* buf
)
117 unsigned short res
= (buf
[1] << 8) | buf
[0];
122 static inline int le2int(unsigned char* buf
)
124 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
129 static inline int be2int(unsigned char* buf
)
131 int32_t res
= (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
136 static inline int getint16le(char* buf
)
138 int16_t res
= (buf
[1] << 8) | buf
[0];
143 static inline void short2le(unsigned short val
, unsigned char* addr
)
145 addr
[0] = val
& 0xFF;
146 addr
[1] = (val
>> 8) & 0xff;
149 static inline void int2le(unsigned int val
, unsigned char* addr
)
151 addr
[0] = val
& 0xFF;
152 addr
[1] = (val
>> 8) & 0xff;
153 addr
[2] = (val
>> 16) & 0xff;
154 addr
[3] = (val
>> 24) & 0xff;
157 static inline void int2be(unsigned int val
, unsigned char* addr
)
159 addr
[0] = (val
>> 24) & 0xff;
160 addr
[1] = (val
>> 16) & 0xff;
161 addr
[2] = (val
>> 8) & 0xff;
162 addr
[3] = val
& 0xFF;
166 #define BYTES2INT32(array,pos)\
167 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
168 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
170 int read_partinfo(struct ipod_t
* ipod
, int silent
)
175 count
= ipod_read(ipod
,ipod_sectorbuf
, ipod
->sector_size
);
178 ipod_print_error(" Error reading from disk: ");
182 memset(ipod
->pinfo
, 0, sizeof(ipod
->pinfo
));
184 if ((ipod_sectorbuf
[510] == 0x55) && (ipod_sectorbuf
[511] == 0xaa)) {
185 /* DOS partition table */
187 /* parse partitions */
188 for ( i
= 0; i
< 4; i
++ ) {
189 unsigned char* ptr
= ipod_sectorbuf
+ 0x1be + 16*i
;
190 ipod
->pinfo
[i
].type
= ptr
[4];
191 ipod
->pinfo
[i
].start
= BYTES2INT32(ptr
, 8);
192 ipod
->pinfo
[i
].size
= BYTES2INT32(ptr
, 12);
195 if ( ipod
->pinfo
[i
].type
== 5 ) {
196 /* not handled yet */
199 } else if ((ipod_sectorbuf
[0] == 'E') && (ipod_sectorbuf
[1] == 'R')) {
200 /* Apple Partition Map */
202 /* APM parsing code based on the check_mac_partitions() function in
203 ipodloader2 - written by Thomas Tempelmann and released
207 int partBlkCount
= 1;
208 int partBlkSizMul
= ipod_sectorbuf
[2] / 2;
210 int pmMapBlkCnt
; /* # of blks in partition map */
211 int pmPyPartStart
; /* physical start blk of partition */
212 int pmPartBlkCnt
; /* # of blks in this partition */
217 memset(ipod
->pinfo
,0,sizeof(ipod
->pinfo
));
219 while (blkNo
<= partBlkCount
) {
220 if (ipod_seek(ipod
, blkNo
* partBlkSizMul
* 512) < 0) {
221 fprintf(stderr
,"[ERR] Seek failed whilst reading APM\n");
225 count
= ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
228 ipod_print_error(" Error reading from disk: ");
232 /* see if it's a partition entry */
233 if ((ipod_sectorbuf
[0] != 'P') || (ipod_sectorbuf
[1] != 'M')) {
234 /* end of partition table -> leave the loop */
238 /* Extract the interesting entries */
239 pmMapBlkCnt
= be2int(ipod_sectorbuf
+ 4);
240 pmPyPartStart
= be2int(ipod_sectorbuf
+ 8);
241 pmPartBlkCnt
= be2int(ipod_sectorbuf
+ 12);
243 /* update the number of part map blocks */
244 partBlkCount
= pmMapBlkCnt
;
246 if (strncmp((char*)(ipod_sectorbuf
+ 48), "Apple_MDFW", 32)==0) {
247 /* A Firmware partition */
248 ipod
->pinfo
[i
].start
= pmPyPartStart
;
249 ipod
->pinfo
[i
].size
= pmPartBlkCnt
;
250 ipod
->pinfo
[i
].type
= 0;
252 } else if (strncmp((char*)(ipod_sectorbuf
+ 48), "Apple_HFS", 32)==0) {
253 /* A HFS partition */
254 ipod
->pinfo
[i
].start
= pmPyPartStart
;
255 ipod
->pinfo
[i
].size
= pmPartBlkCnt
;
256 ipod
->pinfo
[i
].type
= PARTTYPE_HFS
;
260 blkNo
++; /* read next partition map entry */
263 if (!silent
) fprintf(stderr
,"[ERR] Bad boot sector signature\n");
267 /* Check that the partition table looks like an ipod:
268 1) Partition 1 is of type 0 (Empty) but isn't empty.
269 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
271 if ((ipod
->pinfo
[0].type
!= 0) || (ipod
->pinfo
[0].size
== 0) ||
272 ((ipod
->pinfo
[1].type
!= 0xb) && (ipod
->pinfo
[1].type
!= 0xc) &&
273 (ipod
->pinfo
[1].type
!= PARTTYPE_HFS
))) {
274 if (!silent
) fprintf(stderr
,"[ERR] Partition layout is not an ipod\n");
278 ipod
->start
= ipod
->pinfo
[0].start
*ipod
->sector_size
;
282 int read_partition(struct ipod_t
* ipod
, int outfile
)
288 int count
= ipod
->pinfo
[0].size
;
290 if (ipod_seek(ipod
, ipod
->start
) < 0) {
294 fprintf(stderr
,"[INFO] Writing %d sectors to output file\n",count
);
296 bytesleft
= count
* ipod
->sector_size
;
297 while (bytesleft
> 0) {
298 if (bytesleft
> BUFFER_SIZE
) {
299 chunksize
= BUFFER_SIZE
;
301 chunksize
= bytesleft
;
304 n
= ipod_read(ipod
, ipod_sectorbuf
, chunksize
);
312 "[ERR] Short read in disk_read() - requested %d, got %d\n",
319 res
= write(outfile
,ipod_sectorbuf
,n
);
322 perror("[ERR] write in disk_read");
328 "Short write - requested %d, received %d - aborting.\n",(int)n
,res
);
333 fprintf(stderr
,"[INFO] Done.\n");
337 int write_partition(struct ipod_t
* ipod
, int infile
)
342 int byteswritten
= 0;
346 if (ipod_seek(ipod
, ipod
->start
) < 0) {
350 fprintf(stderr
,"[INFO] Writing input file to device\n");
354 n
= read(infile
,ipod_sectorbuf
,BUFFER_SIZE
);
357 perror("[ERR] read in disk_write");
361 if (n
< BUFFER_SIZE
) {
363 /* We need to pad the last write to a multiple of SECTOR_SIZE */
364 if ((n
% ipod
->sector_size
) != 0) {
365 padding
= (ipod
->sector_size
-(n
% ipod
->sector_size
));
372 res
= ipod_write(ipod
, ipod_sectorbuf
, n
);
375 ipod_print_error(" Error writing to disk: ");
376 fprintf(stderr
,"Bytes written: %d\n",byteswritten
);
381 fprintf(stderr
,"[ERR] Short write - requested %d, received %d - aborting.\n",n
,(int)res
);
388 fprintf(stderr
,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
389 byteswritten
-padding
,padding
);
393 char* ftypename
[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
395 int diskmove(struct ipod_t
* ipod
, int delta
)
403 src_start
= ipod
->ipod_directory
[1].devOffset
;
404 src_end
= (ipod
->ipod_directory
[ipod
->nimages
-1].devOffset
+ ipod
->sector_size
+
405 ipod
->ipod_directory
[ipod
->nimages
-1].len
+
406 (ipod
->sector_size
-1)) & ~(ipod
->sector_size
-1);
407 bytesleft
= src_end
- src_start
;
410 fprintf(stderr
,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod
->nimages
,delta
);
411 fprintf(stderr
,"[VERB] src_start = %08x\n",src_start
);
412 fprintf(stderr
,"[VERB] src_end = %08x\n",src_end
);
413 fprintf(stderr
,"[VERB] dest_start = %08x\n",src_start
+delta
);
414 fprintf(stderr
,"[VERB] dest_end = %08x\n",src_end
+delta
);
415 fprintf(stderr
,"[VERB] bytes to copy = %08x\n",bytesleft
);
418 while (bytesleft
> 0) {
419 if (bytesleft
<= BUFFER_SIZE
) {
420 chunksize
= bytesleft
;
422 chunksize
= BUFFER_SIZE
;
426 fprintf(stderr
,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
429 src_end
-chunksize
+delta
,
430 (unsigned int)(ipod
->start
+src_end
-chunksize
),
431 (unsigned int)(ipod
->start
+src_end
-chunksize
+delta
));
435 if (ipod_seek(ipod
, ipod
->start
+src_end
-chunksize
) < 0) {
436 fprintf(stderr
,"[ERR] Seek failed\n");
440 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,chunksize
)) < 0) {
441 perror("[ERR] Write failed\n");
446 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
451 if (ipod_seek(ipod
, ipod
->start
+src_end
-chunksize
+delta
) < 0) {
452 fprintf(stderr
,"[ERR] Seek failed\n");
456 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,chunksize
)) < 0) {
457 perror("[ERR] Write failed\n");
462 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
467 src_end
-= chunksize
;
468 bytesleft
-= chunksize
;
474 static int rename_image(struct ipod_t
* ipod
, char* from
, char* to
)
482 /* diroffset may not be sector-aligned */
483 x
= ipod
->diroffset
% ipod
->sector_size
;
486 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
487 fprintf(stderr
,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod
->diroffset
);
491 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
493 fprintf(stderr
,"[ERR] Read of directory failed.\n");
497 p
= ipod_sectorbuf
+ x
;
499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
502 /* Adjust diroffset */
503 ipod
->diroffset
+= ipod
->sector_size
- x
;
505 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
507 fprintf(stderr
,"[ERR] Read of directory failed.\n");
514 for (i
=0 ; !found
&& i
< MAX_IMAGES
; i
++) {
515 if (memcmp(p
+ 4, from
, 4) == 0) {
516 memcpy(p
+ 4, to
, 4);
524 fprintf(stderr
,"[ERR] Unexpected error - no \"%s\" image!\n", from
);
528 /* Write directory back to disk */
529 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
530 fprintf(stderr
,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod
->diroffset
);
534 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
536 fprintf(stderr
,"[ERR] Write of directory failed in rename_image.\n");
543 static int delete_image(struct ipod_t
* ipod
, char* name
)
551 /* diroffset may not be sector-aligned */
552 x
= ipod
->diroffset
% ipod
->sector_size
;
555 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
556 fprintf(stderr
,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod
->diroffset
);
560 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
562 fprintf(stderr
,"[ERR] Read of directory failed.\n");
566 p
= ipod_sectorbuf
+ x
;
568 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
571 /* Adjust diroffset */
572 ipod
->diroffset
+= ipod
->sector_size
- x
;
574 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
576 fprintf(stderr
,"[ERR] Read of directory failed.\n");
583 for (i
=0 ; !found
&& i
< MAX_IMAGES
; i
++) {
584 if (memcmp(p
+ 4, name
, 4) == 0) {
585 memset(p
, 0, 40); /* Delete directory entry */
592 fprintf(stderr
,"[ERR] Unexpected error - no \"%s\" image!\n", name
);
596 /* Write directory back to disk */
597 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
598 fprintf(stderr
,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod
->diroffset
);
602 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
604 fprintf(stderr
,"[ERR] Write of directory failed in delete_image.\n");
611 int add_new_image(struct ipod_t
* ipod
, char* imagename
, char* filename
, int type
)
620 unsigned long chksum
=0;
621 unsigned long filechksum
=0;
622 unsigned long offset
;
623 unsigned char header
[8]; /* Header for .ipod file */
627 if (type
== FILETYPE_INTERNAL
) {
628 fprintf(stderr
,"[INFO] Using internal bootloader - %d bytes\n",ipod
->bootloader_len
);
629 length
= ipod
->bootloader_len
;
635 /* First check that the input file is the correct type for this ipod. */
636 infile
=open(filename
,O_RDONLY
);
638 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
642 if (type
==FILETYPE_DOT_IPOD
) {
643 n
= read(infile
,header
,8);
645 fprintf(stderr
,"[ERR] Failed to read header from %s\n",filename
);
650 if (memcmp(header
+4, ipod
->modelname
,4)!=0) {
651 fprintf(stderr
,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
652 header
[4],header
[5],header
[6],header
[7], ipod
->modelname
);
657 filechksum
= be2int(header
);
659 length
= filesize(infile
)-8;
661 length
= filesize(infile
);
665 newsize
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
667 fprintf(stderr
,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
670 if (newsize
> BUFFER_SIZE
) {
671 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
672 if (infile
>= 0) close(infile
);
676 /* TODO: Check if we have enough space in the partition for the new image */
679 if (type
== FILETYPE_INTERNAL
) {
680 memcpy(ipod_sectorbuf
,ipod
->bootloader
,ipod
->bootloader_len
);
685 fprintf(stderr
,"[INFO] Reading input file...\n");
687 n
= read(infile
,ipod_sectorbuf
,length
);
689 fprintf(stderr
,"[ERR] Couldn't read input file\n");
696 /* Pad the data with zeros */
697 memset(ipod_sectorbuf
+length
,0,newsize
-length
);
699 if (type
==FILETYPE_DOT_IPOD
) {
700 chksum
= ipod
->modelnum
;
701 for (i
= 0; i
< length
; i
++) {
702 /* add 8 unsigned bits but keep a 32 bit sum */
703 chksum
+= ipod_sectorbuf
[i
];
706 if (chksum
== filechksum
) {
707 fprintf(stderr
,"[INFO] Checksum OK in %s\n",filename
);
709 fprintf(stderr
,"[ERR] Checksum in %s failed check\n",filename
);
715 offset
= ipod
->fwoffset
+ ipod
->ipod_directory
[ipod
->nimages
- 1].devOffset
+
716 ipod
->ipod_directory
[ipod
->nimages
- 1].len
+ ipod
->sector_size
;
718 /* 2nd Gen Nano has encrypted firmware, and the sector
719 preceeding the firmware contains hashes that need to be
720 preserved. Nano 2G images include these extra 2048 (0x800)
723 if (ipod_seek(ipod
, offset
- (ipod
->modelnum
== 62 ? 0x800 : 0)) < 0) {
724 fprintf(stderr
,"[ERR] Seek failed\n");
728 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,newsize
)) < 0) {
729 perror("[ERR] Write failed\n");
734 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
738 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",n
);
740 /* Now we need to create a new directory entry
742 NOTE: On the Nano 2G, the checksum is the checksum of the
743 unencrypted firmware. But this isn't checked by the NOR
744 bootloader (there are cryptographic hashes in the
745 firmware itself), so it doesn't matter that this is
749 for (i
= 0; i
< length
; i
++) {
750 /* add 8 unsigned bits but keep a 32 bit sum */
751 chksum
+= ipod_sectorbuf
[i
];
754 x
= ipod
->diroffset
% ipod
->sector_size
;
757 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
759 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
760 if (n
< 0) { return -1; }
762 /* Create a new directory entry */
764 /* Copy OSOS or OSBK details - we assume one of them exists */
765 p
= ipod_sectorbuf
+ x
;
767 for (i
= 0; !found
&& i
< ipod
->nimages
; i
++) {
768 if ((memcmp(p
+ 4, "soso", 4)==0) || (memcmp(p
+ 4, "kbso", 4)==0)) {
776 fprintf(stderr
,"[ERR] No OSOS or OSBK image to copy directory from\n");
780 /* Copy directory image */
781 memcpy(ipod_sectorbuf
+ x
+ (ipod
->nimages
* 40), p
, 40);
782 p
= ipod_sectorbuf
+ x
+ (ipod
->nimages
* 40);
784 /* Modify directory. */
785 memcpy(p
+ 4, imagename
, 4);
786 int2le(offset
- ipod
->fwoffset
, p
+ 12); /* devOffset */
787 int2le(length
- (ipod
->modelnum
==62 ? 0x800: 0), p
+ 16); /* len */
788 int2le(chksum
, p
+ 28); /* checksum */
790 /* Write directory */
791 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
792 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
793 if (n
< 0) { return -1; }
800 Bootloader installation on the Nano2G consists of renaming the
801 OSOS image to OSBK and then writing the Rockbox bootloader as a
804 Maybe this approach can/should be adapted for other ipods, as it
805 prevents the Apple bootloader loading the original firmware into
806 RAM along with the Rockbox bootloader (and hence will give a
807 faster boot when the user just wants to start Rockbox).
811 static int add_bootloader_nano2g(struct ipod_t
* ipod
, char* filename
, int type
)
816 /* Check if we already have an OSBK image */
817 for (i
= 0; i
< ipod
->nimages
; i
++) {
818 if (ipod
->ipod_directory
[i
].ftype
==FTYPE_OSBK
) {
824 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
825 fprintf(stderr
,"[INFO] Creating OSBK backup image of original firmware\n");
827 if (rename_image(ipod
, "soso", "kbso") < 0) {
828 fprintf(stderr
,"[ERR] Could not rename OSOS image\n");
832 /* Add our bootloader as a brand new image */
833 return add_new_image(ipod
, "soso", filename
, type
);
835 /* This is an update, just replace OSOS with our bootloader */
837 return write_firmware(ipod
, filename
, type
);
842 static int delete_bootloader_nano2g(struct ipod_t
* ipod
)
847 /* Check if we have an OSBK image */
848 for (i
= 0; i
< ipod
->nimages
; i
++) {
849 if (ipod
->ipod_directory
[i
].ftype
==FTYPE_OSBK
) {
855 fprintf(stderr
,"[ERR] No OSBK image found - nothing to uninstall\n");
858 /* Delete our bootloader image */
859 if (delete_image(ipod
, "soso") < 0) {
860 fprintf(stderr
,"[WARN] Could not delete OSOS image\n");
862 fprintf(stderr
,"[INFO] OSOS image deleted\n");
865 if (rename_image(ipod
, "kbso", "soso") < 0) {
866 fprintf(stderr
,"[ERR] Could not rename OSBK image\n");
871 fprintf(stderr
,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
877 int add_bootloader(struct ipod_t
* ipod
, char* filename
, int type
)
887 unsigned long chksum
=0;
888 unsigned long filechksum
=0;
889 unsigned char header
[8]; /* Header for .ipod file */
890 unsigned char* bootloader_buf
;
892 /* The 2nd gen Nano is installed differently */
893 if (ipod
->modelnum
== 62) {
894 return add_bootloader_nano2g(ipod
, filename
, type
);
897 /* Calculate the position in the OSOS image where our bootloader will go. */
898 if (ipod
->ipod_directory
[0].entryOffset
>0) {
899 /* Keep the same entryOffset */
900 entryOffset
= ipod
->ipod_directory
[0].entryOffset
;
902 entryOffset
= (ipod
->ipod_directory
[0].len
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
906 if (type
== FILETYPE_INTERNAL
) {
907 fprintf(stderr
,"[INFO] Using internal bootloader - %d bytes\n",ipod
->bootloader_len
);
908 memcpy(ipod_sectorbuf
+entryOffset
,ipod
->bootloader
,ipod
->bootloader_len
);
909 length
= ipod
->bootloader_len
;
910 paddedlength
=(ipod
->bootloader_len
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
915 infile
=open(filename
,O_RDONLY
);
917 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
921 if (type
==FILETYPE_DOT_IPOD
) {
922 /* First check that the input file is the correct type for this ipod. */
923 n
= read(infile
,header
,8);
925 fprintf(stderr
,"[ERR] Failed to read header from %s\n",filename
);
930 if (memcmp(header
+4, ipod
->modelname
,4)!=0) {
931 fprintf(stderr
,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
932 header
[4],header
[5],header
[6],header
[7], ipod
->modelname
);
937 filechksum
= be2int(header
);
939 length
=filesize(infile
)-8;
941 length
=filesize(infile
);
943 paddedlength
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
945 bootloader_buf
= malloc(length
);
946 if (bootloader_buf
== NULL
) {
947 fprintf(stderr
,"[ERR] Can not allocate memory for bootloader\n");
950 /* Now read our bootloader - we need to check it before modifying the partition*/
951 n
= read(infile
,bootloader_buf
,length
);
955 fprintf(stderr
,"[ERR] Couldn't read input file\n");
959 if (type
==FILETYPE_DOT_IPOD
) {
960 /* Calculate and confirm bootloader checksum */
961 chksum
= ipod
->modelnum
;
962 for (i
= 0; i
< length
; i
++) {
963 /* add 8 unsigned bits but keep a 32 bit sum */
964 chksum
+= bootloader_buf
[i
];
967 if (chksum
== filechksum
) {
968 fprintf(stderr
,"[INFO] Checksum OK in %s\n",filename
);
970 fprintf(stderr
,"[ERR] Checksum in %s failed check\n",filename
);
976 if (entryOffset
+paddedlength
> BUFFER_SIZE
) {
977 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
982 fprintf(stderr
,"[VERB] Original firmware begins at 0x%08x\n", ipod
->ipod_directory
[0].devOffset
+ ipod
->sector_size
);
983 fprintf(stderr
,"[VERB] New entryOffset will be 0x%08x\n",entryOffset
);
984 fprintf(stderr
,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset
+paddedlength
);
987 /* Check if we have enough space */
988 /* TODO: Check the size of the partition. */
989 if (ipod
->nimages
> 1) {
990 if ((ipod
->ipod_directory
[0].devOffset
+entryOffset
+paddedlength
) >
991 ipod
->ipod_directory
[1].devOffset
) {
992 fprintf(stderr
,"[INFO] Moving images to create room for new firmware...\n");
993 delta
= ipod
->ipod_directory
[0].devOffset
+ entryOffset
+paddedlength
994 - ipod
->ipod_directory
[1].devOffset
+ ipod
->sector_size
;
996 if (diskmove(ipod
, delta
) < 0) {
997 fprintf(stderr
,"[ERR] Image movement failed.\n");
1004 /* We have moved the partitions, now we can write our bootloader */
1006 /* Firstly read the original firmware into ipod_sectorbuf */
1007 fprintf(stderr
,"[INFO] Reading original firmware...\n");
1008 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[0].devOffset
) < 0) {
1009 fprintf(stderr
,"[ERR] Seek failed\n");
1013 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,entryOffset
)) < 0) {
1014 perror("[ERR] Read failed\n");
1018 if (n
< entryOffset
) {
1019 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
1024 #ifdef WITH_BOOTOBJS
1025 if (type
== FILETYPE_INTERNAL
) {
1026 memcpy(ipod_sectorbuf
+entryOffset
,ipod
->bootloader
,ipod
->bootloader_len
);
1031 memcpy(ipod_sectorbuf
+entryOffset
,bootloader_buf
,length
);
1032 free(bootloader_buf
);
1035 /* Calculate new checksum for combined image */
1037 for (i
=0;i
<entryOffset
+ length
; i
++) {
1038 chksum
+= ipod_sectorbuf
[i
];
1041 /* Now write the combined firmware image to the disk */
1043 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[0].devOffset
) < 0) {
1044 fprintf(stderr
,"[ERR] Seek failed\n");
1048 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,entryOffset
+paddedlength
)) < 0) {
1049 perror("[ERR] Write failed\n");
1053 if (n
< (entryOffset
+paddedlength
)) {
1054 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n"
1055 ,entryOffset
+paddedlength
,n
);
1059 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset
+paddedlength
);
1061 x
= ipod
->diroffset
% ipod
->sector_size
;
1063 /* Read directory */
1064 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
1065 fprintf(stderr
,"[ERR] Seek failed\n");
1069 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1071 fprintf(stderr
,"[ERR] Directory read failed\n");
1075 /* Update entries for image 0 */
1076 int2le(entryOffset
+length
,ipod_sectorbuf
+x
+16);
1077 int2le(entryOffset
,ipod_sectorbuf
+x
+24);
1078 int2le(chksum
,ipod_sectorbuf
+x
+28);
1079 int2le(0xffffffff,ipod_sectorbuf
+x
+36); /* loadAddr */
1081 /* Update devOffset entries for other images, if we have moved them */
1083 for (i
=1;i
<ipod
->nimages
;i
++) {
1084 int2le(le2int(ipod_sectorbuf
+x
+i
*40+12)+delta
,ipod_sectorbuf
+x
+i
*40+12);
1088 /* Write directory */
1089 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
1090 fprintf(stderr
,"[ERR] Seek to %d failed\n", (int)(ipod
->start
+ipod
->diroffset
-x
));
1093 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1095 fprintf(stderr
,"[ERR] Directory write failed\n");
1102 int delete_bootloader(struct ipod_t
* ipod
)
1108 unsigned long chksum
=0; /* 32 bit checksum - Rockbox .ipod style*/
1110 /* The 2nd gen Nano is installed differently */
1111 if (ipod
->modelnum
== 62) {
1112 return delete_bootloader_nano2g(ipod
);
1115 /* Removing the bootloader involves adjusting the "length",
1116 "chksum" and "entryOffset" values in the osos image's directory
1119 /* Firstly check we have a bootloader... */
1121 if (ipod
->ipod_directory
[0].entryOffset
== 0) {
1122 fprintf(stderr
,"[ERR] No bootloader found.\n");
1126 length
= ipod
->ipod_directory
[0].entryOffset
;
1128 /* Read the firmware so we can calculate the checksum */
1129 fprintf(stderr
,"[INFO] Reading firmware (%d bytes)\n",length
);
1131 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[0].devOffset
) < 0) {
1135 i
= (length
+ipod
->sector_size
-1) & ~(ipod
->sector_size
-1);
1136 fprintf(stderr
,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1139 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,i
)) < 0) {
1144 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
1150 for (i
= 0; i
< length
; i
++) {
1151 /* add 8 unsigned bits but keep a 32 bit sum */
1152 chksum
+= ipod_sectorbuf
[i
];
1155 /* Now write back the updated directory entry */
1157 fprintf(stderr
,"[INFO] Updating firmware checksum\n");
1159 x
= ipod
->diroffset
% ipod
->sector_size
;
1161 /* Read directory */
1162 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
1164 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1165 if (n
< 0) { return -1; }
1167 /* Update entries for image 0 */
1168 int2le(length
,ipod_sectorbuf
+x
+16);
1169 int2le(0,ipod_sectorbuf
+x
+24);
1170 int2le(chksum
,ipod_sectorbuf
+x
+28);
1172 /* Write directory */
1173 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
1174 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1175 if (n
< 0) { return -1; }
1180 int write_firmware(struct ipod_t
* ipod
, char* filename
, int type
)
1189 unsigned long chksum
=0;
1190 unsigned long filechksum
=0;
1191 unsigned long offset
;
1192 unsigned char header
[8]; /* Header for .ipod file */
1195 #ifdef WITH_BOOTOBJS
1196 if (type
== FILETYPE_INTERNAL
) {
1197 fprintf(stderr
,"[INFO] Using internal bootloader - %d bytes\n",ipod
->bootloader_len
);
1198 length
= ipod
->bootloader_len
;
1204 /* First check that the input file is the correct type for this ipod. */
1205 infile
=open(filename
,O_RDONLY
);
1207 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
1211 if (type
==FILETYPE_DOT_IPOD
) {
1212 n
= read(infile
,header
,8);
1214 fprintf(stderr
,"[ERR] Failed to read header from %s\n",filename
);
1219 if (memcmp(header
+4, ipod
->modelname
,4)!=0) {
1220 fprintf(stderr
,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
1221 header
[4],header
[5],header
[6],header
[7], ipod
->modelname
);
1226 filechksum
= be2int(header
);
1228 length
= filesize(infile
)-8;
1230 length
= filesize(infile
);
1234 newsize
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
1236 fprintf(stderr
,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1239 if (newsize
> BUFFER_SIZE
) {
1240 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
1241 if (infile
>= 0) close(infile
);
1245 /* Check if we have enough space */
1246 /* TODO: Check the size of the partition. */
1247 if (ipod
->nimages
> 1) {
1248 bytesavailable
=ipod
->ipod_directory
[1].devOffset
-ipod
->ipod_directory
[0].devOffset
;
1249 if (bytesavailable
< newsize
) {
1250 fprintf(stderr
,"[INFO] Moving images to create room for new firmware...\n");
1252 /* TODO: Implement image movement */
1253 fprintf(stderr
,"[ERR] Image movement not yet implemented.\n");
1259 #ifdef WITH_BOOTOBJS
1260 if (type
== FILETYPE_INTERNAL
) {
1261 memcpy(ipod_sectorbuf
,ipod
->bootloader
,ipod
->bootloader_len
);
1266 fprintf(stderr
,"[INFO] Reading input file...\n");
1267 /* We now know we have enough space, so write it. */
1268 n
= read(infile
,ipod_sectorbuf
,length
);
1270 fprintf(stderr
,"[ERR] Couldn't read input file\n");
1277 /* Pad the data with zeros */
1278 memset(ipod_sectorbuf
+length
,0,newsize
-length
);
1280 if (type
==FILETYPE_DOT_IPOD
) {
1281 chksum
= ipod
->modelnum
;
1282 for (i
= 0; i
< length
; i
++) {
1283 /* add 8 unsigned bits but keep a 32 bit sum */
1284 chksum
+= ipod_sectorbuf
[i
];
1287 if (chksum
== filechksum
) {
1288 fprintf(stderr
,"[INFO] Checksum OK in %s\n",filename
);
1290 fprintf(stderr
,"[ERR] Checksum in %s failed check\n",filename
);
1296 offset
= ipod
->fwoffset
+ipod
->ipod_directory
[ipod
->ososimage
].devOffset
;
1298 if (ipod
->modelnum
==62) {
1300 /* 2nd Gen Nano has encrypted firmware, and the sector
1301 preceeding the firmware contains hashes that need to be
1302 preserved. Nano 2G images include these extra 2048 (0x800)
1308 /* TODO: The above checks need to take into account this 0x800 bytes */
1311 if (ipod_seek(ipod
, offset
) < 0) {
1312 fprintf(stderr
,"[ERR] Seek failed\n");
1316 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,newsize
)) < 0) {
1317 perror("[ERR] Write failed\n");
1322 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
1326 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",n
);
1328 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1330 NOTE: On the Nano 2G, the checksum is the checksum of the
1331 unencrypted firmware. But this isn't checked by the NOR
1332 bootloader (there are cryptographic hashes in the
1333 firmware itself), so it doesn't matter that this is
1337 for (i
= 0; i
< length
; i
++) {
1338 /* add 8 unsigned bits but keep a 32 bit sum */
1339 chksum
+= ipod_sectorbuf
[i
];
1342 x
= ipod
->diroffset
% ipod
->sector_size
;
1344 /* Read directory */
1345 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
1347 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1348 if (n
< 0) { return -1; }
1350 /* Update entries for image */
1351 p
= ipod_sectorbuf
+ x
+ (ipod
->ososimage
* 40);
1352 int2le(length
- (ipod
->modelnum
==62 ? 0x800: 0), p
+ 16);
1354 int2le(chksum
, p
+ 28);
1356 /* Write directory */
1357 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
1358 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1359 if (n
< 0) { return -1; }
1364 int read_firmware(struct ipod_t
* ipod
, char* filename
, int type
)
1370 unsigned long offset
;
1371 unsigned long chksum
=0; /* 32 bit checksum - Rockbox .ipod style*/
1372 unsigned char header
[8]; /* Header for .ipod file */
1374 if (ipod
->ipod_directory
[ipod
->ososimage
].entryOffset
!= 0) {
1375 /* We have a bootloader... */
1376 length
= ipod
->ipod_directory
[ipod
->ososimage
].entryOffset
;
1378 length
= ipod
->ipod_directory
[ipod
->ososimage
].len
;
1381 fprintf(stderr
,"[INFO] Reading firmware (%d bytes)\n",length
);
1383 offset
= ipod
->fwoffset
+ ipod
->ipod_directory
[ipod
->ososimage
].devOffset
;
1384 i
= (length
+ipod
->sector_size
-1) & ~(ipod
->sector_size
-1);
1385 fprintf(stderr
,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1388 if (ipod
->modelnum
==62) {
1389 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1390 sector preceeding the image - it contains hashes */
1396 if (ipod_seek(ipod
, offset
)) {
1400 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,i
)) < 0) {
1405 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
1410 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
1412 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
1416 if (type
== FILETYPE_DOT_IPOD
) {
1417 chksum
= ipod
->modelnum
;
1418 for (i
= 0; i
< length
; i
++) {
1419 /* add 8 unsigned bits but keep a 32 bit sum */
1420 chksum
+= ipod_sectorbuf
[i
];
1423 int2be(chksum
,header
);
1424 memcpy(header
+4, ipod
->modelname
,4);
1426 n
= write(outfile
,header
,8);
1428 fprintf(stderr
,"[ERR] Write error - %d\n",n
);
1432 n
= write(outfile
,ipod_sectorbuf
,length
);
1434 fprintf(stderr
,"[ERR] Write error - %d\n",n
);
1441 int read_directory(struct ipod_t
* ipod
)
1446 unsigned short version
;
1450 /* Read firmware partition header (first 512 bytes of disk - but
1451 let's read a whole sector) */
1453 if (ipod_seek(ipod
, ipod
->start
) < 0) {
1454 fprintf(stderr
,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1455 (unsigned int)(ipod
->start
));
1459 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1461 fprintf(stderr
,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod
->sector_size
);
1465 if (memcmp(ipod_sectorbuf
,apple_stop_sign
,sizeof(apple_stop_sign
))!=0) {
1466 fprintf(stderr
,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1470 if (memcmp(ipod_sectorbuf
+0x100,"]ih[",4)!=0) {
1471 fprintf(stderr
,"[ERR] Bad firmware directory\n");
1475 version
= le2ushort(ipod_sectorbuf
+0x10a);
1476 if ((version
!= 2) && (version
!= 3)) {
1477 fprintf(stderr
,"[ERR] Unknown firmware format version %04x\n",
1480 ipod
->diroffset
=le2int(ipod_sectorbuf
+0x104) + 0x200;
1482 /* diroffset may not be sector-aligned */
1483 x
= ipod
->diroffset
% ipod
->sector_size
;
1485 /* Read directory */
1486 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) {
1487 fprintf(stderr
,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod
->diroffset
);
1491 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1493 fprintf(stderr
,"[ERR] Read of directory failed.\n");
1497 p
= ipod_sectorbuf
+ x
;
1499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1502 /* Adjust diroffset */
1503 ipod
->diroffset
+= ipod
->sector_size
- x
;
1505 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
1507 fprintf(stderr
,"[ERR] Read of directory failed.\n");
1513 ipod
->ososimage
= -1;
1514 while ((ipod
->nimages
< MAX_IMAGES
) && (p
< (ipod_sectorbuf
+ x
+ 400)) &&
1515 ((memcmp(p
,"!ATA",4)==0) || (memcmp(p
,"DNAN",4)==0))) {
1517 if (memcmp(p
,"soso",4)==0) {
1518 ipod
->ipod_directory
[ipod
->nimages
].ftype
=FTYPE_OSOS
;
1519 ipod
->ososimage
= ipod
->nimages
;
1520 } else if (memcmp(p
,"crsr",4)==0) {
1521 ipod
->ipod_directory
[ipod
->nimages
].ftype
=FTYPE_RSRC
;
1522 } else if (memcmp(p
,"dpua",4)==0) {
1523 ipod
->ipod_directory
[ipod
->nimages
].ftype
=FTYPE_AUPD
;
1524 } else if (memcmp(p
,"kbso",4)==0) {
1525 ipod
->ipod_directory
[ipod
->nimages
].ftype
=FTYPE_OSBK
;
1526 } else if (memcmp(p
,"ebih",4)==0) {
1527 ipod
->ipod_directory
[ipod
->nimages
].ftype
=FTYPE_HIBE
;
1529 fprintf(stderr
,"[ERR] Unknown image type %c%c%c%c\n",
1530 p
[0],p
[1],p
[2],p
[3]);
1533 ipod
->ipod_directory
[ipod
->nimages
].id
=le2int(p
);
1535 ipod
->ipod_directory
[ipod
->nimages
].devOffset
=le2int(p
);
1537 ipod
->ipod_directory
[ipod
->nimages
].len
=le2int(p
);
1539 ipod
->ipod_directory
[ipod
->nimages
].addr
=le2int(p
);
1541 ipod
->ipod_directory
[ipod
->nimages
].entryOffset
=le2int(p
);
1543 ipod
->ipod_directory
[ipod
->nimages
].chksum
=le2int(p
);
1545 ipod
->ipod_directory
[ipod
->nimages
].vers
=le2int(p
);
1547 ipod
->ipod_directory
[ipod
->nimages
].loadAddr
=le2int(p
);
1552 if (ipod
->ososimage
< 0) {
1553 fprintf(stderr
,"[ERR] No OSOS image found.\n");
1557 if ((ipod
->nimages
> 1) && (version
==2)) {
1558 /* The 3g firmware image doesn't appear to have a version, so
1559 let's make one up... Note that this is never written back to the
1560 ipod, so it's OK to do. */
1562 if (ipod
->ipod_directory
[ipod
->ososimage
].vers
== 0) { ipod
->ipod_directory
[ipod
->ososimage
].vers
= 3; }
1564 ipod
->fwoffset
= ipod
->start
;
1566 ipod
->fwoffset
= ipod
->start
+ ipod
->sector_size
;
1572 int list_images(struct ipod_t
* ipod
)
1577 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1578 for (i
= 0 ; i
< ipod
->nimages
; i
++) {
1579 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i
,
1580 ftypename
[ipod
->ipod_directory
[i
].ftype
],
1581 ipod
->ipod_directory
[i
].id
,
1582 ipod
->ipod_directory
[i
].devOffset
,
1583 ipod
->ipod_directory
[i
].len
,
1584 ipod
->ipod_directory
[i
].addr
,
1585 ipod
->ipod_directory
[i
].entryOffset
,
1586 ipod
->ipod_directory
[i
].chksum
,
1587 ipod
->ipod_directory
[i
].vers
,
1588 ipod
->ipod_directory
[i
].loadAddr
,
1589 ipod
->ipod_directory
[i
].devOffset
+((ipod
->ipod_directory
[i
].len
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1)));
1594 printf("Listing firmware partition contents:\n");
1597 for (i
= 0 ; i
< ipod
->nimages
; i
++) {
1598 printf("Image %d:\n",i
+1);
1599 switch(ipod
->ipod_directory
[i
].ftype
) {
1601 if (ipod
->ipod_directory
[i
].entryOffset
==0) {
1602 printf(" Main firmware - %d bytes\n",
1603 ipod
->ipod_directory
[i
].len
);
1605 printf(" Main firmware - %d bytes\n",
1606 ipod
->ipod_directory
[i
].entryOffset
);
1607 printf(" Third-party bootloader - %d bytes\n",
1608 ipod
->ipod_directory
[i
].len
-ipod
->ipod_directory
[i
].entryOffset
);
1612 printf(" %s - %d bytes\n",
1613 ftypename
[ipod
->ipod_directory
[i
].ftype
],
1614 ipod
->ipod_directory
[i
].len
);
1622 int getmodel(struct ipod_t
* ipod
, int ipod_version
)
1624 switch (ipod_version
) {
1626 ipod
->modelstr
="1st or 2nd Generation";
1627 ipod
->modelnum
= 19;
1628 ipod
->modelname
= "1g2g";
1629 ipod
->targetname
= "ipod1g2g";
1630 #ifdef WITH_BOOTOBJS
1631 ipod
->bootloader
= ipod1g2g
;
1632 ipod
->bootloader_len
= LEN_ipod1g2g
;
1636 ipod
->modelstr
="3rd Generation";
1638 ipod
->modelname
= "ip3g";
1639 ipod
->targetname
= "ipod3g";
1640 #ifdef WITH_BOOTOBJS
1641 ipod
->bootloader
= ipod3g
;
1642 ipod
->bootloader_len
= LEN_ipod3g
;
1646 ipod
->modelstr
="1st Generation Mini";
1648 ipod
->modelname
= "mini";
1649 ipod
->targetname
= "ipodmini1g";
1650 #ifdef WITH_BOOTOBJS
1651 ipod
->bootloader
= ipodmini1g
;
1652 ipod
->bootloader_len
= LEN_ipodmini1g
;
1656 ipod
->modelstr
="4th Generation";
1658 ipod
->modelname
= "ip4g";
1659 ipod
->targetname
= "ipod4gray";
1660 #ifdef WITH_BOOTOBJS
1661 ipod
->bootloader
= ipod4g
;
1662 ipod
->bootloader_len
= LEN_ipod4g
;
1666 ipod
->modelstr
="Photo/Color";
1668 ipod
->modelname
= "ipco";
1669 ipod
->targetname
= "ipodcolor";
1670 #ifdef WITH_BOOTOBJS
1671 ipod
->bootloader
= ipodcolor
;
1672 ipod
->bootloader_len
= LEN_ipodcolor
;
1676 ipod
->modelstr
="2nd Generation Mini";
1677 ipod
->modelnum
= 11;
1678 ipod
->modelname
= "mn2g";
1679 ipod
->targetname
= "ipodmini2g";
1680 #ifdef WITH_BOOTOBJS
1681 ipod
->bootloader
= ipodmini2g
;
1682 ipod
->bootloader_len
= LEN_ipodmini2g
;
1686 ipod
->modelstr
="1st Generation Nano";
1688 ipod
->modelname
= "nano";
1689 ipod
->targetname
= "ipodnano1g";
1690 #ifdef WITH_BOOTOBJS
1691 ipod
->bootloader
= ipodnano1g
;
1692 ipod
->bootloader_len
= LEN_ipodnano1g
;
1696 ipod
->modelstr
="Video (aka 5th Generation)";
1698 ipod
->modelname
= "ipvd";
1699 ipod
->targetname
= "ipodvideo";
1700 #ifdef WITH_BOOTOBJS
1701 ipod
->bootloader
= ipodvideo
;
1702 ipod
->bootloader_len
= LEN_ipodvideo
;
1706 ipod
->modelstr
="2nd Generation Nano";
1707 ipod
->modelnum
= 62;
1708 ipod
->modelname
= "nn2x";
1709 ipod
->targetname
= "ipodnano2g";
1710 #ifdef WITH_BOOTOBJS
1711 ipod
->bootloader
= ipodnano2g
;
1712 ipod
->bootloader_len
= LEN_ipodnano2g
;
1716 ipod
->modelname
= NULL
;
1718 ipod
->targetname
= NULL
;
1719 #ifdef WITH_BOOTOBJS
1720 ipod
->bootloader
= NULL
;
1721 ipod
->bootloader_len
= 0;
1728 /* returns number of found ipods or -1 if no ipods found and permission
1729 * for raw disc access was denied. */
1730 int ipod_scan(struct ipod_t
* ipod
)
1735 struct ipod_t ipod_found
;
1739 printf("[INFO] Scanning disk devices...\n");
1741 for (i
= 0; i
<= 25 ; i
++) {
1743 sprintf(ipod
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
1744 #elif defined(linux) || defined (__linux)
1745 sprintf(ipod
->diskname
,"/dev/sd%c",'a'+i
);
1746 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1747 || defined(__bsdi__) || defined(__DragonFly__)
1748 sprintf(ipod
->diskname
,"/dev/da%d",i
);
1749 #elif defined(__APPLE__) && defined(__MACH__)
1750 sprintf(ipod
->diskname
,"/dev/disk%d",i
);
1752 #error No disk paths defined for this platform
1754 if ((result
= ipod_open(ipod
, 1)) < 0) {
1762 if (read_partinfo(ipod
,1) < 0) {
1767 if ((ipod
->pinfo
[0].start
==0) || (ipod
->pinfo
[0].type
!= 0)) {
1772 if (read_directory(ipod
) < 0) {
1777 ipod_version
=(ipod
->ipod_directory
[ipod
->ososimage
].vers
>>8);
1780 /* Windows requires the ipod in R/W mode for SCSI Inquiry.
1781 * ipod_reopen_rw does unmount the player on OS X so do this on
1782 * W32 only during scanning. */
1783 ipod_reopen_rw(ipod
);
1785 ipod_get_xmlinfo(ipod
);
1786 ipod_get_ramsize(ipod
);
1787 if (getmodel(ipod
,ipod_version
) < 0) {
1793 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1794 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",i
);
1796 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1797 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",ipod
->diskname
);
1800 /* save the complete ipod_t structure for match. The for loop might
1801 * overwrite it, so we need to restore it later if only one found. */
1802 memcpy(&ipod_found
, ipod
, sizeof(struct ipod_t
));
1807 /* restore the ipod_t structure, it might have been overwritten */
1808 memcpy(ipod
, &ipod_found
, sizeof(struct ipod_t
));
1810 else if(n
== 0 && denied
) {
1811 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied
);
1813 printf("[ERR] You need to run this program with administrator priviledges!\n");
1815 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1818 return (n
== 0 && denied
) ? -1 : n
;
1821 static void put_int32le(uint32_t x
, unsigned char* p
)
1824 p
[1] = (x
>> 8) & 0xff;
1825 p
[2] = (x
>> 16) & 0xff;
1826 p
[3] = (x
>> 24) & 0xff;
1829 int write_dos_partition_table(struct ipod_t
* ipod
)
1835 /* Only support 512-byte sectors at the moment */
1836 if ( ipod
->sector_size
!= 512 )
1838 fprintf(stderr
,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1842 /* Firstly zero the entire MBR */
1843 memset(ipod_sectorbuf
, 0, ipod
->sector_size
);
1845 /* Now add the partition info */
1846 for (i
=0; i
< 4 ; i
++)
1848 p
= ipod_sectorbuf
+ 0x1be + i
*16;
1850 /* Ensure first partition is type 0, and second is 0xb */
1851 if (i
==0) { type
= 0; }
1852 else if (i
==1) { type
= 0xb; }
1853 else { type
= ipod
->pinfo
[i
].type
; }
1855 put_int32le(type
, p
+ 4);
1856 put_int32le(ipod
->pinfo
[i
].start
, p
+ 8);
1857 put_int32le(ipod
->pinfo
[i
].size
, p
+ 12);
1860 /* Finally add the magic */
1861 ipod_sectorbuf
[0x1fe] = 0x55;
1862 ipod_sectorbuf
[0x1ff] = 0xaa;
1864 if (ipod_seek(ipod
, 0) < 0) {
1865 fprintf(stderr
,"[ERR] Seek failed writing MBR\n");
1870 if ((n
= ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
)) < 0) {
1871 perror("[ERR] Write failed\n");
1878 /* Get the XML Device Information, as documented here:
1880 http://www.ipodlinux.org/wiki/Device_Information
1883 int ipod_get_xmlinfo(struct ipod_t
* ipod
)
1885 unsigned char hdr
[255];
1886 unsigned char buf
[255];
1892 if (ipod_scsi_inquiry(ipod
, 0xc0, buf
, sizeof(buf
)) < 0)
1894 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1898 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1900 memcpy(hdr
, buf
, sizeof(hdr
));
1904 psize
= npages
* 0xf8; /* Hopefully this is enough. */
1906 ipod
->xmlinfo
= malloc(psize
);
1907 ipod
->xmlinfo_len
= 0;
1909 if (ipod
->xmlinfo
== NULL
) {
1910 fprintf(stderr
,"[ERR] Could not allocate RAM for xmlinfo\n");
1916 for (i
=0; i
< npages
; i
++) {
1917 if (ipod_scsi_inquiry(ipod
, hdr
[i
+4], buf
, sizeof(buf
)) < 0) {
1918 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1922 if ((buf
[3] + ipod
->xmlinfo_len
) > psize
) {
1923 fprintf(stderr
,"[ERR] Ran out of memory reading xmlinfo\n");
1924 free(ipod
->xmlinfo
);
1925 ipod
->xmlinfo
= NULL
;
1926 ipod
->xmlinfo_len
= 0;
1930 memcpy(p
, buf
+ 4, buf
[3]);
1932 ipod
->xmlinfo_len
+= buf
[3];
1935 /* NULL-terminate the XML info */
1938 fprintf(stderr
,"[INFO] Read XML info (%d bytes)\n",ipod
->xmlinfo_len
);
1943 void ipod_get_ramsize(struct ipod_t
* ipod
)
1945 const char needle
[] = "<key>RAM</key>\n<integer>";
1948 if (ipod
->xmlinfo
== NULL
)
1951 p
= strstr(ipod
->xmlinfo
, needle
);
1954 ipod
->ramsize
= atoi(p
+ sizeof(needle
) - 1);
1960 static inline uint32_t getuint32le(unsigned char* buf
)
1962 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
1967 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1968 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1972 static bool testMarker(int marker
)
1974 int mask
, decrypt
, temp1
, temp2
;
1976 mask
= (marker
&0xff)|((marker
&0xff)<<8)|((marker
&0xff)<<16)|((marker
&0xff)<<24);
1977 decrypt
= marker
^ mask
;
1978 temp1
=(int)((unsigned int)decrypt
>>24);
1984 temp2
=(int)((unsigned int)temp2
>>24);
1985 decrypt
=decrypt
<<16;
1986 decrypt
=(int)((unsigned int)decrypt
>>24);
1988 if ((temp1
< temp2
) && (temp2
< decrypt
))
1990 temp1
= temp1
& 0xf;
1991 temp2
= temp2
& 0xf;
1992 decrypt
= decrypt
& 0xf;
1994 if ((temp1
> temp2
) && (temp2
> decrypt
) && (decrypt
!= 0))
2002 static int GetSecurityBlockKey(unsigned char *data
, unsigned char* this_key
)
2004 int constant
= 0x54c3a298;
2011 static const int offset
[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2013 for (c
= 0; c
< 8; c
++)
2016 aMarker
= getuint32le(data
+ pos
);
2018 if (testMarker(aMarker
))
2021 pos
=(offset
[c
+1]*4)+4;
2023 pos
=(offset
[0]*4)+4;
2029 for (count
=0;count
<2;count
++){
2030 int word
= getuint32le(data
+ pos
);
2033 temp1
= temp1
^constant
;
2043 for (count
=2;count
<128;count
=count
+2){
2044 r2
=getuint32le(data
+count
*4);
2045 r12
=getuint32le(data
+(count
*4)+4);
2046 r_tmp
=(unsigned int)r12
>>16;
2047 r14
=r2
| ((int)r_tmp
);
2055 // Invert key, little endian
2056 this_key
[0] = key
& 0xff;
2057 this_key
[1] = (key
>> 8) & 0xff;
2058 this_key
[2] = (key
>> 16) & 0xff;
2059 this_key
[3] = (key
>> 24) & 0xff;
2066 static int find_key(struct ipod_t
* ipod
, int aupd
, unsigned char* key
)
2070 /* Firstly read the security block and find the RC4 key. This is
2071 in the sector preceeding the AUPD image. */
2073 fprintf(stderr
, "[INFO] Reading security block at offset 0x%08x\n",ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
);
2074 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
) < 0) {
2078 if ((n
= ipod_read(ipod
, ipod_sectorbuf
, 512)) < 0) {
2082 n
= GetSecurityBlockKey(ipod_sectorbuf
, key
);
2086 fprintf(stderr
, "[ERR] %d keys found in security block, can not continue\n",n
);
2093 int read_aupd(struct ipod_t
* ipod
, char* filename
)
2100 struct rc4_key_t rc4
;
2101 unsigned char key
[4];
2102 unsigned long chksum
=0;
2105 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2110 if (aupd
== ipod
->nimages
)
2112 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2116 length
= ipod
->ipod_directory
[aupd
].len
;
2118 fprintf(stderr
,"[INFO] Reading firmware (%d bytes)\n",length
);
2120 if (find_key(ipod
, aupd
, key
) < 0)
2125 fprintf(stderr
, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2127 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2131 i
= (length
+ipod
->sector_size
-1) & ~(ipod
->sector_size
-1);
2133 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,i
)) < 0) {
2138 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
2143 /* Perform the decryption - this is standard (A)RC4 */
2144 matrixArc4Init(&rc4
, key
, 4);
2145 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2148 for (i
= 0; i
< (int)length
; i
++) {
2149 /* add 8 unsigned bits but keep a 32 bit sum */
2150 chksum
+= ipod_sectorbuf
[i
];
2153 if (chksum
!= ipod
->ipod_directory
[aupd
].chksum
)
2155 fprintf(stderr
,"[ERR] Decryption failed - checksum error\n");
2158 fprintf(stderr
,"[INFO] Decrypted OK (checksum matches header)\n");
2160 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
2162 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
2166 n
= write(outfile
,ipod_sectorbuf
,length
);
2168 fprintf(stderr
,"[ERR] Write error - %d\n",n
);
2175 int write_aupd(struct ipod_t
* ipod
, char* filename
)
2177 unsigned int length
;
2184 unsigned long chksum
=0;
2185 struct rc4_key_t rc4
;
2186 unsigned char key
[4];
2188 /* First check that the input file is the correct type for this ipod. */
2189 infile
=open(filename
,O_RDONLY
);
2191 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
2195 length
= filesize(infile
);
2196 newsize
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
2198 fprintf(stderr
,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2201 if (newsize
> BUFFER_SIZE
) {
2202 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
2203 if (infile
>= 0) close(infile
);
2207 /* Find aupd image number */
2209 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2214 if (aupd
== ipod
->nimages
)
2216 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2220 if (length
!= ipod
->ipod_directory
[aupd
].len
)
2222 fprintf(stderr
,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2223 ipod
->ipod_directory
[aupd
].len
, filename
, length
);
2227 if (find_key(ipod
, aupd
, key
) < 0)
2232 fprintf(stderr
, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2234 /* We now know we have enough space, so write it. */
2236 fprintf(stderr
,"[INFO] Reading input file...\n");
2237 n
= read(infile
,ipod_sectorbuf
,length
);
2239 fprintf(stderr
,"[ERR] Couldn't read input file\n");
2245 /* Pad the data with zeros */
2246 memset(ipod_sectorbuf
+length
,0,newsize
-length
);
2248 /* Calculate the new checksum (before we encrypt) */
2250 for (i
= 0; i
< (int)length
; i
++) {
2251 /* add 8 unsigned bits but keep a 32 bit sum */
2252 chksum
+= ipod_sectorbuf
[i
];
2255 /* Perform the encryption - this is standard (A)RC4 */
2256 matrixArc4Init(&rc4
, key
, 4);
2257 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2259 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2260 fprintf(stderr
,"[ERR] Seek failed\n");
2264 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,newsize
)) < 0) {
2265 perror("[ERR] Write failed\n");
2270 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
2274 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",n
);
2276 x
= ipod
->diroffset
% ipod
->sector_size
;
2278 /* Read directory */
2279 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2281 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2282 if (n
< 0) { return -1; }
2284 /* Update checksum */
2285 fprintf(stderr
,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum
,le2int(ipod_sectorbuf
+ x
+ aupd
*40 + 28));
2286 int2le(chksum
,ipod_sectorbuf
+x
+aupd
*40+28);
2288 /* Write directory */
2289 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2290 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2291 if (n
< 0) { return -1; }