From 748b00a7fcd0e9d820fd04fdf13422eaad4c2dd4 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Fri, 11 Mar 2022 20:34:50 +0100 Subject: ipodpatcher: Split executable only parts out. Allow building both as library and executable at the same time. Change-Id: Idc40354fdedaeace727043936352fc17232bf16e --- utils/CMakeLists.txt | 11 + utils/ipodpatcher/ipodpatcher-aupd.c | 398 +++++++++++++++++++++++++++++++++++ utils/ipodpatcher/ipodpatcher.c | 355 ------------------------------- 3 files changed, 409 insertions(+), 355 deletions(-) create mode 100644 utils/ipodpatcher/ipodpatcher-aupd.c (limited to 'utils') diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 9797d020d3..d874f083b5 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -82,6 +82,17 @@ if(APPLE) endif() +add_executable(ipodpatcher-bin + ipodpatcher/main.c + ipodpatcher/ipodpatcher-aupd.c + ) +target_link_libraries(ipodpatcher-bin ipodpatcher) +target_compile_definitions(ipodpatcher-bin PRIVATE VERSION="none") +set_target_properties(ipodpatcher-bin PROPERTIES OUTPUT_NAME ipodpatcher) +if(APPLE) + target_link_libraries(ipodpatcher-bin ${FRAMEWORK_IOKIT} ${FRAMEWORK_COREFOUNDATION}) +endif() + add_library(ipodpatcher ipodpatcher/arc4.h ipodpatcher/arc4.c diff --git a/utils/ipodpatcher/ipodpatcher-aupd.c b/utils/ipodpatcher/ipodpatcher-aupd.c new file mode 100644 index 0000000000..69b027284c --- /dev/null +++ b/utils/ipodpatcher/ipodpatcher-aupd.c @@ -0,0 +1,398 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006-2007 Dave Chapman + * + * This program is free software; 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipodpatcher.h" + +#include "arc4.h" + +static inline int le2int(unsigned char* buf) +{ + int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + return res; +} + +static inline void int2le(unsigned int val, unsigned char* addr) +{ + addr[0] = val & 0xFF; + addr[1] = (val >> 8) & 0xff; + addr[2] = (val >> 16) & 0xff; + addr[3] = (val >> 24) & 0xff; +} + +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. */ + + if(ipod->sectorbuf == NULL) { + fprintf(stderr,"[ERR] Buffer not initialized."); + return -1; + } + 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, 512)) < 0) { + return -1; + } + + n = GetSecurityBlockKey(ipod->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; + + if(ipod->sectorbuf == NULL) { + fprintf(stderr,"[ERR] Buffer not initialized."); + return -1; + } + 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,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, ipod->sectorbuf, ipod->sectorbuf, length); + + chksum = 0; + for (i = 0; i < (int)length; i++) { + /* add 8 unsigned bits but keep a 32 bit sum */ + chksum += ipod->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,ipod->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]; + + if(ipod->sectorbuf == NULL) { + fprintf(stderr,"[ERR] Buffer not initialized."); + return -1; + } + /* 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,ipod->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(ipod->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 += ipod->sectorbuf[i]; + } + + /* Perform the encryption - this is standard (A)RC4 */ + matrixArc4Init(&rc4, key, 4); + matrixArc4(&rc4, ipod->sectorbuf, ipod->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,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, 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(ipod->sectorbuf + x + aupd*40 + 28)); + int2le(chksum,ipod->sectorbuf+x+aupd*40+28); + + /* Write directory */ + if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } + n=ipod_write(ipod, ipod->sector_size); + if (n < 0) { return -1; } + + return 0; +} + diff --git a/utils/ipodpatcher/ipodpatcher.c b/utils/ipodpatcher/ipodpatcher.c index e047e52abe..e7c0cc3358 100644 --- a/utils/ipodpatcher/ipodpatcher.c +++ b/utils/ipodpatcher/ipodpatcher.c @@ -45,10 +45,6 @@ #include "ipodnano2g.h" #endif -#ifndef RBUTIL -#include "arc4.h" -#endif - int ipod_verbose = 0; @@ -1997,354 +1993,3 @@ void ipod_get_ramsize(struct ipod_t* ipod) } } -#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. */ - - if(ipod->sectorbuf == NULL) { - fprintf(stderr,"[ERR] Buffer not initialized."); - return -1; - } - 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, 512)) < 0) { - return -1; - } - - n = GetSecurityBlockKey(ipod->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; - - if(ipod->sectorbuf == NULL) { - fprintf(stderr,"[ERR] Buffer not initialized."); - return -1; - } - 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,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, ipod->sectorbuf, ipod->sectorbuf, length); - - chksum = 0; - for (i = 0; i < (int)length; i++) { - /* add 8 unsigned bits but keep a 32 bit sum */ - chksum += ipod->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,ipod->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]; - - if(ipod->sectorbuf == NULL) { - fprintf(stderr,"[ERR] Buffer not initialized."); - return -1; - } - /* 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,ipod->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(ipod->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 += ipod->sectorbuf[i]; - } - - /* Perform the encryption - this is standard (A)RC4 */ - matrixArc4Init(&rc4, key, 4); - matrixArc4(&rc4, ipod->sectorbuf, ipod->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,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, 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(ipod->sectorbuf + x + aupd*40 + 28)); - int2le(chksum,ipod->sectorbuf+x+aupd*40+28); - - /* Write directory */ - if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } - n=ipod_write(ipod, ipod->sector_size); - if (n < 0) { return -1; } - - return 0; -} - -#endif -- cgit v1.2.3