mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-10 13:45:10 -05:00
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
This commit is contained in:
parent
6c24189d27
commit
6e7971553e
6 changed files with 537 additions and 3 deletions
|
|
@ -22,7 +22,7 @@ endif
|
||||||
NATIVECC = gcc
|
NATIVECC = gcc
|
||||||
CC = $(CROSS)gcc
|
CC = $(CROSS)gcc
|
||||||
|
|
||||||
SRC = main.c ipodpatcher.c fat32format.c parttypes.h
|
SRC = main.c ipodpatcher.c fat32format.c parttypes.h arc4.c
|
||||||
|
|
||||||
all: $(OUTPUT)
|
all: $(OUTPUT)
|
||||||
|
|
||||||
|
|
|
||||||
108
rbutil/ipodpatcher/arc4.c
Normal file
108
rbutil/ipodpatcher/arc4.c
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* arc4.c
|
||||||
|
* Release $Name: MATRIXSSL_1_8_3_OPEN $
|
||||||
|
*
|
||||||
|
* ARC4 stream cipher implementation
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
|
||||||
|
* The latest version of this code is available at http://www.matrixssl.org
|
||||||
|
*
|
||||||
|
* This software is open source; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This General Public License does NOT permit incorporating this software
|
||||||
|
* into proprietary programs. If you are unable to comply with the GPL, a
|
||||||
|
* commercial license for this software may be purchased from PeerSec Networks
|
||||||
|
* at http://www.peersec.com
|
||||||
|
*
|
||||||
|
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
||||||
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include "arc4.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
|
||||||
|
more than 2^30 bytes should be processed without rekeying, so we
|
||||||
|
enforce that limit here. FYI, this is equal to 1GB of data transferred.
|
||||||
|
*/
|
||||||
|
#define ARC4_MAX_BYTES 0x40000000
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/*
|
||||||
|
SSL_RSA_WITH_RC4_* cipher callbacks
|
||||||
|
*/
|
||||||
|
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen)
|
||||||
|
{
|
||||||
|
unsigned char index1, index2, tmp, *state;
|
||||||
|
int16_t counter;
|
||||||
|
|
||||||
|
ctx->byteCount = 0;
|
||||||
|
state = &ctx->state[0];
|
||||||
|
|
||||||
|
for (counter = 0; counter < 256; counter++) {
|
||||||
|
state[counter] = (unsigned char)counter;
|
||||||
|
}
|
||||||
|
ctx->x = 0;
|
||||||
|
ctx->y = 0;
|
||||||
|
index1 = 0;
|
||||||
|
index2 = 0;
|
||||||
|
|
||||||
|
for (counter = 0; counter < 256; counter++) {
|
||||||
|
index2 = (key[index1] + state[counter] + index2) & 0xff;
|
||||||
|
|
||||||
|
tmp = state[counter];
|
||||||
|
state[counter] = state[index2];
|
||||||
|
state[index2] = tmp;
|
||||||
|
|
||||||
|
index1 = (index1 + 1) % keylen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
|
||||||
|
unsigned char *out, int32_t len)
|
||||||
|
{
|
||||||
|
unsigned char x, y, *state, xorIndex, tmp;
|
||||||
|
int counter; /* NOTE BY DAVE CHAPMAN: This was a short in
|
||||||
|
the original code, which caused a segfault
|
||||||
|
when attempting to process data > 32767
|
||||||
|
bytes. */
|
||||||
|
|
||||||
|
ctx->byteCount += len;
|
||||||
|
if (ctx->byteCount > ARC4_MAX_BYTES) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = ctx->x;
|
||||||
|
y = ctx->y;
|
||||||
|
state = &ctx->state[0];
|
||||||
|
for (counter = 0; counter < len; counter++) {
|
||||||
|
x = (x + 1) & 0xff;
|
||||||
|
y = (state[x] + y) & 0xff;
|
||||||
|
|
||||||
|
tmp = state[x];
|
||||||
|
state[x] = state[y];
|
||||||
|
state[y] = tmp;
|
||||||
|
|
||||||
|
xorIndex = (state[x] + state[y]) & 0xff;
|
||||||
|
|
||||||
|
tmp = in[counter];
|
||||||
|
tmp ^= state[xorIndex];
|
||||||
|
out[counter] = tmp;
|
||||||
|
}
|
||||||
|
ctx->x = x;
|
||||||
|
ctx->y = y;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
47
rbutil/ipodpatcher/arc4.h
Normal file
47
rbutil/ipodpatcher/arc4.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
arc4.h - based on matrixssl-1-8-3-open
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
|
||||||
|
* The latest version of this code is available at http://www.matrixssl.org
|
||||||
|
*
|
||||||
|
* This software is open source; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This General Public License does NOT permit incorporating this software
|
||||||
|
* into proprietary programs. If you are unable to comply with the GPL, a
|
||||||
|
* commercial license for this software may be purchased from PeerSec Networks
|
||||||
|
* at http://www.peersec.com
|
||||||
|
*
|
||||||
|
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
||||||
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html
|
||||||
|
*/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _ARC4_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct rc4_key_t
|
||||||
|
{
|
||||||
|
unsigned char state[256];
|
||||||
|
uint32_t byteCount;
|
||||||
|
unsigned char x;
|
||||||
|
unsigned char y;
|
||||||
|
};
|
||||||
|
|
||||||
|
void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen);
|
||||||
|
int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
|
||||||
|
unsigned char *out, int32_t len);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
@ -41,6 +42,10 @@
|
||||||
#include "ipodvideo.h"
|
#include "ipodvideo.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RBUTIL
|
||||||
|
#include "arc4.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern int verbose;
|
extern int verbose;
|
||||||
|
|
||||||
unsigned char* sectorbuf;
|
unsigned char* sectorbuf;
|
||||||
|
|
@ -392,7 +397,7 @@ int diskmove(struct ipod_t* ipod, int delta)
|
||||||
int chunksize;
|
int chunksize;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
src_start = ipod->ipod_directory[1].devOffset + ipod->sector_size;
|
src_start = ipod->ipod_directory[1].devOffset;
|
||||||
src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
|
src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
|
||||||
ipod->ipod_directory[ipod->nimages-1].len +
|
ipod->ipod_directory[ipod->nimages-1].len +
|
||||||
(ipod->sector_size-1)) & ~(ipod->sector_size-1);
|
(ipod->sector_size-1)) & ~(ipod->sector_size-1);
|
||||||
|
|
@ -575,7 +580,7 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type)
|
||||||
ipod->ipod_directory[1].devOffset) {
|
ipod->ipod_directory[1].devOffset) {
|
||||||
fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
|
fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
|
||||||
delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
|
delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
|
||||||
- ipod->ipod_directory[1].devOffset;
|
- ipod->ipod_directory[1].devOffset + ipod->sector_size;
|
||||||
|
|
||||||
if (diskmove(ipod, delta) < 0) {
|
if (diskmove(ipod, delta) < 0) {
|
||||||
fprintf(stderr,"[ERR] Image movement failed.\n");
|
fprintf(stderr,"[ERR] Image movement failed.\n");
|
||||||
|
|
@ -1373,3 +1378,343 @@ int write_dos_partition_table(struct ipod_t* ipod)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef RBUTIL
|
||||||
|
|
||||||
|
static inline uint32_t getuint32le(unsigned char* buf)
|
||||||
|
{
|
||||||
|
int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
|
||||||
|
Kingstone, posted at http://ipodlinux.org/Flash_Decryption
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool testMarker(int marker)
|
||||||
|
{
|
||||||
|
int mask, decrypt, temp1, temp2;
|
||||||
|
|
||||||
|
mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
|
||||||
|
decrypt = marker ^ mask;
|
||||||
|
temp1=(int)((unsigned int)decrypt>>24);
|
||||||
|
temp2=decrypt<<8;
|
||||||
|
|
||||||
|
if (temp1==0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
temp2=(int)((unsigned int)temp2>>24);
|
||||||
|
decrypt=decrypt<<16;
|
||||||
|
decrypt=(int)((unsigned int)decrypt>>24);
|
||||||
|
|
||||||
|
if ((temp1 < temp2) && (temp2 < decrypt))
|
||||||
|
{
|
||||||
|
temp1 = temp1 & 0xf;
|
||||||
|
temp2 = temp2 & 0xf;
|
||||||
|
decrypt = decrypt & 0xf;
|
||||||
|
|
||||||
|
if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
|
||||||
|
{
|
||||||
|
int constant = 0x54c3a298;
|
||||||
|
int key=0;
|
||||||
|
int nkeys = 0;
|
||||||
|
int aMarker=0;
|
||||||
|
int pos=0;
|
||||||
|
int c, count;
|
||||||
|
int temp1;
|
||||||
|
static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
|
||||||
|
|
||||||
|
for (c = 0; c < 8; c++)
|
||||||
|
{
|
||||||
|
pos = offset[c]*4;
|
||||||
|
aMarker = getuint32le(data + pos);
|
||||||
|
|
||||||
|
if (testMarker(aMarker))
|
||||||
|
{
|
||||||
|
if (c<7)
|
||||||
|
pos =(offset[c+1]*4)+4;
|
||||||
|
else
|
||||||
|
pos =(offset[0]*4)+4;
|
||||||
|
|
||||||
|
key=0;
|
||||||
|
|
||||||
|
temp1=aMarker;
|
||||||
|
|
||||||
|
for (count=0;count<2;count++){
|
||||||
|
int word = getuint32le(data + pos);
|
||||||
|
temp1 = aMarker;
|
||||||
|
temp1 = temp1^word;
|
||||||
|
temp1 = temp1^constant;
|
||||||
|
key = temp1;
|
||||||
|
pos = pos+4;
|
||||||
|
}
|
||||||
|
int r1=0x6f;
|
||||||
|
int r2=0;
|
||||||
|
int r12;
|
||||||
|
int r14;
|
||||||
|
unsigned int r_tmp;
|
||||||
|
|
||||||
|
for (count=2;count<128;count=count+2){
|
||||||
|
r2=getuint32le(data+count*4);
|
||||||
|
r12=getuint32le(data+(count*4)+4);
|
||||||
|
r_tmp=(unsigned int)r12>>16;
|
||||||
|
r14=r2 | ((int)r_tmp);
|
||||||
|
r2=r2&0xffff;
|
||||||
|
r2=r2 | r12;
|
||||||
|
r1=r1^r14;
|
||||||
|
r1=r1+r2;
|
||||||
|
}
|
||||||
|
key=key^r1;
|
||||||
|
|
||||||
|
// Invert key, little endian
|
||||||
|
this_key[0] = key & 0xff;
|
||||||
|
this_key[1] = (key >> 8) & 0xff;
|
||||||
|
this_key[2] = (key >> 16) & 0xff;
|
||||||
|
this_key[3] = (key >> 24) & 0xff;
|
||||||
|
nkeys++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Firstly read the security block and find the RC4 key. This is
|
||||||
|
in the sector preceeding the AUPD image. */
|
||||||
|
|
||||||
|
fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
|
||||||
|
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n = ipod_read(ipod, sectorbuf, 512)) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = GetSecurityBlockKey(sectorbuf, key);
|
||||||
|
|
||||||
|
if (n != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_aupd(struct ipod_t* ipod, char* filename)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
int i;
|
||||||
|
int outfile;
|
||||||
|
int n;
|
||||||
|
int aupd;
|
||||||
|
struct rc4_key_t rc4;
|
||||||
|
unsigned char key[4];
|
||||||
|
unsigned long chksum=0;
|
||||||
|
|
||||||
|
aupd = 0;
|
||||||
|
while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
|
||||||
|
{
|
||||||
|
aupd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aupd == ipod->nimages)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = ipod->ipod_directory[aupd].len;
|
||||||
|
|
||||||
|
fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
|
||||||
|
|
||||||
|
if (find_key(ipod, aupd, key) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
|
||||||
|
|
||||||
|
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
|
||||||
|
|
||||||
|
if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < i) {
|
||||||
|
fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
|
||||||
|
i,n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the decryption - this is standard (A)RC4 */
|
||||||
|
matrixArc4Init(&rc4, key, 4);
|
||||||
|
matrixArc4(&rc4, sectorbuf, sectorbuf, length);
|
||||||
|
|
||||||
|
chksum = 0;
|
||||||
|
for (i = 0; i < (int)length; i++) {
|
||||||
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||||
|
chksum += sectorbuf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chksum != ipod->ipod_directory[aupd].chksum)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
|
||||||
|
|
||||||
|
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
|
||||||
|
if (outfile < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = write(outfile,sectorbuf,length);
|
||||||
|
if (n != length) {
|
||||||
|
fprintf(stderr,"[ERR] Write error - %d\n",n);
|
||||||
|
}
|
||||||
|
close(outfile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_aupd(struct ipod_t* ipod, char* filename)
|
||||||
|
{
|
||||||
|
unsigned int length;
|
||||||
|
int i;
|
||||||
|
int x;
|
||||||
|
int n;
|
||||||
|
int infile;
|
||||||
|
int newsize;
|
||||||
|
int aupd;
|
||||||
|
unsigned long chksum=0;
|
||||||
|
struct rc4_key_t rc4;
|
||||||
|
unsigned char key[4];
|
||||||
|
|
||||||
|
/* First check that the input file is the correct type for this ipod. */
|
||||||
|
infile=open(filename,O_RDONLY);
|
||||||
|
if (infile < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = filesize(infile);
|
||||||
|
newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
|
||||||
|
|
||||||
|
fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
|
||||||
|
length,newsize);
|
||||||
|
|
||||||
|
if (newsize > BUFFER_SIZE) {
|
||||||
|
fprintf(stderr,"[ERR] Input file too big for buffer\n");
|
||||||
|
if (infile >= 0) close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find aupd image number */
|
||||||
|
aupd = 0;
|
||||||
|
while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
|
||||||
|
{
|
||||||
|
aupd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aupd == ipod->nimages)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length != ipod->ipod_directory[aupd].len)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
|
||||||
|
ipod->ipod_directory[aupd].len, filename, length);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_key(ipod, aupd, key) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
|
||||||
|
|
||||||
|
/* We now know we have enough space, so write it. */
|
||||||
|
|
||||||
|
fprintf(stderr,"[INFO] Reading input file...\n");
|
||||||
|
n = read(infile,sectorbuf,length);
|
||||||
|
if (n < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Couldn't read input file\n");
|
||||||
|
close(infile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(infile);
|
||||||
|
|
||||||
|
/* Pad the data with zeros */
|
||||||
|
memset(sectorbuf+length,0,newsize-length);
|
||||||
|
|
||||||
|
/* Calculate the new checksum (before we encrypt) */
|
||||||
|
chksum = 0;
|
||||||
|
for (i = 0; i < (int)length; i++) {
|
||||||
|
/* add 8 unsigned bits but keep a 32 bit sum */
|
||||||
|
chksum += sectorbuf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the encryption - this is standard (A)RC4 */
|
||||||
|
matrixArc4Init(&rc4, key, 4);
|
||||||
|
matrixArc4(&rc4, sectorbuf, sectorbuf, length);
|
||||||
|
|
||||||
|
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
|
||||||
|
fprintf(stderr,"[ERR] Seek failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) {
|
||||||
|
perror("[ERR] Write failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < newsize) {
|
||||||
|
fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
|
||||||
|
,newsize,n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
|
||||||
|
|
||||||
|
x = ipod->diroffset % ipod->sector_size;
|
||||||
|
|
||||||
|
/* Read directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
||||||
|
|
||||||
|
n=ipod_read(ipod, sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) { return -1; }
|
||||||
|
|
||||||
|
/* Update checksum */
|
||||||
|
fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(sectorbuf + x + aupd*40 + 28));
|
||||||
|
int2le(chksum,sectorbuf+x+aupd*40+28);
|
||||||
|
|
||||||
|
/* Write directory */
|
||||||
|
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
|
||||||
|
n=ipod_write(ipod, sectorbuf, ipod->sector_size);
|
||||||
|
if (n < 0) { return -1; }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ int list_images(struct ipod_t* ipod);
|
||||||
int getmodel(struct ipod_t* ipod, int ipod_version);
|
int getmodel(struct ipod_t* ipod, int ipod_version);
|
||||||
int ipod_scan(struct ipod_t* ipod);
|
int ipod_scan(struct ipod_t* ipod);
|
||||||
int write_dos_partition_table(struct ipod_t* ipod);
|
int write_dos_partition_table(struct ipod_t* ipod);
|
||||||
|
int read_aupd(struct ipod_t* ipod, char* filename);
|
||||||
|
int write_aupd(struct ipod_t* ipod, char* filename);
|
||||||
off_t filesize(int fd);
|
off_t filesize(int fd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ enum {
|
||||||
ADD_BOOTLOADER,
|
ADD_BOOTLOADER,
|
||||||
READ_FIRMWARE,
|
READ_FIRMWARE,
|
||||||
WRITE_FIRMWARE,
|
WRITE_FIRMWARE,
|
||||||
|
READ_AUPD,
|
||||||
|
WRITE_AUPD,
|
||||||
READ_PARTITION,
|
READ_PARTITION,
|
||||||
WRITE_PARTITION,
|
WRITE_PARTITION,
|
||||||
FORMAT_PARTITION,
|
FORMAT_PARTITION,
|
||||||
|
|
@ -89,6 +91,8 @@ void print_usage(void)
|
||||||
fprintf(stderr," -d, --delete-bootloader\n");
|
fprintf(stderr," -d, --delete-bootloader\n");
|
||||||
fprintf(stderr," -f, --format\n");
|
fprintf(stderr," -f, --format\n");
|
||||||
fprintf(stderr," -c, --convert\n");
|
fprintf(stderr," -c, --convert\n");
|
||||||
|
fprintf(stderr," --read-aupd filename.bin\n");
|
||||||
|
fprintf(stderr," --write-aupd filename.bin\n");
|
||||||
fprintf(stderr,"\n");
|
fprintf(stderr,"\n");
|
||||||
|
|
||||||
#ifdef __WIN32__
|
#ifdef __WIN32__
|
||||||
|
|
@ -299,6 +303,18 @@ int main(int argc, char* argv[])
|
||||||
(strcmp(argv[i],"--format")==0)) {
|
(strcmp(argv[i],"--format")==0)) {
|
||||||
action = FORMAT_PARTITION;
|
action = FORMAT_PARTITION;
|
||||||
i++;
|
i++;
|
||||||
|
} else if (strcmp(argv[i],"--read-aupd")==0) {
|
||||||
|
action = READ_AUPD;
|
||||||
|
i++;
|
||||||
|
if (i == argc) { print_usage(); return 1; }
|
||||||
|
filename=argv[i];
|
||||||
|
i++;
|
||||||
|
} else if (strcmp(argv[i],"--write-aupd")==0) {
|
||||||
|
action = WRITE_AUPD;
|
||||||
|
i++;
|
||||||
|
if (i == argc) { print_usage(); return 1; }
|
||||||
|
filename=argv[i];
|
||||||
|
i++;
|
||||||
} else if ((strcmp(argv[i],"-c")==0) ||
|
} else if ((strcmp(argv[i],"-c")==0) ||
|
||||||
(strcmp(argv[i],"--convert")==0)) {
|
(strcmp(argv[i],"--convert")==0)) {
|
||||||
action = CONVERT_TO_FAT32;
|
action = CONVERT_TO_FAT32;
|
||||||
|
|
@ -444,6 +460,22 @@ int main(int argc, char* argv[])
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,"[ERR] --read-firmware failed.\n");
|
fprintf(stderr,"[ERR] --read-firmware failed.\n");
|
||||||
}
|
}
|
||||||
|
} else if (action==READ_AUPD) {
|
||||||
|
if (read_aupd(&ipod, filename)==0) {
|
||||||
|
fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"[ERR] --read-aupd failed.\n");
|
||||||
|
}
|
||||||
|
} else if (action==WRITE_AUPD) {
|
||||||
|
if (ipod_reopen_rw(&ipod) < 0) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write_aupd(&ipod, filename)==0) {
|
||||||
|
fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"[ERR] --write-aupd failed.\n");
|
||||||
|
}
|
||||||
} else if (action==READ_PARTITION) {
|
} else if (action==READ_PARTITION) {
|
||||||
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
|
outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
|
||||||
if (outfile < 0) {
|
if (outfile < 0) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue