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 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 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 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 char last_ipod
[4096];
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);
1783 /* Windows requires the ipod in R/W mode for SCSI Inquiry */
1785 ipod_reopen_rw(ipod
);
1786 ipod_get_xmlinfo(ipod
);
1787 ipod_get_ramsize(ipod
);
1788 if (getmodel(ipod
,ipod_version
) < 0) {
1794 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1795 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",i
);
1797 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1798 ipod
->modelstr
,ipod
->macpod
? "macpod" : "winpod",ipod
->diskname
);
1801 strcpy(last_ipod
,ipod
->diskname
);
1806 /* Remember the disk name */
1807 strcpy(ipod
->diskname
,last_ipod
);
1809 else if(n
== 0 && denied
) {
1810 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied
);
1812 printf("[ERR] You need to run this program with administrator priviledges!\n");
1814 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1817 return (n
== 0 && denied
) ? -1 : n
;
1820 static void put_int32le(uint32_t x
, unsigned char* p
)
1823 p
[1] = (x
>> 8) & 0xff;
1824 p
[2] = (x
>> 16) & 0xff;
1825 p
[3] = (x
>> 24) & 0xff;
1828 int write_dos_partition_table(struct ipod_t
* ipod
)
1834 /* Only support 512-byte sectors at the moment */
1835 if ( ipod
->sector_size
!= 512 )
1837 fprintf(stderr
,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1841 /* Firstly zero the entire MBR */
1842 memset(ipod_sectorbuf
, 0, ipod
->sector_size
);
1844 /* Now add the partition info */
1845 for (i
=0; i
< 4 ; i
++)
1847 p
= ipod_sectorbuf
+ 0x1be + i
*16;
1849 /* Ensure first partition is type 0, and second is 0xb */
1850 if (i
==0) { type
= 0; }
1851 else if (i
==1) { type
= 0xb; }
1852 else { type
= ipod
->pinfo
[i
].type
; }
1854 put_int32le(type
, p
+ 4);
1855 put_int32le(ipod
->pinfo
[i
].start
, p
+ 8);
1856 put_int32le(ipod
->pinfo
[i
].size
, p
+ 12);
1859 /* Finally add the magic */
1860 ipod_sectorbuf
[0x1fe] = 0x55;
1861 ipod_sectorbuf
[0x1ff] = 0xaa;
1863 if (ipod_seek(ipod
, 0) < 0) {
1864 fprintf(stderr
,"[ERR] Seek failed writing MBR\n");
1869 if ((n
= ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
)) < 0) {
1870 perror("[ERR] Write failed\n");
1877 /* Get the XML Device Information, as documented here:
1879 http://www.ipodlinux.org/wiki/Device_Information
1882 int ipod_get_xmlinfo(struct ipod_t
* ipod
)
1884 unsigned char hdr
[255];
1885 unsigned char buf
[255];
1891 if (ipod_scsi_inquiry(ipod
, 0xc0, buf
, sizeof(buf
)) < 0)
1893 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1897 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1899 memcpy(hdr
, buf
, sizeof(hdr
));
1903 psize
= npages
* 0xf8; /* Hopefully this is enough. */
1905 ipod
->xmlinfo
= malloc(psize
);
1906 ipod
->xmlinfo_len
= 0;
1908 if (ipod
->xmlinfo
== NULL
) {
1909 fprintf(stderr
,"[ERR] Could not allocate RAM for xmlinfo\n");
1915 for (i
=0; i
< npages
; i
++) {
1916 if (ipod_scsi_inquiry(ipod
, hdr
[i
+4], buf
, sizeof(buf
)) < 0) {
1917 fprintf(stderr
,"[ERR] Sending SCSI Command failed.\n");
1921 if ((buf
[3] + ipod
->xmlinfo_len
) > psize
) {
1922 fprintf(stderr
,"[ERR] Ran out of memory reading xmlinfo\n");
1923 free(ipod
->xmlinfo
);
1924 ipod
->xmlinfo
= NULL
;
1925 ipod
->xmlinfo_len
= 0;
1929 memcpy(p
, buf
+ 4, buf
[3]);
1931 ipod
->xmlinfo_len
+= buf
[3];
1934 /* NULL-terminate the XML info */
1937 fprintf(stderr
,"[INFO] Read XML info (%d bytes)\n",ipod
->xmlinfo_len
);
1942 void ipod_get_ramsize(struct ipod_t
* ipod
)
1944 const char needle
[] = "<key>RAM</key>\n<integer>";
1947 if (ipod
->xmlinfo
== NULL
)
1950 p
= strstr(ipod
->xmlinfo
, needle
);
1953 ipod
->ramsize
= atoi(p
+ sizeof(needle
) - 1);
1959 static inline uint32_t getuint32le(unsigned char* buf
)
1961 int32_t res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
1966 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1967 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1971 static bool testMarker(int marker
)
1973 int mask
, decrypt
, temp1
, temp2
;
1975 mask
= (marker
&0xff)|((marker
&0xff)<<8)|((marker
&0xff)<<16)|((marker
&0xff)<<24);
1976 decrypt
= marker
^ mask
;
1977 temp1
=(int)((unsigned int)decrypt
>>24);
1983 temp2
=(int)((unsigned int)temp2
>>24);
1984 decrypt
=decrypt
<<16;
1985 decrypt
=(int)((unsigned int)decrypt
>>24);
1987 if ((temp1
< temp2
) && (temp2
< decrypt
))
1989 temp1
= temp1
& 0xf;
1990 temp2
= temp2
& 0xf;
1991 decrypt
= decrypt
& 0xf;
1993 if ((temp1
> temp2
) && (temp2
> decrypt
) && (decrypt
!= 0))
2001 static int GetSecurityBlockKey(unsigned char *data
, unsigned char* this_key
)
2003 int constant
= 0x54c3a298;
2010 static const int offset
[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2012 for (c
= 0; c
< 8; c
++)
2015 aMarker
= getuint32le(data
+ pos
);
2017 if (testMarker(aMarker
))
2020 pos
=(offset
[c
+1]*4)+4;
2022 pos
=(offset
[0]*4)+4;
2028 for (count
=0;count
<2;count
++){
2029 int word
= getuint32le(data
+ pos
);
2032 temp1
= temp1
^constant
;
2042 for (count
=2;count
<128;count
=count
+2){
2043 r2
=getuint32le(data
+count
*4);
2044 r12
=getuint32le(data
+(count
*4)+4);
2045 r_tmp
=(unsigned int)r12
>>16;
2046 r14
=r2
| ((int)r_tmp
);
2054 // Invert key, little endian
2055 this_key
[0] = key
& 0xff;
2056 this_key
[1] = (key
>> 8) & 0xff;
2057 this_key
[2] = (key
>> 16) & 0xff;
2058 this_key
[3] = (key
>> 24) & 0xff;
2065 static int find_key(struct ipod_t
* ipod
, int aupd
, unsigned char* key
)
2069 /* Firstly read the security block and find the RC4 key. This is
2070 in the sector preceeding the AUPD image. */
2072 fprintf(stderr
, "[INFO] Reading security block at offset 0x%08x\n",ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
);
2073 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
-ipod
->sector_size
) < 0) {
2077 if ((n
= ipod_read(ipod
, ipod_sectorbuf
, 512)) < 0) {
2081 n
= GetSecurityBlockKey(ipod_sectorbuf
, key
);
2085 fprintf(stderr
, "[ERR] %d keys found in security block, can not continue\n",n
);
2092 int read_aupd(struct ipod_t
* ipod
, char* filename
)
2099 struct rc4_key_t rc4
;
2100 unsigned char key
[4];
2101 unsigned long chksum
=0;
2104 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2109 if (aupd
== ipod
->nimages
)
2111 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2115 length
= ipod
->ipod_directory
[aupd
].len
;
2117 fprintf(stderr
,"[INFO] Reading firmware (%d bytes)\n",length
);
2119 if (find_key(ipod
, aupd
, key
) < 0)
2124 fprintf(stderr
, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2126 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2130 i
= (length
+ipod
->sector_size
-1) & ~(ipod
->sector_size
-1);
2132 if ((n
= ipod_read(ipod
,ipod_sectorbuf
,i
)) < 0) {
2137 fprintf(stderr
,"[ERR] Short read - requested %d bytes, received %d\n",
2142 /* Perform the decryption - this is standard (A)RC4 */
2143 matrixArc4Init(&rc4
, key
, 4);
2144 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2147 for (i
= 0; i
< (int)length
; i
++) {
2148 /* add 8 unsigned bits but keep a 32 bit sum */
2149 chksum
+= ipod_sectorbuf
[i
];
2152 if (chksum
!= ipod
->ipod_directory
[aupd
].chksum
)
2154 fprintf(stderr
,"[ERR] Decryption failed - checksum error\n");
2157 fprintf(stderr
,"[INFO] Decrypted OK (checksum matches header)\n");
2159 outfile
= open(filename
,O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
,0666);
2161 fprintf(stderr
,"[ERR] Couldn't open file %s\n",filename
);
2165 n
= write(outfile
,ipod_sectorbuf
,length
);
2167 fprintf(stderr
,"[ERR] Write error - %d\n",n
);
2174 int write_aupd(struct ipod_t
* ipod
, char* filename
)
2176 unsigned int length
;
2183 unsigned long chksum
=0;
2184 struct rc4_key_t rc4
;
2185 unsigned char key
[4];
2187 /* First check that the input file is the correct type for this ipod. */
2188 infile
=open(filename
,O_RDONLY
);
2190 fprintf(stderr
,"[ERR] Couldn't open input file %s\n",filename
);
2194 length
= filesize(infile
);
2195 newsize
=(length
+ipod
->sector_size
-1)&~(ipod
->sector_size
-1);
2197 fprintf(stderr
,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2200 if (newsize
> BUFFER_SIZE
) {
2201 fprintf(stderr
,"[ERR] Input file too big for buffer\n");
2202 if (infile
>= 0) close(infile
);
2206 /* Find aupd image number */
2208 while ((aupd
< ipod
->nimages
) && (ipod
->ipod_directory
[aupd
].ftype
!= FTYPE_AUPD
))
2213 if (aupd
== ipod
->nimages
)
2215 fprintf(stderr
,"[ERR] No AUPD image in firmware partition.\n");
2219 if (length
!= ipod
->ipod_directory
[aupd
].len
)
2221 fprintf(stderr
,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2222 ipod
->ipod_directory
[aupd
].len
, filename
, length
);
2226 if (find_key(ipod
, aupd
, key
) < 0)
2231 fprintf(stderr
, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key
[0],key
[1],key
[2],key
[3]);
2233 /* We now know we have enough space, so write it. */
2235 fprintf(stderr
,"[INFO] Reading input file...\n");
2236 n
= read(infile
,ipod_sectorbuf
,length
);
2238 fprintf(stderr
,"[ERR] Couldn't read input file\n");
2244 /* Pad the data with zeros */
2245 memset(ipod_sectorbuf
+length
,0,newsize
-length
);
2247 /* Calculate the new checksum (before we encrypt) */
2249 for (i
= 0; i
< (int)length
; i
++) {
2250 /* add 8 unsigned bits but keep a 32 bit sum */
2251 chksum
+= ipod_sectorbuf
[i
];
2254 /* Perform the encryption - this is standard (A)RC4 */
2255 matrixArc4Init(&rc4
, key
, 4);
2256 matrixArc4(&rc4
, ipod_sectorbuf
, ipod_sectorbuf
, length
);
2258 if (ipod_seek(ipod
, ipod
->fwoffset
+ipod
->ipod_directory
[aupd
].devOffset
) < 0) {
2259 fprintf(stderr
,"[ERR] Seek failed\n");
2263 if ((n
= ipod_write(ipod
,ipod_sectorbuf
,newsize
)) < 0) {
2264 perror("[ERR] Write failed\n");
2269 fprintf(stderr
,"[ERR] Short write - requested %d bytes, received %d\n"
2273 fprintf(stderr
,"[INFO] Wrote %d bytes to firmware partition\n",n
);
2275 x
= ipod
->diroffset
% ipod
->sector_size
;
2277 /* Read directory */
2278 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2280 n
=ipod_read(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2281 if (n
< 0) { return -1; }
2283 /* Update checksum */
2284 fprintf(stderr
,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum
,le2int(ipod_sectorbuf
+ x
+ aupd
*40 + 28));
2285 int2le(chksum
,ipod_sectorbuf
+x
+aupd
*40+28);
2287 /* Write directory */
2288 if (ipod_seek(ipod
, ipod
->start
+ ipod
->diroffset
- x
) < 0) { return -1; }
2289 n
=ipod_write(ipod
, ipod_sectorbuf
, ipod
->sector_size
);
2290 if (n
< 0) { return -1; }