diff options
author | Dave Chapman <dave@dchapman.com> | 2007-09-08 23:27:49 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2007-09-08 23:27:49 +0000 |
commit | 6e7971553e021a7fe72987490439bf9a5475fb44 (patch) | |
tree | aaa6074b94e30cf4e37fed446b30ce059f36dbaa /rbutil/ipodpatcher | |
parent | 6c24189d27f1bdd6f2e0458ada99a8d7e5896689 (diff) | |
download | rockbox-6e7971553e021a7fe72987490439bf9a5475fb44.tar.gz rockbox-6e7971553e021a7fe72987490439bf9a5475fb44.zip |
Add functions to read and write the AUPD (flash update) image. "--read-aupd aupd.bin" will read (and decrypt) the AUPD image, and "--write-aupd aupd.bin" will write (and encrypt) an image. Also fix a bug in the "diskmove" function which corrupted the AUPD image when a bootloader was installed. So in order to manipulate the aupd image, you need to restore a clean firmware partition, and install the bootloader with this version of ipodpatcher. Decryption functions based on the description and sample code at http://ipodlinux.org/Flash_Decryption
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14644 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'rbutil/ipodpatcher')
-rw-r--r-- | rbutil/ipodpatcher/Makefile | 2 | ||||
-rw-r--r-- | rbutil/ipodpatcher/arc4.c | 108 | ||||
-rw-r--r-- | rbutil/ipodpatcher/arc4.h | 47 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.c | 349 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.h | 2 | ||||
-rw-r--r-- | rbutil/ipodpatcher/main.c | 32 |
6 files changed, 537 insertions, 3 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile index f65234a505..f76715b9f6 100644 --- a/rbutil/ipodpatcher/Makefile +++ b/rbutil/ipodpatcher/Makefile | |||
@@ -22,7 +22,7 @@ endif | |||
22 | NATIVECC = gcc | 22 | NATIVECC = gcc |
23 | CC = $(CROSS)gcc | 23 | CC = $(CROSS)gcc |
24 | 24 | ||
25 | SRC = main.c ipodpatcher.c fat32format.c parttypes.h | 25 | SRC = main.c ipodpatcher.c fat32format.c parttypes.h arc4.c |
26 | 26 | ||
27 | all: $(OUTPUT) | 27 | all: $(OUTPUT) |
28 | 28 | ||
diff --git a/rbutil/ipodpatcher/arc4.c b/rbutil/ipodpatcher/arc4.c new file mode 100644 index 0000000000..75b1862b89 --- /dev/null +++ b/rbutil/ipodpatcher/arc4.c | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * arc4.c | ||
3 | * Release $Name: MATRIXSSL_1_8_3_OPEN $ | ||
4 | * | ||
5 | * ARC4 stream cipher implementation | ||
6 | */ | ||
7 | /* | ||
8 | * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved. | ||
9 | * The latest version of this code is available at http://www.matrixssl.org | ||
10 | * | ||
11 | * This software is open source; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This General Public License does NOT permit incorporating this software | ||
17 | * into proprietary programs. If you are unable to comply with the GPL, a | ||
18 | * commercial license for this software may be purchased from PeerSec Networks | ||
19 | * at http://www.peersec.com | ||
20 | * | ||
21 | * This program is distributed in WITHOUT ANY WARRANTY; without even the | ||
22 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
23 | * See the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * http://www.gnu.org/copyleft/gpl.html | ||
29 | */ | ||
30 | /******************************************************************************/ | ||
31 | |||
32 | #include "arc4.h" | ||
33 | |||
34 | /* | ||
35 | Some accounts, such as O'Reilly's Secure Programming Cookbook say that no | ||
36 | more than 2^30 bytes should be processed without rekeying, so we | ||
37 | enforce that limit here. FYI, this is equal to 1GB of data transferred. | ||
38 | */ | ||
39 | #define ARC4_MAX_BYTES 0x40000000 | ||
40 | |||
41 | /******************************************************************************/ | ||
42 | /* | ||
43 | SSL_RSA_WITH_RC4_* cipher callbacks | ||
44 | */ | ||
45 | void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen) | ||
46 | { | ||
47 | unsigned char index1, index2, tmp, *state; | ||
48 | int16_t counter; | ||
49 | |||
50 | ctx->byteCount = 0; | ||
51 | state = &ctx->state[0]; | ||
52 | |||
53 | for (counter = 0; counter < 256; counter++) { | ||
54 | state[counter] = (unsigned char)counter; | ||
55 | } | ||
56 | ctx->x = 0; | ||
57 | ctx->y = 0; | ||
58 | index1 = 0; | ||
59 | index2 = 0; | ||
60 | |||
61 | for (counter = 0; counter < 256; counter++) { | ||
62 | index2 = (key[index1] + state[counter] + index2) & 0xff; | ||
63 | |||
64 | tmp = state[counter]; | ||
65 | state[counter] = state[index2]; | ||
66 | state[index2] = tmp; | ||
67 | |||
68 | index1 = (index1 + 1) % keylen; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in, | ||
73 | unsigned char *out, int32_t len) | ||
74 | { | ||
75 | unsigned char x, y, *state, xorIndex, tmp; | ||
76 | int counter; /* NOTE BY DAVE CHAPMAN: This was a short in | ||
77 | the original code, which caused a segfault | ||
78 | when attempting to process data > 32767 | ||
79 | bytes. */ | ||
80 | |||
81 | ctx->byteCount += len; | ||
82 | if (ctx->byteCount > ARC4_MAX_BYTES) { | ||
83 | return -1; | ||
84 | } | ||
85 | |||
86 | x = ctx->x; | ||
87 | y = ctx->y; | ||
88 | state = &ctx->state[0]; | ||
89 | for (counter = 0; counter < len; counter++) { | ||
90 | x = (x + 1) & 0xff; | ||
91 | y = (state[x] + y) & 0xff; | ||
92 | |||
93 | tmp = state[x]; | ||
94 | state[x] = state[y]; | ||
95 | state[y] = tmp; | ||
96 | |||
97 | xorIndex = (state[x] + state[y]) & 0xff; | ||
98 | |||
99 | tmp = in[counter]; | ||
100 | tmp ^= state[xorIndex]; | ||
101 | out[counter] = tmp; | ||
102 | } | ||
103 | ctx->x = x; | ||
104 | ctx->y = y; | ||
105 | return len; | ||
106 | } | ||
107 | |||
108 | /*****************************************************************************/ | ||
diff --git a/rbutil/ipodpatcher/arc4.h b/rbutil/ipodpatcher/arc4.h new file mode 100644 index 0000000000..8bff0e2dc1 --- /dev/null +++ b/rbutil/ipodpatcher/arc4.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | arc4.h - based on matrixssl-1-8-3-open | ||
3 | |||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved. | ||
8 | * The latest version of this code is available at http://www.matrixssl.org | ||
9 | * | ||
10 | * This software is open source; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This General Public License does NOT permit incorporating this software | ||
16 | * into proprietary programs. If you are unable to comply with the GPL, a | ||
17 | * commercial license for this software may be purchased from PeerSec Networks | ||
18 | * at http://www.peersec.com | ||
19 | * | ||
20 | * This program is distributed in WITHOUT ANY WARRANTY; without even the | ||
21 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
22 | * See the GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | * http://www.gnu.org/copyleft/gpl.html | ||
28 | */ | ||
29 | /*****************************************************************************/ | ||
30 | |||
31 | #ifndef _ARC4_H | ||
32 | |||
33 | #include <stdint.h> | ||
34 | |||
35 | struct rc4_key_t | ||
36 | { | ||
37 | unsigned char state[256]; | ||
38 | uint32_t byteCount; | ||
39 | unsigned char x; | ||
40 | unsigned char y; | ||
41 | }; | ||
42 | |||
43 | void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen); | ||
44 | int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in, | ||
45 | unsigned char *out, int32_t len); | ||
46 | |||
47 | #endif | ||
diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c index 2655c57113..08ba9263d2 100644 --- a/rbutil/ipodpatcher/ipodpatcher.c +++ b/rbutil/ipodpatcher/ipodpatcher.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <inttypes.h> | 25 | #include <inttypes.h> |
26 | #include <stdbool.h> | ||
26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
27 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
28 | 29 | ||
@@ -41,6 +42,10 @@ | |||
41 | #include "ipodvideo.h" | 42 | #include "ipodvideo.h" |
42 | #endif | 43 | #endif |
43 | 44 | ||
45 | #ifndef RBUTIL | ||
46 | #include "arc4.h" | ||
47 | #endif | ||
48 | |||
44 | extern int verbose; | 49 | extern int verbose; |
45 | 50 | ||
46 | unsigned char* sectorbuf; | 51 | unsigned char* sectorbuf; |
@@ -392,7 +397,7 @@ int diskmove(struct ipod_t* ipod, int delta) | |||
392 | int chunksize; | 397 | int chunksize; |
393 | int n; | 398 | int n; |
394 | 399 | ||
395 | src_start = ipod->ipod_directory[1].devOffset + ipod->sector_size; | 400 | src_start = ipod->ipod_directory[1].devOffset; |
396 | src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size + | 401 | src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size + |
397 | ipod->ipod_directory[ipod->nimages-1].len + | 402 | ipod->ipod_directory[ipod->nimages-1].len + |
398 | (ipod->sector_size-1)) & ~(ipod->sector_size-1); | 403 | (ipod->sector_size-1)) & ~(ipod->sector_size-1); |
@@ -575,7 +580,7 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type) | |||
575 | ipod->ipod_directory[1].devOffset) { | 580 | ipod->ipod_directory[1].devOffset) { |
576 | fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); | 581 | fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); |
577 | delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength | 582 | delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength |
578 | - ipod->ipod_directory[1].devOffset; | 583 | - ipod->ipod_directory[1].devOffset + ipod->sector_size; |
579 | 584 | ||
580 | if (diskmove(ipod, delta) < 0) { | 585 | if (diskmove(ipod, delta) < 0) { |
581 | fprintf(stderr,"[ERR] Image movement failed.\n"); | 586 | fprintf(stderr,"[ERR] Image movement failed.\n"); |
@@ -1373,3 +1378,343 @@ int write_dos_partition_table(struct ipod_t* ipod) | |||
1373 | 1378 | ||
1374 | return 0; | 1379 | return 0; |
1375 | } | 1380 | } |
1381 | |||
1382 | #ifndef RBUTIL | ||
1383 | |||
1384 | static inline uint32_t getuint32le(unsigned char* buf) | ||
1385 | { | ||
1386 | int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
1387 | |||
1388 | return res; | ||
1389 | } | ||
1390 | |||
1391 | /* testMarker and GetSecurityBlockKey based on code from BadBlocks and | ||
1392 | Kingstone, posted at http://ipodlinux.org/Flash_Decryption | ||
1393 | |||
1394 | */ | ||
1395 | |||
1396 | static bool testMarker(int marker) | ||
1397 | { | ||
1398 | int mask, decrypt, temp1, temp2; | ||
1399 | |||
1400 | mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24); | ||
1401 | decrypt = marker ^ mask; | ||
1402 | temp1=(int)((unsigned int)decrypt>>24); | ||
1403 | temp2=decrypt<<8; | ||
1404 | |||
1405 | if (temp1==0) | ||
1406 | return false; | ||
1407 | |||
1408 | temp2=(int)((unsigned int)temp2>>24); | ||
1409 | decrypt=decrypt<<16; | ||
1410 | decrypt=(int)((unsigned int)decrypt>>24); | ||
1411 | |||
1412 | if ((temp1 < temp2) && (temp2 < decrypt)) | ||
1413 | { | ||
1414 | temp1 = temp1 & 0xf; | ||
1415 | temp2 = temp2 & 0xf; | ||
1416 | decrypt = decrypt & 0xf; | ||
1417 | |||
1418 | if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0)) | ||
1419 | { | ||
1420 | return true; | ||
1421 | } | ||
1422 | } | ||
1423 | return false; | ||
1424 | } | ||
1425 | |||
1426 | static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key) | ||
1427 | { | ||
1428 | int constant = 0x54c3a298; | ||
1429 | int key=0; | ||
1430 | int nkeys = 0; | ||
1431 | int aMarker=0; | ||
1432 | int pos=0; | ||
1433 | int c, count; | ||
1434 | int temp1; | ||
1435 | static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34}; | ||
1436 | |||
1437 | for (c = 0; c < 8; c++) | ||
1438 | { | ||
1439 | pos = offset[c]*4; | ||
1440 | aMarker = getuint32le(data + pos); | ||
1441 | |||
1442 | if (testMarker(aMarker)) | ||
1443 | { | ||
1444 | if (c<7) | ||
1445 | pos =(offset[c+1]*4)+4; | ||
1446 | else | ||
1447 | pos =(offset[0]*4)+4; | ||
1448 | |||
1449 | key=0; | ||
1450 | |||
1451 | temp1=aMarker; | ||
1452 | |||
1453 | for (count=0;count<2;count++){ | ||
1454 | int word = getuint32le(data + pos); | ||
1455 | temp1 = aMarker; | ||
1456 | temp1 = temp1^word; | ||
1457 | temp1 = temp1^constant; | ||
1458 | key = temp1; | ||
1459 | pos = pos+4; | ||
1460 | } | ||
1461 | int r1=0x6f; | ||
1462 | int r2=0; | ||
1463 | int r12; | ||
1464 | int r14; | ||
1465 | unsigned int r_tmp; | ||
1466 | |||
1467 | for (count=2;count<128;count=count+2){ | ||
1468 | r2=getuint32le(data+count*4); | ||
1469 | r12=getuint32le(data+(count*4)+4); | ||
1470 | r_tmp=(unsigned int)r12>>16; | ||
1471 | r14=r2 | ((int)r_tmp); | ||
1472 | r2=r2&0xffff; | ||
1473 | r2=r2 | r12; | ||
1474 | r1=r1^r14; | ||
1475 | r1=r1+r2; | ||
1476 | } | ||
1477 | key=key^r1; | ||
1478 | |||
1479 | // Invert key, little endian | ||
1480 | this_key[0] = key & 0xff; | ||
1481 | this_key[1] = (key >> 8) & 0xff; | ||
1482 | this_key[2] = (key >> 16) & 0xff; | ||
1483 | this_key[3] = (key >> 24) & 0xff; | ||
1484 | nkeys++; | ||
1485 | } | ||
1486 | } | ||
1487 | return nkeys; | ||
1488 | } | ||
1489 | |||
1490 | static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key) | ||
1491 | { | ||
1492 | int n; | ||
1493 | |||
1494 | /* Firstly read the security block and find the RC4 key. This is | ||
1495 | in the sector preceeding the AUPD image. */ | ||
1496 | |||
1497 | fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size); | ||
1498 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) { | ||
1499 | return -1; | ||
1500 | } | ||
1501 | |||
1502 | if ((n = ipod_read(ipod, sectorbuf, 512)) < 0) { | ||
1503 | return -1; | ||
1504 | } | ||
1505 | |||
1506 | n = GetSecurityBlockKey(sectorbuf, key); | ||
1507 | |||
1508 | if (n != 1) | ||
1509 | { | ||
1510 | fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n); | ||
1511 | return -1; | ||
1512 | } | ||
1513 | |||
1514 | return 0; | ||
1515 | } | ||
1516 | |||
1517 | int read_aupd(struct ipod_t* ipod, char* filename) | ||
1518 | { | ||
1519 | int length; | ||
1520 | int i; | ||
1521 | int outfile; | ||
1522 | int n; | ||
1523 | int aupd; | ||
1524 | struct rc4_key_t rc4; | ||
1525 | unsigned char key[4]; | ||
1526 | unsigned long chksum=0; | ||
1527 | |||
1528 | aupd = 0; | ||
1529 | while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD)) | ||
1530 | { | ||
1531 | aupd++; | ||
1532 | } | ||
1533 | |||
1534 | if (aupd == ipod->nimages) | ||
1535 | { | ||
1536 | fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n"); | ||
1537 | return -1; | ||
1538 | } | ||
1539 | |||
1540 | length = ipod->ipod_directory[aupd].len; | ||
1541 | |||
1542 | fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); | ||
1543 | |||
1544 | if (find_key(ipod, aupd, key) < 0) | ||
1545 | { | ||
1546 | return -1; | ||
1547 | } | ||
1548 | |||
1549 | fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]); | ||
1550 | |||
1551 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) { | ||
1552 | return -1; | ||
1553 | } | ||
1554 | |||
1555 | i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); | ||
1556 | |||
1557 | if ((n = ipod_read(ipod,sectorbuf,i)) < 0) { | ||
1558 | return -1; | ||
1559 | } | ||
1560 | |||
1561 | if (n < i) { | ||
1562 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", | ||
1563 | i,n); | ||
1564 | return -1; | ||
1565 | } | ||
1566 | |||
1567 | /* Perform the decryption - this is standard (A)RC4 */ | ||
1568 | matrixArc4Init(&rc4, key, 4); | ||
1569 | matrixArc4(&rc4, sectorbuf, sectorbuf, length); | ||
1570 | |||
1571 | chksum = 0; | ||
1572 | for (i = 0; i < (int)length; i++) { | ||
1573 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
1574 | chksum += sectorbuf[i]; | ||
1575 | } | ||
1576 | |||
1577 | if (chksum != ipod->ipod_directory[aupd].chksum) | ||
1578 | { | ||
1579 | fprintf(stderr,"[ERR] Decryption failed - checksum error\n"); | ||
1580 | return -1; | ||
1581 | } | ||
1582 | fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n"); | ||
1583 | |||
1584 | outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666); | ||
1585 | if (outfile < 0) { | ||
1586 | fprintf(stderr,"[ERR] Couldn't open file %s\n",filename); | ||
1587 | return -1; | ||
1588 | } | ||
1589 | |||
1590 | n = write(outfile,sectorbuf,length); | ||
1591 | if (n != length) { | ||
1592 | fprintf(stderr,"[ERR] Write error - %d\n",n); | ||
1593 | } | ||
1594 | close(outfile); | ||
1595 | |||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | int write_aupd(struct ipod_t* ipod, char* filename) | ||
1600 | { | ||
1601 | unsigned int length; | ||
1602 | int i; | ||
1603 | int x; | ||
1604 | int n; | ||
1605 | int infile; | ||
1606 | int newsize; | ||
1607 | int aupd; | ||
1608 | unsigned long chksum=0; | ||
1609 | struct rc4_key_t rc4; | ||
1610 | unsigned char key[4]; | ||
1611 | |||
1612 | /* First check that the input file is the correct type for this ipod. */ | ||
1613 | infile=open(filename,O_RDONLY); | ||
1614 | if (infile < 0) { | ||
1615 | fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); | ||
1616 | return -1; | ||
1617 | } | ||
1618 | |||
1619 | length = filesize(infile); | ||
1620 | newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
1621 | |||
1622 | fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n", | ||
1623 | length,newsize); | ||
1624 | |||
1625 | if (newsize > BUFFER_SIZE) { | ||
1626 | fprintf(stderr,"[ERR] Input file too big for buffer\n"); | ||
1627 | if (infile >= 0) close(infile); | ||
1628 | return -1; | ||
1629 | } | ||
1630 | |||
1631 | /* Find aupd image number */ | ||
1632 | aupd = 0; | ||
1633 | while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD)) | ||
1634 | { | ||
1635 | aupd++; | ||
1636 | } | ||
1637 | |||
1638 | if (aupd == ipod->nimages) | ||
1639 | { | ||
1640 | fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n"); | ||
1641 | return -1; | ||
1642 | } | ||
1643 | |||
1644 | if (length != ipod->ipod_directory[aupd].len) | ||
1645 | { | ||
1646 | fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n", | ||
1647 | ipod->ipod_directory[aupd].len, filename, length); | ||
1648 | return -1; | ||
1649 | } | ||
1650 | |||
1651 | if (find_key(ipod, aupd, key) < 0) | ||
1652 | { | ||
1653 | return -1; | ||
1654 | } | ||
1655 | |||
1656 | fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]); | ||
1657 | |||
1658 | /* We now know we have enough space, so write it. */ | ||
1659 | |||
1660 | fprintf(stderr,"[INFO] Reading input file...\n"); | ||
1661 | n = read(infile,sectorbuf,length); | ||
1662 | if (n < 0) { | ||
1663 | fprintf(stderr,"[ERR] Couldn't read input file\n"); | ||
1664 | close(infile); | ||
1665 | return -1; | ||
1666 | } | ||
1667 | close(infile); | ||
1668 | |||
1669 | /* Pad the data with zeros */ | ||
1670 | memset(sectorbuf+length,0,newsize-length); | ||
1671 | |||
1672 | /* Calculate the new checksum (before we encrypt) */ | ||
1673 | chksum = 0; | ||
1674 | for (i = 0; i < (int)length; i++) { | ||
1675 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
1676 | chksum += sectorbuf[i]; | ||
1677 | } | ||
1678 | |||
1679 | /* Perform the encryption - this is standard (A)RC4 */ | ||
1680 | matrixArc4Init(&rc4, key, 4); | ||
1681 | matrixArc4(&rc4, sectorbuf, sectorbuf, length); | ||
1682 | |||
1683 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) { | ||
1684 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
1685 | return -1; | ||
1686 | } | ||
1687 | |||
1688 | if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) { | ||
1689 | perror("[ERR] Write failed\n"); | ||
1690 | return -1; | ||
1691 | } | ||
1692 | |||
1693 | if (n < newsize) { | ||
1694 | fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" | ||
1695 | ,newsize,n); | ||
1696 | return -1; | ||
1697 | } | ||
1698 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); | ||
1699 | |||
1700 | x = ipod->diroffset % ipod->sector_size; | ||
1701 | |||
1702 | /* Read directory */ | ||
1703 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
1704 | |||
1705 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
1706 | if (n < 0) { return -1; } | ||
1707 | |||
1708 | /* Update checksum */ | ||
1709 | fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(sectorbuf + x + aupd*40 + 28)); | ||
1710 | int2le(chksum,sectorbuf+x+aupd*40+28); | ||
1711 | |||
1712 | /* Write directory */ | ||
1713 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
1714 | n=ipod_write(ipod, sectorbuf, ipod->sector_size); | ||
1715 | if (n < 0) { return -1; } | ||
1716 | |||
1717 | return 0; | ||
1718 | } | ||
1719 | |||
1720 | #endif | ||
diff --git a/rbutil/ipodpatcher/ipodpatcher.h b/rbutil/ipodpatcher/ipodpatcher.h index d816c68724..0d9222268f 100644 --- a/rbutil/ipodpatcher/ipodpatcher.h +++ b/rbutil/ipodpatcher/ipodpatcher.h | |||
@@ -47,6 +47,8 @@ int list_images(struct ipod_t* ipod); | |||
47 | int getmodel(struct ipod_t* ipod, int ipod_version); | 47 | int getmodel(struct ipod_t* ipod, int ipod_version); |
48 | int ipod_scan(struct ipod_t* ipod); | 48 | int ipod_scan(struct ipod_t* ipod); |
49 | int write_dos_partition_table(struct ipod_t* ipod); | 49 | int write_dos_partition_table(struct ipod_t* ipod); |
50 | int read_aupd(struct ipod_t* ipod, char* filename); | ||
51 | int write_aupd(struct ipod_t* ipod, char* filename); | ||
50 | off_t filesize(int fd); | 52 | off_t filesize(int fd); |
51 | 53 | ||
52 | #endif | 54 | #endif |
diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c index c47063cba8..f113c8aff4 100644 --- a/rbutil/ipodpatcher/main.c +++ b/rbutil/ipodpatcher/main.c | |||
@@ -45,6 +45,8 @@ enum { | |||
45 | ADD_BOOTLOADER, | 45 | ADD_BOOTLOADER, |
46 | READ_FIRMWARE, | 46 | READ_FIRMWARE, |
47 | WRITE_FIRMWARE, | 47 | WRITE_FIRMWARE, |
48 | READ_AUPD, | ||
49 | WRITE_AUPD, | ||
48 | READ_PARTITION, | 50 | READ_PARTITION, |
49 | WRITE_PARTITION, | 51 | WRITE_PARTITION, |
50 | FORMAT_PARTITION, | 52 | FORMAT_PARTITION, |
@@ -89,6 +91,8 @@ void print_usage(void) | |||
89 | fprintf(stderr," -d, --delete-bootloader\n"); | 91 | fprintf(stderr," -d, --delete-bootloader\n"); |
90 | fprintf(stderr," -f, --format\n"); | 92 | fprintf(stderr," -f, --format\n"); |
91 | fprintf(stderr," -c, --convert\n"); | 93 | fprintf(stderr," -c, --convert\n"); |
94 | fprintf(stderr," --read-aupd filename.bin\n"); | ||
95 | fprintf(stderr," --write-aupd filename.bin\n"); | ||
92 | fprintf(stderr,"\n"); | 96 | fprintf(stderr,"\n"); |
93 | 97 | ||
94 | #ifdef __WIN32__ | 98 | #ifdef __WIN32__ |
@@ -299,6 +303,18 @@ int main(int argc, char* argv[]) | |||
299 | (strcmp(argv[i],"--format")==0)) { | 303 | (strcmp(argv[i],"--format")==0)) { |
300 | action = FORMAT_PARTITION; | 304 | action = FORMAT_PARTITION; |
301 | i++; | 305 | i++; |
306 | } else if (strcmp(argv[i],"--read-aupd")==0) { | ||
307 | action = READ_AUPD; | ||
308 | i++; | ||
309 | if (i == argc) { print_usage(); return 1; } | ||
310 | filename=argv[i]; | ||
311 | i++; | ||
312 | } else if (strcmp(argv[i],"--write-aupd")==0) { | ||
313 | action = WRITE_AUPD; | ||
314 | i++; | ||
315 | if (i == argc) { print_usage(); return 1; } | ||
316 | filename=argv[i]; | ||
317 | i++; | ||
302 | } else if ((strcmp(argv[i],"-c")==0) || | 318 | } else if ((strcmp(argv[i],"-c")==0) || |
303 | (strcmp(argv[i],"--convert")==0)) { | 319 | (strcmp(argv[i],"--convert")==0)) { |
304 | action = CONVERT_TO_FAT32; | 320 | action = CONVERT_TO_FAT32; |
@@ -444,6 +460,22 @@ int main(int argc, char* argv[]) | |||
444 | } else { | 460 | } else { |
445 | fprintf(stderr,"[ERR] --read-firmware failed.\n"); | 461 | fprintf(stderr,"[ERR] --read-firmware failed.\n"); |
446 | } | 462 | } |
463 | } else if (action==READ_AUPD) { | ||
464 | if (read_aupd(&ipod, filename)==0) { | ||
465 | fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename); | ||
466 | } else { | ||
467 | fprintf(stderr,"[ERR] --read-aupd failed.\n"); | ||
468 | } | ||
469 | } else if (action==WRITE_AUPD) { | ||
470 | if (ipod_reopen_rw(&ipod) < 0) { | ||
471 | return 5; | ||
472 | } | ||
473 | |||
474 | if (write_aupd(&ipod, filename)==0) { | ||
475 | fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename); | ||
476 | } else { | ||
477 | fprintf(stderr,"[ERR] --write-aupd failed.\n"); | ||
478 | } | ||
447 | } else if (action==READ_PARTITION) { | 479 | } else if (action==READ_PARTITION) { |
448 | outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); | 480 | outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); |
449 | if (outfile < 0) { | 481 | if (outfile < 0) { |