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"
41 #include "ipodmini2g.h"
42 #include "ipodcolor.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
= ipodmini
;
1652 ipod
->bootloader_len
= LEN_ipodmini
;
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
= "ipodnano";
1690 #ifdef WITH_BOOTOBJS
1691 ipod
->bootloader
= ipodnano
;
1692 ipod
->bootloader_len
= LEN_ipodnano
;
1696 ipod
->modelstr
="Video (aka 5th Generation)";
1698 ipod
->modelname
= "ipvd";
1699 if(ipod
->ramsize
== 64) {
1700 ipod
->targetname
= "ipodvideo64mb";
1703 ipod
->targetname
= "ipodvideo";
1705 #ifdef WITH_BOOTOBJS
1706 ipod
->bootloader
= ipodvideo
;
1707 ipod
->bootloader_len
= LEN_ipodvideo
;
1711 ipod
->modelstr
="2nd Generation Nano";
1712 ipod
->modelnum
= 62;
1713 ipod
->modelname
= "nn2x";
1714 ipod
->targetname
= "ipodnano2g";
1715 #ifdef WITH_BOOTOBJS
1716 ipod
->bootloader
= ipodnano2g
;
1717 ipod
->bootloader_len
= LEN_ipodnano2g
;
1721 ipod
->modelname
= NULL
;
1723 ipod
->targetname
= NULL
;
1724 #ifdef WITH_BOOTOBJS
1725 ipod
->bootloader
= NULL
;
1726 ipod
->bootloader_len
= 0;
1733 /* returns number of found ipods or -1 if no ipods found and permission
1734 * for raw disc access was denied. */
1735 int ipod_scan(struct ipod_t
* ipod
)
1740 struct ipod_t ipod_found
;
1744 printf("[INFO] Scanning disk devices...\n");
1746 for (i
= 0; i
<= 25 ; i
++) {
1748 sprintf(ipod
->diskname
,"\\\\.\\PhysicalDrive%d",i
);
1749 #elif defined(linux) || defined (__linux)
1750 sprintf(ipod
->diskname
,"/dev/sd%c",'a'+i
);
1751 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1752 || defined(__bsdi__) || defined(__DragonFly__)
1753 sprintf(ipod
->diskname
,"/dev/da%d",i
);
1754 #elif defined(__APPLE__) && defined(__MACH__)
1755 sprintf(ipod
->diskname
,"/dev/disk%d",i
);
1757 #error No disk paths defined for this platform
1759 if ((result
= ipod_open(ipod
, 1)) < 0) {
1767 if (read_partinfo(ipod
,1) < 0) {
1772 if ((ipod
->pinfo
[0].start
==0) || (ipod
->pinfo
[0].type
!= 0)) {
1777 if (read_directory(ipod
) < 0) {
1782 ipod_version
=(ipod
->ipod_directory
[ipod
->ososimage
].vers
>>8);
1785 /* Windows requires the ipod in R/W mode for SCSI Inquiry.
1786 * ipod_reopen_rw does unmount the player on OS X so do this on
1787 * W32 only during scanning. */
1788 ipod_reopen_rw(ipod
);
1790 ipod_get_xmlinfo(ipod
);
1791 ipod_get_ramsize(ipod
);
1792 if (getmodel(ipod
,ipod_version
) < 0) {
1798 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1799 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",i
);
1801 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1802 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",ipod
->diskname
);
1805 /* save the complete ipod_t structure for match. The for loop might
1806 * overwrite it, so we need to restore it later if only one found. */
1807 memcpy(&ipod_found
, ipod
, sizeof(struct ipod_t
));
1812 /* restore the ipod_t structure, it might have been overwritten */
1813 memcpy(ipod
, &ipod_found
, sizeof(struct ipod_t
));
1815 else if(n
== 0 && denied
) {
1816 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied
);
1818 printf("[ERR] You need to run this program with administrator priviledges!\n");
1820 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1823 return (n
== 0 && denied
) ? -1 : n
;
1826 static void put_int32le(uint32_t x
, unsigned char* p
)
1829 p
[1] = (x
>> 8) & 0xff;
1830 p
[2] = (x
>> 16) & 0xff;
1831 p
[3] = (x
>> 24) & 0xff;
1834 int write_dos_partition_table(struct ipod_t
* ipod
)
1840 /* Only support 512-byte sectors at the moment */
1841 if ( ipod
->sector_size
!= 512 )
1843 fprintf(stderr
,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1847 /* Firstly zero the entire MBR */
1848 memset(ipod_sectorbuf
, 0, ipod
->sector_size
);
1850 /* Now add the partition info */
1851 for (i
=0; i
< 4 ; i
++)
1853 p
= ipod_sectorbuf
+ 0x1be + i
*16;
1855 /* Ensure first partition is type 0, and second is 0xb */
1856 if (i
==0) { type
= 0; }
1857 else if (i
==1) { type
= 0xb; }
1858 else { type
= ipod
->pinfo
[i
].type
; }
1860 put_int32le(type
, p
+ 4);
1861 put_int32le(ipod
->pinfo
[i
].start
, p
+ 8);
1862 put_int32le(ipod
->pinfo
[i
].size
, p
+ 12);
1865 /* Finally add the magic */
1866 ipod_sectorbuf
[0x1fe] = 0x55;
1867 ipod_sectorbuf
[0x1ff] = 0xaa;
1869 if (ipod_seek(ipod
, 0) < 0) {
1870 fprintf(stderr
,"[ERR] Seek failed writing MBR\n");
1875 if ((n
= ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
)) < 0) {
1876 perror("[ERR] Write failed\n");
1883 /* Get the XML Device Information, as documented here:
1885 http://www.ipodlinux.org/wiki/Device_Information
1888 int ipod_get_xmlinfo(struct ipod_t
* ipod
)
1890 unsigned char hdr
[255];
1891 unsigned char buf
[255];
1897 if (ipod_scsi_inquiry(ipod
, 0xc0, buf
, sizeof(buf
)) < 0)
1899 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1903 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1905 memcpy(hdr
, buf
, sizeof(hdr
));
1909 psize
= npages
* 0xf8; /* Hopefully this is enough. */
1911 ipod
->xmlinfo
= malloc(psize
);
1912 ipod
->xmlinfo_len
= 0;
1914 if (ipod
->xmlinfo
== NULL
) {
1915 fprintf(stderr
,"[ERR] Could not allocate RAM for xmlinfo\n");
1921 for (i
=0; i
< npages
; i
++) {
1922 if (ipod_scsi_inquiry(ipod
, hdr
[i
+4], buf
, sizeof(buf
)) < 0) {
1923 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1927 if ((buf
[3] + ipod
->xmlinfo_len
) > psize
) {
1928 fprintf(stderr
,"[ERR] Ran out of memory reading xmlinfo\n");
1929 free(ipod
->xmlinfo
);
1930 ipod
->xmlinfo
= NULL
;
1931 ipod
->xmlinfo_len
= 0;
1935 memcpy(p
, buf
+ 4, buf
[3]);
1937 ipod
->xmlinfo_len
+= buf
[3];
1940 /* NULL-terminate the XML info */
1943 fprintf(stderr
,"[INFO] Read XML info (%d bytes)\n",ipod
->xmlinfo_len
);
1948 void ipod_get_ramsize(struct ipod_t
* ipod
)
1950 const char needle
[] = "<key>RAM</key>\n<integer>";
1953 if (ipod
->xmlinfo
== NULL
)
1956 p
= strstr(ipod
->xmlinfo
, needle
);
1959 ipod
->ramsize
= atoi(p
+ sizeof(needle
) - 1);
1965 static inline uint32_t getuint32le(unsigned char* buf
)
1967 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
1972 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1973 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1977 static bool testMarker(int marker
)
1979 int mask
, decrypt
, temp1
, temp2
;
1981 mask
= (marker
&0xff)|((marker
&0xff)<<8)|((marker
&0xff)<<16)|((marker
&0xff)<<24);
1982 decrypt
= marker
^ mask
;
1983 temp1
=(int)((unsigned int)decrypt
>>24);
1989 temp2
=(int)((unsigned int)temp2
>>24);
1990 decrypt
=decrypt
<<16;
1991 decrypt
=(int)((unsigned int)decrypt
>>24);
1993 if ((temp1
< temp2
) && (temp2
< decrypt
))
1995 temp1
= temp1
& 0xf;
1996 temp2
= temp2
& 0xf;
1997 decrypt
= decrypt
& 0xf;
1999 if ((temp1
> temp2
) && (temp2
> decrypt
) && (decrypt
!= 0))
2007 static int GetSecurityBlockKey(unsigned char *data
, unsigned char* this_key
)
2009 int constant
= 0x54c3a298;
2016 static const int offset
[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2018 for (c
= 0; c
< 8; c
++)
2021 aMarker
= getuint32le(data
+ pos
);
2023 if (testMarker(aMarker
))
2026 pos
=(offset
[c
+1]*4)+4;
2028 pos
=(offset
[0]*4)+4;
2034 for (count
=0;count
<2;count
++){
2035 int word
= getuint32le(data
+ pos
);
2038 temp1
= temp1
^constant
;
2048 for (count
=2;count
<128;count
=count
+2){
2049 r2
=getuint32le(data
+count
*4);
2050 r12
=getuint32le(data
+(count
*4)+4);
2051 r_tmp
=(unsigned int)r12
>>16;
2052 r14
=r2
| ((int)r_tmp
);
2060 // Invert key, little endian
2061 this_key
[0] = key
& 0xff;
2062 this_key
[1] = (key
>> 8) & 0xff;
2063 this_key
[2] = (key
>> 16) & 0xff;
2064 this_key
[3] = (key
>> 24) & 0xff;
2071 static int find_key(struct ipod_t
* ipod
, int aupd
, unsigned char* key
)
2075 /* Firstly read the security block and find the RC4 key. This is
2076 in the sector preceeding the AUPD image. */
2078 fprintf(stderr
, "[INFO] Reading security block at offset 0x%08x\n",ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
);
2079 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
) < 0) {
2083 if ((n
= ipod_read(ipod
, ipod_sectorbuf
, 512)) < 0) {
2087 n
= GetSecurityBlockKey(ipod_sectorbuf
, key
);
2091 fprintf(stderr
, "[ERR] %d keys found in security block, can not continue\n",n
);
2098 int read_aupd(struct ipod_t
* ipod
, char* filename
)
2105 struct rc4_key_t rc4
;
2106 unsigned char key
[4];
2107 unsigned long chksum
=0;
2110 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2115 if (aupd
== ipod
->nimages
)
2117 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2121 length
= ipod
->ipod_directory
[aupd
].len
;
2123 fprintf(stderr
,"[INFO] Reading firmware (%d bytes)\n",length
);
2125 if (find_key(ipod
, aupd
, key
) < 0)
2130 fprintf(stderr
, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2132 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2136 i
= (length
+ipod
->sector_size
-1) & ~(ipod
->sector_size
-1);
2138 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,i
)) < 0) {
2143 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
2148 /* Perform the decryption - this is standard (A)RC4 */
2149 matrixArc4Init(&rc4
, key
, 4);
2150 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2153 for (i
= 0; i
< (int)length
; i
++) {
2154 /* add 8 unsigned bits but keep a 32 bit sum */
2155 chksum
+= ipod_sectorbuf
[i
];
2158 if (chksum
!= ipod
->ipod_directory
[aupd
].chksum
)
2160 fprintf(stderr
,"[ERR] Decryption failed - checksum error\n");
2163 fprintf(stderr
,"[INFO] Decrypted OK (checksum matches header)\n");
2165 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
2167 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
2171 n
= write(outfile
,ipod_sectorbuf
,length
);
2173 fprintf(stderr
,"[ERR] Write error - %d\n",n
);
2180 int write_aupd(struct ipod_t
* ipod
, char* filename
)
2182 unsigned int length
;
2189 unsigned long chksum
=0;
2190 struct rc4_key_t rc4
;
2191 unsigned char key
[4];
2193 /* First check that the input file is the correct type for this ipod. */
2194 infile
=open(filename
,O_RDONLY
);
2196 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
2200 length
= filesize(infile
);
2201 newsize
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
2203 fprintf(stderr
,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2206 if (newsize
> BUFFER_SIZE
) {
2207 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
2208 if (infile
>= 0) close(infile
);
2212 /* Find aupd image number */
2214 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2219 if (aupd
== ipod
->nimages
)
2221 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2225 if (length
!= ipod
->ipod_directory
[aupd
].len
)
2227 fprintf(stderr
,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2228 ipod
->ipod_directory
[aupd
].len
, filename
, length
);
2232 if (find_key(ipod
, aupd
, key
) < 0)
2237 fprintf(stderr
, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2239 /* We now know we have enough space, so write it. */
2241 fprintf(stderr
,"[INFO] Reading input file...\n");
2242 n
= read(infile
,ipod_sectorbuf
,length
);
2244 fprintf(stderr
,"[ERR] Couldn't read input file\n");
2250 /* Pad the data with zeros */
2251 memset(ipod_sectorbuf
+length
,0,newsize
-length
);
2253 /* Calculate the new checksum (before we encrypt) */
2255 for (i
= 0; i
< (int)length
; i
++) {
2256 /* add 8 unsigned bits but keep a 32 bit sum */
2257 chksum
+= ipod_sectorbuf
[i
];
2260 /* Perform the encryption - this is standard (A)RC4 */
2261 matrixArc4Init(&rc4
, key
, 4);
2262 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2264 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2265 fprintf(stderr
,"[ERR] Seek failed\n");
2269 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,newsize
)) < 0) {
2270 perror("[ERR] Write failed\n");
2275 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
2279 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",n
);
2281 x
= ipod
->diroffset
% ipod
->sector_size
;
2283 /* Read directory */
2284 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2286 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2287 if (n
< 0) { return -1; }
2289 /* Update checksum */
2290 fprintf(stderr
,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum
,le2int(ipod_sectorbuf
+ x
+ aupd
*40 + 28));
2291 int2le(chksum
,ipod_sectorbuf
+x
+aupd
*40+28);
2293 /* Write directory */
2294 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2295 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2296 if (n
< 0) { return -1; }