summaryrefslogtreecommitdiff
path: root/utils/ipodpatcher/ipodpatcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ipodpatcher/ipodpatcher.c')
-rw-r--r--utils/ipodpatcher/ipodpatcher.c2350
1 files changed, 2350 insertions, 0 deletions
diff --git a/utils/ipodpatcher/ipodpatcher.c b/utils/ipodpatcher/ipodpatcher.c
new file mode 100644
index 0000000000..e047e52abe
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.c
@@ -0,0 +1,2350 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include <stdbool.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include "parttypes.h"
33#include "ipodio.h"
34#include "ipodpatcher.h"
35
36#ifdef WITH_BOOTOBJS
37#include "ipod1g2g.h"
38#include "ipod3g.h"
39#include "ipod4g.h"
40#include "ipodmini1g.h"
41#include "ipodmini2g.h"
42#include "ipodcolor.h"
43#include "ipodnano1g.h"
44#include "ipodvideo.h"
45#include "ipodnano2g.h"
46#endif
47
48#ifndef RBUTIL
49#include "arc4.h"
50#endif
51
52int ipod_verbose = 0;
53
54
55/* The following string appears at the start of the firmware partition */
56static const char apple_stop_sign[] = "{{~~ /-----\\ "\
57 "{{~~ / \\ "\
58 "{{~~| | "\
59 "{{~~| S T O P | "\
60 "{{~~| | "\
61 "{{~~ \\ / "\
62 "{{~~ \\-----/ "\
63 "Copyright(C) 200"\
64 "1 Apple Computer"\
65 ", Inc.----------"\
66 "----------------"\
67 "----------------"\
68 "----------------"\
69 "----------------"\
70 "----------------"\
71 "---------------";
72
73/* Windows requires the buffer for disk I/O to be aligned in memory on a
74 multiple of the disk volume size - so we use a single global variable
75 and initialise it with ipod_alloc_buf()
76*/
77
78char* get_parttype(unsigned int pt)
79{
80 int i;
81 static char unknown[]="Unknown";
82
83 if (pt == PARTTYPE_HFS) {
84 return "HFS/HFS+";
85 }
86
87 i=0;
88 while (parttypes[i].name != NULL) {
89 if (parttypes[i].type == pt) {
90 return (parttypes[i].name);
91 }
92 i++;
93 }
94
95 return unknown;
96}
97
98off_t filesize(int fd) {
99 struct stat buf;
100
101 if (fstat(fd,&buf) < 0) {
102 perror("[ERR] Checking filesize of input file");
103 return -1;
104 } else {
105 return(buf.st_size);
106 }
107}
108
109/* Partition table parsing code taken from Rockbox */
110
111#define MAX_SECTOR_SIZE 2048
112#define SECTOR_SIZE 512
113
114static inline unsigned short le2ushort(unsigned char* buf)
115{
116 unsigned short res = (buf[1] << 8) | buf[0];
117
118 return res;
119}
120
121static inline int le2int(unsigned char* buf)
122{
123 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
124
125 return res;
126}
127
128static inline int be2int(unsigned char* buf)
129{
130 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
131
132 return res;
133}
134
135static inline int getint16le(char* buf)
136{
137 int16_t res = (buf[1] << 8) | buf[0];
138
139 return res;
140}
141
142static inline void short2le(unsigned short val, unsigned char* addr)
143{
144 addr[0] = val & 0xFF;
145 addr[1] = (val >> 8) & 0xff;
146}
147
148static inline void int2le(unsigned int val, unsigned char* addr)
149{
150 addr[0] = val & 0xFF;
151 addr[1] = (val >> 8) & 0xff;
152 addr[2] = (val >> 16) & 0xff;
153 addr[3] = (val >> 24) & 0xff;
154}
155
156static inline void int2be(unsigned int val, unsigned char* addr)
157{
158 addr[0] = (val >> 24) & 0xff;
159 addr[1] = (val >> 16) & 0xff;
160 addr[2] = (val >> 8) & 0xff;
161 addr[3] = val & 0xFF;
162}
163
164
165#define BYTES2INT32(array,pos)\
166 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
167 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
168
169int read_partinfo(struct ipod_t* ipod, int silent)
170{
171 int i;
172 unsigned long count;
173
174 if(ipod->sectorbuf == NULL) {
175 fprintf(stderr,"[ERR] Buffer not initialized.");
176 return -1;
177 }
178
179 count = ipod_read(ipod,ipod->sector_size);
180
181 if (count <= 0) {
182 ipod_print_error(" Error reading from disk: ");
183 return -1;
184 }
185
186 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
187
188 if ((ipod->sectorbuf[510] == 0x55) && (ipod->sectorbuf[511] == 0xaa)) {
189 /* DOS partition table */
190 ipod->macpod = 0;
191 /* parse partitions */
192 for ( i = 0; i < 4; i++ ) {
193 unsigned char* ptr = ipod->sectorbuf + 0x1be + 16*i;
194 ipod->pinfo[i].type = ptr[4];
195 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
196 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
197
198 /* extended? */
199 if ( ipod->pinfo[i].type == 5 ) {
200 /* not handled yet */
201 }
202 }
203 } else if ((ipod->sectorbuf[0] == 'E') && (ipod->sectorbuf[1] == 'R')) {
204 /* Apple Partition Map */
205
206 /* APM parsing code based on the check_mac_partitions() function in
207 ipodloader2 - written by Thomas Tempelmann and released
208 under the GPL. */
209
210 int blkNo = 1;
211 int partBlkCount = 1;
212 int partBlkSizMul = ipod->sectorbuf[2] / 2;
213
214 int pmMapBlkCnt; /* # of blks in partition map */
215 int pmPyPartStart; /* physical start blk of partition */
216 int pmPartBlkCnt; /* # of blks in this partition */
217 int i = 0;
218
219 ipod->macpod = 1;
220
221 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
222
223 while (blkNo <= partBlkCount) {
224 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
225 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
226 return -1;
227 }
228
229 count = ipod_read(ipod, ipod->sector_size);
230
231 if (count <= 0) {
232 ipod_print_error(" Error reading from disk: ");
233 return -1;
234 }
235
236 /* see if it's a partition entry */
237 if ((ipod->sectorbuf[0] != 'P') || (ipod->sectorbuf[1] != 'M')) {
238 /* end of partition table -> leave the loop */
239 break;
240 }
241
242 /* Extract the interesting entries */
243 pmMapBlkCnt = be2int(ipod->sectorbuf + 4);
244 pmPyPartStart = be2int(ipod->sectorbuf + 8);
245 pmPartBlkCnt = be2int(ipod->sectorbuf + 12);
246
247 /* update the number of part map blocks */
248 partBlkCount = pmMapBlkCnt;
249
250 if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_MDFW", 32)==0) {
251 /* A Firmware partition */
252 ipod->pinfo[i].start = pmPyPartStart;
253 ipod->pinfo[i].size = pmPartBlkCnt;
254 ipod->pinfo[i].type = 0;
255 i++;
256 } else if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_HFS", 32)==0) {
257 /* A HFS partition */
258 ipod->pinfo[i].start = pmPyPartStart;
259 ipod->pinfo[i].size = pmPartBlkCnt;
260 ipod->pinfo[i].type = PARTTYPE_HFS;
261 i++;
262 }
263
264 blkNo++; /* read next partition map entry */
265 }
266 } else {
267 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
268 return -1;
269 }
270
271 /* Check that the partition table looks like an ipod:
272 1) Partition 1 is of type 0 (Empty) but isn't empty.
273 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
274 */
275 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
276 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
277 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
278 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
279 return -1;
280 }
281
282 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
283 return 0;
284}
285
286int read_partition(struct ipod_t* ipod, int outfile)
287{
288 int res;
289 ssize_t n;
290 int bytesleft;
291 int chunksize;
292 int count = ipod->pinfo[0].size;
293
294 if (ipod_seek(ipod, ipod->start) < 0) {
295 return -1;
296 }
297 if(ipod->sectorbuf == NULL) {
298 fprintf(stderr,"[ERR] Buffer not initialized.");
299 return -1;
300 }
301
302 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
303
304 bytesleft = count * ipod->sector_size;
305 while (bytesleft > 0) {
306 if (bytesleft > BUFFER_SIZE) {
307 chunksize = BUFFER_SIZE;
308 } else {
309 chunksize = bytesleft;
310 }
311
312 n = ipod_read(ipod, chunksize);
313
314 if (n < 0) {
315 return -1;
316 }
317
318 if (n < chunksize) {
319 fprintf(stderr,
320 "[ERR] Short read in disk_read() - requested %d, got %d\n",
321 chunksize,(int)n);
322 return -1;
323 }
324
325 bytesleft -= n;
326
327 res = write(outfile,ipod->sectorbuf,n);
328
329 if (res < 0) {
330 perror("[ERR] write in disk_read");
331 return -1;
332 }
333
334 if (res != n) {
335 fprintf(stderr,
336 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
337 return -1;
338 }
339 }
340
341 fprintf(stderr,"[INFO] Done.\n");
342 return 0;
343}
344
345int write_partition(struct ipod_t* ipod, int infile)
346{
347 ssize_t res;
348 int n;
349 int bytesread;
350 int byteswritten = 0;
351 int eof;
352 int padding = 0;
353
354 if (ipod_seek(ipod, ipod->start) < 0) {
355 return -1;
356 }
357 if(ipod->sectorbuf == NULL) {
358 fprintf(stderr,"[ERR] Buffer not initialized.");
359 return -1;
360 }
361
362 fprintf(stderr,"[INFO] Writing input file to device\n");
363 bytesread = 0;
364 eof = 0;
365 while (!eof) {
366 n = read(infile,ipod->sectorbuf,BUFFER_SIZE);
367
368 if (n < 0) {
369 perror("[ERR] read in disk_write");
370 return -1;
371 }
372
373 if (n < BUFFER_SIZE) {
374 eof = 1;
375 /* We need to pad the last write to a multiple of SECTOR_SIZE */
376 if ((n % ipod->sector_size) != 0) {
377 padding = (ipod->sector_size-(n % ipod->sector_size));
378 n += padding;
379 }
380 }
381
382 bytesread += n;
383
384 res = ipod_write(ipod, n);
385
386 if (res < 0) {
387 ipod_print_error(" Error writing to disk: ");
388 fprintf(stderr,"Bytes written: %d\n",byteswritten);
389 return -1;
390 }
391
392 if (res != n) {
393 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
394 return -1;
395 }
396
397 byteswritten += res;
398 }
399
400 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
401 byteswritten-padding,padding);
402 return 0;
403}
404
405char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
406
407int diskmove(struct ipod_t* ipod, int delta)
408{
409 int src_start;
410 int src_end;
411 int bytesleft;
412 int chunksize;
413 int n;
414
415 src_start = ipod->ipod_directory[1].devOffset;
416 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
417 ipod->ipod_directory[ipod->nimages-1].len +
418 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
419 bytesleft = src_end - src_start;
420
421 if (ipod_verbose) {
422 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
423 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
424 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
425 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
426 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
427 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
428 }
429
430 while (bytesleft > 0) {
431 if (bytesleft <= BUFFER_SIZE) {
432 chunksize = bytesleft;
433 } else {
434 chunksize = BUFFER_SIZE;
435 }
436
437 if (ipod_verbose) {
438 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
439 chunksize,
440 src_end-chunksize,
441 src_end-chunksize+delta,
442 (unsigned int)(ipod->start+src_end-chunksize),
443 (unsigned int)(ipod->start+src_end-chunksize+delta));
444 }
445
446
447 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
448 fprintf(stderr,"[ERR] Seek failed\n");
449 return -1;
450 }
451
452 if ((n = ipod_read(ipod,chunksize)) < 0) {
453 perror("[ERR] Write failed\n");
454 return -1;
455 }
456
457 if (n < chunksize) {
458 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
459 chunksize,n);
460 return -1;
461 }
462
463 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
464 fprintf(stderr,"[ERR] Seek failed\n");
465 return -1;
466 }
467
468 if ((n = ipod_write(ipod,chunksize)) < 0) {
469 perror("[ERR] Write failed\n");
470 return -1;
471 }
472
473 if (n < chunksize) {
474 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
475 ,chunksize,n);
476 return -1;
477 }
478
479 src_end -= chunksize;
480 bytesleft -= chunksize;
481 }
482
483 return 0;
484}
485
486static int rename_image(struct ipod_t* ipod, char* from, char* to)
487{
488 int n;
489 int x;
490 int found;
491 int i;
492 unsigned char* p;
493
494 /* diroffset may not be sector-aligned */
495 x = ipod->diroffset % ipod->sector_size;
496
497 if(ipod->sectorbuf == NULL) {
498 fprintf(stderr,"[ERR] Buffer not initialized.");
499 return -1;
500 }
501 /* Read directory */
502 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
503 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
504 return -1;
505 }
506
507 n=ipod_read(ipod, ipod->sector_size);
508 if (n < 0) {
509 fprintf(stderr,"[ERR] Read of directory failed.\n");
510 return -1;
511 }
512
513 p = ipod->sectorbuf + x;
514
515 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
516 if (p[0] == 0)
517 {
518 /* Adjust diroffset */
519 ipod->diroffset += ipod->sector_size - x;
520
521 n=ipod_read(ipod, ipod->sector_size);
522 if (n < 0) {
523 fprintf(stderr,"[ERR] Read of directory failed.\n");
524 return -1;
525 }
526 p = ipod->sectorbuf;
527 }
528
529 found = 0;
530 for (i=0 ; !found && i < MAX_IMAGES; i++) {
531 if (memcmp(p + 4, from, 4) == 0) {
532 memcpy(p + 4, to, 4);
533
534 found = 1;
535 }
536 p += 40;
537 }
538
539 if (!found) {
540 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
541 return -1;
542 }
543
544 /* Write directory back to disk */
545 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
546 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
547 return -1;
548 }
549
550 n=ipod_write(ipod, ipod->sector_size);
551 if (n < 0) {
552 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
553 return -1;
554 }
555
556 return 0;
557}
558
559static int delete_image(struct ipod_t* ipod, char* name)
560{
561 int n;
562 int x;
563 int found;
564 int i;
565 unsigned char* p;
566
567 /* diroffset may not be sector-aligned */
568 x = ipod->diroffset % ipod->sector_size;
569
570 /* Read directory */
571 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
572 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
573 return -1;
574 }
575
576 n=ipod_read(ipod, ipod->sector_size);
577 if (n < 0) {
578 fprintf(stderr,"[ERR] Read of directory failed.\n");
579 return -1;
580 }
581
582 p = ipod->sectorbuf + x;
583
584 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
585 if (p[0] == 0)
586 {
587 /* Adjust diroffset */
588 ipod->diroffset += ipod->sector_size - x;
589
590 n=ipod_read(ipod, ipod->sector_size);
591 if (n < 0) {
592 fprintf(stderr,"[ERR] Read of directory failed.\n");
593 return -1;
594 }
595 p = ipod->sectorbuf;
596 }
597
598 found = 0;
599 for (i=0 ; !found && i < MAX_IMAGES; i++) {
600 if (memcmp(p + 4, name, 4) == 0) {
601 memset(p, 0, 40); /* Delete directory entry */
602 found = 1;
603 }
604 p += 40;
605 }
606
607 if (!found) {
608 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
609 return -1;
610 }
611
612 /* Write directory back to disk */
613 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
614 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
615 return -1;
616 }
617
618 n=ipod_write(ipod, ipod->sector_size);
619 if (n < 0) {
620 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
621 return -1;
622 }
623
624 return 0;
625}
626
627int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
628{
629 int length;
630 int found;
631 int i;
632 int x;
633 int n;
634 int infile;
635 int newsize;
636 unsigned long chksum=0;
637 unsigned long filechksum=0;
638 unsigned long offset;
639 unsigned char header[8]; /* Header for .ipod file */
640 unsigned char* p;
641
642 if(ipod->sectorbuf == NULL) {
643 fprintf(stderr,"[ERR] Buffer not initialized.");
644 return -1;
645 }
646#ifdef WITH_BOOTOBJS
647 if (type == FILETYPE_INTERNAL) {
648 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
649 length = ipod->bootloader_len;
650 infile = -1;
651 }
652 else
653#endif
654 {
655 /* First check that the input file is the correct type for this ipod. */
656 infile=open(filename,O_RDONLY);
657 if (infile < 0) {
658 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
659 return -1;
660 }
661
662 if (type==FILETYPE_DOT_IPOD) {
663 n = read(infile,header,8);
664 if (n < 8) {
665 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
666 close(infile);
667 return -1;
668 }
669
670 if (memcmp(header+4, ipod->modelname,4)!=0) {
671 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
672 header[4],header[5],header[6],header[7], ipod->modelname);
673 close(infile);
674 return -1;
675 }
676
677 filechksum = be2int(header);
678
679 length = filesize(infile)-8;
680 } else {
681 length = filesize(infile);
682 }
683 }
684
685 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
686
687 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
688 length,newsize);
689
690 if (newsize > BUFFER_SIZE) {
691 fprintf(stderr,"[ERR] Input file too big for buffer\n");
692 if (infile >= 0) close(infile);
693 return -1;
694 }
695
696 /* TODO: Check if we have enough space in the partition for the new image */
697
698#ifdef WITH_BOOTOBJS
699 if (type == FILETYPE_INTERNAL) {
700 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
701 }
702 else
703#endif
704 {
705 fprintf(stderr,"[INFO] Reading input file...\n");
706
707 n = read(infile,ipod->sectorbuf,length);
708 if (n < 0) {
709 fprintf(stderr,"[ERR] Couldn't read input file\n");
710 close(infile);
711 return -1;
712 }
713 close(infile);
714 }
715
716 /* Pad the data with zeros */
717 memset(ipod->sectorbuf+length,0,newsize-length);
718
719 if (type==FILETYPE_DOT_IPOD) {
720 chksum = ipod->modelnum;
721 for (i = 0; i < length; i++) {
722 /* add 8 unsigned bits but keep a 32 bit sum */
723 chksum += ipod->sectorbuf[i];
724 }
725
726 if (chksum == filechksum) {
727 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
728 } else {
729 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
730 return -1;
731 }
732 }
733
734
735 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
736 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
737
738 /* 2nd Gen Nano has encrypted firmware, and the sector
739 preceeding the firmware contains hashes that need to be
740 preserved. Nano 2G images include these extra 2048 (0x800)
741 bytes
742 */
743 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
744 fprintf(stderr,"[ERR] Seek failed\n");
745 return -1;
746 }
747
748 if ((n = ipod_write(ipod,newsize)) < 0) {
749 perror("[ERR] Write failed\n");
750 return -1;
751 }
752
753 if (n < newsize) {
754 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
755 ,newsize,n);
756 return -1;
757 }
758 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
759
760 /* Now we need to create a new directory entry
761
762 NOTE: On the Nano 2G, the checksum is the checksum of the
763 unencrypted firmware. But this isn't checked by the NOR
764 bootloader (there are cryptographic hashes in the
765 firmware itself), so it doesn't matter that this is
766 wrong.
767 */
768 chksum = 0;
769 for (i = 0; i < length; i++) {
770 /* add 8 unsigned bits but keep a 32 bit sum */
771 chksum += ipod->sectorbuf[i];
772 }
773
774 x = ipod->diroffset % ipod->sector_size;
775
776 /* Read directory */
777 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
778
779 n=ipod_read(ipod, ipod->sector_size);
780 if (n < 0) { return -1; }
781
782 /* Create a new directory entry */
783
784 /* Copy OSOS or OSBK details - we assume one of them exists */
785 p = ipod->sectorbuf + x;
786 found = 0;
787 for (i = 0; !found && i < ipod->nimages; i++) {
788 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
789 found = 1;
790 } else {
791 p += 40;
792 }
793 }
794
795 if (!found) {
796 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
797 return -1;
798 }
799
800 /* Copy directory image */
801 memcpy(ipod->sectorbuf + x + (ipod->nimages * 40), p, 40);
802 p = ipod->sectorbuf + x + (ipod->nimages * 40);
803
804 /* Modify directory. */
805 memcpy(p + 4, imagename, 4);
806 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
807 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
808 int2le(chksum, p + 28); /* checksum */
809
810 /* Write directory */
811 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
812 n=ipod_write(ipod, ipod->sector_size);
813 if (n < 0) { return -1; }
814
815 return 0;
816}
817
818
819int ipod_has_bootloader(struct ipod_t* ipod)
820{
821 /* The 2nd gen Nano is installed differently */
822 if (ipod->modelnum == 62) {
823 int i;
824 int has_osbk = 0;
825 /* Check if we have an OSBK image */
826 for (i = 0; i < ipod->nimages; i++) {
827 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
828 has_osbk = 1;
829 }
830 }
831 return has_osbk;
832 }
833 else {
834 return (ipod->ipod_directory[0].entryOffset != 0);
835 }
836}
837
838
839/*
840 Bootloader installation on the Nano2G consists of renaming the
841 OSOS image to OSBK and then writing the Rockbox bootloader as a
842 new OSOS image.
843
844 Maybe this approach can/should be adapted for other ipods, as it
845 prevents the Apple bootloader loading the original firmware into
846 RAM along with the Rockbox bootloader (and hence will give a
847 faster boot when the user just wants to start Rockbox).
848
849*/
850
851static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
852{
853 /* Check if we already have an OSBK image */
854 if (ipod_has_bootloader(ipod) == 0) {
855 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
856 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
857
858 if (rename_image(ipod, "soso", "kbso") < 0) {
859 fprintf(stderr,"[ERR] Could not rename OSOS image\n");
860 return -1;
861 }
862
863 /* Add our bootloader as a brand new image */
864 return add_new_image(ipod, "soso", filename, type);
865 } else {
866 /* This is an update, just replace OSOS with our bootloader */
867
868 return write_firmware(ipod, filename, type);
869 }
870}
871
872
873static int delete_bootloader_nano2g(struct ipod_t* ipod)
874{
875 /* Check if we have an OSBK image */
876 if (ipod_has_bootloader(ipod) == 0) {
877 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
878 return -1;
879 } else {
880 /* Delete our bootloader image */
881 if (delete_image(ipod, "soso") < 0) {
882 fprintf(stderr,"[WARN] Could not delete OSOS image\n");
883 } else {
884 fprintf(stderr,"[INFO] OSOS image deleted\n");
885 }
886
887 if (rename_image(ipod, "kbso", "soso") < 0) {
888 fprintf(stderr,"[ERR] Could not rename OSBK image\n");
889 return -1;
890 }
891
892
893 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
894 return 0;
895 }
896}
897
898
899int add_bootloader(struct ipod_t* ipod, char* filename, int type)
900{
901 int length;
902 int i;
903 int x;
904 int n;
905 int infile;
906 int paddedlength;
907 int entryOffset;
908 int delta = 0;
909 unsigned long chksum=0;
910 unsigned long filechksum=0;
911 unsigned char header[8]; /* Header for .ipod file */
912 unsigned char* bootloader_buf;
913
914 /* The 2nd gen Nano is installed differently */
915 if (ipod->modelnum == 62) {
916 return add_bootloader_nano2g(ipod, filename, type);
917 }
918 if(ipod->sectorbuf == NULL) {
919 fprintf(stderr,"[ERR] Buffer not initialized.");
920 return -1;
921 }
922
923 /* Calculate the position in the OSOS image where our bootloader will go. */
924 if (ipod->ipod_directory[0].entryOffset>0) {
925 /* Keep the same entryOffset */
926 entryOffset = ipod->ipod_directory[0].entryOffset;
927 } else {
928 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
929 }
930
931#ifdef WITH_BOOTOBJS
932 if (type == FILETYPE_INTERNAL) {
933 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
934 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
935 length = ipod->bootloader_len;
936 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
937 }
938 else
939#endif
940 {
941 infile=open(filename,O_RDONLY);
942 if (infile < 0) {
943 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
944 return -1;
945 }
946
947 if (type==FILETYPE_DOT_IPOD) {
948 /* First check that the input file is the correct type for this ipod. */
949 n = read(infile,header,8);
950 if (n < 8) {
951 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
952 close(infile);
953 return -1;
954 }
955
956 if (memcmp(header+4, ipod->modelname,4)!=0) {
957 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
958 header[4],header[5],header[6],header[7], ipod->modelname);
959 close(infile);
960 return -1;
961 }
962
963 filechksum = be2int(header);
964
965 length=filesize(infile)-8;
966 } else {
967 length=filesize(infile);
968 }
969 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
970
971 bootloader_buf = malloc(length);
972 if (bootloader_buf == NULL) {
973 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
974 return -1;
975 }
976 /* Now read our bootloader - we need to check it before modifying the partition*/
977 n = read(infile,bootloader_buf,length);
978 close(infile);
979
980 if (n < 0) {
981 fprintf(stderr,"[ERR] Couldn't read input file\n");
982 return -1;
983 }
984
985 if (type==FILETYPE_DOT_IPOD) {
986 /* Calculate and confirm bootloader checksum */
987 chksum = ipod->modelnum;
988 for (i = 0; i < length; i++) {
989 /* add 8 unsigned bits but keep a 32 bit sum */
990 chksum += bootloader_buf[i];
991 }
992
993 if (chksum == filechksum) {
994 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
995 } else {
996 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
997 return -1;
998 }
999 }
1000 }
1001
1002 if (entryOffset+paddedlength > BUFFER_SIZE) {
1003 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1004 return -1;
1005 }
1006
1007 if (ipod_verbose) {
1008 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
1009 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
1010 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
1011 }
1012
1013 /* Check if we have enough space */
1014 /* TODO: Check the size of the partition. */
1015 if (ipod->nimages > 1) {
1016 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
1017 ipod->ipod_directory[1].devOffset) {
1018 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1019 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
1020 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
1021
1022 if (diskmove(ipod, delta) < 0) {
1023 fprintf(stderr,"[ERR] Image movement failed.\n");
1024 return -1;
1025 }
1026 }
1027 }
1028
1029
1030 /* We have moved the partitions, now we can write our bootloader */
1031
1032 /* Firstly read the original firmware into ipod->sectorbuf */
1033 fprintf(stderr,"[INFO] Reading original firmware...\n");
1034 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1035 fprintf(stderr,"[ERR] Seek failed\n");
1036 return -1;
1037 }
1038
1039 if ((n = ipod_read(ipod,entryOffset)) < 0) {
1040 perror("[ERR] Read failed\n");
1041 return -1;
1042 }
1043
1044 if (n < entryOffset) {
1045 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1046 ,entryOffset,n);
1047 return -1;
1048 }
1049
1050#ifdef WITH_BOOTOBJS
1051 if (type == FILETYPE_INTERNAL) {
1052 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
1053 }
1054 else
1055#endif
1056 {
1057 memcpy(ipod->sectorbuf+entryOffset,bootloader_buf,length);
1058 free(bootloader_buf);
1059 }
1060
1061 /* Calculate new checksum for combined image */
1062 chksum = 0;
1063 for (i=0;i<entryOffset + length; i++) {
1064 chksum += ipod->sectorbuf[i];
1065 }
1066
1067 /* Now write the combined firmware image to the disk */
1068
1069 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1070 fprintf(stderr,"[ERR] Seek failed\n");
1071 return -1;
1072 }
1073
1074 if ((n = ipod_write(ipod,entryOffset+paddedlength)) < 0) {
1075 perror("[ERR] Write failed\n");
1076 return -1;
1077 }
1078
1079 if (n < (entryOffset+paddedlength)) {
1080 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1081 ,entryOffset+paddedlength,n);
1082 return -1;
1083 }
1084
1085 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
1086
1087 x = ipod->diroffset % ipod->sector_size;
1088
1089 /* Read directory */
1090 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1091 fprintf(stderr,"[ERR] Seek failed\n");
1092 return -1;
1093 }
1094
1095 n=ipod_read(ipod, ipod->sector_size);
1096 if (n < 0) {
1097 fprintf(stderr,"[ERR] Directory read failed\n");
1098 return -1;
1099 }
1100
1101 /* Update entries for image 0 */
1102 int2le(entryOffset+length,ipod->sectorbuf+x+16);
1103 int2le(entryOffset,ipod->sectorbuf+x+24);
1104 int2le(chksum,ipod->sectorbuf+x+28);
1105 int2le(0xffffffff,ipod->sectorbuf+x+36); /* loadAddr */
1106
1107 /* Update devOffset entries for other images, if we have moved them */
1108 if (delta > 0) {
1109 for (i=1;i<ipod->nimages;i++) {
1110 int2le(le2int(ipod->sectorbuf+x+i*40+12)+delta,ipod->sectorbuf+x+i*40+12);
1111 }
1112 }
1113
1114 /* Write directory */
1115 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1116 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
1117 return -1;
1118 }
1119 n=ipod_write(ipod, ipod->sector_size);
1120 if (n < 0) {
1121 fprintf(stderr,"[ERR] Directory write failed\n");
1122 return -1;
1123 }
1124
1125 return 0;
1126}
1127
1128int delete_bootloader(struct ipod_t* ipod)
1129{
1130 int length;
1131 int i;
1132 int x;
1133 int n;
1134 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1135
1136 /* The 2nd gen Nano is installed differently */
1137 if (ipod->modelnum == 62) {
1138 return delete_bootloader_nano2g(ipod);
1139 }
1140 if(ipod->sectorbuf == NULL) {
1141 fprintf(stderr,"[ERR] Buffer not initialized.");
1142 return -1;
1143 }
1144
1145 /* Removing the bootloader involves adjusting the "length",
1146 "chksum" and "entryOffset" values in the osos image's directory
1147 entry. */
1148
1149 /* Firstly check we have a bootloader... */
1150
1151 if (ipod_has_bootloader(ipod) == 0) {
1152 fprintf(stderr,"[ERR] No bootloader found.\n");
1153 return -1;
1154 }
1155
1156 length = ipod->ipod_directory[0].entryOffset;
1157
1158 /* Read the firmware so we can calculate the checksum */
1159 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1160
1161 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1162 return -1;
1163 }
1164
1165 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1166 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1167 length,i);
1168
1169 if ((n = ipod_read(ipod,i)) < 0) {
1170 return -1;
1171 }
1172
1173 if (n < i) {
1174 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1175 i,n);
1176 return -1;
1177 }
1178
1179 chksum = 0;
1180 for (i = 0; i < length; i++) {
1181 /* add 8 unsigned bits but keep a 32 bit sum */
1182 chksum += ipod->sectorbuf[i];
1183 }
1184
1185 /* Now write back the updated directory entry */
1186
1187 fprintf(stderr,"[INFO] Updating firmware checksum\n");
1188
1189 x = ipod->diroffset % ipod->sector_size;
1190
1191 /* Read directory */
1192 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1193
1194 n=ipod_read(ipod, ipod->sector_size);
1195 if (n < 0) { return -1; }
1196
1197 /* Update entries for image 0 */
1198 int2le(length,ipod->sectorbuf+x+16);
1199 int2le(0,ipod->sectorbuf+x+24);
1200 int2le(chksum,ipod->sectorbuf+x+28);
1201
1202 /* Write directory */
1203 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1204 n=ipod_write(ipod, ipod->sector_size);
1205 if (n < 0) { return -1; }
1206
1207 return 0;
1208}
1209
1210int write_firmware(struct ipod_t* ipod, char* filename, int type)
1211{
1212 int length;
1213 int i;
1214 int x;
1215 int n;
1216 int infile;
1217 int newsize;
1218 int bytesavailable;
1219 unsigned long chksum=0;
1220 unsigned long filechksum=0;
1221 unsigned long offset;
1222 unsigned char header[8]; /* Header for .ipod file */
1223 unsigned char* p;
1224
1225 if(ipod->sectorbuf == NULL) {
1226 fprintf(stderr,"[ERR] Buffer not initialized.");
1227 return -1;
1228 }
1229#ifdef WITH_BOOTOBJS
1230 if (type == FILETYPE_INTERNAL) {
1231 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
1232 length = ipod->bootloader_len;
1233 infile = -1;
1234 }
1235 else
1236#endif
1237 {
1238 /* First check that the input file is the correct type for this ipod. */
1239 infile=open(filename,O_RDONLY);
1240 if (infile < 0) {
1241 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
1242 return -1;
1243 }
1244
1245 if (type==FILETYPE_DOT_IPOD) {
1246 n = read(infile,header,8);
1247 if (n < 8) {
1248 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
1249 close(infile);
1250 return -1;
1251 }
1252
1253 if (memcmp(header+4, ipod->modelname,4)!=0) {
1254 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
1255 header[4],header[5],header[6],header[7], ipod->modelname);
1256 close(infile);
1257 return -1;
1258 }
1259
1260 filechksum = be2int(header);
1261
1262 length = filesize(infile)-8;
1263 } else {
1264 length = filesize(infile);
1265 }
1266 }
1267
1268 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
1269
1270 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1271 length,newsize);
1272
1273 if (newsize > BUFFER_SIZE) {
1274 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1275 if (infile >= 0) close(infile);
1276 return -1;
1277 }
1278
1279 /* Check if we have enough space */
1280 /* TODO: Check the size of the partition. */
1281 if (ipod->nimages > 1) {
1282 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
1283 if (bytesavailable < newsize) {
1284 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1285
1286 /* TODO: Implement image movement */
1287 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
1288 close(infile);
1289 return -1;
1290 }
1291 }
1292
1293#ifdef WITH_BOOTOBJS
1294 if (type == FILETYPE_INTERNAL) {
1295 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
1296 }
1297 else
1298#endif
1299 {
1300 fprintf(stderr,"[INFO] Reading input file...\n");
1301 /* We now know we have enough space, so write it. */
1302 n = read(infile,ipod->sectorbuf,length);
1303 if (n < 0) {
1304 fprintf(stderr,"[ERR] Couldn't read input file\n");
1305 close(infile);
1306 return -1;
1307 }
1308 close(infile);
1309 }
1310
1311 /* Pad the data with zeros */
1312 memset(ipod->sectorbuf+length,0,newsize-length);
1313
1314 if (type==FILETYPE_DOT_IPOD) {
1315 chksum = ipod->modelnum;
1316 for (i = 0; i < length; i++) {
1317 /* add 8 unsigned bits but keep a 32 bit sum */
1318 chksum += ipod->sectorbuf[i];
1319 }
1320
1321 if (chksum == filechksum) {
1322 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
1323 } else {
1324 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
1325 return -1;
1326 }
1327 }
1328
1329
1330 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
1331
1332 if (ipod->modelnum==62) {
1333
1334 /* 2nd Gen Nano has encrypted firmware, and the sector
1335 preceeding the firmware contains hashes that need to be
1336 preserved. Nano 2G images include these extra 2048 (0x800)
1337 bytes
1338 */
1339
1340 offset -= 0x800;
1341
1342 /* TODO: The above checks need to take into account this 0x800 bytes */
1343 }
1344
1345 if (ipod_seek(ipod, offset) < 0) {
1346 fprintf(stderr,"[ERR] Seek failed\n");
1347 return -1;
1348 }
1349
1350 if ((n = ipod_write(ipod,newsize)) < 0) {
1351 perror("[ERR] Write failed\n");
1352 return -1;
1353 }
1354
1355 if (n < newsize) {
1356 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
1357 ,newsize,n);
1358 return -1;
1359 }
1360 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1361
1362 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1363
1364 NOTE: On the Nano 2G, the checksum is the checksum of the
1365 unencrypted firmware. But this isn't checked by the NOR
1366 bootloader (there are cryptographic hashes in the
1367 firmware itself), so it doesn't matter that this is
1368 wrong.
1369 */
1370 chksum = 0;
1371 for (i = 0; i < length; i++) {
1372 /* add 8 unsigned bits but keep a 32 bit sum */
1373 chksum += ipod->sectorbuf[i];
1374 }
1375
1376 x = ipod->diroffset % ipod->sector_size;
1377
1378 /* Read directory */
1379 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1380
1381 n=ipod_read(ipod, ipod->sector_size);
1382 if (n < 0) { return -1; }
1383
1384 /* Update entries for image */
1385 p = ipod->sectorbuf + x + (ipod->ososimage * 40);
1386 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
1387 int2le(0, p + 24);
1388 int2le(chksum, p + 28);
1389
1390 /* Write directory */
1391 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1392 n=ipod_write(ipod, ipod->sector_size);
1393 if (n < 0) { return -1; }
1394
1395 return 0;
1396}
1397
1398int read_firmware(struct ipod_t* ipod, char* filename, int type)
1399{
1400 int length;
1401 int i;
1402 int outfile;
1403 int n;
1404 unsigned long offset;
1405 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1406 unsigned char header[8]; /* Header for .ipod file */
1407
1408 if(ipod->sectorbuf == NULL) {
1409 fprintf(stderr,"[ERR] Buffer not initialized.");
1410 return -1;
1411 }
1412 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
1413 /* We have a bootloader... */
1414 length = ipod->ipod_directory[ipod->ososimage].entryOffset;
1415 } else {
1416 length = ipod->ipod_directory[ipod->ososimage].len;
1417 }
1418
1419 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1420
1421 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
1422 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1423 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1424 length,i);
1425
1426 if (ipod->modelnum==62) {
1427 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1428 sector preceeding the image - it contains hashes */
1429 offset -= 0x800;
1430 length += 0x800;
1431 i += 0x800;
1432 }
1433
1434 if (ipod_seek(ipod, offset)) {
1435 return -1;
1436 }
1437
1438 if ((n = ipod_read(ipod,i)) < 0) {
1439 return -1;
1440 }
1441
1442 if (n < i) {
1443 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1444 i,n);
1445 return -1;
1446 }
1447
1448 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
1449 if (outfile < 0) {
1450 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1451 return -1;
1452 }
1453
1454 if (type == FILETYPE_DOT_IPOD) {
1455 chksum = ipod->modelnum;
1456 for (i = 0; i < length; i++) {
1457 /* add 8 unsigned bits but keep a 32 bit sum */
1458 chksum += ipod->sectorbuf[i];
1459 }
1460
1461 int2be(chksum,header);
1462 memcpy(header+4, ipod->modelname,4);
1463
1464 n = write(outfile,header,8);
1465 if (n != 8) {
1466 fprintf(stderr,"[ERR] Write error - %d\n",n);
1467 }
1468 }
1469
1470 n = write(outfile,ipod->sectorbuf,length);
1471 if (n != length) {
1472 fprintf(stderr,"[ERR] Write error - %d\n",n);
1473 }
1474 close(outfile);
1475
1476 return 0;
1477}
1478
1479int read_directory(struct ipod_t* ipod)
1480{
1481 ssize_t n;
1482 int x;
1483 unsigned char* p;
1484 unsigned short version;
1485
1486 ipod->nimages=0;
1487
1488 /* Read firmware partition header (first 512 bytes of disk - but
1489 let's read a whole sector) */
1490
1491 if (ipod_seek(ipod, ipod->start) < 0) {
1492 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1493 (unsigned int)(ipod->start));
1494 return -1;
1495 }
1496
1497 n=ipod_read(ipod, ipod->sector_size);
1498 if (n < 0) {
1499 fprintf(stderr,"[ERR] ipod_read(ipod,0x%08x) failed in read_directory()\n", ipod->sector_size);
1500 return -1;
1501 }
1502
1503 if (memcmp(ipod->sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
1504 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1505 return -1;
1506 }
1507
1508 if (memcmp(ipod->sectorbuf+0x100,"]ih[",4)!=0) {
1509 fprintf(stderr,"[ERR] Bad firmware directory\n");
1510 return -1;
1511 }
1512
1513 version = le2ushort(ipod->sectorbuf+0x10a);
1514 if ((version != 2) && (version != 3)) {
1515 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1516 version);
1517 }
1518 ipod->diroffset=le2int(ipod->sectorbuf+0x104) + 0x200;
1519
1520 /* diroffset may not be sector-aligned */
1521 x = ipod->diroffset % ipod->sector_size;
1522
1523 /* Read directory */
1524 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1525 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
1526 return -1;
1527 }
1528
1529 n=ipod_read(ipod, ipod->sector_size);
1530 if (n < 0) {
1531 fprintf(stderr,"[ERR] Read of directory failed.\n");
1532 return -1;
1533 }
1534
1535 p = ipod->sectorbuf + x;
1536
1537 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1538 if (p[0] == 0)
1539 {
1540 /* Adjust diroffset */
1541 ipod->diroffset += ipod->sector_size - x;
1542
1543 n=ipod_read(ipod, ipod->sector_size);
1544 if (n < 0) {
1545 fprintf(stderr,"[ERR] Read of directory failed.\n");
1546 return -1;
1547 }
1548 p = ipod->sectorbuf;
1549 }
1550
1551 ipod->ososimage = -1;
1552 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod->sectorbuf + x + 400)) &&
1553 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1554 p+=4;
1555 if (memcmp(p,"soso",4)==0) {
1556 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1557 ipod->ososimage = ipod->nimages;
1558 } else if (memcmp(p,"crsr",4)==0) {
1559 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1560 } else if (memcmp(p,"dpua",4)==0) {
1561 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1562 } else if (memcmp(p,"kbso",4)==0) {
1563 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
1564 } else if (memcmp(p,"ebih",4)==0) {
1565 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1566 } else {
1567 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1568 p[0],p[1],p[2],p[3]);
1569 }
1570 p+=4;
1571 ipod->ipod_directory[ipod->nimages].id=le2int(p);
1572 p+=4;
1573 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
1574 p+=4;
1575 ipod->ipod_directory[ipod->nimages].len=le2int(p);
1576 p+=4;
1577 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
1578 p+=4;
1579 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
1580 p+=4;
1581 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
1582 p+=4;
1583 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
1584 p+=4;
1585 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
1586 p+=4;
1587 ipod->nimages++;
1588 }
1589
1590 if (ipod->ososimage < 0) {
1591 fprintf(stderr,"[ERR] No OSOS image found.\n");
1592 return -1;
1593 }
1594
1595 if ((ipod->nimages > 1) && (version==2)) {
1596 /* The 3g firmware image doesn't appear to have a version, so
1597 let's make one up... Note that this is never written back to the
1598 ipod, so it's OK to do. */
1599
1600 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
1601
1602 ipod->fwoffset = ipod->start;
1603 } else {
1604 ipod->fwoffset = ipod->start + ipod->sector_size;
1605 }
1606
1607 return 0;
1608}
1609
1610int list_images(struct ipod_t* ipod)
1611{
1612 int i;
1613
1614 if (ipod_verbose) {
1615 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1616 for (i = 0 ; i < ipod->nimages; i++) {
1617 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
1618 ftypename[ipod->ipod_directory[i].ftype],
1619 ipod->ipod_directory[i].id,
1620 ipod->ipod_directory[i].devOffset,
1621 ipod->ipod_directory[i].len,
1622 ipod->ipod_directory[i].addr,
1623 ipod->ipod_directory[i].entryOffset,
1624 ipod->ipod_directory[i].chksum,
1625 ipod->ipod_directory[i].vers,
1626 ipod->ipod_directory[i].loadAddr,
1627 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
1628 }
1629 }
1630
1631 printf("\n");
1632 printf("Listing firmware partition contents:\n");
1633 printf("\n");
1634
1635 for (i = 0 ; i < ipod->nimages; i++) {
1636 printf("Image %d:\n",i+1);
1637 switch(ipod->ipod_directory[i].ftype) {
1638 case FTYPE_OSOS:
1639 if (ipod->ipod_directory[i].entryOffset==0) {
1640 printf(" Main firmware - %d bytes\n",
1641 ipod->ipod_directory[i].len);
1642 } else {
1643 printf(" Main firmware - %d bytes\n",
1644 ipod->ipod_directory[i].entryOffset);
1645 printf(" Third-party bootloader - %d bytes\n",
1646 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
1647 }
1648 break;
1649 default:
1650 printf(" %s - %d bytes\n",
1651 ftypename[ipod->ipod_directory[i].ftype],
1652 ipod->ipod_directory[i].len);
1653 }
1654 }
1655 printf("\n");
1656
1657 return 0;
1658}
1659
1660int getmodel(struct ipod_t* ipod, int ipod_version)
1661{
1662 switch (ipod_version) {
1663 case 0x01:
1664 ipod->modelstr="1st or 2nd Generation";
1665 ipod->modelnum = 19;
1666 ipod->modelname = "1g2g";
1667 ipod->targetname = "ipod1g2g";
1668#ifdef WITH_BOOTOBJS
1669 ipod->bootloader = ipod1g2g;
1670 ipod->bootloader_len = LEN_ipod1g2g;
1671#endif
1672 break;
1673 case 0x02:
1674 ipod->modelstr="3rd Generation";
1675 ipod->modelnum = 7;
1676 ipod->modelname = "ip3g";
1677 ipod->targetname = "ipod3g";
1678#ifdef WITH_BOOTOBJS
1679 ipod->bootloader = ipod3g;
1680 ipod->bootloader_len = LEN_ipod3g;
1681#endif
1682 break;
1683 case 0x40:
1684 ipod->modelstr="1st Generation Mini";
1685 ipod->modelnum = 9;
1686 ipod->modelname = "mini";
1687 ipod->targetname = "ipodmini1g";
1688#ifdef WITH_BOOTOBJS
1689 ipod->bootloader = ipodmini1g;
1690 ipod->bootloader_len = LEN_ipodmini1g;
1691#endif
1692 break;
1693 case 0x50:
1694 ipod->modelstr="4th Generation";
1695 ipod->modelnum = 8;
1696 ipod->modelname = "ip4g";
1697 ipod->targetname = "ipod4gray";
1698#ifdef WITH_BOOTOBJS
1699 ipod->bootloader = ipod4g;
1700 ipod->bootloader_len = LEN_ipod4g;
1701#endif
1702 break;
1703 case 0x60:
1704 ipod->modelstr="Photo/Color";
1705 ipod->modelnum = 3;
1706 ipod->modelname = "ipco";
1707 ipod->targetname = "ipodcolor";
1708#ifdef WITH_BOOTOBJS
1709 ipod->bootloader = ipodcolor;
1710 ipod->bootloader_len = LEN_ipodcolor;
1711#endif
1712 break;
1713 case 0x70:
1714 ipod->modelstr="2nd Generation Mini";
1715 ipod->modelnum = 11;
1716 ipod->modelname = "mn2g";
1717 ipod->targetname = "ipodmini2g";
1718#ifdef WITH_BOOTOBJS
1719 ipod->bootloader = ipodmini2g;
1720 ipod->bootloader_len = LEN_ipodmini2g;
1721#endif
1722 break;
1723 case 0xc0:
1724 ipod->modelstr="1st Generation Nano";
1725 ipod->modelnum = 4;
1726 ipod->modelname = "nano";
1727 ipod->targetname = "ipodnano1g";
1728#ifdef WITH_BOOTOBJS
1729 ipod->bootloader = ipodnano1g;
1730 ipod->bootloader_len = LEN_ipodnano1g;
1731#endif
1732 break;
1733 case 0xb0:
1734 ipod->modelstr="Video (aka 5th Generation)";
1735 ipod->modelnum = 5;
1736 ipod->modelname = "ipvd";
1737 ipod->targetname = "ipodvideo";
1738#ifdef WITH_BOOTOBJS
1739 ipod->bootloader = ipodvideo;
1740 ipod->bootloader_len = LEN_ipodvideo;
1741#endif
1742 break;
1743 case 0x100:
1744 ipod->modelstr="2nd Generation Nano";
1745 ipod->modelnum = 62;
1746 ipod->modelname = "nn2x";
1747 ipod->targetname = "ipodnano2g";
1748#ifdef WITH_BOOTOBJS
1749 ipod->bootloader = ipodnano2g;
1750 ipod->bootloader_len = LEN_ipodnano2g;
1751#endif
1752 break;
1753 default:
1754 ipod->modelname = NULL;
1755 ipod->modelnum = 0;
1756 ipod->targetname = NULL;
1757#ifdef WITH_BOOTOBJS
1758 ipod->bootloader = NULL;
1759 ipod->bootloader_len = 0;
1760#endif
1761 return -1;
1762 }
1763 return 0;
1764}
1765
1766/* returns number of found ipods or -1 if no ipods found and permission
1767 * for raw disc access was denied. */
1768int ipod_scan(struct ipod_t* ipod)
1769{
1770 int i;
1771 int n = 0;
1772 int ipod_version;
1773 struct ipod_t ipod_found;
1774 int denied = 0;
1775 int result;
1776
1777 printf("[INFO] Scanning disk devices...\n");
1778
1779 for (i = 0; i <= 25 ; i++) {
1780#ifdef __WIN32__
1781 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
1782#elif defined(linux) || defined (__linux)
1783 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
1784#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1785 || defined(__bsdi__) || defined(__DragonFly__)
1786 sprintf(ipod->diskname,"/dev/da%d",i);
1787#elif defined(__APPLE__) && defined(__MACH__)
1788 sprintf(ipod->diskname,"/dev/disk%d",i);
1789#else
1790 #error No disk paths defined for this platform
1791#endif
1792 if ((result = ipod_open(ipod, 1)) < 0) {
1793 if(result == -2) {
1794 denied++;
1795 }
1796 ipod_close(ipod);
1797 continue;
1798 }
1799
1800 if (read_partinfo(ipod,1) < 0) {
1801 ipod_close(ipod);
1802 continue;
1803 }
1804
1805 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
1806 ipod_close(ipod);
1807 continue;
1808 }
1809
1810 if (read_directory(ipod) < 0) {
1811 ipod_close(ipod);
1812 continue;
1813 }
1814
1815 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
1816 ipod->ramsize = 0;
1817#ifdef __WIN32__
1818 /* Windows requires the ipod in R/W mode for SCSI Inquiry.
1819 * ipod_reopen_rw does unmount the player on OS X so do this on
1820 * W32 only during scanning. */
1821 ipod_reopen_rw(ipod);
1822#endif
1823 ipod_get_xmlinfo(ipod);
1824 ipod_get_ramsize(ipod);
1825 if (getmodel(ipod,ipod_version) < 0) {
1826 ipod_close(ipod);
1827 continue;
1828 }
1829
1830#ifdef __WIN32__
1831 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1832 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
1833#else
1834 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1835 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
1836#endif
1837 n++;
1838 /* save the complete ipod_t structure for match. The for loop might
1839 * overwrite it, so we need to restore it later if only one found. */
1840 memcpy(&ipod_found, ipod, sizeof(struct ipod_t));
1841 ipod_close(ipod);
1842 }
1843
1844 if (n==1) {
1845 /* restore the ipod_t structure, it might have been overwritten */
1846 memcpy(ipod, &ipod_found, sizeof(struct ipod_t));
1847 }
1848 else if(n == 0 && denied) {
1849 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied);
1850#ifdef __WIN32__
1851 printf("[ERR] You need to run this program with administrator priviledges!\n");
1852#else
1853 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1854#endif
1855 }
1856 return (n == 0 && denied) ? -1 : n;
1857}
1858
1859static void put_int32le(uint32_t x, unsigned char* p)
1860{
1861 p[0] = x & 0xff;
1862 p[1] = (x >> 8) & 0xff;
1863 p[2] = (x >> 16) & 0xff;
1864 p[3] = (x >> 24) & 0xff;
1865}
1866
1867int write_dos_partition_table(struct ipod_t* ipod)
1868{
1869 unsigned char* p;
1870 int i, n;
1871 uint32_t type;
1872
1873 /* Only support 512-byte sectors at the moment */
1874 if ( ipod->sector_size != 512 )
1875 {
1876 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1877 return -1;
1878 }
1879 if(ipod->sectorbuf == NULL) {
1880 fprintf(stderr,"[ERR] Buffer not initialized.");
1881 return -1;
1882 }
1883
1884 /* Firstly zero the entire MBR */
1885 memset(ipod->sectorbuf, 0, ipod->sector_size);
1886
1887 /* Now add the partition info */
1888 for (i=0; i < 4 ; i++)
1889 {
1890 p = ipod->sectorbuf + 0x1be + i*16;
1891
1892 /* Ensure first partition is type 0, and second is 0xb */
1893 if (i==0) { type = 0; }
1894 else if (i==1) { type = 0xb; }
1895 else { type = ipod->pinfo[i].type; }
1896
1897 put_int32le(type, p + 4);
1898 put_int32le(ipod->pinfo[i].start, p + 8);
1899 put_int32le(ipod->pinfo[i].size, p + 12);
1900 }
1901
1902 /* Finally add the magic */
1903 ipod->sectorbuf[0x1fe] = 0x55;
1904 ipod->sectorbuf[0x1ff] = 0xaa;
1905
1906 if (ipod_seek(ipod, 0) < 0) {
1907 fprintf(stderr,"[ERR] Seek failed writing MBR\n");
1908 return -1;
1909 }
1910
1911 /* Write MBR */
1912 if ((n = ipod_write(ipod, ipod->sector_size)) < 0) {
1913 perror("[ERR] Write failed\n");
1914 return -1;
1915 }
1916
1917 return 0;
1918}
1919
1920/* Get the XML Device Information, as documented here:
1921
1922 http://www.ipodlinux.org/wiki/Device_Information
1923*/
1924
1925int ipod_get_xmlinfo(struct ipod_t* ipod)
1926{
1927 unsigned char hdr[255];
1928 unsigned char buf[255];
1929 char* p;
1930 int psize;
1931 int npages;
1932 int i;
1933
1934 if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0)
1935 {
1936 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1937 return -1;
1938 }
1939
1940 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1941 win32 */
1942 memcpy(hdr, buf, sizeof(hdr));
1943
1944 npages = hdr[3];
1945
1946 psize = npages * 0xf8; /* Hopefully this is enough. */
1947
1948 ipod->xmlinfo = malloc(psize);
1949 ipod->xmlinfo_len = 0;
1950
1951 if (ipod->xmlinfo == NULL) {
1952 fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n");
1953 return -1;
1954 }
1955
1956 p = ipod->xmlinfo;
1957
1958 for (i=0; i < npages; i++) {
1959 if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) {
1960 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1961 return -1;
1962 }
1963
1964 if ((buf[3] + ipod->xmlinfo_len) > psize) {
1965 fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n");
1966 free(ipod->xmlinfo);
1967 ipod->xmlinfo = NULL;
1968 ipod->xmlinfo_len = 0;
1969 return -1;
1970 }
1971
1972 memcpy(p, buf + 4, buf[3]);
1973 p += buf[3];
1974 ipod->xmlinfo_len += buf[3];
1975 }
1976
1977 /* NULL-terminate the XML info */
1978 *p = 0;
1979
1980 fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len);
1981
1982 return 0;
1983}
1984
1985void ipod_get_ramsize(struct ipod_t* ipod)
1986{
1987 const char needle[] = "<key>RAM</key>\n<integer>";
1988 char* p;
1989
1990 if (ipod->xmlinfo == NULL)
1991 return;
1992
1993 p = strstr(ipod->xmlinfo, needle);
1994
1995 if (p) {
1996 ipod->ramsize = atoi(p + sizeof(needle) - 1);
1997 }
1998}
1999
2000#ifndef RBUTIL
2001
2002static inline uint32_t getuint32le(unsigned char* buf)
2003{
2004 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
2005
2006 return res;
2007}
2008
2009/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
2010 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
2011
2012*/
2013
2014static bool testMarker(int marker)
2015{
2016 int mask, decrypt, temp1, temp2;
2017
2018 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
2019 decrypt = marker ^ mask;
2020 temp1=(int)((unsigned int)decrypt>>24);
2021 temp2=decrypt<<8;
2022
2023 if (temp1==0)
2024 return false;
2025
2026 temp2=(int)((unsigned int)temp2>>24);
2027 decrypt=decrypt<<16;
2028 decrypt=(int)((unsigned int)decrypt>>24);
2029
2030 if ((temp1 < temp2) && (temp2 < decrypt))
2031 {
2032 temp1 = temp1 & 0xf;
2033 temp2 = temp2 & 0xf;
2034 decrypt = decrypt & 0xf;
2035
2036 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
2037 {
2038 return true;
2039 }
2040 }
2041 return false;
2042}
2043
2044static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
2045{
2046 int constant = 0x54c3a298;
2047 int key=0;
2048 int nkeys = 0;
2049 int aMarker=0;
2050 int pos=0;
2051 int c, count;
2052 int temp1;
2053 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2054
2055 for (c = 0; c < 8; c++)
2056 {
2057 pos = offset[c]*4;
2058 aMarker = getuint32le(data + pos);
2059
2060 if (testMarker(aMarker))
2061 {
2062 if (c<7)
2063 pos =(offset[c+1]*4)+4;
2064 else
2065 pos =(offset[0]*4)+4;
2066
2067 key=0;
2068
2069 temp1=aMarker;
2070
2071 for (count=0;count<2;count++){
2072 int word = getuint32le(data + pos);
2073 temp1 = aMarker;
2074 temp1 = temp1^word;
2075 temp1 = temp1^constant;
2076 key = temp1;
2077 pos = pos+4;
2078 }
2079 int r1=0x6f;
2080 int r2=0;
2081 int r12;
2082 int r14;
2083 unsigned int r_tmp;
2084
2085 for (count=2;count<128;count=count+2){
2086 r2=getuint32le(data+count*4);
2087 r12=getuint32le(data+(count*4)+4);
2088 r_tmp=(unsigned int)r12>>16;
2089 r14=r2 | ((int)r_tmp);
2090 r2=r2&0xffff;
2091 r2=r2 | r12;
2092 r1=r1^r14;
2093 r1=r1+r2;
2094 }
2095 key=key^r1;
2096
2097 // Invert key, little endian
2098 this_key[0] = key & 0xff;
2099 this_key[1] = (key >> 8) & 0xff;
2100 this_key[2] = (key >> 16) & 0xff;
2101 this_key[3] = (key >> 24) & 0xff;
2102 nkeys++;
2103 }
2104 }
2105 return nkeys;
2106}
2107
2108static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
2109{
2110 int n;
2111
2112 /* Firstly read the security block and find the RC4 key. This is
2113 in the sector preceeding the AUPD image. */
2114
2115 if(ipod->sectorbuf == NULL) {
2116 fprintf(stderr,"[ERR] Buffer not initialized.");
2117 return -1;
2118 }
2119 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
2120 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
2121 return -1;
2122 }
2123
2124 if ((n = ipod_read(ipod, 512)) < 0) {
2125 return -1;
2126 }
2127
2128 n = GetSecurityBlockKey(ipod->sectorbuf, key);
2129
2130 if (n != 1)
2131 {
2132 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
2133 return -1;
2134 }
2135
2136 return 0;
2137}
2138
2139int read_aupd(struct ipod_t* ipod, char* filename)
2140{
2141 int length;
2142 int i;
2143 int outfile;
2144 int n;
2145 int aupd;
2146 struct rc4_key_t rc4;
2147 unsigned char key[4];
2148 unsigned long chksum=0;
2149
2150 if(ipod->sectorbuf == NULL) {
2151 fprintf(stderr,"[ERR] Buffer not initialized.");
2152 return -1;
2153 }
2154 aupd = 0;
2155 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2156 {
2157 aupd++;
2158 }
2159
2160 if (aupd == ipod->nimages)
2161 {
2162 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2163 return -1;
2164 }
2165
2166 length = ipod->ipod_directory[aupd].len;
2167
2168 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
2169
2170 if (find_key(ipod, aupd, key) < 0)
2171 {
2172 return -1;
2173 }
2174
2175 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2176
2177 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2178 return -1;
2179 }
2180
2181 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
2182
2183 if ((n = ipod_read(ipod,i)) < 0) {
2184 return -1;
2185 }
2186
2187 if (n < i) {
2188 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
2189 i,n);
2190 return -1;
2191 }
2192
2193 /* Perform the decryption - this is standard (A)RC4 */
2194 matrixArc4Init(&rc4, key, 4);
2195 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2196
2197 chksum = 0;
2198 for (i = 0; i < (int)length; i++) {
2199 /* add 8 unsigned bits but keep a 32 bit sum */
2200 chksum += ipod->sectorbuf[i];
2201 }
2202
2203 if (chksum != ipod->ipod_directory[aupd].chksum)
2204 {
2205 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
2206 return -1;
2207 }
2208 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
2209
2210 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
2211 if (outfile < 0) {
2212 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
2213 return -1;
2214 }
2215
2216 n = write(outfile,ipod->sectorbuf,length);
2217 if (n != length) {
2218 fprintf(stderr,"[ERR] Write error - %d\n",n);
2219 }
2220 close(outfile);
2221
2222 return 0;
2223}
2224
2225int write_aupd(struct ipod_t* ipod, char* filename)
2226{
2227 unsigned int length;
2228 int i;
2229 int x;
2230 int n;
2231 int infile;
2232 int newsize;
2233 int aupd;
2234 unsigned long chksum=0;
2235 struct rc4_key_t rc4;
2236 unsigned char key[4];
2237
2238 if(ipod->sectorbuf == NULL) {
2239 fprintf(stderr,"[ERR] Buffer not initialized.");
2240 return -1;
2241 }
2242 /* First check that the input file is the correct type for this ipod. */
2243 infile=open(filename,O_RDONLY);
2244 if (infile < 0) {
2245 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
2246 return -1;
2247 }
2248
2249 length = filesize(infile);
2250 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
2251
2252 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2253 length,newsize);
2254
2255 if (newsize > BUFFER_SIZE) {
2256 fprintf(stderr,"[ERR] Input file too big for buffer\n");
2257 if (infile >= 0) close(infile);
2258 return -1;
2259 }
2260
2261 /* Find aupd image number */
2262 aupd = 0;
2263 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2264 {
2265 aupd++;
2266 }
2267
2268 if (aupd == ipod->nimages)
2269 {
2270 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2271 return -1;
2272 }
2273
2274 if (length != ipod->ipod_directory[aupd].len)
2275 {
2276 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2277 ipod->ipod_directory[aupd].len, filename, length);
2278 return -1;
2279 }
2280
2281 if (find_key(ipod, aupd, key) < 0)
2282 {
2283 return -1;
2284 }
2285
2286 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2287
2288 /* We now know we have enough space, so write it. */
2289
2290 fprintf(stderr,"[INFO] Reading input file...\n");
2291 n = read(infile,ipod->sectorbuf,length);
2292 if (n < 0) {
2293 fprintf(stderr,"[ERR] Couldn't read input file\n");
2294 close(infile);
2295 return -1;
2296 }
2297 close(infile);
2298
2299 /* Pad the data with zeros */
2300 memset(ipod->sectorbuf+length,0,newsize-length);
2301
2302 /* Calculate the new checksum (before we encrypt) */
2303 chksum = 0;
2304 for (i = 0; i < (int)length; i++) {
2305 /* add 8 unsigned bits but keep a 32 bit sum */
2306 chksum += ipod->sectorbuf[i];
2307 }
2308
2309 /* Perform the encryption - this is standard (A)RC4 */
2310 matrixArc4Init(&rc4, key, 4);
2311 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2312
2313 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2314 fprintf(stderr,"[ERR] Seek failed\n");
2315 return -1;
2316 }
2317
2318 if ((n = ipod_write(ipod,newsize)) < 0) {
2319 perror("[ERR] Write failed\n");
2320 return -1;
2321 }
2322
2323 if (n < newsize) {
2324 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
2325 ,newsize,n);
2326 return -1;
2327 }
2328 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
2329
2330 x = ipod->diroffset % ipod->sector_size;
2331
2332 /* Read directory */
2333 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2334
2335 n=ipod_read(ipod, ipod->sector_size);
2336 if (n < 0) { return -1; }
2337
2338 /* Update checksum */
2339 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod->sectorbuf + x + aupd*40 + 28));
2340 int2le(chksum,ipod->sectorbuf+x+aupd*40+28);
2341
2342 /* Write directory */
2343 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2344 n=ipod_write(ipod, ipod->sector_size);
2345 if (n < 0) { return -1; }
2346
2347 return 0;
2348}
2349
2350#endif