From bab56cf4083c2d0695215ba785019532ffae5749 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Wed, 2 Jun 2010 04:13:25 +0800 Subject: Began major refactoring, not quite finished yet, this branch is probably broke --- src/dfu.c | 28 +++++ src/dfu.h | 7 +- src/idevicerestore.c | 339 ++++++++++++++++++++++++++++++++------------------- src/idevicerestore.h | 55 ++++++++- src/img3.h | 4 +- src/ipsw.h | 4 +- src/normal.c | 169 ++++++++++++++++++++++++- src/normal.h | 11 +- src/recovery.c | 78 +++++++++++- src/recovery.h | 19 +-- src/restore.c | 43 ++++++- src/restore.h | 9 +- src/tss.h | 4 +- 13 files changed, 609 insertions(+), 161 deletions(-) (limited to 'src') diff --git a/src/dfu.c b/src/dfu.c index 5e13f38..1da895d 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -20,9 +20,37 @@ */ #include +#include #include "dfu.h" +int dfu_check_mode() { + irecv_client_t dfu = NULL; + irecv_error_t dfu_error = IRECV_E_SUCCESS; + + dfu_error = irecv_open(&dfu); + if (dfu_error != IRECV_E_SUCCESS) { + return -1; + } + + if(dfu->mode != kDfuMode) { + irecv_close(dfu); + return -1; + } + + irecv_close(dfu); + dfu = NULL; + return 0; +} + +int dfu_get_cpid(uint32_t* cpid) { + return 0; +} + +int dfu_get_bdid(uint32_t* bdid) { + return 0; +} + int dfu_get_ecid(uint64_t* ecid) { return 0; } diff --git a/src/dfu.h b/src/dfu.h index ef9d911..f8f34fc 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -19,11 +19,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef DFU_H -#define DFU_H +#ifndef IDEVICERESTORE_DFU_H +#define IDEVICERESTORE_DFU_H #include +int dfu_check_mode(); +int dfu_get_cpid(uint32_t* cpid); +int dfu_get_bdid(uint32_t* bdid); int dfu_get_ecid(uint64_t* ecid); #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index aaff4d6..f03e30e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -38,25 +38,203 @@ #include "recovery.h" #include "idevicerestore.h" -#define UNKNOWN_MODE 0 -#define DFU_MODE 1 -#define NORMAL_MODE 2 -#define RECOVERY_MODE 3 -#define RESTORE_MODE 4 - +int idevicerestore_quit = 0; int idevicerestore_debug = 0; -static int idevicerestore_mode = 0; -static int idevicerestore_quit = 0; -static int idevicerestore_custom = 0; +int idevicerestore_custom = 0; +int idevicerestore_verbose = 0; +idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE; +idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE; void usage(int argc, char* argv[]); +int get_device(const char* uuid); +idevicerestore_mode_t check_mode(const char* uuid); +int get_ecid(const char* uuid, uint64_t* ecid); +int get_bdid(const char* uuid, uint32_t* bdid); +int get_cpid(const char* uuid, uint32_t* cpid); int write_file(const char* filename, char* data, int size); +int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob); int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob); void device_callback(const idevice_event_t* event, void *user_data); int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize); +idevicerestore_mode_t check_mode(const char* uuid) { + if(normal_check_mode(uuid) == 0) { + info("Found device in normal mode\n"); + idevicerestore_mode = NORMAL_MODE; + } + + else if(recovery_check_mode() == 0) { + info("Found device in recovery mode\n"); + idevicerestore_mode = RECOVERY_MODE; + } + + else if(dfu_check_mode() == 0) { + info("Found device in DFU mode\n"); + idevicerestore_mode = DFU_MODE; + } + + else if(restore_check_mode(uuid) == 0) { + info("Found device in restore mode\n"); + idevicerestore_mode = RESTORE_MODE; + } + + return idevicerestore_mode; +} + +int get_device(const char* uuid) { + uint32_t bdid = 0; + uint32_t cpid = 0; + + if(get_cpid(uuid, &cpid) < 0) { + error("ERROR: Unable to get device CPID\n"); + return -1; + } + + switch(cpid) { + case IPHONE2G_CPID: + // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID + // so we need to check the BoardID + if(get_bdid(uuid, &bdid) < 0) { + error("ERROR: Unable to get device BDID\n"); + return -1; + } + + switch(bdid) { + case IPHONE2G_BDID: + idevicerestore_device = IPHONE2G_DEVICE; + break; + + case IPHONE3G_BDID: + idevicerestore_device = IPHONE3G_DEVICE; + break; + + case IPOD1G_BDID: + idevicerestore_device = IPOD1G_DEVICE; + break; + + default: + idevicerestore_device = UNKNOWN_DEVICE; + break; + } + break; + + case IPHONE3GS_CPID: + idevicerestore_device = IPHONE3GS_DEVICE; + break; + + case IPOD2G_CPID: + idevicerestore_device = IPOD2G_DEVICE; + break; + + case IPOD3G_CPID: + idevicerestore_device = IPOD3G_DEVICE; + break; + + case IPAD1G_CPID: + idevicerestore_device = IPAD1G_DEVICE; + break; + + default: + idevicerestore_device = UNKNOWN_DEVICE; + break; + } + + return idevicerestore_device; +} + +int get_bdid(const char* uuid, uint32_t* bdid) { + switch(idevicerestore_mode) { + case NORMAL_MODE: + if(normal_get_bdid(uuid, bdid) < 0) { + *bdid = -1; + return -1; + } + break; + + case RECOVERY_MODE: + if(recovery_get_bdid(bdid) < 0) { + *bdid = -1; + return -1; + } + break; + + case DFU_MODE: + if(dfu_get_bdid(bdid) < 0) { + *bdid = -1; + return -1; + } + break; + + default: + error("ERROR: Device is in an invalid state\n"); + return -1; + } + + return 0; +} + +int get_cpid(const char* uuid, uint32_t* cpid) { + switch(idevicerestore_mode) { + case NORMAL_MODE: + if(normal_get_cpid(uuid, cpid) < 0) { + *cpid = -1; + return -1; + } + break; + + case RECOVERY_MODE: + if(recovery_get_cpid(cpid) < 0) { + *cpid = -1; + return -1; + } + break; + + case DFU_MODE: + if(dfu_get_cpid(cpid) < 0) { + *cpid = -1; + return -1; + } + break; + + default: + error("ERROR: Device is in an invalid state\n"); + return -1; + } + + return 0; +} + +int get_ecid(const char* uuid, uint64_t* ecid) { + if(normal_get_ecid(uuid, ecid) == 0) { + info("Found device in normal mode\n"); + idevicerestore_mode = NORMAL_MODE; + } + + else if(recovery_get_ecid(ecid) == 0) { + info("Found device in recovery mode\n"); + idevicerestore_mode = RECOVERY_MODE; + } + + else if(dfu_get_ecid(ecid) == 0) { + info("Found device in DFU mode\n"); + idevicerestore_mode = DFU_MODE; + } + + return idevicerestore_mode; +} + +int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { + int size = 0; + char* data = NULL; + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { + return -1; + } + plist_from_xml(data, size, buildmanifest); + return 0; +} + int main(int argc, char* argv[]) { int opt = 0; char* ipsw = NULL; @@ -68,16 +246,16 @@ int main(int argc, char* argv[]) { usage(argc, argv); break; - case 'v': - idevicerestore_debug += 1; + case 'd': + idevicerestore_debug = 1; break; case 'c': idevicerestore_custom = 1; break; - case 'd': - idevicerestore_debug = 3; + case 'v': + idevicerestore_verbose = 1; break; case 'u': @@ -86,7 +264,7 @@ int main(int argc, char* argv[]) { default: usage(argc, argv); - break; + return -1; } } @@ -97,105 +275,40 @@ int main(int argc, char* argv[]) { ipsw = argv[0]; if (ipsw == NULL) { + usage(argc, argv); error("ERROR: Please supply an IPSW\n"); return -1; } - idevice_t device = NULL; - irecv_client_t recovery = NULL; - lockdownd_client_t lockdown = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; - - /* determine recovery or normal mode */ - info("Checking for device in normal mode...\n"); - device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - info("Checking for the device in recovery mode...\n"); - recovery_error = irecv_open(&recovery); - if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to find device, is it plugged in?\n"); - return -1; - } - info("Found device in recovery mode\n"); - idevicerestore_mode = RECOVERY_MODE; - - } else { - info("Found device in normal mode\n"); - idevicerestore_mode = NORMAL_MODE; - } - - /* retrieve ECID */ - if (idevicerestore_mode == NORMAL_MODE) { - lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to connect to lockdownd\n"); - idevice_free(device); - return -1; - } - - plist_t unique_chip_node = NULL; - lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to get UniqueChipID from lockdownd\n"); - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { - error("ERROR: Unable to get ECID\n"); - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - plist_get_uint_val(unique_chip_node, &ecid); - lockdownd_client_free(lockdown); - plist_free(unique_chip_node); - idevice_free(device); - lockdown = NULL; - device = NULL; - - } else if (idevicerestore_mode == RECOVERY_MODE) { - recovery_error = irecv_get_ecid(recovery, &ecid); - if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to get device ECID\n"); - irecv_close(recovery); - return -1; - } - irecv_close(recovery); - recovery = NULL; + /* discover the device type */ + if(get_device(uuid) < 0) { + error("ERROR: Unable to find device type\n"); + return -1; } - if (ecid != 0) { - info("Found ECID %llu\n", ecid); - } else { - error("Unable to find device ECID\n"); + /* get the device ECID and determine mode */ + if(get_ecid(uuid, &ecid) < 0 || ecid == 0) { + error("ERROR: Unable to find device ECID\n"); return -1; } + info("Found ECID %llu\n", ecid); - /* parse buildmanifest */ - int buildmanifest_size = 0; - char* buildmanifest_data = NULL; + /* extract buildmanifest */ + plist_t buildmanifest = NULL; info("Extracting BuildManifest.plist from IPSW\n"); - if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) { - error("ERROR: Unable to extract BuildManifest.plist IPSW\n"); + if(extract_buildmanifest(ipsw, &buildmanifest) < 0) { + error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); return -1; } - plist_t manifest = NULL; - plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest); - info("Creating TSS request\n"); - plist_t tss_request = tss_create_request(manifest, ecid); + plist_t tss_request = tss_create_request(buildmanifest, ecid); if (tss_request == NULL) { error("ERROR: Unable to create TSS request\n"); - plist_free(manifest); + plist_free(buildmanifest); return -1; } - plist_free(manifest); + plist_free(buildmanifest); info("Sending TSS request\n"); plist_t tss_response = tss_send_request(tss_request); @@ -240,34 +353,12 @@ int main(int argc, char* argv[]) { /* place device into recovery mode if required */ if (idevicerestore_mode == NORMAL_MODE) { info("Entering recovery mode...\n"); - device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to find device\n"); - plist_free(tss_response); - return -1; - } - - lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to connect to lockdownd service\n"); - plist_free(tss_response); - idevice_free(device); - return -1; - } - - lockdown_error = lockdownd_enter_recovery(lockdown); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to place device in recovery mode\n"); - lockdownd_client_free(lockdown); + if(normal_enter_recovery(uuid) < 0) { + error("ERROR: Unable to place device into recovery mode\n"); plist_free(tss_response); - idevice_free(device); return -1; } - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; } /* upload data to make device boot restore mode */ @@ -315,7 +406,8 @@ int main(int argc, char* argv[]) { sleep(1); } - device_error = idevice_new(&device, uuid); + idevice_t device = NULL; + idevice_error_t device_error = idevice_new(&device, uuid); if (device_error != IDEVICE_E_SUCCESS) { error("ERROR: Unable to open device\n"); plist_free(tss_response); @@ -364,7 +456,7 @@ int main(int argc, char* argv[]) { char *datatype = NULL; plist_get_string_val(datatype_node, &datatype); if (!strcmp(datatype, "SystemImageData")) { - asr_send_system_image_data_from_file(device, restore, filesystem); + restore_send_filesystem(device, restore, filesystem); } else if (!strcmp(datatype, "KernelCache")) { int kernelcache_size = 0; @@ -377,7 +469,7 @@ int main(int argc, char* argv[]) { free(kernelcache_data); } else if (!strcmp(datatype, "NORData")) { - restore_send_nor_data(restore, ipsw, tss_response); + restore_send_nor(restore, ipsw, tss_response); } else { // Unknown DataType!! @@ -428,9 +520,8 @@ void usage(int argc, char* argv[]) { printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n"); printf(" -h, \t\tprints usage information\n"); printf(" -c, \t\trestore with a custom firmware\n"); - printf(" -v, \t\tenable incremental levels of verboseness\n"); + printf(" -v, \t\tenable verbose output\n"); printf("\n"); - exit(1); } int write_file(const char* filename, char* data, int size) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 3dcf1d5..f1861e9 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -22,10 +22,61 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H +#define info(...) printf(__VA_ARGS__) #define error(...) fprintf(stderr, __VA_ARGS__) -#define info(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) -#define debug(...) if(idevicerestore_debug >= 2) fprintf(stderr, __VA_ARGS__) +#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) +#define IPHONE2G_CPID 8900 +#define IPHONE3G_CPID 8900 +#define IPHONE3GS_CPID 8920 +#define IPOD1G_CPID 8900 +#define IPOD2G_CPID 8720 +#define IPOD3G_CPID 8922 +#define IPAD1G_CPID 8930 + +#define IPHONE2G_BDID 0 +#define IPHONE3G_BDID 4 +#define IPHONE3GS_BDID 0 +#define IPOD1G_BDID 2 +#define IPOD2G_BDID 0 +#define IPOD3G_BDID 2 +#define IPAD1G_BDID 2 + +typedef enum { + UNKNOWN_MODE = -1, + DFU_MODE = 0, + NORMAL_MODE = 1, + RECOVERY_MODE = 2, + RESTORE_MODE = 3 +} idevicerestore_mode_t; + +typedef enum { + UNKNOWN_DEVICE = -1, + IPHONE2G_DEVICE = 0, + IPHONE3G_DEVICE = 1, + IPHONE3GS_DEVICE = 2, + IPOD1G_DEVICE = 3, + IPOD2G_DEVICE = 4, + IPOD3G_DEVICE = 5, + IPAD1G_DEVICE = 6 +} idevicerestore_device_t; + +static char* idevicerestore_products[] = { + "iPhone1,1", + "iPhone1,2", + "iPhone2,1", + "iPod1,1", + "iPod2,1", + "iPod3,1", + "iPad1,1", + NULL +}; + +extern int idevicerestore_quit; extern int idevicerestore_debug; +extern int idevicerestore_custom; +extern int idevicerestore_verbose; +extern idevicerestore_mode_t idevicerestore_mode; +extern idevicerestore_device_t idevicerestore_device; #endif diff --git a/src/img3.h b/src/img3.h index a19ae99..c172455 100644 --- a/src/img3.h +++ b/src/img3.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IMG3_H -#define IMG3_H +#ifndef IDEVICERESTORE_IMG3_H +#define IDEVICERESTORE_IMG3_H typedef enum { kNorContainer = 0x696D6733, // img3 diff --git a/src/ipsw.h b/src/ipsw.h index f764611..20f6bf5 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IPSW_H -#define IPSW_H +#ifndef IDEVICERESTORE_IPSW_H +#define IDEVICERESTORE_IPSW_H #include diff --git a/src/normal.c b/src/normal.c index c7baefd..0420a82 100644 --- a/src/normal.c +++ b/src/normal.c @@ -19,10 +19,177 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include +#include +#include #include "normal.h" +#include "idevicerestore.h" -int normal_get_ecid(uint64_t* ecid) { +int normal_check_mode(const char* uuid) { + char* type = NULL; + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + idevice_free(device); + return -1; + } + + lockdown_error = lockdownd_query_type(lockdown, &type); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; return 0; } + +int normal_get_device(const char* uuid) { + idevice_t device = NULL; + char* product_type = NULL; + plist_t product_type_node = NULL; + lockdownd_client_t lockdown = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + idevice_free(device); + return -1; + } + + lockdown_error = lockdownd_get_value(lockdown, NULL, "ProductType", &product_type_node); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + + if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) { + if(product_type_node) plist_free(product_type_node); + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + plist_get_string_val(product_type_node, &product_type); + plist_free(product_type_node); + + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; + + int i = 0; + for(i = 0; idevicerestore_products[i] != NULL; i++) { + if(!strcmp(product_type, idevicerestore_products[i])) { + idevicerestore_device = i; + break; + } + } + + return idevicerestore_device; +} + +int normal_enter_recovery(const char* uuid) { + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to find device\n"); + return -1; + } + + lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to connect to lockdownd service\n"); + idevice_free(device); + return -1; + } + + lockdown_error = lockdownd_enter_recovery(lockdown); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to place device in recovery mode\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; + return 0; +} + +int normal_get_cpid(const char* uuid, uint32_t* cpid) { + return 0; +} + +int normal_get_bdid(const char* uuid, uint32_t* bdid) { + return 0; +} + +int normal_get_ecid(const char* uuid, uint64_t* ecid) { + idevice_t device = NULL; + plist_t unique_chip_node = NULL; + lockdownd_client_t lockdown = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if(device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to connect to lockdownd\n"); + idevice_free(device); + return -1; + } + + lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to get UniqueChipID from lockdownd\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + + if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { + error("ERROR: Unable to get ECID\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; + } + plist_get_uint_val(unique_chip_node, ecid); + plist_free(unique_chip_node); + + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; +} diff --git a/src/normal.h b/src/normal.h index 3e2868d..bde1de0 100644 --- a/src/normal.h +++ b/src/normal.h @@ -19,11 +19,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef NORMAL_H -#define NORMAL_H +#ifndef IDEVICERESTORE_NORMAL_H +#define IDEVICERESTORE_NORMAL_H #include -int normal_get_ecid(uint64_t* ecid); +int normal_check_mode(const char* uuid); +int normal_get_device(const char* uuid); +int normal_enter_recovery(const char* uuid); +int normal_get_cpid(const char* uuid, uint32_t* cpid); +int normal_get_bdid(const char* uuid, uint32_t* cpid); +int normal_get_ecid(const char* uuid, uint64_t* ecid); #endif diff --git a/src/recovery.c b/src/recovery.c index 4e2e7ad..9885982 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -29,7 +29,26 @@ #include "recovery.h" #include "idevicerestore.h" -int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component) { +int recovery_check_mode() { + irecv_client_t recovery = NULL; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + recovery_error = irecv_open(&recovery); + if (recovery_error != IRECV_E_SUCCESS) { + return -1; + } + + if(recovery->mode == kDfuMode) { + irecv_close(recovery); + return -1; + } + + irecv_close(recovery); + recovery = NULL; + return 0; +} + +int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) { int size = 0; char* data = NULL; char* path = NULL; @@ -77,7 +96,7 @@ irecv_error_t recovery_open_with_timeout(irecv_client_t* client) { return error; } -int recovery_send_ibec(char* ipsw, plist_t tss) { +int recovery_send_ibec(const char* ipsw, plist_t tss) { irecv_error_t error = 0; irecv_client_t client = NULL; char* component = "iBEC"; @@ -125,7 +144,7 @@ int recovery_send_ibec(char* ipsw, plist_t tss) { return 0; } -int recovery_send_applelogo(char* ipsw, plist_t tss) { +int recovery_send_applelogo(const char* ipsw, plist_t tss) { irecv_error_t error = 0; irecv_client_t client = NULL; char* component = "AppleLogo"; @@ -167,7 +186,7 @@ int recovery_send_applelogo(char* ipsw, plist_t tss) { return 0; } -int recovery_send_devicetree(char* ipsw, plist_t tss) { +int recovery_send_devicetree(const char* ipsw, plist_t tss) { irecv_error_t error = 0; irecv_client_t client = NULL; char *component = "RestoreDeviceTree"; @@ -199,7 +218,7 @@ int recovery_send_devicetree(char* ipsw, plist_t tss) { return 0; } -int recovery_send_ramdisk(char* ipsw, plist_t tss) { +int recovery_send_ramdisk(const char* ipsw, plist_t tss) { irecv_error_t error = 0; irecv_client_t client = NULL; char *component = "RestoreRamDisk"; @@ -231,7 +250,7 @@ int recovery_send_ramdisk(char* ipsw, plist_t tss) { return 0; } -int recovery_send_kernelcache(char* ipsw, plist_t tss) { +int recovery_send_kernelcache(const char* ipsw, plist_t tss) { irecv_error_t error = 0; irecv_client_t client = NULL; char *component = "RestoreKernelCache"; @@ -265,5 +284,52 @@ int recovery_send_kernelcache(char* ipsw, plist_t tss) { int recovery_get_ecid(uint64_t* ecid) { + irecv_client_t recovery = NULL; + if(recovery_open_with_timeout(&recovery) < 0) { + return -1; + } + + irecv_error_t error = irecv_get_ecid(recovery, ecid); + if (error != IRECV_E_SUCCESS) { + irecv_close(recovery); + return -1; + } + + irecv_close(recovery); + recovery = NULL; + return 0; +} + +int recovery_get_cpid(uint32_t* cpid) { + irecv_client_t recovery = NULL; + if(recovery_open_with_timeout(&recovery) < 0) { + return -1; + } + + irecv_error_t error = irecv_get_ecid(recovery, cpid); + if (error != IRECV_E_SUCCESS) { + irecv_close(recovery); + return -1; + } + + irecv_close(recovery); + recovery = NULL; + return 0; +} + +int recovery_get_bdid(uint32_t* bdid) { + irecv_client_t recovery = NULL; + if(recovery_open_with_timeout(&recovery) < 0) { + return -1; + } + + irecv_error_t error = irecv_get_ecid(recovery, bdid); + if (error != IRECV_E_SUCCESS) { + irecv_close(recovery); + return -1; + } + + irecv_close(recovery); + recovery = NULL; return 0; } diff --git a/src/recovery.h b/src/recovery.h index 5495638..86e3af2 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -19,19 +19,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RECOVERY_H -#define RECOVERY_H +#ifndef IDEVICERESTORE_RECOVERY_H +#define IDEVICERESTORE_RECOVERY_H #include #include -int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component); +int recovery_check_mode(); +int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component); irecv_error_t recovery_open_with_timeout(irecv_client_t* client); -int recovery_send_ibec(char* ipsw, plist_t tss); -int recovery_send_applelogo(char* ipsw, plist_t tss); -int recovery_send_devicetree(char* ipsw, plist_t tss); -int recovery_send_ramdisk(char* ipsw, plist_t tss); -int recovery_send_kernelcache(char* ipsw, plist_t tss); +int recovery_send_ibec(const char* ipsw, plist_t tss); +int recovery_send_applelogo(const char* ipsw, plist_t tss); +int recovery_send_devicetree(const char* ipsw, plist_t tss); +int recovery_send_ramdisk(const char* ipsw, plist_t tss); +int recovery_send_kernelcache(const char* ipsw, plist_t tss); int recovery_get_ecid(uint64_t* ecid); +int recovery_get_cpid(uint32_t* cpid); +int recovery_get_bdid(uint32_t* bdid); #endif diff --git a/src/restore.c b/src/restore.c index 485df9b..90d8c0e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -44,6 +44,39 @@ #define WAIT_FOR_DEVICE 33 #define LOAD_NOR 36 +int restore_check_mode(const char* uuid) { + char* type = NULL; + uint64_t version = 0; + idevice_t device = NULL; + restored_client_t restore = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + restored_error_t restore_error = RESTORE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + restore_error = restored_client_new(device, &restore, "idevicerestore"); + if (restore_error != RESTORE_E_SUCCESS) { + idevice_free(device); + return -1; + } + + restore_error = restored_query_type(restore, &type, &version); + if (restore_error != RESTORE_E_SUCCESS) { + restored_client_free(restore); + idevice_free(device); + return -1; + } + + restored_client_free(restore); + idevice_free(device); + restore = NULL; + device = NULL; + return 0; +} + const char* restore_progress_string(unsigned int operation) { switch(operation) { case CREATE_PARTITION_MAP: @@ -98,7 +131,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_t node = NULL; uint64_t operation = 0; uint64_t uprogress = 0; - uint32_t progress = 0; + uint64_t progress = 0; node = plist_dict_get_item(msg, "Operation"); if (node && PLIST_UINT == plist_get_node_type(node)) { @@ -111,14 +144,14 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) { node = plist_dict_get_item(msg, "Progress"); if (node && PLIST_UINT == plist_get_node_type(node)) { plist_get_uint_val(node, &uprogress); - progress = (uint32_t) uprogress; + progress = uprogress; } else { debug("Failed to parse progress from ProgressMsg plist \n"); return 0; } if ((progress > 0) && (progress < 100)) - info("%s - Progress: %ul%%\n", restore_progress_string(operation), progress); + info("%s - Progress: %02ull%%\n", restore_progress_string(operation), progress); else info("%s\n", restore_progress_string(operation)); @@ -130,7 +163,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) { return 0; } -int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem) { +int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem) { int i = 0; char buffer[0x1000]; uint32_t recv_bytes = 0; @@ -314,7 +347,7 @@ int restore_send_kernelcache(restored_client_t client, char *kernel_data, int le return 0; } -int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss) { +int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { char* llb_path = NULL; char* llb_blob = NULL; if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) { diff --git a/src/restore.h b/src/restore.h index 644658a..f344b5d 100644 --- a/src/restore.h +++ b/src/restore.h @@ -19,18 +19,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RESTORED_H -#define RESTORED_H +#ifndef IDEVICERESTORE_RESTORE_H +#define IDEVICERESTORE_RESTORE_H #include #include "restore.h" +int restore_check_mode(const char* uuid); int restore_handle_progress_msg(restored_client_t client, plist_t msg); int restore_handle_status_msg(restored_client_t client, plist_t msg); -int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem); +int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem); int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len); -int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss); +int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss); const char* restore_progress_string(unsigned int operation); #endif diff --git a/src/tss.h b/src/tss.h index c1ff4b4..c264ee3 100644 --- a/src/tss.h +++ b/src/tss.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef TSS_H -#define TSS_H +#ifndef IDEVICERESTORE_TSS_H +#define IDEVICERESTORE_TSS_H #include -- cgit v1.1-32-gdbae From f37ceaa046ac9114789a9334cfff04fba3805601 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Fri, 4 Jun 2010 05:03:33 +0800 Subject: Continuing to refactor code and add support for other devices --- src/idevicerestore.c | 376 ++++++++++++++++++++++++++++++++++----------------- src/idevicerestore.h | 13 +- src/restore.c | 2 +- src/tss.c | 25 +--- src/tss.h | 2 +- 5 files changed, 266 insertions(+), 152 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index f03e30e..cc9c4ba 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -40,6 +40,7 @@ int idevicerestore_quit = 0; int idevicerestore_debug = 0; +int idevicerestore_erase = 0; int idevicerestore_custom = 0; int idevicerestore_verbose = 0; idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE; @@ -47,121 +48,141 @@ idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE; void usage(int argc, char* argv[]); int get_device(const char* uuid); -idevicerestore_mode_t check_mode(const char* uuid); +int check_mode(const char* uuid); int get_ecid(const char* uuid, uint64_t* ecid); int get_bdid(const char* uuid, uint32_t* bdid); int get_cpid(const char* uuid, uint32_t* cpid); int write_file(const char* filename, char* data, int size); int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); +plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); +int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob); int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob); void device_callback(const idevice_event_t* event, void *user_data); int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize); -idevicerestore_mode_t check_mode(const char* uuid) { - if(normal_check_mode(uuid) == 0) { +int check_mode(const char* uuid) { + idevicerestore_mode_t mode = UNKNOWN_MODE; + if (normal_check_mode(uuid) == 0) { info("Found device in normal mode\n"); - idevicerestore_mode = NORMAL_MODE; + mode = NORMAL_MODE; } - else if(recovery_check_mode() == 0) { + else if (recovery_check_mode() == 0) { info("Found device in recovery mode\n"); - idevicerestore_mode = RECOVERY_MODE; + mode = RECOVERY_MODE; } - else if(dfu_check_mode() == 0) { + else if (dfu_check_mode() == 0) { info("Found device in DFU mode\n"); - idevicerestore_mode = DFU_MODE; + mode = DFU_MODE; } - else if(restore_check_mode(uuid) == 0) { + else if (restore_check_mode(uuid) == 0) { info("Found device in restore mode\n"); - idevicerestore_mode = RESTORE_MODE; + mode = RESTORE_MODE; } - return idevicerestore_mode; + return mode; } int get_device(const char* uuid) { uint32_t bdid = 0; uint32_t cpid = 0; + idevicerestore_device_t device = UNKNOWN_DEVICE; - if(get_cpid(uuid, &cpid) < 0) { - error("ERROR: Unable to get device CPID\n"); - return -1; - } - - switch(cpid) { - case IPHONE2G_CPID: - // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID - // so we need to check the BoardID - if(get_bdid(uuid, &bdid) < 0) { - error("ERROR: Unable to get device BDID\n"); - return -1; + switch (idevicerestore_mode) { + case NORMAL_MODE: + if (normal_get_device(uuid) < 0) { + device = UNKNOWN_DEVICE; } + break; - switch(bdid) { - case IPHONE2G_BDID: - idevicerestore_device = IPHONE2G_DEVICE; + case DFU_MODE: + case RECOVERY_MODE: + if (get_cpid(uuid, &cpid) < 0) { + error("ERROR: Unable to get device CPID\n"); break; + } - case IPHONE3G_BDID: - idevicerestore_device = IPHONE3G_DEVICE; - break; + switch (cpid) { + case IPHONE2G_CPID: + // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID + // so we need to check the BoardID + if (get_bdid(uuid, &bdid) < 0) { + error("ERROR: Unable to get device BDID\n"); + break; + } + + switch (bdid) { + case IPHONE2G_BDID: + device = IPHONE2G_DEVICE; + break; + + case IPHONE3G_BDID: + device = IPHONE3G_DEVICE; + break; - case IPOD1G_BDID: - idevicerestore_device = IPOD1G_DEVICE; + case IPOD1G_BDID: + device = IPOD1G_DEVICE; + break; + + default: + device = UNKNOWN_DEVICE; + break; + } break; - default: - idevicerestore_device = UNKNOWN_DEVICE; + case IPHONE3GS_CPID: + device = IPHONE3GS_DEVICE; break; - } - break; - case IPHONE3GS_CPID: - idevicerestore_device = IPHONE3GS_DEVICE; - break; + case IPOD2G_CPID: + device = IPOD2G_DEVICE; + break; - case IPOD2G_CPID: - idevicerestore_device = IPOD2G_DEVICE; - break; + case IPOD3G_CPID: + device = IPOD3G_DEVICE; + break; - case IPOD3G_CPID: - idevicerestore_device = IPOD3G_DEVICE; - break; + case IPAD1G_CPID: + device = IPAD1G_DEVICE; + break; - case IPAD1G_CPID: - idevicerestore_device = IPAD1G_DEVICE; + default: + device = UNKNOWN_DEVICE; + break; + } break; default: - idevicerestore_device = UNKNOWN_DEVICE; + device = UNKNOWN_MODE; break; + } - return idevicerestore_device; + return device; } int get_bdid(const char* uuid, uint32_t* bdid) { - switch(idevicerestore_mode) { + switch (idevicerestore_mode) { case NORMAL_MODE: - if(normal_get_bdid(uuid, bdid) < 0) { + if (normal_get_bdid(uuid, bdid) < 0) { *bdid = -1; return -1; } break; case RECOVERY_MODE: - if(recovery_get_bdid(bdid) < 0) { + if (recovery_get_bdid(bdid) < 0) { *bdid = -1; return -1; } break; case DFU_MODE: - if(dfu_get_bdid(bdid) < 0) { + if (dfu_get_bdid(bdid) < 0) { *bdid = -1; return -1; } @@ -176,24 +197,24 @@ int get_bdid(const char* uuid, uint32_t* bdid) { } int get_cpid(const char* uuid, uint32_t* cpid) { - switch(idevicerestore_mode) { + switch (idevicerestore_mode) { case NORMAL_MODE: - if(normal_get_cpid(uuid, cpid) < 0) { - *cpid = -1; + if (normal_get_cpid(uuid, cpid) < 0) { + *cpid = 0; return -1; } break; case RECOVERY_MODE: - if(recovery_get_cpid(cpid) < 0) { - *cpid = -1; + if (recovery_get_cpid(cpid) < 0) { + *cpid = 0; return -1; } break; case DFU_MODE: - if(dfu_get_cpid(cpid) < 0) { - *cpid = -1; + if (dfu_get_cpid(cpid) < 0) { + *cpid = 0; return -1; } break; @@ -207,40 +228,125 @@ int get_cpid(const char* uuid, uint32_t* cpid) { } int get_ecid(const char* uuid, uint64_t* ecid) { - if(normal_get_ecid(uuid, ecid) == 0) { - info("Found device in normal mode\n"); - idevicerestore_mode = NORMAL_MODE; - } + switch (idevicerestore_mode) { + case NORMAL_MODE: + if (normal_get_ecid(uuid, ecid) < 0) { + *ecid = 0; + return -1; + } + break; - else if(recovery_get_ecid(ecid) == 0) { - info("Found device in recovery mode\n"); - idevicerestore_mode = RECOVERY_MODE; - } + case RECOVERY_MODE: + if (recovery_get_ecid(ecid) < 0) { + *ecid = 0; + return -1; + } + break; - else if(dfu_get_ecid(ecid) == 0) { - info("Found device in DFU mode\n"); - idevicerestore_mode = DFU_MODE; + case DFU_MODE: + if (dfu_get_ecid(ecid) < 0) { + *ecid = 0; + return -1; + } + break; + + default: + error("ERROR: Device is in an invalid state\n"); + return -1; } - return idevicerestore_mode; + return 0; } int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { int size = 0; char* data = NULL; - if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { + if (idevicerestore_device >= IPHONE2G_DEVICE && idevicerestore_device <= IPOD2G_DEVICE) { + // Older devices that don't require personalized firmwares use BuildManifesto.plist + if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) { + return -1; + } + + } else if (idevicerestore_device >= IPHONE3GS_DEVICE && idevicerestore_device <= IPAD1G_DEVICE) { + // Whereas newer devices that do require personalized firmwares use BuildManifest.plist + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { + return -1; + } + + } else { return -1; } + plist_from_xml(data, size, buildmanifest); return 0; } +plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { + // fetch build identities array from BuildManifest + plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); + if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { + error("ERROR: Unable to find build identities node\n"); + return NULL; + } + + // check and make sure this identity exists in buildmanifest + if(identity >= plist_array_get_size(build_identities_array)) { + return NULL; + } + + plist_t build_identity = plist_array_get_item(build_identities_array, identity); + if (!build_identity || plist_get_node_type(build_identity) != PLIST_DICT) { + error("ERROR: Unable to find build identities node\n"); + return NULL; + } + + return build_identity; +} + +int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { + char* filename = NULL; + + plist_t manifest_node = plist_dict_get_item(build_identity, "OS"); + if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { + error("ERROR: Unable to find manifest node\n"); + return -1; + } + + plist_t filesystem_node = plist_dict_get_item(build_identity, "OS"); + if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { + error("ERROR: Unable to find filesystem node\n"); + return -1; + } + + plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); + if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { + error("ERROR: Unable to find filesystem info node\n"); + return -1; + } + + plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); + if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { + error("ERROR: Unable to find filesystem info path node\n"); + return -1; + } + plist_get_string_val(filesystem_info_path_node, &filename); + + info("Extracting filesystem from IPSW\n"); + if (ipsw_extract_to_file(ipsw, filename, filename) < 0) { + error("ERROR: Unable to extract filesystem\n"); + return -1; + } + + *filesystem = filename; + return 0; +} + int main(int argc, char* argv[]) { int opt = 0; char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt(argc, argv, "vdhcu:")) > 0) { + while ((opt = getopt(argc, argv, "vdhceu:")) > 0) { switch (opt) { case 'h': usage(argc, argv); @@ -250,6 +356,10 @@ int main(int argc, char* argv[]) { idevicerestore_debug = 1; break; + case 'e': + idevicerestore_erase = 1; + break; + case 'c': idevicerestore_custom = 1; break; @@ -280,85 +390,101 @@ int main(int argc, char* argv[]) { return -1; } - /* discover the device type */ - if(get_device(uuid) < 0) { - error("ERROR: Unable to find device type\n"); + // check which mode the device is currently in so we know where to start + idevicerestore_mode = check_mode(uuid); + if (idevicerestore_mode < 0) { + error("ERROR: Unable to discover device current mode\n"); return -1; } - /* get the device ECID and determine mode */ - if(get_ecid(uuid, &ecid) < 0 || ecid == 0) { - error("ERROR: Unable to find device ECID\n"); + // discover the device type + idevicerestore_device = get_device(uuid); + if (idevicerestore_device < 0) { + error("ERROR: Unable to discover device type\n"); return -1; } - info("Found ECID %llu\n", ecid); - /* extract buildmanifest */ + // extract buildmanifest plist_t buildmanifest = NULL; - info("Extracting BuildManifest.plist from IPSW\n"); - if(extract_buildmanifest(ipsw, &buildmanifest) < 0) { + info("Extracting BuildManifest from IPSW\n"); + if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); return -1; } - info("Creating TSS request\n"); - plist_t tss_request = tss_create_request(buildmanifest, ecid); - if (tss_request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(buildmanifest); - return -1; - } - plist_free(buildmanifest); + // choose whether this is an upgrade or a restore (default to upgrade) + plist_t build_identity = NULL; + if(idevicerestore_erase) { + build_identity = get_build_identity(buildmanifest, 0); + if(build_identity == NULL) { + error("ERROR: Unable to find build any identities\n"); + plist_free(buildmanifest); + return -1; + } - info("Sending TSS request\n"); - plist_t tss_response = tss_send_request(tss_request); - if (tss_response == NULL) { - error("ERROR: Unable to get response from TSS server\n"); - plist_free(tss_request); - return -1; + } else { + build_identity = get_build_identity(buildmanifest, 1); + if(build_identity == NULL) { + build_identity = get_build_identity(buildmanifest, 0); + if(build_identity == NULL) { + error("ERROR: Unable to find build any identities\n"); + plist_free(buildmanifest); + return -1; + } + info("No upgrade ramdisk found, default to full restore\n"); + } } - info("Got TSS response\n"); - // Get name of filesystem DMG in IPSW - char* filesystem = NULL; - plist_t filesystem_node = plist_dict_get_item(tss_request, "OS"); - if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { - error("ERROR: Unable to find filesystem node\n"); - plist_free(tss_request); - return -1; - } + // devices are listed in order from oldest to newest + // devices that come after iPod2g require personalized firmwares + plist_t tss_request = NULL; + plist_t tss_response = NULL; + if(idevicerestore_device > IPOD2G_DEVICE) { - plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); - if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { - error("ERROR: Unable to find filesystem info node\n"); - plist_free(tss_request); - return -1; - } + info("Creating TSS request\n"); + // fetch the device's ECID for the TSS request + if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + error("ERROR: Unable to find device ECID\n"); + return -1; + } + info("Found ECID %llu\n", ecid); - plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); - if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { - error("ERROR: Unable to find filesystem info path node\n"); + tss_request = tss_create_request(build_identity, ecid); + if (tss_request == NULL) { + error("ERROR: Unable to create TSS request\n"); + plist_free(buildmanifest); + return -1; + } + plist_free(buildmanifest); + + info("Sending TSS request\n"); + tss_response = tss_send_request(tss_request); + if (tss_response == NULL) { + error("ERROR: Unable to get response from TSS server\n"); + plist_free(tss_request); + return -1; + } + info("Got TSS response\n"); plist_free(tss_request); - return -1; } - plist_get_string_val(filesystem_info_path_node, &filesystem); - plist_free(tss_request); - info("Extracting filesystem from IPSW\n"); - if (ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) { - error("ERROR: Unable to extract filesystem\n"); + // Extract filesystem from IPSW and return its name + char* filesystem = NULL; + if(extract_filesystem(ipsw, build_identity, &filesystem) < 0) { + error("ERROR: Unable to extract filesystem from IPSW\n"); + if(tss_response) plist_free(tss_response); + plist_free(buildmanifest); return -1; } - /* place device into recovery mode if required */ + // place device into recovery mode if required if (idevicerestore_mode == NORMAL_MODE) { info("Entering recovery mode...\n"); - if(normal_enter_recovery(uuid) < 0) { + if (normal_enter_recovery(uuid) < 0) { error("ERROR: Unable to place device into recovery mode\n"); plist_free(tss_response); return -1; } - } /* upload data to make device boot restore mode */ @@ -507,7 +633,7 @@ int main(int argc, char* argv[]) { void device_callback(const idevice_event_t* event, void *user_data) { if (event->event == IDEVICE_DEVICE_ADD) { idevicerestore_mode = RESTORE_MODE; - } else if(event->event == IDEVICE_DEVICE_REMOVE) { + } else if (event->event == IDEVICE_DEVICE_REMOVE) { idevicerestore_quit = 1; } } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index f1861e9..40d5543 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -45,18 +45,18 @@ typedef enum { UNKNOWN_MODE = -1, DFU_MODE = 0, - NORMAL_MODE = 1, - RECOVERY_MODE = 2, - RESTORE_MODE = 3 + RECOVERY_MODE = 1, + RESTORE_MODE = 2, + NORMAL_MODE = 3, } idevicerestore_mode_t; typedef enum { UNKNOWN_DEVICE = -1, IPHONE2G_DEVICE = 0, IPHONE3G_DEVICE = 1, - IPHONE3GS_DEVICE = 2, - IPOD1G_DEVICE = 3, - IPOD2G_DEVICE = 4, + IPOD1G_DEVICE = 2, + IPOD2G_DEVICE = 3, + IPHONE3GS_DEVICE = 4, IPOD3G_DEVICE = 5, IPAD1G_DEVICE = 6 } idevicerestore_device_t; @@ -74,6 +74,7 @@ static char* idevicerestore_products[] = { extern int idevicerestore_quit; extern int idevicerestore_debug; +extern int idevicerestore_erase; extern int idevicerestore_custom; extern int idevicerestore_verbose; extern idevicerestore_mode_t idevicerestore_mode; diff --git a/src/restore.c b/src/restore.c index 90d8c0e..fd6fec2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -151,7 +151,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) { } if ((progress > 0) && (progress < 100)) - info("%s - Progress: %02ull%%\n", restore_progress_string(operation), progress); + info("%s - Progress: %llu%%\n", restore_progress_string(operation), progress); else info("%s\n", restore_progress_string(operation)); diff --git a/src/tss.c b/src/tss.c index 4fc8b57..f36bc5f 100644 --- a/src/tss.c +++ b/src/tss.c @@ -36,23 +36,10 @@ typedef struct { char* content; } tss_response; -plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { - // Fetch build information from BuildManifest - plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); - if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { - error("ERROR: Unable to find BuildIdentities array\n"); - return NULL; - } - - plist_t restore_identity_dict = plist_array_get_item(build_identities_array, 0); - if (!restore_identity_dict || plist_get_node_type(restore_identity_dict) != PLIST_DICT) { - error("ERROR: Unable to find restore identity\n"); - return NULL; - } - +plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { uint64_t unique_build_size = 0; char* unique_build_data = NULL; - plist_t unique_build_node = plist_dict_get_item(restore_identity_dict, "UniqueBuildID"); + plist_t unique_build_node = plist_dict_get_item(build_identity, "UniqueBuildID"); if (!unique_build_node || plist_get_node_type(unique_build_node) != PLIST_DATA) { error("ERROR: Unable to find UniqueBuildID node\n"); return NULL; @@ -61,7 +48,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { int chip_id = 0; char* chip_id_string = NULL; - plist_t chip_id_node = plist_dict_get_item(restore_identity_dict, "ApChipID"); + plist_t chip_id_node = plist_dict_get_item(build_identity, "ApChipID"); if (!chip_id_node || plist_get_node_type(chip_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApChipID node\n"); return NULL; @@ -71,7 +58,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { int board_id = 0; char* board_id_string = NULL; - plist_t board_id_node = plist_dict_get_item(restore_identity_dict, "ApBoardID"); + plist_t board_id_node = plist_dict_get_item(build_identity, "ApBoardID"); if (!board_id_node || plist_get_node_type(board_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApBoardID node\n"); return NULL; @@ -81,7 +68,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { int security_domain = 0; char* security_domain_string = NULL; - plist_t security_domain_node = plist_dict_get_item(restore_identity_dict, "ApSecurityDomain"); + plist_t security_domain_node = plist_dict_get_item(build_identity, "ApSecurityDomain"); if (!security_domain_node || plist_get_node_type(security_domain_node) != PLIST_STRING) { error("ERROR: Unable to find ApSecurityDomain node\n"); return NULL; @@ -112,7 +99,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { free(unique_build_data); // Add all firmware files to TSS request - plist_t manifest_node = plist_dict_get_item(restore_identity_dict, "Manifest"); + plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: Unable to find restore manifest\n"); plist_free(tss_request); diff --git a/src/tss.h b/src/tss.h index c264ee3..e18843b 100644 --- a/src/tss.h +++ b/src/tss.h @@ -26,7 +26,7 @@ #include "img3.h" -plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid); +plist_t tss_create_request(plist_t build_identity, uint64_t ecid); plist_t tss_send_request(plist_t tss_request); void tss_stitch_img3(img3_file* file, plist_t signature); -- cgit v1.1-32-gdbae From ce999c67996515b278f49ea88f4e306dc0308ff3 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 04:02:05 +0800 Subject: Refactoring continued, lots of bug fixes, probably about half way through --- src/idevicerestore.c | 84 ++++++++++++++++++++-------------------------------- src/normal.c | 30 ++++++++++++++++++- src/recovery.c | 41 +++++++++++++++++++++++-- src/recovery.h | 1 + src/tss.c | 1 - 5 files changed, 101 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index cc9c4ba..7d382eb 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -94,7 +94,8 @@ int get_device(const char* uuid) { switch (idevicerestore_mode) { case NORMAL_MODE: - if (normal_get_device(uuid) < 0) { + device = normal_get_device(uuid); + if (device < 0) { device = UNKNOWN_DEVICE; } break; @@ -282,6 +283,7 @@ int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { } plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { + // fetch build identities array from BuildManifest plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { @@ -300,19 +302,25 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { return NULL; } - return build_identity; + return plist_copy(build_identity); } int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; - plist_t manifest_node = plist_dict_get_item(build_identity, "OS"); + int sz = 0; + char* xml = NULL; + plist_to_xml(build_identity, &xml, &sz); + debug("%s", xml); + free(xml); + + plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: Unable to find manifest node\n"); return -1; } - plist_t filesystem_node = plist_dict_get_item(build_identity, "OS"); + plist_t filesystem_node = plist_dict_get_item(manifest_node, "OS"); if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { error("ERROR: Unable to find filesystem node\n"); return -1; @@ -438,7 +446,7 @@ int main(int argc, char* argv[]) { // devices are listed in order from oldest to newest // devices that come after iPod2g require personalized firmwares plist_t tss_request = NULL; - plist_t tss_response = NULL; + plist_t tss = NULL; if(idevicerestore_device > IPOD2G_DEVICE) { info("Creating TSS request\n"); @@ -455,11 +463,10 @@ int main(int argc, char* argv[]) { plist_free(buildmanifest); return -1; } - plist_free(buildmanifest); info("Sending TSS request\n"); - tss_response = tss_send_request(tss_request); - if (tss_response == NULL) { + tss = tss_send_request(tss_request); + if (tss == NULL) { error("ERROR: Unable to get response from TSS server\n"); plist_free(tss_request); return -1; @@ -472,7 +479,7 @@ int main(int argc, char* argv[]) { char* filesystem = NULL; if(extract_filesystem(ipsw, build_identity, &filesystem) < 0) { error("ERROR: Unable to extract filesystem from IPSW\n"); - if(tss_response) plist_free(tss_response); + if(tss) plist_free(tss); plist_free(buildmanifest); return -1; } @@ -482,47 +489,20 @@ int main(int argc, char* argv[]) { info("Entering recovery mode...\n"); if (normal_enter_recovery(uuid) < 0) { error("ERROR: Unable to place device into recovery mode\n"); - plist_free(tss_response); + if(tss) plist_free(tss); + plist_free(buildmanifest); return -1; } } - /* upload data to make device boot restore mode */ - if (recovery_send_ibec(ipsw, tss_response) < 0) { - error("ERROR: Unable to send iBEC\n"); - plist_free(tss_response); - return -1; - } - sleep(1); - - if (recovery_send_applelogo(ipsw, tss_response) < 0) { - error("ERROR: Unable to send AppleLogo\n"); - plist_free(tss_response); - return -1; - } - - if (recovery_send_devicetree(ipsw, tss_response) < 0) { - error("ERROR: Unable to send DeviceTree\n"); - plist_free(tss_response); - return -1; - } - - if (recovery_send_ramdisk(ipsw, tss_response) < 0) { - error("ERROR: Unable to send Ramdisk\n"); - plist_free(tss_response); - return -1; - } - - // for some reason iboot requires a hard reset after ramdisk - // or things start getting wacky - printf("Please unplug your device, then plug it back in\n"); - printf("Hit any key to continue..."); - getchar(); - - if (recovery_send_kernelcache(ipsw, tss_response) < 0) { - error("ERROR: Unable to send KernelCache\n"); - plist_free(tss_response); - return -1; + // place device into restore mode if required + if (idevicerestore_mode == RECOVERY_MODE) { + if (recovery_enter_restore(ipsw, tss) < 0) { + error("ERROR: Unable to place device into restore mode\n"); + if(tss) plist_free(tss); + plist_free(buildmanifest); + return -1; + } } idevice_event_subscribe(&device_callback, NULL); @@ -536,7 +516,7 @@ int main(int argc, char* argv[]) { idevice_error_t device_error = idevice_new(&device, uuid); if (device_error != IDEVICE_E_SUCCESS) { error("ERROR: Unable to open device\n"); - plist_free(tss_response); + plist_free(tss); return -1; } @@ -544,7 +524,7 @@ int main(int argc, char* argv[]) { restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to start restored client\n"); - plist_free(tss_response); + plist_free(tss); idevice_free(device); return -1; } @@ -553,7 +533,7 @@ int main(int argc, char* argv[]) { uint64_t version = 0; if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); - plist_free(tss_response); + plist_free(tss); restored_client_free(restore); idevice_free(device); return -1; @@ -587,7 +567,7 @@ int main(int argc, char* argv[]) { } else if (!strcmp(datatype, "KernelCache")) { int kernelcache_size = 0; char* kernelcache_data = NULL; - if (get_signed_component_by_name(ipsw, tss_response, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { + if (get_signed_component_by_name(ipsw, tss, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { error("ERROR: Unable to get kernelcache file\n"); return -1; } @@ -595,7 +575,7 @@ int main(int argc, char* argv[]) { free(kernelcache_data); } else if (!strcmp(datatype, "NORData")) { - restore_send_nor(restore, ipsw, tss_response); + restore_send_nor(restore, ipsw, tss); } else { // Unknown DataType!! @@ -624,7 +604,7 @@ int main(int argc, char* argv[]) { } restored_client_free(restore); - plist_free(tss_response); + plist_free(tss); idevice_free(device); unlink(filesystem); return 0; diff --git a/src/normal.c b/src/normal.c index 0420a82..3c2bf5c 100644 --- a/src/normal.c +++ b/src/normal.c @@ -21,10 +21,12 @@ #include #include +#include #include #include #include "normal.h" +#include "recovery.h" #include "idevicerestore.h" int normal_check_mode(const char* uuid) { @@ -112,9 +114,11 @@ int normal_get_device(const char* uuid) { int normal_enter_recovery(const char* uuid) { idevice_t device = NULL; + irecv_client_t recovery = NULL; lockdownd_client_t lockdown = NULL; + irecv_error_t recovery_error = IRECV_E_SUCCESS; idevice_error_t device_error = IDEVICE_E_SUCCESS; - lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; device_error = idevice_new(&device, uuid); if (device_error != IDEVICE_E_SUCCESS) { @@ -141,6 +145,29 @@ int normal_enter_recovery(const char* uuid) { idevice_free(device); lockdown = NULL; device = NULL; + + if(recovery_open_with_timeout(&recovery) < 0) { + error("ERROR: Unable to enter recovery mode\n"); + return -1; + } + + recovery_error = irecv_send_command(recovery, "setenv auto-boot true"); + if (recovery_error != IRECV_E_SUCCESS) { + error("ERROR: Unable to reset auto-boot variable\n"); + irecv_close(recovery); + return -1; + } + + recovery_error = irecv_send_command(recovery, "saveenv"); + if (recovery_error != IRECV_E_SUCCESS) { + error("ERROR: Unable to save auto-boot variable\n"); + irecv_close(recovery); + return -1; + } + + idevicerestore_mode = RECOVERY_MODE; + irecv_close(recovery); + recovery = NULL; return 0; } @@ -192,4 +219,5 @@ int normal_get_ecid(const char* uuid, uint64_t* ecid) { idevice_free(device); lockdown = NULL; device = NULL; + return 0; } diff --git a/src/recovery.c b/src/recovery.c index 9885982..3bfb97e 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -48,6 +48,43 @@ int recovery_check_mode() { return 0; } +int recovery_enter_restore(const char* ipsw, plist_t tss) { + // upload data to make device boot restore mode + if (recovery_send_ibec(ipsw, tss) < 0) { + error("ERROR: Unable to send iBEC\n"); + return -1; + } + sleep(1); + + if (recovery_send_applelogo(ipsw, tss) < 0) { + error("ERROR: Unable to send AppleLogo\n"); + return -1; + } + + if (recovery_send_devicetree(ipsw, tss) < 0) { + error("ERROR: Unable to send DeviceTree\n"); + return -1; + } + + if (recovery_send_ramdisk(ipsw, tss) < 0) { + error("ERROR: Unable to send Ramdisk\n"); + return -1; + } + + // for some reason iboot requires a hard reset after ramdisk + // or things start getting wacky + printf("Please unplug your device, then plug it back in\n"); + printf("Hit any key to continue..."); + getchar(); + + if (recovery_send_kernelcache(ipsw, tss) < 0) { + error("ERROR: Unable to send KernelCache\n"); + return -1; + } + + return 0; +} + int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) { int size = 0; char* data = NULL; @@ -306,7 +343,7 @@ int recovery_get_cpid(uint32_t* cpid) { return -1; } - irecv_error_t error = irecv_get_ecid(recovery, cpid); + irecv_error_t error = irecv_get_cpid(recovery, cpid); if (error != IRECV_E_SUCCESS) { irecv_close(recovery); return -1; @@ -323,7 +360,7 @@ int recovery_get_bdid(uint32_t* bdid) { return -1; } - irecv_error_t error = irecv_get_ecid(recovery, bdid); + irecv_error_t error = irecv_get_bdid(recovery, bdid); if (error != IRECV_E_SUCCESS) { irecv_close(recovery); return -1; diff --git a/src/recovery.h b/src/recovery.h index 86e3af2..b191aa5 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -26,6 +26,7 @@ #include int recovery_check_mode(); +int recovery_enter_restore(const char* ipsw, plist_t tss); int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component); irecv_error_t recovery_open_with_timeout(irecv_client_t* client); int recovery_send_ibec(const char* ipsw, plist_t tss); diff --git a/src/tss.c b/src/tss.c index f36bc5f..a9e9456 100644 --- a/src/tss.c +++ b/src/tss.c @@ -124,7 +124,6 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { plist_dict_insert_item(tss_request, key, tss_entry); free(key); } - plist_free(manifest_node); int sz = 0; char* xml = NULL; -- cgit v1.1-32-gdbae From 3761295840ba6c7672aebcb2b084a2dbf7099735 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 04:05:16 +0800 Subject: small bugfix in idevicerestore.c get_build_identity and went ahead and added activate code to be cleaned up and added to process later --- src/Makefile.am | 2 +- src/activate.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/activate.h | 30 ++++++ src/idevicerestore.c | 2 +- 4 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 src/activate.c create mode 100644 src/activate.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 6840a0c..b641d00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c +idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file diff --git a/src/activate.c b/src/activate.c new file mode 100644 index 0000000..2cb4452 --- /dev/null +++ b/src/activate.c @@ -0,0 +1,254 @@ +/* + * activate.c + * Functions to fetch activation records from Apple's servers + * + * Copyright (c) 2010 Joshua Hill. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +typedef struct { + int length; + char* content; +} activate_response; + +size_t activate_write_callback(char* data, size_t size, size_t nmemb, activate_response* response) { + size_t total = size * nmemb; + if (total != 0) { + response->content = realloc(response->content, response->length + total + 1); + memcpy(response->content + response->length, data, total); + response->content[response->length + total] = '\0'; + response->length += total; + } + //printf("%s", data); + return total; +} + +int activate_fetch_record(lockdownd_client_t client, plist_t* record) { + int size = 0; + char* request = NULL; + struct curl_httppost* post = NULL; + struct curl_httppost* last = NULL; + activate_response* response = NULL; + + char* imei = NULL; + char* imsi = NULL; + char* iccid = NULL; + char* serial_number = NULL; + char* activation_info = NULL; + + plist_t imei_node = NULL; + plist_t imsi_node = NULL; + plist_t iccid_node = NULL; + plist_t serial_number_node = NULL; + plist_t activation_info_node = NULL; + + char* device_class = NULL; + plist_t device_class_node = NULL; + lockdownd_get_value(client, NULL, "DeviceClass", &device_class_node); + if (!device_class_node || plist_get_node_type(device_class_node) != PLIST_STRING) { + fprintf(stderr, "Unable to get DeviceClass from lockdownd\n"); + return -1; + } + plist_get_string_val(device_class_node, &device_class); + plist_free(device_class_node); + + if (!strcmp(device_class, "iPhone")) { + lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &iccid_node); + if (!iccid_node || plist_get_node_type(iccid_node) != PLIST_STRING) { + fprintf(stderr, "Unable to get ICCID from lockdownd\n"); + return -1; + } + plist_get_string_val(iccid_node, &iccid); + plist_free(iccid_node); + + lockdownd_get_value(client, NULL, "InternationalMobileEquipmentIdentity", &imei_node); + if (!imei_node || plist_get_node_type(imei_node) != PLIST_STRING) { + fprintf(stderr, "Unable to get IMEI from lockdownd\n"); + return -1; + } + plist_get_string_val(imei_node, &imei); + plist_free(imei_node); + + lockdownd_get_value(client, NULL, "InternationalMobileSubscriberIdentity", &imsi_node); + if (!imsi_node || plist_get_node_type(imsi_node) != PLIST_STRING) { + fprintf(stderr, "Unable to get IMSI from lockdownd\n"); + return -1; + } + plist_get_string_val(imsi_node, &imsi); + plist_free(imsi_node); + } + + lockdownd_get_value(client, NULL, "SerialNumber", &serial_number_node); + if (!serial_number_node || plist_get_node_type(serial_number_node) != PLIST_STRING) { + fprintf(stderr, "Unable to get SerialNumber from lockdownd\n"); + return -1; + } + plist_get_string_val(serial_number_node, &serial_number); + plist_free(serial_number_node); + + lockdownd_get_value(client, NULL, "ActivationInfo", &activation_info_node); + int type = plist_get_node_type(activation_info_node); + if (!activation_info_node || plist_get_node_type(activation_info_node) != PLIST_DICT) { + fprintf(stderr, "Unable to get ActivationInfo from lockdownd\n"); + return -1; + } + //plist_get_string_val(activation_info_node, &activation_info); + + uint32_t activation_info_size = 0; + char* activation_info_data = NULL; + plist_to_xml(activation_info_node, &activation_info_data, &activation_info_size); + plist_free(activation_info_node); + //printf("%s\n\n", activation_info_data); + + char* activation_info_start = strstr(activation_info_data, ""); + if (activation_info_start == NULL) { + fprintf(stderr, "Unable to locate beginning of ActivationInfo\n"); + return -1; + } + + char* activation_info_stop = strstr(activation_info_data, ""); + if (activation_info_stop == NULL) { + fprintf(stderr, "Unable to locate end of ActivationInfo\n"); + return -1; + } + + activation_info_stop += strlen(""); + activation_info_size = activation_info_stop - activation_info_start; + activation_info = malloc(activation_info_size + 1); + memset(activation_info, '\0', activation_info_size + 1); + memcpy(activation_info, activation_info_start, activation_info_size); + free(activation_info_data); + + curl_global_init(CURL_GLOBAL_ALL); + CURL* handle = curl_easy_init(); + if (handle == NULL) { + fprintf(stderr, "Unable to initialize libcurl\n"); + curl_global_cleanup(); + return -1; + } + + curl_formadd(&post, &last, CURLFORM_COPYNAME, "machineName", CURLFORM_COPYCONTENTS, "linux", CURLFORM_END); + curl_formadd(&post, &last, CURLFORM_COPYNAME, "InStoreActivation", CURLFORM_COPYCONTENTS, "false", CURLFORM_END); + if (imei != NULL) { + curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMEI", CURLFORM_COPYCONTENTS, imei, CURLFORM_END); + free(imei); + } + + if (imsi != NULL) { + curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMSI", CURLFORM_COPYCONTENTS, imsi, CURLFORM_END); + free(imsi); + } + + if (iccid != NULL) { + curl_formadd(&post, &last, CURLFORM_COPYNAME, "ICCID", CURLFORM_COPYCONTENTS, iccid, CURLFORM_END); + free(iccid); + } + + if (serial_number != NULL) { + curl_formadd(&post, &last, CURLFORM_COPYNAME, "AppleSerialNumber", CURLFORM_COPYCONTENTS, serial_number, CURLFORM_END); + free(serial_number); + } + + if (activation_info != NULL) { + curl_formadd(&post, &last, CURLFORM_COPYNAME, "activation-info", CURLFORM_COPYCONTENTS, activation_info, CURLFORM_END); + free(activation_info); + } + + struct curl_slist* header = NULL; + header = curl_slist_append(header, "X-Apple-Tz: -14400"); + header = curl_slist_append(header, "X-Apple-Store-Front: 143441-1"); + + response = malloc(sizeof(activate_response)); + if (response == NULL) { + fprintf(stderr, "Unable to allocate sufficent memory\n"); + return -1; + } + + response->length = 0; + response->content = malloc(1); + + curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &activate_write_callback); + curl_easy_setopt(handle, CURLOPT_USERAGENT, "iTunes/9.1 (Macintosh; U; Intel Mac OS X 10.5.6)"); + curl_easy_setopt(handle, CURLOPT_URL, "https://albert.apple.com/WebObjects/ALUnbrick.woa/wa/deviceActivation"); + + curl_easy_perform(handle); + curl_slist_free_all(header); + curl_easy_cleanup(handle); + curl_global_cleanup(); + + uint32_t ticket_size = response->length; + char* ticket_data = response->content; + + char* ticket_start = strstr(ticket_data, ""); + if (ticket_stop == NULL) { + fprintf(stderr, "Unable to locate end of ActivationInfo\n"); + return -1; + } + + ticket_stop += strlen(""); + ticket_size = ticket_stop - ticket_start; + char* ticket = malloc(ticket_size + 1); + memset(ticket, '\0', ticket_size + 1); + memcpy(ticket, ticket_start, ticket_size); + //free(ticket_data); + + //printf("%s\n\n", ticket); + + plist_t ticket_dict = NULL; + plist_from_xml(ticket, ticket_size, &ticket_dict); + if (ticket_dict == NULL) { + printf("Unable to convert activation ticket into plist\n"); + return -1; + } + + plist_t iphone_activation_node = plist_dict_get_item(ticket_dict, "iphone-activation"); + if (!iphone_activation_node) { + iphone_activation_node = plist_dict_get_item(ticket_dict, "device-activation"); + if (!iphone_activation_node) { + printf("Unable to find device activation node\n"); + return -1; + } + } + + plist_t activation_record = plist_dict_get_item(iphone_activation_node, "activation-record"); + if (!activation_record) { + printf("Unable to find activation record node"); + return -1; + } + + *record = plist_copy(activation_record); + + //free(response->content); + //free(response); + //free(request); + return 0; +} diff --git a/src/activate.h b/src/activate.h new file mode 100644 index 0000000..1feb11e --- /dev/null +++ b/src/activate.h @@ -0,0 +1,30 @@ +/* + * activate.h + * Functions to fetch activation records from Apple's servers + * + * Copyright (c) 2010 Joshua Hill. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ACTIVATE_H +#define ACTIVATE_H + +#include +#include + +int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record); + +#endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 7d382eb..4494f04 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -302,7 +302,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { return NULL; } - return plist_copy(build_identity); + return build_identity; } int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { -- cgit v1.1-32-gdbae From 7f98089a5e6663be50521063cf7171ab1bbc9fa2 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 11:17:05 +0800 Subject: Even more major cleanups and refactoring, this branch is still broken but starting to mature really well --- src/activate.c | 8 + src/activate.h | 2 + src/dfu.c | 49 ++- src/dfu.h | 5 +- src/idevicerestore.c | 829 ++++++++++++++++++--------------------------------- src/img3.c | 120 ++++---- src/img3.h | 56 ++-- src/ipsw.c | 3 +- src/ipsw.h | 3 +- src/normal.c | 13 +- src/normal.h | 2 +- src/recovery.c | 247 ++++++++------- src/recovery.h | 2 +- src/restore.c | 199 ++++++++++++- src/restore.h | 15 +- src/tss.c | 125 +++++++- src/tss.h | 8 +- 17 files changed, 885 insertions(+), 801 deletions(-) (limited to 'src') diff --git a/src/activate.c b/src/activate.c index 2cb4452..1fcd2e2 100644 --- a/src/activate.c +++ b/src/activate.c @@ -252,3 +252,11 @@ int activate_fetch_record(lockdownd_client_t client, plist_t* record) { //free(request); return 0; } + +int activate_check_status(const char* uuid) { + return 1; +} + +int activate_device(const char* uuid) { + return 0; +} diff --git a/src/activate.h b/src/activate.h index 1feb11e..f992d4f 100644 --- a/src/activate.h +++ b/src/activate.h @@ -25,6 +25,8 @@ #include #include +int activate_device(const char* uuid); +int activate_check_status(const char* uuid); int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record); #endif diff --git a/src/dfu.c b/src/dfu.c index 1da895d..1a5a037 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -19,10 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include +#include #include #include "dfu.h" +#include "recovery.h" +#include "idevicerestore.h" int dfu_check_mode() { irecv_client_t dfu = NULL; @@ -33,7 +36,7 @@ int dfu_check_mode() { return -1; } - if(dfu->mode != kDfuMode) { + if (dfu->mode != kDfuMode) { irecv_close(dfu); return -1; } @@ -43,14 +46,42 @@ int dfu_check_mode() { return 0; } -int dfu_get_cpid(uint32_t* cpid) { - return 0; -} +int dfu_enter_recovery(const char* ipsw, plist_t tss) { + irecv_client_t dfu = NULL; + const char* component = "iBSS"; + irecv_error_t dfu_error = IRECV_E_SUCCESS; + if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode != kDfuMode) { + error("ERROR: Unable to connect to DFU device\n"); + if (dfu) + irecv_close(dfu); + return -1; + } -int dfu_get_bdid(uint32_t* bdid) { - return 0; -} + if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) { + error("ERROR: Unable to send %s to device\n", component); + irecv_close(dfu); + return -1; + } -int dfu_get_ecid(uint64_t* ecid) { + dfu_error = irecv_reset(dfu); + if (dfu_error != IRECV_E_SUCCESS) { + error("ERROR: Unable to reset device\n"); + irecv_close(dfu); + return -1; + } + irecv_close(dfu); + dfu = NULL; + + // Reconnect to device, but this time make sure we're not still in DFU mode + if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode == kDfuMode) { + error("ERROR: Unable to connect to recovery device\n"); + if (dfu) + irecv_close(dfu); + return -1; + } + + idevicerestore_mode = RECOVERY_MODE; + irecv_close(dfu); + dfu = NULL; return 0; } diff --git a/src/dfu.h b/src/dfu.h index f8f34fc..3577888 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -23,10 +23,9 @@ #define IDEVICERESTORE_DFU_H #include +#include int dfu_check_mode(); -int dfu_get_cpid(uint32_t* cpid); -int dfu_get_bdid(uint32_t* bdid); -int dfu_get_ecid(uint64_t* ecid); +int dfu_enter_recovery(const char* ipsw, plist_t tss); #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 4494f04..d2f6039 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -46,21 +46,246 @@ int idevicerestore_verbose = 0; idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE; idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE; -void usage(int argc, char* argv[]); -int get_device(const char* uuid); int check_mode(const char* uuid); +int check_device(const char* uuid); +void usage(int argc, char* argv[]); int get_ecid(const char* uuid, uint64_t* ecid); int get_bdid(const char* uuid, uint32_t* bdid); int get_cpid(const char* uuid, uint32_t* cpid); -int write_file(const char* filename, char* data, int size); +void device_callback(const idevice_event_t* event, void* user_data); int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); +int write_file(const char* filename, const char* data, uint32_t size); +int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob); -int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob); -void device_callback(const idevice_event_t* event, void *user_data); -int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); -int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize); +int get_signed_component_by_name(char* ipsw, plist_t tss, const char* component, char** data, uint32_t* size); +int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); + +void usage(int argc, char* argv[]) { + char *name = strrchr(argv[0], '/'); + printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); + printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); + printf(" -d, \t\tenable communication debugging\n"); + printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n"); + printf(" -h, \t\tprints usage information\n"); + printf(" -c, \t\trestore with a custom firmware\n"); + printf(" -v, \t\tenable verbose output\n"); + printf("\n"); +} + +int main(int argc, char* argv[]) { + int opt = 0; + char* ipsw = NULL; + char* uuid = NULL; + uint64_t ecid = 0; + while ((opt = getopt(argc, argv, "vdhceu:")) > 0) { + switch (opt) { + case 'h': + usage(argc, argv); + break; + + case 'd': + idevicerestore_debug = 1; + break; + + case 'e': + idevicerestore_erase = 1; + break; + + case 'c': + idevicerestore_custom = 1; + break; + + case 'v': + idevicerestore_verbose = 1; + break; + + case 'u': + uuid = optarg; + break; + + default: + usage(argc, argv); + return -1; + } + } + + argc -= optind; + argv += optind; + + if (argc == 1) + ipsw = argv[0]; + + if (ipsw == NULL) { + usage(argc, argv); + error("ERROR: Please supply an IPSW\n"); + return -1; + } + + // check which mode the device is currently in so we know where to start + idevicerestore_mode = check_mode(uuid); + if (idevicerestore_mode < 0) { + error("ERROR: Unable to discover current device state\n"); + return -1; + } + + // discover the device type + idevicerestore_device = check_device(uuid); + if (idevicerestore_device < 0) { + error("ERROR: Unable to discover device type\n"); + return -1; + } + + // extract buildmanifest + plist_t buildmanifest = NULL; + info("Extracting BuildManifest from IPSW\n"); + if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { + error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); + return -1; + } + + // choose whether this is an upgrade or a restore (default to upgrade) + plist_t build_identity = NULL; + if (idevicerestore_erase) { + build_identity = get_build_identity(buildmanifest, 0); + if (build_identity == NULL) { + error("ERROR: Unable to find build any identities\n"); + plist_free(buildmanifest); + return -1; + } + + } else { + build_identity = get_build_identity(buildmanifest, 1); + if (build_identity == NULL) { + build_identity = get_build_identity(buildmanifest, 0); + if (build_identity == NULL) { + error("ERROR: Unable to find build any identities\n"); + plist_free(buildmanifest); + return -1; + } + info("No upgrade ramdisk found, default to full restore\n"); + } + } + + // devices are listed in order from oldest to newest + // devices that come after iPod2g require personalized firmwares + plist_t tss_request = NULL; + plist_t tss = NULL; + if (idevicerestore_device > IPOD2G_DEVICE) { + info("Creating TSS request\n"); + // fetch the device's ECID for the TSS request + if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + error("ERROR: Unable to find device ECID\n"); + return -1; + } + info("Found ECID %llu\n", ecid); + + // fetch the SHSH blobs for this build identity + if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { + // this might fail if the TSS server doesn't have the saved blobs for the + // update identity, so go ahead and try again with the restore identity + if (idevicerestore_erase != 1) { + info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); + build_identity = get_build_identity(buildmanifest, 0); + if (build_identity == NULL) { + error("ERROR: Unable to find restore identity\n"); + plist_free(buildmanifest); + return -1; + } + + if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { + // if this fails then no SHSH blobs have been saved for this firmware + error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); + plist_free(buildmanifest); + return -1; + } + + } else { + error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); + plist_free(buildmanifest); + return -1; + } + } + } + + // Extract filesystem from IPSW and return its name + char* filesystem = NULL; + if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) { + error("ERROR: Unable to extract filesystem from IPSW\n"); + if (tss) + plist_free(tss); + plist_free(buildmanifest); + return -1; + } + + // if the device is in normal mode, place device into recovery mode + if (idevicerestore_mode == NORMAL_MODE) { + info("Entering recovery mode...\n"); + if (normal_enter_recovery(uuid) < 0) { + error("ERROR: Unable to place device into recovery mode\n"); + if (tss) + plist_free(tss); + plist_free(buildmanifest); + return -1; + } + } + + // if the device is in DFU mode, place device into recovery mode + if (idevicerestore_mode == DFU_MODE) { + if (dfu_enter_recovery(ipsw, tss) < 0) { + error("ERROR: Unable to place device into recovery mode\n"); + plist_free(buildmanifest); + if (tss) + plist_free(tss); + return -1; + } + } + + // if the device is in recovery mode, place device into restore mode + if (idevicerestore_mode == RECOVERY_MODE) { + if (recovery_enter_restore(uuid, ipsw, tss) < 0) { + error("ERROR: Unable to place device into restore mode\n"); + plist_free(buildmanifest); + if (tss) + plist_free(tss); + return -1; + } + } + + // device is finally in restore mode, let's do this + if (idevicerestore_mode == RESTORE_MODE) { + info("Restoring device... \n"); + if (restore_device(uuid, ipsw, tss, filesystem) < 0) { + error("ERROR: Unable to restore device\n"); + return -1; + } + } + + // device has finished restoring, lets see if we need to activate + if (idevicerestore_mode == NORMAL_MODE) { + info("Checking activation status\n"); + int activation = activate_check_status(uuid); + if (activation < 0) { + error("ERROR: Unable to check activation status\n"); + return -1; + } + + if (activation == 0) { + info("Activating device... \n"); + if (activate_device(uuid) < 0) { + error("ERROR: Unable to activate device\n"); + return -1; + } + } + } + + info("Cleaning up...\n"); + if (filesystem) + unlink(filesystem); + + info("DONE\n"); + return 0; +} int check_mode(const char* uuid) { idevicerestore_mode_t mode = UNKNOWN_MODE; @@ -87,14 +312,14 @@ int check_mode(const char* uuid) { return mode; } -int get_device(const char* uuid) { +int check_device(const char* uuid) { uint32_t bdid = 0; uint32_t cpid = 0; idevicerestore_device_t device = UNKNOWN_DEVICE; switch (idevicerestore_mode) { case NORMAL_MODE: - device = normal_get_device(uuid); + device = normal_check_device(uuid); if (device < 0) { device = UNKNOWN_DEVICE; } @@ -175,6 +400,7 @@ int get_bdid(const char* uuid, uint32_t* bdid) { } break; + case DFU_MODE: case RECOVERY_MODE: if (recovery_get_bdid(bdid) < 0) { *bdid = -1; @@ -182,13 +408,6 @@ int get_bdid(const char* uuid, uint32_t* bdid) { } break; - case DFU_MODE: - if (dfu_get_bdid(bdid) < 0) { - *bdid = -1; - return -1; - } - break; - default: error("ERROR: Device is in an invalid state\n"); return -1; @@ -206,6 +425,7 @@ int get_cpid(const char* uuid, uint32_t* cpid) { } break; + case DFU_MODE: case RECOVERY_MODE: if (recovery_get_cpid(cpid) < 0) { *cpid = 0; @@ -213,13 +433,6 @@ int get_cpid(const char* uuid, uint32_t* cpid) { } break; - case DFU_MODE: - if (dfu_get_cpid(cpid) < 0) { - *cpid = 0; - return -1; - } - break; - default: error("ERROR: Device is in an invalid state\n"); return -1; @@ -237,6 +450,7 @@ int get_ecid(const char* uuid, uint64_t* ecid) { } break; + case DFU_MODE: case RECOVERY_MODE: if (recovery_get_ecid(ecid) < 0) { *ecid = 0; @@ -244,13 +458,6 @@ int get_ecid(const char* uuid, uint64_t* ecid) { } break; - case DFU_MODE: - if (dfu_get_ecid(ecid) < 0) { - *ecid = 0; - return -1; - } - break; - default: error("ERROR: Device is in an invalid state\n"); return -1; @@ -292,7 +499,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { } // check and make sure this identity exists in buildmanifest - if(identity >= plist_array_get_size(build_identities_array)) { + if (identity >= plist_array_get_size(build_identities_array)) { return NULL; } @@ -302,18 +509,35 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { return NULL; } - return build_identity; + return plist_copy(build_identity); +} + +int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { + plist_t request = NULL; + plist_t response = NULL; + *tss = NULL; + + request = tss_create_request(build_identity, ecid); + if (request == NULL) { + error("ERROR: Unable to create TSS request\n"); + return -1; + } + + info("Sending TSS request\n"); + response = tss_send_request(request); + if (response == NULL) { + plist_free(request); + return -1; + } + + plist_free(request); + *tss = response; + return 0; } int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; - int sz = 0; - char* xml = NULL; - plist_to_xml(build_identity, &xml, &sz); - debug("%s", xml); - free(xml); - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: Unable to find manifest node\n"); @@ -349,538 +573,79 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst return 0; } -int main(int argc, char* argv[]) { - int opt = 0; - char* ipsw = NULL; - char* uuid = NULL; - uint64_t ecid = 0; - while ((opt = getopt(argc, argv, "vdhceu:")) > 0) { - switch (opt) { - case 'h': - usage(argc, argv); - break; - - case 'd': - idevicerestore_debug = 1; - break; - - case 'e': - idevicerestore_erase = 1; - break; - - case 'c': - idevicerestore_custom = 1; - break; - - case 'v': - idevicerestore_verbose = 1; - break; - - case 'u': - uuid = optarg; - break; - - default: - usage(argc, argv); - return -1; - } - } - - argc -= optind; - argv += optind; - - if (argc == 1) - ipsw = argv[0]; - - if (ipsw == NULL) { - usage(argc, argv); - error("ERROR: Please supply an IPSW\n"); - return -1; - } - - // check which mode the device is currently in so we know where to start - idevicerestore_mode = check_mode(uuid); - if (idevicerestore_mode < 0) { - error("ERROR: Unable to discover device current mode\n"); - return -1; - } - - // discover the device type - idevicerestore_device = get_device(uuid); - if (idevicerestore_device < 0) { - error("ERROR: Unable to discover device type\n"); - return -1; - } - - // extract buildmanifest - plist_t buildmanifest = NULL; - info("Extracting BuildManifest from IPSW\n"); - if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { - error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); - return -1; - } - - // choose whether this is an upgrade or a restore (default to upgrade) - plist_t build_identity = NULL; - if(idevicerestore_erase) { - build_identity = get_build_identity(buildmanifest, 0); - if(build_identity == NULL) { - error("ERROR: Unable to find build any identities\n"); - plist_free(buildmanifest); - return -1; - } - - } else { - build_identity = get_build_identity(buildmanifest, 1); - if(build_identity == NULL) { - build_identity = get_build_identity(buildmanifest, 0); - if(build_identity == NULL) { - error("ERROR: Unable to find build any identities\n"); - plist_free(buildmanifest); - return -1; - } - info("No upgrade ramdisk found, default to full restore\n"); - } - } - - // devices are listed in order from oldest to newest - // devices that come after iPod2g require personalized firmwares - plist_t tss_request = NULL; - plist_t tss = NULL; - if(idevicerestore_device > IPOD2G_DEVICE) { - - info("Creating TSS request\n"); - // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { - error("ERROR: Unable to find device ECID\n"); - return -1; - } - info("Found ECID %llu\n", ecid); - - tss_request = tss_create_request(build_identity, ecid); - if (tss_request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(buildmanifest); - return -1; - } - - info("Sending TSS request\n"); - tss = tss_send_request(tss_request); - if (tss == NULL) { - error("ERROR: Unable to get response from TSS server\n"); - plist_free(tss_request); - return -1; - } - info("Got TSS response\n"); - plist_free(tss_request); - } - - // Extract filesystem from IPSW and return its name - char* filesystem = NULL; - if(extract_filesystem(ipsw, build_identity, &filesystem) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - if(tss) plist_free(tss); - plist_free(buildmanifest); - return -1; - } - - // place device into recovery mode if required - if (idevicerestore_mode == NORMAL_MODE) { - info("Entering recovery mode...\n"); - if (normal_enter_recovery(uuid) < 0) { - error("ERROR: Unable to place device into recovery mode\n"); - if(tss) plist_free(tss); - plist_free(buildmanifest); - return -1; - } - } - - // place device into restore mode if required - if (idevicerestore_mode == RECOVERY_MODE) { - if (recovery_enter_restore(ipsw, tss) < 0) { - error("ERROR: Unable to place device into restore mode\n"); - if(tss) plist_free(tss); - plist_free(buildmanifest); - return -1; - } - } - - idevice_event_subscribe(&device_callback, NULL); - info("Waiting for device to enter restore mode\n"); - // block program until device has entered restore mode - while (idevicerestore_mode != RESTORE_MODE) { - sleep(1); - } - - idevice_t device = NULL; - idevice_error_t device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to open device\n"); - plist_free(tss); - return -1; - } - - restored_client_t restore = NULL; - restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to start restored client\n"); - plist_free(tss); - idevice_free(device); - return -1; - } - - char* type = NULL; - uint64_t version = 0; - if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { - error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); - plist_free(tss); - restored_client_free(restore); - idevice_free(device); - return -1; - } - info("Device has successfully entered restore mode\n"); - - /* start restore process */ - char* kernelcache = NULL; - info("Restore protocol version is %llu.\n", version); - restore_error = restored_start_restore(restore); - if (restore_error == RESTORE_E_SUCCESS) { - while (!idevicerestore_quit) { - plist_t message = NULL; - restore_error = restored_receive(restore, &message); - plist_t msgtype_node = plist_dict_get_item(message, "MsgType"); - if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) { - char *msgtype = NULL; - plist_get_string_val(msgtype_node, &msgtype); - if (!strcmp(msgtype, "ProgressMsg")) { - restore_error = restore_handle_progress_msg(restore, message); - - } else if (!strcmp(msgtype, "DataRequestMsg")) { - // device is requesting data to be sent - plist_t datatype_node = plist_dict_get_item(message, "DataType"); - if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) { - char *datatype = NULL; - plist_get_string_val(datatype_node, &datatype); - if (!strcmp(datatype, "SystemImageData")) { - restore_send_filesystem(device, restore, filesystem); - - } else if (!strcmp(datatype, "KernelCache")) { - int kernelcache_size = 0; - char* kernelcache_data = NULL; - if (get_signed_component_by_name(ipsw, tss, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { - error("ERROR: Unable to get kernelcache file\n"); - return -1; - } - restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); - free(kernelcache_data); - - } else if (!strcmp(datatype, "NORData")) { - restore_send_nor(restore, ipsw, tss); - - } else { - // Unknown DataType!! - error("Unknown DataType\n"); - return -1; - } - } - - } else if (!strcmp(msgtype, "StatusMsg")) { - restore_error = restore_handle_status_msg(restore, message); - - } else { - info("Received unknown message type: %s\n", msgtype); - } - } - - if (RESTORE_E_SUCCESS != restore_error) { - error("Invalid return status %d\n", restore_error); - //idevicerestore_quit = 1; - } - - plist_free(message); - } - } else { - error("ERROR: Could not start restore. %d\n", restore_error); - } - - restored_client_free(restore); - plist_free(tss); - idevice_free(device); - unlink(filesystem); - return 0; -} - -void device_callback(const idevice_event_t* event, void *user_data) { - if (event->event == IDEVICE_DEVICE_ADD) { - idevicerestore_mode = RESTORE_MODE; - } else if (event->event == IDEVICE_DEVICE_REMOVE) { - idevicerestore_quit = 1; - } -} - -void usage(int argc, char* argv[]) { - char *name = strrchr(argv[0], '/'); - printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); - printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); - printf(" -d, \t\tenable communication debugging\n"); - printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n"); - printf(" -h, \t\tprints usage information\n"); - printf(" -c, \t\trestore with a custom firmware\n"); - printf(" -v, \t\tenable verbose output\n"); - printf("\n"); -} - -int write_file(const char* filename, char* data, int size) { - debug("Writing data to %s\n", filename); - FILE* file = fopen(filename, "wb"); - if (file == NULL) { - error("read_file: Unable to open file %s\n", filename); - return -1; - } - - int bytes = fwrite(data, 1, size, file); - fclose(file); - - if (bytes != size) { - error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); - return -1; - } - - return size; -} - -int get_tss_data_by_path(plist_t tss, const char* path, char** pname, char** pblob) { - *pname = NULL; - *pblob = NULL; - - char* key = NULL; - plist_t tss_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(tss, &iter); - while (1) { - plist_dict_next_item(tss, iter, &key, &tss_entry); - if (key == NULL) - break; - - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - continue; - } - - char* entry_path = NULL; - plist_t entry_path_node = plist_dict_get_item(tss_entry, "Path"); - if (!entry_path_node || plist_get_node_type(entry_path_node) != PLIST_STRING) { - error("ERROR: Unable to find TSS path node in entry %s\n", key); - return -1; - } - plist_get_string_val(entry_path_node, &entry_path); - if (strcmp(path, entry_path) == 0) { - char* blob = NULL; - uint64_t blob_size = 0; - plist_t blob_node = plist_dict_get_item(tss_entry, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find TSS blob node in entry %s\n", key); - return -1; - } - plist_get_data_val(blob_node, &blob, &blob_size); - *pname = key; - *pblob = blob; - return 0; - } - - free(key); - } - plist_free(tss_entry); - - return -1; -} - -int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) { - *ppath = NULL; - *pblob = NULL; - - plist_t node = plist_dict_get_item(tss, entry); - if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to find %s entry in TSS response\n", entry); - return -1; - } - - char* path = NULL; - plist_t path_node = plist_dict_get_item(node, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - error("ERROR: Unable to find %s path in entry\n", path); - return -1; - } - plist_get_string_val(path_node, &path); - - char* blob = NULL; - uint64_t blob_size = 0; - plist_t blob_node = plist_dict_get_item(node, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find %s blob in entry\n", path); - free(path); - return -1; - } - plist_get_data_val(blob_node, &blob, &blob_size); - - *ppath = path; - *pblob = blob; - return 0; -} - -int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize) { - int size = 0; - char* data = NULL; - char* path = NULL; - char* blob = NULL; +int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { img3_file* img3 = NULL; - irecv_error_t error = 0; - - info("Extracting %s from TSS response\n", component); - if (get_tss_data_by_name(tss, component, &path, &blob) < 0) { - error("ERROR: Unable to get data for TSS %s entry\n", component); - return -1; - } + uint32_t component_size = 0; + char* component_data = NULL; + char* component_blob = NULL; info("Extracting %s from %s\n", path, ipsw); - if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { + if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) { error("ERROR: Unable to extract %s from %s\n", path, ipsw); - free(path); - free(blob); return -1; } - img3 = img3_parse_file(data, size); + img3 = img3_parse_file(component_data, component_size); if (img3 == NULL) { error("ERROR: Unable to parse IMG3: %s\n", path); - free(data); - free(path); - free(blob); + free(component_data); return -1; } - if (data) { - free(data); - data = NULL; + free(component_data); + + if (tss_get_blob_by_path(tss, path, &component_blob) < 0) { + error("ERROR: Unable to get SHSH blob for TSS %s entry\n", path); + img3_free(img3); + return -1; } - if (idevicerestore_custom == 0) { - if (img3_replace_signature(img3, blob) < 0) { + if (idevicerestore_device > IPOD2G_DEVICE && idevicerestore_custom == 0) { + if (img3_replace_signature(img3, component_blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); - free(path); - free(blob); + free(component_blob); + img3_free(img3); return -1; } } + free(component_blob); - if (img3_get_data(img3, &data, &size) < 0) { + if (img3_get_data(img3, &component_data, &component_size) < 0) { error("ERROR: Unable to reconstruct IMG3\n"); img3_free(img3); - free(path); return -1; } + img3_free(img3); if (idevicerestore_debug) { char* out = strrchr(path, '/'); if (out != NULL) { out++; } else { - out = path; + out = (char*) path; } - write_file(out, data, size); - } - - if (img3) { - img3_free(img3); - img3 = NULL; - } - if (blob) { - free(blob); - blob = NULL; - } - if (path) { - free(path); - path = NULL; + write_file(out, component_data, component_size); } - *pdata = data; - *psize = size; + *data = component_data; + *size = component_size; return 0; } -int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize) { - int size = 0; - char* data = NULL; - char* name = NULL; - char* blob = NULL; - img3_file* img3 = NULL; - irecv_error_t error = 0; - - info("Extracting %s from TSS response\n", path); - if (get_tss_data_by_path(tss, path, &name, &blob) < 0) { - error("ERROR: Unable to get data for TSS %s entry\n", path); - return -1; - } - - info("Extracting %s from %s\n", path, ipsw); - if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { - error("ERROR: Unable to extract %s from %s\n", path, ipsw); - free(path); - free(blob); - return -1; - } - - img3 = img3_parse_file(data, size); - if (img3 == NULL) { - error("ERROR: Unable to parse IMG3: %s\n", path); - free(data); - free(path); - free(blob); +int write_file(const char* filename, const char* data, uint32_t size) { + info("Writing data to %s\n", filename); + FILE* file = fopen(filename, "wb"); + if (file == NULL) { + error("read_file: Unable to open file %s\n", filename); return -1; } - if (data) { - free(data); - data = NULL; - } - if (idevicerestore_custom == 0) { - if (img3_replace_signature(img3, blob) < 0) { - error("ERROR: Unable to replace IMG3 signature\n"); - free(name); - free(blob); - return -1; - } - } + int bytes = fwrite(data, 1, size, file); + fclose(file); - if (img3_get_data(img3, &data, &size) < 0) { - error("ERROR: Unable to reconstruct IMG3\n"); - img3_free(img3); - free(name); + if (bytes != size) { + error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); return -1; } - if (idevicerestore_debug) { - char* out = strrchr(path, '/'); - if (out != NULL) { - out++; - } else { - out = path; - } - write_file(out, data, size); - } - - if (img3) { - img3_free(img3); - img3 = NULL; - } - if (blob) { - free(blob); - blob = NULL; - } - if (path) { - free(name); - name = NULL; - } - - *pdata = data; - *psize = size; - return 0; + return size; } diff --git a/src/img3.c b/src/img3.c index ec7bcbf..5c79e54 100644 --- a/src/img3.c +++ b/src/img3.c @@ -29,20 +29,20 @@ img3_file* img3_parse_file(char* data, int size) { int data_offset = 0; img3_header* header = (img3_header*) data; - if(header->signature != kImg3Container) { + if (header->signature != kImg3Container) { error("ERROR: Invalid IMG3 file\n"); return NULL; } img3_file* image = (img3_file*) malloc(sizeof(img3_file)); - if(image == NULL) { + if (image == NULL) { error("ERROR: Unable to allocate memory for IMG3 file\n"); return NULL; } memset(image, '\0', sizeof(img3_file)); image->header = (img3_header*) malloc(sizeof(img3_header)); - if(image->header == NULL) { + if (image->header == NULL) { error("ERROR: Unable to allocate memory for IMG3 header\n"); img3_free(image); return NULL; @@ -51,12 +51,12 @@ img3_file* img3_parse_file(char* data, int size) { data_offset += sizeof(img3_header); img3_element_header* current = NULL; - while(data_offset < size) { + while (data_offset < size) { current = (img3_element_header*) &data[data_offset]; - switch(current->signature) { + switch (current->signature) { case kTypeElement: image->type_element = img3_parse_element(&data[data_offset]); - if(image->type_element == NULL) { + if (image->type_element == NULL) { error("ERROR: Unable to parse TYPE element\n"); img3_free(image); return NULL; @@ -66,7 +66,7 @@ img3_file* img3_parse_file(char* data, int size) { case kDataElement: image->data_element = img3_parse_element(&data[data_offset]); - if(image->data_element == NULL) { + if (image->data_element == NULL) { error("ERROR: Unable to parse DATA element\n"); img3_free(image); return NULL; @@ -76,7 +76,7 @@ img3_file* img3_parse_file(char* data, int size) { case kVersElement: image->vers_element = img3_parse_element(&data[data_offset]); - if(image->vers_element == NULL) { + if (image->vers_element == NULL) { error("ERROR: Unable to parse VERS element\n"); img3_free(image); return NULL; @@ -86,7 +86,7 @@ img3_file* img3_parse_file(char* data, int size) { case kSepoElement: image->sepo_element = img3_parse_element(&data[data_offset]); - if(image->sepo_element == NULL) { + if (image->sepo_element == NULL) { error("ERROR: Unable to parse SEPO element\n"); img3_free(image); return NULL; @@ -96,7 +96,7 @@ img3_file* img3_parse_file(char* data, int size) { case kBordElement: image->bord_element = img3_parse_element(&data[data_offset]); - if(image->bord_element == NULL) { + if (image->bord_element == NULL) { error("ERROR: Unable to parse BORD element\n"); img3_free(image); return NULL; @@ -105,9 +105,9 @@ img3_file* img3_parse_file(char* data, int size) { break; case kKbagElement: - if(image->kbag1_element == NULL) { + if (image->kbag1_element == NULL) { image->kbag1_element = img3_parse_element(&data[data_offset]); - if(image->kbag1_element == NULL) { + if (image->kbag1_element == NULL) { error("ERROR: Unable to parse first KBAG element\n"); img3_free(image); return NULL; @@ -115,7 +115,7 @@ img3_file* img3_parse_file(char* data, int size) { } else { image->kbag2_element = img3_parse_element(&data[data_offset]); - if(image->kbag2_element == NULL) { + if (image->kbag2_element == NULL) { error("ERROR: Unable to parse second KBAG element\n"); img3_free(image); return NULL; @@ -126,7 +126,7 @@ img3_file* img3_parse_file(char* data, int size) { case kEcidElement: image->ecid_element = img3_parse_element(&data[data_offset]); - if(image->ecid_element == NULL) { + if (image->ecid_element == NULL) { error("ERROR: Unable to parse ECID element\n"); img3_free(image); return NULL; @@ -136,7 +136,7 @@ img3_file* img3_parse_file(char* data, int size) { case kShshElement: image->shsh_element = img3_parse_element(&data[data_offset]); - if(image->shsh_element == NULL) { + if (image->shsh_element == NULL) { error("ERROR: Unable to parse SHSH element\n"); img3_free(image); return NULL; @@ -146,7 +146,7 @@ img3_file* img3_parse_file(char* data, int size) { case kCertElement: image->cert_element = img3_parse_element(&data[data_offset]); - if(image->cert_element == NULL) { + if (image->cert_element == NULL) { error("ERROR: Unable to parse CERT element\n"); img3_free(image); return NULL; @@ -168,14 +168,14 @@ img3_file* img3_parse_file(char* data, int size) { img3_element* img3_parse_element(char* data) { img3_element_header* element_header = (img3_element_header*) data; img3_element* element = (img3_element*) malloc(sizeof(img3_element)); - if(element == NULL) { + if (element == NULL) { error("ERROR: Unable to allocate memory for IMG3 element\n"); return NULL; } memset(element, '\0', sizeof(img3_element)); element->data = (char*) malloc(element_header->full_size); - if(element->data == NULL) { + if (element->data == NULL) { error("ERROR: Unable to allocate memory for IMG3 element data\n"); free(element); return NULL; @@ -188,57 +188,57 @@ img3_element* img3_parse_element(char* data) { } void img3_free(img3_file* image) { - if(image != NULL) { - if(image->header != NULL) { + if (image != NULL) { + if (image->header != NULL) { free(image->header); } - if(image->type_element != NULL) { + if (image->type_element != NULL) { img3_free_element(image->type_element); image->type_element = NULL; } - if(image->data_element != NULL) { + if (image->data_element != NULL) { img3_free_element(image->data_element); image->data_element = NULL; } - if(image->vers_element != NULL) { + if (image->vers_element != NULL) { img3_free_element(image->vers_element); image->vers_element = NULL; } - if(image->sepo_element != NULL) { + if (image->sepo_element != NULL) { img3_free_element(image->sepo_element); image->sepo_element = NULL; } - if(image->bord_element != NULL) { + if (image->bord_element != NULL) { img3_free_element(image->bord_element); image->bord_element = NULL; } - if(image->kbag1_element != NULL) { + if (image->kbag1_element != NULL) { img3_free_element(image->kbag1_element); image->kbag1_element = NULL; } - if(image->kbag2_element != NULL) { + if (image->kbag2_element != NULL) { img3_free_element(image->kbag2_element); image->kbag2_element = NULL; } - if(image->ecid_element != NULL) { + if (image->ecid_element != NULL) { img3_free_element(image->ecid_element); image->ecid_element = NULL; } - if(image->shsh_element != NULL) { + if (image->shsh_element != NULL) { img3_free_element(image->shsh_element); image->shsh_element = NULL; } - if(image->cert_element != NULL) { + if (image->cert_element != NULL) { img3_free_element(image->cert_element); image->cert_element = NULL; } @@ -249,8 +249,8 @@ void img3_free(img3_file* image) { } void img3_free_element(img3_element* element) { - if(element != NULL) { - if(element->data != NULL) { + if (element != NULL) { + if (element->data != NULL) { free(element->data); element->data = NULL; } @@ -262,37 +262,37 @@ void img3_free_element(img3_element* element) { int img3_replace_signature(img3_file* image, char* signature) { int offset = 0; img3_element* ecid = img3_parse_element(&signature[offset]); - if(ecid == NULL || ecid->type != kEcidElement) { + if (ecid == NULL || ecid->type != kEcidElement) { error("ERROR: Unable to find ECID element in signature\n"); return -1; } offset += ecid->header->full_size; img3_element* shsh = img3_parse_element(&signature[offset]); - if(shsh == NULL || shsh->type != kShshElement) { + if (shsh == NULL || shsh->type != kShshElement) { error("ERROR: Unable to find SHSH element in signature\n"); return -1; } offset += shsh->header->full_size; img3_element* cert = img3_parse_element(&signature[offset]); - if(cert == NULL || cert->type != kCertElement) { + if (cert == NULL || cert->type != kCertElement) { error("ERROR: Unable to find CERT element in signature\n"); return -1; } offset += cert->header->full_size; - if(image->ecid_element != NULL) { + if (image->ecid_element != NULL) { img3_free_element(image->ecid_element); } image->ecid_element = ecid; - if(image->shsh_element != NULL) { + if (image->shsh_element != NULL) { img3_free_element(image->shsh_element); } image->shsh_element = shsh; - if(image->cert_element != NULL) { + if (image->cert_element != NULL) { img3_free_element(image->cert_element); } image->cert_element = cert; @@ -305,39 +305,39 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { int size = sizeof(img3_header); // Add up the size of the image first so we can allocate our memory - if(image->type_element != NULL) { + if (image->type_element != NULL) { size += image->type_element->header->full_size; } - if(image->data_element != NULL) { + if (image->data_element != NULL) { size += image->data_element->header->full_size; } - if(image->vers_element != NULL) { + if (image->vers_element != NULL) { size += image->vers_element->header->full_size; } - if(image->sepo_element != NULL) { + if (image->sepo_element != NULL) { size += image->sepo_element->header->full_size; } - if(image->bord_element != NULL) { + if (image->bord_element != NULL) { size += image->bord_element->header->full_size; } - if(image->kbag1_element != NULL) { + if (image->kbag1_element != NULL) { size += image->kbag1_element->header->full_size; } - if(image->kbag2_element != NULL) { + if (image->kbag2_element != NULL) { size += image->kbag2_element->header->full_size; } - if(image->ecid_element != NULL) { + if (image->ecid_element != NULL) { size += image->ecid_element->header->full_size; } - if(image->shsh_element != NULL) { + if (image->shsh_element != NULL) { size += image->shsh_element->header->full_size; } - if(image->cert_element != NULL) { + if (image->cert_element != NULL) { size += image->cert_element->header->full_size; } char* data = (char*) malloc(size); - if(data == NULL) { + if (data == NULL) { error("ERROR: Unable to allocate memory for IMG3 data\n"); return -1; } @@ -351,49 +351,49 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { offset += sizeof(img3_header); // Copy each section over to the new buffer - if(image->type_element != NULL) { + if (image->type_element != NULL) { memcpy(&data[offset], image->type_element->data, image->type_element->header->full_size); offset += image->type_element->header->full_size; } - if(image->data_element != NULL) { + if (image->data_element != NULL) { memcpy(&data[offset], image->data_element->data, image->data_element->header->full_size); offset += image->data_element->header->full_size; } - if(image->vers_element != NULL) { + if (image->vers_element != NULL) { memcpy(&data[offset], image->vers_element->data, image->vers_element->header->full_size); offset += image->vers_element->header->full_size; } - if(image->sepo_element != NULL) { + if (image->sepo_element != NULL) { memcpy(&data[offset], image->sepo_element->data, image->sepo_element->header->full_size); offset += image->sepo_element->header->full_size; } - if(image->bord_element != NULL) { + if (image->bord_element != NULL) { memcpy(&data[offset], image->bord_element->data, image->bord_element->header->full_size); offset += image->bord_element->header->full_size; } - if(image->kbag1_element != NULL) { + if (image->kbag1_element != NULL) { memcpy(&data[offset], image->kbag1_element->data, image->kbag1_element->header->full_size); offset += image->kbag1_element->header->full_size; } - if(image->kbag2_element != NULL) { + if (image->kbag2_element != NULL) { memcpy(&data[offset], image->kbag2_element->data, image->kbag2_element->header->full_size); offset += image->kbag2_element->header->full_size; } - if(image->ecid_element != NULL) { + if (image->ecid_element != NULL) { memcpy(&data[offset], image->ecid_element->data, image->ecid_element->header->full_size); offset += image->ecid_element->header->full_size; } - if(image->shsh_element != NULL) { + if (image->shsh_element != NULL) { memcpy(&data[offset], image->shsh_element->data, image->shsh_element->header->full_size); header->shsh_offset = offset - sizeof(img3_header); offset += image->shsh_element->header->full_size; } - if(image->cert_element != NULL) { + if (image->cert_element != NULL) { memcpy(&data[offset], image->cert_element->data, image->cert_element->header->full_size); offset += image->cert_element->header->full_size; } - if(offset != size) { + if (offset != size) { error("ERROR: Incorrectly sized image data\n"); free(data); *pdata = 0; diff --git a/src/img3.h b/src/img3.h index c172455..5fddbfc 100644 --- a/src/img3.h +++ b/src/img3.h @@ -23,39 +23,39 @@ #define IDEVICERESTORE_IMG3_H typedef enum { - kNorContainer = 0x696D6733, // img3 - kImg3Container = 0x496D6733, // Img3 - k8900Container = 0x30303938, // 8900 - kImg2Container = 0x494D4732 // IMG2 + kNorContainer = 0x696D6733, // img3 + kImg3Container = 0x496D6733, // Img3 + k8900Container = 0x30303938, // 8900 + kImg2Container = 0x494D4732 // IMG2 } img3_container; typedef enum { - kDataElement = 0x44415441, // DATA - kTypeElement = 0x54595045, // TYPE - kKbagElement = 0x4B424147, // KBAG - kShshElement = 0x53485348, // SHSH - kCertElement = 0x43455254, // CERT - kChipElement = 0x43484950, // CHIP - kProdElement = 0x50524F44, // PROD - kSdomElement = 0x53444F4D, // SDOM - kVersElement = 0x56455253, // VERS - kBordElement = 0x424F5244, // BORD - kSepoElement = 0x5345504F, // SEPO - kEcidElement = 0x45434944 // ECID + kDataElement = 0x44415441, // DATA + kTypeElement = 0x54595045, // TYPE + kKbagElement = 0x4B424147, // KBAG + kShshElement = 0x53485348, // SHSH + kCertElement = 0x43455254, // CERT + kChipElement = 0x43484950, // CHIP + kProdElement = 0x50524F44, // PROD + kSdomElement = 0x53444F4D, // SDOM + kVersElement = 0x56455253, // VERS + kBordElement = 0x424F5244, // BORD + kSepoElement = 0x5345504F, // SEPO + kEcidElement = 0x45434944 // ECID } img3_element_type; typedef struct { - unsigned int signature; - unsigned int full_size; - unsigned int data_size; - unsigned int shsh_offset; - unsigned int image_type; + unsigned int signature; + unsigned int full_size; + unsigned int data_size; + unsigned int shsh_offset; + unsigned int image_type; } img3_header; typedef struct { - unsigned int signature; - unsigned int full_size; - unsigned int data_size; + unsigned int signature; + unsigned int full_size; + unsigned int data_size; } img3_element_header; typedef struct { @@ -79,11 +79,11 @@ typedef struct { img3_element* cert_element; } img3_file; -img3_file* img3_parse_file(char* data, int size); -img3_element* img3_parse_element(char* data); -int img3_replace_signature(img3_file* image, char* signature); void img3_free(img3_file* image); -int img3_get_data(img3_file* image, char** pdata, int* psize); +img3_element* img3_parse_element(char* data); void img3_free_element(img3_element* element); +img3_file* img3_parse_file(char* data, int size); +int img3_get_data(img3_file* image, char** pdata, int* psize); +int img3_replace_signature(img3_file* image, char* signature); #endif diff --git a/src/ipsw.c b/src/ipsw.c index ca28596..6c5d504 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -119,7 +120,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi return 0; } -int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize) { +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize) { ipsw_archive* archive = ipsw_open(ipsw); if (archive == NULL || archive->zip == NULL) { error("ERROR: Invalid archive\n"); diff --git a/src/ipsw.h b/src/ipsw.h index 20f6bf5..aa0fd1d 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -23,6 +23,7 @@ #define IDEVICERESTORE_IPSW_H #include +#include typedef struct { int index; @@ -31,7 +32,7 @@ typedef struct { unsigned char* data; } ipsw_file; -int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize); +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize); void ipsw_free_file(ipsw_file* file); #endif diff --git a/src/normal.c b/src/normal.c index 3c2bf5c..ab9216c 100644 --- a/src/normal.c +++ b/src/normal.c @@ -61,7 +61,7 @@ int normal_check_mode(const char* uuid) { return 0; } -int normal_get_device(const char* uuid) { +int normal_check_device(const char* uuid) { idevice_t device = NULL; char* product_type = NULL; plist_t product_type_node = NULL; @@ -88,7 +88,8 @@ int normal_get_device(const char* uuid) { } if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) { - if(product_type_node) plist_free(product_type_node); + if (product_type_node) + plist_free(product_type_node); lockdownd_client_free(lockdown); idevice_free(device); return -1; @@ -102,8 +103,8 @@ int normal_get_device(const char* uuid) { device = NULL; int i = 0; - for(i = 0; idevicerestore_products[i] != NULL; i++) { - if(!strcmp(product_type, idevicerestore_products[i])) { + for (i = 0; idevicerestore_products[i] != NULL; i++) { + if (!strcmp(product_type, idevicerestore_products[i])) { idevicerestore_device = i; break; } @@ -146,7 +147,7 @@ int normal_enter_recovery(const char* uuid) { lockdown = NULL; device = NULL; - if(recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(&recovery) < 0) { error("ERROR: Unable to enter recovery mode\n"); return -1; } @@ -187,7 +188,7 @@ int normal_get_ecid(const char* uuid, uint64_t* ecid) { lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; device_error = idevice_new(&device, uuid); - if(device_error != IDEVICE_E_SUCCESS) { + if (device_error != IDEVICE_E_SUCCESS) { return -1; } diff --git a/src/normal.h b/src/normal.h index bde1de0..cdc29ba 100644 --- a/src/normal.h +++ b/src/normal.h @@ -25,7 +25,7 @@ #include int normal_check_mode(const char* uuid); -int normal_get_device(const char* uuid); +int normal_check_device(const char* uuid); int normal_enter_recovery(const char* uuid); int normal_get_cpid(const char* uuid, uint32_t* cpid); int normal_get_bdid(const char* uuid, uint32_t* cpid); diff --git a/src/recovery.c b/src/recovery.c index 3bfb97e..a0a1151 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "tss.h" #include "img3.h" @@ -38,7 +40,7 @@ int recovery_check_mode() { return -1; } - if(recovery->mode == kDfuMode) { + if (recovery->mode == kDfuMode) { irecv_close(recovery); return -1; } @@ -48,7 +50,10 @@ int recovery_check_mode() { return 0; } -int recovery_enter_restore(const char* ipsw, plist_t tss) { +int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { + idevice_t device = NULL; + restored_client_t restore = NULL; + // upload data to make device boot restore mode if (recovery_send_ibec(ipsw, tss) < 0) { error("ERROR: Unable to send iBEC\n"); @@ -72,7 +77,7 @@ int recovery_enter_restore(const char* ipsw, plist_t tss) { } // for some reason iboot requires a hard reset after ramdisk - // or things start getting wacky + // or things start getting wacky printf("Please unplug your device, then plug it back in\n"); printf("Hit any key to continue..."); getchar(); @@ -82,6 +87,13 @@ int recovery_enter_restore(const char* ipsw, plist_t tss) { return -1; } + info("Waiting for device to enter restore mode\n"); + if (restore_open_with_timeout(uuid, &device, &restore) < 0) { + error("ERROR: Unable to connect to device in restore mode\n"); + return -1; + } + restore_close(device, restore); + return 0; } @@ -90,244 +102,225 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis char* data = NULL; char* path = NULL; char* blob = NULL; - img3_file* img3 = NULL; irecv_error_t error = 0; - if (get_signed_component_by_name(ipsw, tss, component, &data, &size) < 0) { + if (tss_get_entry_path(tss, component, &path) < 0) { + error("ERROR: Unable to get component path\n"); + return -1; + } + + if (get_signed_component(ipsw, tss, path, &data, &size) < 0) { error("ERROR: Unable to get signed component: %s\n", component); + free(path); return -1; } + free(path); info("Sending %s...\n", component); error = irecv_send_buffer(client, data, size); if (error != IRECV_E_SUCCESS) { - error("ERROR: Unable to send IMG3: %s\n", path); - img3_free(img3); + error("ERROR: Unable to send component: %s\n", component); free(data); - free(path); return -1; } - - if (data) { - free(data); - data = NULL; - } + free(data); return 0; } -irecv_error_t recovery_open_with_timeout(irecv_client_t* client) { +int recovery_open_with_timeout(irecv_client_t* client) { int i = 0; - irecv_error_t error = 0; - for (i = 10; i > 0; i--) { - error = irecv_open(client); - if (error == IRECV_E_SUCCESS) { - return error; + int attempts = 10; + irecv_client_t recovery = NULL; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + for (i = 1; i <= attempts; i++) { + recovery_error = irecv_open(client); + if (recovery_error == IRECV_E_SUCCESS) { + break; + } + + if (i == attempts) { + error("ERROR: Unable to connect to device in recovery mode\n"); + return -1; } sleep(2); - info("Retrying connection...\n"); + debug("Retrying connection...\n"); } - error("ERROR: Unable to connect to recovery device.\n"); - return error; + *client = recovery; + return 0; } int recovery_send_ibec(const char* ipsw, plist_t tss) { - irecv_error_t error = 0; - irecv_client_t client = NULL; - char* component = "iBEC"; + irecv_client_t recovery = NULL; + const char* component = "iBEC"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - error = irecv_send_command(client, "setenv auto-boot true"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "setenv auto-boot true"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set auto-boot environmental variable\n"); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "saveenv"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "saveenv"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to save environmental variable\n"); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_signed_component(recovery, ipsw, tss, "iBEC") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "go"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "go"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (client) { - irecv_close(client); - client = NULL; - } + irecv_close(recovery); + recovery = NULL; return 0; } int recovery_send_applelogo(const char* ipsw, plist_t tss) { - irecv_error_t error = 0; - irecv_client_t client = NULL; - char* component = "AppleLogo"; + irecv_client_t recovery = NULL; + const char* component = "applelogo"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; info("Sending %s...\n", component); - - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_signed_component(recovery, ipsw, tss, "AppleLogo") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "setpicture 1"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "setpicture 1"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "bgcolor 0 0 0"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "bgcolor 0 0 0"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to display %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (client) { - irecv_close(client); - client = NULL; - } + irecv_close(recovery); + recovery = NULL; return 0; } int recovery_send_devicetree(const char* ipsw, plist_t tss) { - irecv_error_t error = 0; - irecv_client_t client = NULL; - char *component = "RestoreDeviceTree"; + irecv_client_t recovery = NULL; + const char* component = "devicetree"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreDeviceTree") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "devicetree"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "devicetree"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (client) { - irecv_close(client); - client = NULL; - } + irecv_close(recovery); + recovery = NULL; return 0; } int recovery_send_ramdisk(const char* ipsw, plist_t tss) { - irecv_error_t error = 0; - irecv_client_t client = NULL; - char *component = "RestoreRamDisk"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + irecv_client_t recovery = NULL; + const char *component = "ramdisk"; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + recovery_error = recovery_open_with_timeout(&recovery); + if (recovery_error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreRamDisk") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "ramdisk"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "ramdisk"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (client) { - irecv_close(client); - client = NULL; - } + irecv_close(recovery); + recovery = NULL; return 0; } int recovery_send_kernelcache(const char* ipsw, plist_t tss) { - irecv_error_t error = 0; - irecv_client_t client = NULL; - char *component = "RestoreKernelCache"; + irecv_client_t recovery = NULL; + const char* component = "kernelcache"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreKernelCache") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - error = irecv_send_command(client, "bootx"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(recovery, "bootx"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; + irecv_close(recovery); return -1; } - if (client) { - irecv_close(client); - client = NULL; - } + irecv_close(recovery); + recovery = NULL; return 0; } - int recovery_get_ecid(uint64_t* ecid) { irecv_client_t recovery = NULL; - if(recovery_open_with_timeout(&recovery) < 0) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - irecv_error_t error = irecv_get_ecid(recovery, ecid); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_get_ecid(recovery, ecid); + if (recovery_error != IRECV_E_SUCCESS) { irecv_close(recovery); return -1; } @@ -339,12 +332,14 @@ int recovery_get_ecid(uint64_t* ecid) { int recovery_get_cpid(uint32_t* cpid) { irecv_client_t recovery = NULL; - if(recovery_open_with_timeout(&recovery) < 0) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - irecv_error_t error = irecv_get_cpid(recovery, cpid); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_get_cpid(recovery, cpid); + if (recovery_error != IRECV_E_SUCCESS) { irecv_close(recovery); return -1; } @@ -356,12 +351,14 @@ int recovery_get_cpid(uint32_t* cpid) { int recovery_get_bdid(uint32_t* bdid) { irecv_client_t recovery = NULL; - if(recovery_open_with_timeout(&recovery) < 0) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if (recovery_open_with_timeout(&recovery) < 0) { return -1; } - irecv_error_t error = irecv_get_bdid(recovery, bdid); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_get_bdid(recovery, bdid); + if (recovery_error != IRECV_E_SUCCESS) { irecv_close(recovery); return -1; } diff --git a/src/recovery.h b/src/recovery.h index b191aa5..1953c6a 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -26,7 +26,7 @@ #include int recovery_check_mode(); -int recovery_enter_restore(const char* ipsw, plist_t tss); +int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss); int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component); irecv_error_t recovery_open_with_timeout(irecv_client_t* client); int recovery_send_ibec(const char* ipsw, plist_t tss); diff --git a/src/restore.c b/src/restore.c index fd6fec2..ce9d41b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -24,6 +24,7 @@ #include #include +#include "tss.h" #include "restore.h" #include "idevicerestore.h" @@ -44,6 +45,8 @@ #define WAIT_FOR_DEVICE 33 #define LOAD_NOR 36 +static int restore_device_connected = 0; + int restore_check_mode(const char* uuid) { char* type = NULL; uint64_t version = 0; @@ -77,8 +80,81 @@ int restore_check_mode(const char* uuid) { return 0; } +void restore_device_callback(const idevice_event_t* event, void* user_data) { + if (event->event == IDEVICE_DEVICE_ADD) { + restore_device_connected = 1; + + } else if (event->event == IDEVICE_DEVICE_REMOVE) { + restore_device_connected = 0; + } +} + +int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) { + int i = 0; + int attempt = 10; + char* type = NULL; + uint64_t version = 0; + idevice_t context = NULL; + restored_client_t client = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + restored_error_t restore_error = RESTORE_E_SUCCESS; + + *device = NULL; + *restore = NULL; + + device_error = idevice_event_subscribe(&restore_device_callback, NULL); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to subscribe to device events\n"); + return -1; + } + + for (i = 1; i <= attempt; i++) { + if (restore_device_connected == 1) { + break; + } + + if (i == attempt) { + error("ERROR: Unable to connect to device in restore mode\n"); + } + + sleep(2); + } + + device_error = idevice_new(&context, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + restore_error = restored_client_new(context, &client, "idevicerestore"); + if (restore_error != RESTORE_E_SUCCESS) { + idevice_event_unsubscribe(); + idevice_free(context); + return -1; + } + + restore_error = restored_query_type(client, &type, &version); + if (restore_error != RESTORE_E_SUCCESS) { + restored_client_free(client); + idevice_event_unsubscribe(); + idevice_free(context); + return -1; + } + + *device = context; + *restore = client; + return 0; +} + +void restore_close(idevice_t device, restored_client_t restore) { + if (restore) + restored_client_free(restore); + if (device) + idevice_free(device); + idevice_event_unsubscribe(); +} + const char* restore_progress_string(unsigned int operation) { - switch(operation) { + switch (operation) { case CREATE_PARTITION_MAP: return "Creating partition map"; @@ -126,7 +202,6 @@ const char* restore_progress_string(unsigned int operation) { } } - int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_t node = NULL; uint64_t operation = 0; @@ -163,7 +238,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) { return 0; } -int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem) { +int restore_send_filesystem(idevice_t device, restored_client_t client, const char* filesystem) { int i = 0; char buffer[0x1000]; uint32_t recv_bytes = 0; @@ -327,7 +402,7 @@ int restore_send_filesystem(idevice_t device, restored_client_t client, const ch return ret; } -int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len) { +int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) { info("Sending kernelcache\n"); plist_t kernelcache_node = plist_new_data(kernel_data, len); @@ -347,19 +422,17 @@ int restore_send_kernelcache(restored_client_t client, char *kernel_data, int le return 0; } -int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { +int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { char* llb_path = NULL; - char* llb_blob = NULL; - if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) { + if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) { error("ERROR: Unable to get LLB info from TSS response\n"); return -1; } char* llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { - error("ERROR: Unable to extrac firmware path from LLB filename\n"); + error("ERROR: Unable to extract firmware path from LLB filename\n"); free(llb_path); - free(llb_blob); return -1; } @@ -378,7 +451,6 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { error("ERROR: Unable to extract firmware manifest from ipsw\n"); free(llb_path); - free(llb_blob); return -1; } @@ -392,7 +464,7 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { if (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } @@ -407,7 +479,7 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { while (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } @@ -436,3 +508,106 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) { plist_free(dict); return 0; } + +int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { + idevice_t device = NULL; + idevice_error_t device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to open device\n"); + plist_free(tss); + return -1; + } + + restored_client_t restore = NULL; + restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to start restored client\n"); + plist_free(tss); + idevice_free(device); + return -1; + } + + char* type = NULL; + uint64_t version = 0; + if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { + error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); + plist_free(tss); + restored_client_free(restore); + idevice_free(device); + return -1; + } + info("Device has successfully entered restore mode\n"); + + /* start restore process */ + char* kernelcache = NULL; + info("Restore protocol version is %llu.\n", version); + restore_error = restored_start_restore(restore); + if (restore_error == RESTORE_E_SUCCESS) { + while (!idevicerestore_quit) { + plist_t message = NULL; + restore_error = restored_receive(restore, &message); + plist_t msgtype_node = plist_dict_get_item(message, "MsgType"); + if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) { + char *msgtype = NULL; + plist_get_string_val(msgtype_node, &msgtype); + if (!strcmp(msgtype, "ProgressMsg")) { + restore_error = restore_handle_progress_msg(restore, message); + + } else if (!strcmp(msgtype, "DataRequestMsg")) { + // device is requesting data to be sent + plist_t datatype_node = plist_dict_get_item(message, "DataType"); + if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) { + char *datatype = NULL; + plist_get_string_val(datatype_node, &datatype); + if (!strcmp(datatype, "SystemImageData")) { + restore_send_filesystem(device, restore, filesystem); + + } else if (!strcmp(datatype, "KernelCache")) { + int kernelcache_size = 0; + char* kernelcache_data = NULL; + char* kernelcache_path = NULL; + if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { + error("ERROR: Unable to find kernelcache path\n"); + return -1; + } + + if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { + error("ERROR: Unable to get kernelcache file\n"); + return -1; + } + restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); + free(kernelcache_data); + + } else if (!strcmp(datatype, "NORData")) { + restore_send_nor(restore, ipsw, tss); + + } else { + // Unknown DataType!! + error("Unknown DataType\n"); + return -1; + } + } + + } else if (!strcmp(msgtype, "StatusMsg")) { + restore_error = restore_handle_status_msg(restore, message); + + } else { + info("Received unknown message type: %s\n", msgtype); + } + } + + if (RESTORE_E_SUCCESS != restore_error) { + error("Invalid return status %d\n", restore_error); + //idevicerestore_quit = 1; + } + + plist_free(message); + } + } else { + error("ERROR: Could not start restore. %d\n", restore_error); + } + + restored_client_free(restore); + idevice_free(device); + return 0; +} diff --git a/src/restore.h b/src/restore.h index f344b5d..99ba80b 100644 --- a/src/restore.h +++ b/src/restore.h @@ -22,16 +22,19 @@ #ifndef IDEVICERESTORE_RESTORE_H #define IDEVICERESTORE_RESTORE_H +#include #include - -#include "restore.h" +#include int restore_check_mode(const char* uuid); -int restore_handle_progress_msg(restored_client_t client, plist_t msg); +const char* restore_progress_string(unsigned int operation); +void restore_close(idevice_t device, restored_client_t restore); int restore_handle_status_msg(restored_client_t client, plist_t msg); -int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem); +int restore_handle_progress_msg(restored_client_t client, plist_t msg); +int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss); int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len); -int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss); -const char* restore_progress_string(unsigned int operation); +int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); +int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client); +int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem); #endif diff --git a/src/tss.c b/src/tss.c index a9e9456..6696b60 100644 --- a/src/tss.c +++ b/src/tss.c @@ -125,11 +125,13 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { free(key); } - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_request, &xml, &sz); - debug("%s", xml); - free(xml); + if (idevicerestore_debug) { + int sz = 0; + char* xml = NULL; + plist_to_xml(tss_request, &xml, &sz); + debug("%s", xml); + free(xml); + } return tss_request; } @@ -184,7 +186,6 @@ plist_t tss_send_request(plist_t tss_request) { curl_global_cleanup(); if (strstr(response->content, "MESSAGE=SUCCESS") == NULL) { - error("ERROR: Unable to get signature from this firmware\n"); free(response->content); free(response); return NULL; @@ -205,15 +206,115 @@ plist_t tss_send_request(plist_t tss_request) { free(response->content); free(response); - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_response, &xml, &sz); - debug("%s", xml); - free(xml); + if (idevicerestore_debug) { + int sz = 0; + char* xml = NULL; + plist_to_xml(tss_response, &xml, &sz); + debug("%s", xml); + free(xml); + } return tss_response; } -void tss_stitch_img3(img3_file* file, plist_t signature) { +int tss_get_entry_path(plist_t tss, const char* entry, char** path) { + char* path_string = NULL; + plist_t path_node = NULL; + plist_t entry_node = NULL; + + *path = NULL; + + entry_node = plist_dict_get_item(tss, entry); + if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) { + error("ERROR: Unable to find %s entry in TSS response\n", entry); + return -1; + } + + path_node = plist_dict_get_item(entry_node, "Path"); + if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { + error("ERROR: Unable to find %s path in entry\n", path_string); + return -1; + } + plist_get_string_val(path_node, &path_string); + + *path = path_string; + return 0; +} + +int tss_get_blob_by_path(plist_t tss, const char* path, char** blob) { + int i = 0; + uint32_t tss_size = 0; + uint64_t blob_size = 0; + char* entry_key = NULL; + char* blob_data = NULL; + char* entry_path = NULL; + plist_t tss_entry = NULL; + plist_t blob_node = NULL; + plist_t path_node = NULL; + plist_dict_iter iter = NULL; + + *blob = NULL; + + plist_dict_new_iter(tss, &iter); + tss_size = plist_dict_get_size(tss); + for (i = 0; i < tss_size; i++) { + plist_dict_next_item(tss, iter, &entry_key, &tss_entry); + if (entry_key == NULL) + break; + + if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { + continue; + } + + path_node = plist_dict_get_item(tss_entry, "Path"); + if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { + error("ERROR: Unable to find TSS path node in entry %s\n", entry_key); + return -1; + } + + plist_get_string_val(path_node, &entry_path); + if (strcmp(path, entry_path) == 0) { + blob_node = plist_dict_get_item(tss_entry, "Blob"); + if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { + error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key); + return -1; + } + plist_get_data_val(blob_node, &blob_data, &blob_size); + break; + } + + free(entry_key); + } + + if (blob_data == NULL || blob_size <= 0) { + return -1; + } + + *blob = blob_data; + return 0; +} + +int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob) { + uint64_t blob_size = 0; + char* blob_data = NULL; + plist_t blob_node = NULL; + plist_t tss_entry = NULL; + + *blob = NULL; + + tss_entry = plist_dict_get_item(tss, entry); + if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { + error("ERROR: Unable to find %s entry in TSS response\n", entry); + return -1; + } + + blob_node = plist_dict_get_item(tss_entry, "Blob"); + if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { + error("ERROR: Unable to find blob in %s entry\n", entry); + return -1; + } + plist_get_data_val(blob_node, &blob_data, &blob_size); + *blob = blob_data; + return 0; } diff --git a/src/tss.h b/src/tss.h index e18843b..ff60da0 100644 --- a/src/tss.h +++ b/src/tss.h @@ -24,10 +24,10 @@ #include -#include "img3.h" - +plist_t tss_send_request(plist_t request); plist_t tss_create_request(plist_t build_identity, uint64_t ecid); -plist_t tss_send_request(plist_t tss_request); -void tss_stitch_img3(img3_file* file, plist_t signature); +int tss_get_entry_path(plist_t tss, const char* entry, char** path); +int tss_get_blob_by_path(plist_t tss, const char* path, char** blob); +int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob); #endif -- cgit v1.1-32-gdbae From c21f7031b44e4cd61c1a6e630f9681742923ffa0 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 17:11:41 +0800 Subject: Added long options and moved the function main source file function declarations into the header file for easier maintainance --- src/idevicerestore.c | 60 +++++++++++++++++++++++++++++----------------------- src/idevicerestore.h | 18 ++++++++++++++++ 2 files changed, 51 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index d2f6039..c6a532a 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -43,42 +44,42 @@ int idevicerestore_debug = 0; int idevicerestore_erase = 0; int idevicerestore_custom = 0; int idevicerestore_verbose = 0; +int idevicerestore_exclude = 0; idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE; idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE; -int check_mode(const char* uuid); -int check_device(const char* uuid); -void usage(int argc, char* argv[]); -int get_ecid(const char* uuid, uint64_t* ecid); -int get_bdid(const char* uuid, uint32_t* bdid); -int get_cpid(const char* uuid, uint32_t* cpid); -void device_callback(const idevice_event_t* event, void* user_data); -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); -int write_file(const char* filename, const char* data, uint32_t size); -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); -int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_signed_component_by_name(char* ipsw, plist_t tss, const char* component, char** data, uint32_t* size); -int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); +static struct option long_opts[] = { + { "uuid", required_argument, NULL, 'u' }, + { "debug", no_argument, NULL, 'd' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { "erase", no_argument, NULL, 'e' }, + { "custom", no_argument, NULL, 'c' }, + { "exclude", no_argument, NULL, 'x' }, + { NULL, 0, NULL, 0} +}; void usage(int argc, char* argv[]) { char *name = strrchr(argv[0], '/'); printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); - printf(" -d, \t\tenable communication debugging\n"); - printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n"); - printf(" -h, \t\tprints usage information\n"); - printf(" -c, \t\trestore with a custom firmware\n"); - printf(" -v, \t\tenable verbose output\n"); + printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); + printf(" -d, --debug\t\tenable communication debugging\n"); + printf(" -v, --verbose\t\tenable verbose output\n"); + printf(" -h, --help\t\tprints usage information\n"); + printf(" -e, --erase\t\tperform a full restore, erasing all data\n"); + printf(" -c, --custom\t\trestore with a custom firmware\n"); + printf(" -x, --exclude\t\texclude nor/baseband upgrade\n"); printf("\n"); } int main(int argc, char* argv[]) { int opt = 0; + int optindex = 0; char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt(argc, argv, "vdhceu:")) > 0) { + while (opt = getopt_long(argc, argv, "vdhceu:", long_opts, &optindex) > 0) { switch (opt) { case 'h': usage(argc, argv); @@ -96,6 +97,10 @@ int main(int argc, char* argv[]) { idevicerestore_custom = 1; break; + case 'x': + idevicerestore_exclude = 1; + break; + case 'v': idevicerestore_verbose = 1; break; @@ -113,12 +118,10 @@ int main(int argc, char* argv[]) { argc -= optind; argv += optind; - if (argc == 1) + if (argc == 1) { ipsw = argv[0]; - - if (ipsw == NULL) { + } else { usage(argc, argv); - error("ERROR: Please supply an IPSW\n"); return -1; } @@ -631,15 +634,18 @@ int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, return 0; } -int write_file(const char* filename, const char* data, uint32_t size) { +int write_file(const char* filename, const void* data, size_t size) { + size_t bytes = 0; + FILE* file = NULL; + info("Writing data to %s\n", filename); - FILE* file = fopen(filename, "wb"); + file = fopen(filename, "wb"); if (file == NULL) { error("read_file: Unable to open file %s\n", filename); return -1; } - int bytes = fwrite(data, 1, size, file); + bytes = fwrite(data, 1, size, file); fclose(file); if (bytes != size) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 40d5543..adea68e 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -22,6 +22,9 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H +#include +#include + #define info(...) printf(__VA_ARGS__) #define error(...) fprintf(stderr, __VA_ARGS__) #define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) @@ -76,8 +79,23 @@ extern int idevicerestore_quit; extern int idevicerestore_debug; extern int idevicerestore_erase; extern int idevicerestore_custom; +extern int idevicerestore_exclude; extern int idevicerestore_verbose; extern idevicerestore_mode_t idevicerestore_mode; extern idevicerestore_device_t idevicerestore_device; +int check_mode(const char* uuid); +int check_device(const char* uuid); +void usage(int argc, char* argv[]); +int get_ecid(const char* uuid, uint64_t* ecid); +int get_bdid(const char* uuid, uint32_t* bdid); +int get_cpid(const char* uuid, uint32_t* cpid); +int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); +plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); +int write_file(const char* filename, const void* data, size_t size); +int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); +int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); +int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); + + #endif -- cgit v1.1-32-gdbae From 9279f889d7e296880fd7ea9d6c7cec499db62ea4 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sun, 6 Jun 2010 06:09:06 +0800 Subject: Changed the device type to a structure array for cleaner code and cross state access --- src/dfu.c | 2 +- src/idevicerestore.c | 119 ++++++++++++++++++++++++++++----------------------- src/idevicerestore.h | 95 ++++++++++++++++++++++------------------ src/normal.c | 26 +++++------ src/recovery.c | 6 +-- src/restore.c | 58 +++++++++++++++++++++++++ src/restore.h | 1 + 7 files changed, 194 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/dfu.c b/src/dfu.c index 1a5a037..1b0e8e7 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -80,7 +80,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) { return -1; } - idevicerestore_mode = RECOVERY_MODE; + idevicerestore_mode = MODE_RECOVERY; irecv_close(dfu); dfu = NULL; return 0; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index c6a532a..0e77447 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -45,8 +45,8 @@ int idevicerestore_erase = 0; int idevicerestore_custom = 0; int idevicerestore_verbose = 0; int idevicerestore_exclude = 0; -idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE; -idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE; +int idevicerestore_mode = MODE_UNKNOWN; +idevicerestore_device_t* idevicerestore_device = NULL; static struct option long_opts[] = { { "uuid", required_argument, NULL, 'u' }, @@ -79,7 +79,7 @@ int main(int argc, char* argv[]) { char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while (opt = getopt_long(argc, argv, "vdhceu:", long_opts, &optindex) > 0) { + while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv); @@ -125,6 +125,10 @@ int main(int argc, char* argv[]) { return -1; } + if(idevicerestore_debug) { + idevice_set_debug_level(5); + } + // check which mode the device is currently in so we know where to start idevicerestore_mode = check_mode(uuid); if (idevicerestore_mode < 0) { @@ -174,7 +178,7 @@ int main(int argc, char* argv[]) { // devices that come after iPod2g require personalized firmwares plist_t tss_request = NULL; plist_t tss = NULL; - if (idevicerestore_device > IPOD2G_DEVICE) { + if (idevicerestore_device > DEVICE_IPOD2G) { info("Creating TSS request\n"); // fetch the device's ECID for the TSS request if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { @@ -222,7 +226,7 @@ int main(int argc, char* argv[]) { } // if the device is in normal mode, place device into recovery mode - if (idevicerestore_mode == NORMAL_MODE) { + if (idevicerestore_mode == MODE_NORMAL) { info("Entering recovery mode...\n"); if (normal_enter_recovery(uuid) < 0) { error("ERROR: Unable to place device into recovery mode\n"); @@ -234,7 +238,7 @@ int main(int argc, char* argv[]) { } // if the device is in DFU mode, place device into recovery mode - if (idevicerestore_mode == DFU_MODE) { + if (idevicerestore_mode == MODE_DFU) { if (dfu_enter_recovery(ipsw, tss) < 0) { error("ERROR: Unable to place device into recovery mode\n"); plist_free(buildmanifest); @@ -245,7 +249,7 @@ int main(int argc, char* argv[]) { } // if the device is in recovery mode, place device into restore mode - if (idevicerestore_mode == RECOVERY_MODE) { + if (idevicerestore_mode == MODE_RECOVERY) { if (recovery_enter_restore(uuid, ipsw, tss) < 0) { error("ERROR: Unable to place device into restore mode\n"); plist_free(buildmanifest); @@ -256,7 +260,7 @@ int main(int argc, char* argv[]) { } // device is finally in restore mode, let's do this - if (idevicerestore_mode == RESTORE_MODE) { + if (idevicerestore_mode == MODE_RESTORE) { info("Restoring device... \n"); if (restore_device(uuid, ipsw, tss, filesystem) < 0) { error("ERROR: Unable to restore device\n"); @@ -265,7 +269,7 @@ int main(int argc, char* argv[]) { } // device has finished restoring, lets see if we need to activate - if (idevicerestore_mode == NORMAL_MODE) { + if (idevicerestore_mode == MODE_NORMAL) { info("Checking activation status\n"); int activation = activate_check_status(uuid); if (activation < 0) { @@ -291,52 +295,60 @@ int main(int argc, char* argv[]) { } int check_mode(const char* uuid) { - idevicerestore_mode_t mode = UNKNOWN_MODE; - if (normal_check_mode(uuid) == 0) { - info("Found device in normal mode\n"); - mode = NORMAL_MODE; - } + int mode = MODE_UNKNOWN; - else if (recovery_check_mode() == 0) { + if (recovery_check_mode() == 0) { info("Found device in recovery mode\n"); - mode = RECOVERY_MODE; + mode = MODE_RECOVERY; } else if (dfu_check_mode() == 0) { info("Found device in DFU mode\n"); - mode = DFU_MODE; + mode = MODE_DFU; + } + + else if (normal_check_mode(uuid) == 0) { + info("Found device in normal mode\n"); + mode = MODE_NORMAL; } else if (restore_check_mode(uuid) == 0) { info("Found device in restore mode\n"); - mode = RESTORE_MODE; + mode = MODE_RESTORE; } return mode; } int check_device(const char* uuid) { + int device = DEVICE_UNKNOWN; uint32_t bdid = 0; uint32_t cpid = 0; - idevicerestore_device_t device = UNKNOWN_DEVICE; switch (idevicerestore_mode) { - case NORMAL_MODE: + case MODE_RESTORE: + device = restore_check_device(uuid); + if (device < 0) { + device = DEVICE_UNKNOWN; + } + break; + + case MODE_NORMAL: device = normal_check_device(uuid); if (device < 0) { - device = UNKNOWN_DEVICE; + device = DEVICE_UNKNOWN; } break; - case DFU_MODE: - case RECOVERY_MODE: + case MODE_DFU: + case MODE_RECOVERY: if (get_cpid(uuid, &cpid) < 0) { error("ERROR: Unable to get device CPID\n"); break; } switch (cpid) { - case IPHONE2G_CPID: + case CPID_IPHONE2G: // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID // so we need to check the BoardID if (get_bdid(uuid, &bdid) < 0) { @@ -345,48 +357,48 @@ int check_device(const char* uuid) { } switch (bdid) { - case IPHONE2G_BDID: - device = IPHONE2G_DEVICE; + case BDID_IPHONE2G: + device = DEVICE_IPHONE2G; break; - case IPHONE3G_BDID: - device = IPHONE3G_DEVICE; + case BDID_IPHONE3G: + device = DEVICE_IPHONE3G; break; - case IPOD1G_BDID: - device = IPOD1G_DEVICE; + case BDID_IPOD1G: + device = DEVICE_IPOD1G; break; default: - device = UNKNOWN_DEVICE; + device = DEVICE_UNKNOWN; break; } break; - case IPHONE3GS_CPID: - device = IPHONE3GS_DEVICE; + case CPID_IPHONE3GS: + device = DEVICE_IPHONE3GS; break; - case IPOD2G_CPID: - device = IPOD2G_DEVICE; + case CPID_IPOD2G: + device = DEVICE_IPOD2G; break; - case IPOD3G_CPID: - device = IPOD3G_DEVICE; + case CPID_IPOD3G: + device = DEVICE_IPOD3G; break; - case IPAD1G_CPID: - device = IPAD1G_DEVICE; + case CPID_IPAD1G: + device = DEVICE_IPAD1G; break; default: - device = UNKNOWN_DEVICE; + device = DEVICE_UNKNOWN; break; } break; default: - device = UNKNOWN_MODE; + device = DEVICE_UNKNOWN; break; } @@ -396,15 +408,15 @@ int check_device(const char* uuid) { int get_bdid(const char* uuid, uint32_t* bdid) { switch (idevicerestore_mode) { - case NORMAL_MODE: + case MODE_NORMAL: if (normal_get_bdid(uuid, bdid) < 0) { *bdid = -1; return -1; } break; - case DFU_MODE: - case RECOVERY_MODE: + case MODE_DFU: + case MODE_RECOVERY: if (recovery_get_bdid(bdid) < 0) { *bdid = -1; return -1; @@ -421,15 +433,15 @@ int get_bdid(const char* uuid, uint32_t* bdid) { int get_cpid(const char* uuid, uint32_t* cpid) { switch (idevicerestore_mode) { - case NORMAL_MODE: + case MODE_NORMAL: if (normal_get_cpid(uuid, cpid) < 0) { *cpid = 0; return -1; } break; - case DFU_MODE: - case RECOVERY_MODE: + case MODE_DFU: + case MODE_RECOVERY: if (recovery_get_cpid(cpid) < 0) { *cpid = 0; return -1; @@ -446,15 +458,15 @@ int get_cpid(const char* uuid, uint32_t* cpid) { int get_ecid(const char* uuid, uint64_t* ecid) { switch (idevicerestore_mode) { - case NORMAL_MODE: + case MODE_NORMAL: if (normal_get_ecid(uuid, ecid) < 0) { *ecid = 0; return -1; } break; - case DFU_MODE: - case RECOVERY_MODE: + case MODE_DFU: + case MODE_RECOVERY: if (recovery_get_ecid(ecid) < 0) { *ecid = 0; return -1; @@ -472,13 +484,14 @@ int get_ecid(const char* uuid, uint64_t* ecid) { int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { int size = 0; char* data = NULL; - if (idevicerestore_device >= IPHONE2G_DEVICE && idevicerestore_device <= IPOD2G_DEVICE) { + int device = idevicerestore_device->device_id; + if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) { // Older devices that don't require personalized firmwares use BuildManifesto.plist if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) { return -1; } - } else if (idevicerestore_device >= IPHONE3GS_DEVICE && idevicerestore_device <= IPAD1G_DEVICE) { + } else if (device >= DEVICE_IPHONE3GS && device <= DEVICE_IPAD1G) { // Whereas newer devices that do require personalized firmwares use BuildManifest.plist if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { return -1; @@ -602,7 +615,7 @@ int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, return -1; } - if (idevicerestore_device > IPOD2G_DEVICE && idevicerestore_custom == 0) { + if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { if (img3_replace_signature(img3, component_blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); free(component_blob); diff --git a/src/idevicerestore.h b/src/idevicerestore.h index adea68e..af66892 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -29,60 +29,66 @@ #define error(...) fprintf(stderr, __VA_ARGS__) #define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) -#define IPHONE2G_CPID 8900 -#define IPHONE3G_CPID 8900 -#define IPHONE3GS_CPID 8920 -#define IPOD1G_CPID 8900 -#define IPOD2G_CPID 8720 -#define IPOD3G_CPID 8922 -#define IPAD1G_CPID 8930 +#define MODE_UNKNOWN -1 +#define MODE_DFU 0 +#define MODE_RECOVERY 1 +#define MODE_RESTORE 2 +#define MODE_NORMAL 3 -#define IPHONE2G_BDID 0 -#define IPHONE3G_BDID 4 -#define IPHONE3GS_BDID 0 -#define IPOD1G_BDID 2 -#define IPOD2G_BDID 0 -#define IPOD3G_BDID 2 -#define IPAD1G_BDID 2 +#define CPID_UNKNOWN -1 +#define CPID_IPHONE2G 8900 +#define CPID_IPOD1G 8900 +#define CPID_IPHONE3G 8900 +#define CPID_IPOD2G 8720 +#define CPID_IPHONE3GS 8920 +#define CPID_IPOD3G 8922 +#define CPID_IPAD1G 8930 -typedef enum { - UNKNOWN_MODE = -1, - DFU_MODE = 0, - RECOVERY_MODE = 1, - RESTORE_MODE = 2, - NORMAL_MODE = 3, -} idevicerestore_mode_t; +#define BDID_UNKNOWN -1 +#define BDID_IPHONE2G 0 +#define BDID_IPOD1G 2 +#define BDID_IPHONE3G 4 +#define BDID_IPOD2G 0 +#define BDID_IPHONE3GS 0 +#define BDID_IPOD3G 2 +#define BDID_IPAD1G 2 -typedef enum { - UNKNOWN_DEVICE = -1, - IPHONE2G_DEVICE = 0, - IPHONE3G_DEVICE = 1, - IPOD1G_DEVICE = 2, - IPOD2G_DEVICE = 3, - IPHONE3GS_DEVICE = 4, - IPOD3G_DEVICE = 5, - IPAD1G_DEVICE = 6 +#define DEVICE_UNKNOWN -1 +#define DEVICE_IPHONE2G 0 +#define DEVICE_IPOD1G 1 +#define DEVICE_IPHONE3G 2 +#define DEVICE_IPOD2G 3 +#define DEVICE_IPHONE3GS 4 +#define DEVICE_IPOD3G 5 +#define DEVICE_IPAD1G 6 + +typedef struct { + int device_id; + const char* product; + const char* model; + int board_id; + int chip_id; } idevicerestore_device_t; -static char* idevicerestore_products[] = { - "iPhone1,1", - "iPhone1,2", - "iPhone2,1", - "iPod1,1", - "iPod2,1", - "iPod3,1", - "iPad1,1", - NULL +static idevicerestore_device_t idevicerestore_devices[] = { + { 0, "iPhone1,1", "M68AP", 0, 8900 }, + { 1, "iPod1,1", "N45AP", 2, 8900 }, + { 2, "iPhone1,2", "N82AP", 4, 8900 }, + { 3, "iPod2,1", "N72AP", 0, 8720 }, + { 4, "iPhone2,1", "N88AP", 0, 8920 }, + { 5, "iPod3,1", "N18AP", 2, 8922 }, + { 6, "iPad1,1", "K48AP", 2, 8930 }, + { -1, NULL, NULL, -1, -1 } }; +extern int idevicerestore_mode; extern int idevicerestore_quit; extern int idevicerestore_debug; extern int idevicerestore_erase; extern int idevicerestore_custom; extern int idevicerestore_exclude; extern int idevicerestore_verbose; -extern idevicerestore_mode_t idevicerestore_mode; -extern idevicerestore_device_t idevicerestore_device; +extern idevicerestore_device_t* idevicerestore_device; int check_mode(const char* uuid); int check_device(const char* uuid); @@ -97,5 +103,12 @@ int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); +inline static void debug_plist(plist_t plist) { + int size = 0; + char* data = NULL; + plist_to_xml(plist, &data, &size); + debug("%s", data); + free(data); +} #endif diff --git a/src/normal.c b/src/normal.c index ab9216c..b9270d8 100644 --- a/src/normal.c +++ b/src/normal.c @@ -62,6 +62,7 @@ int normal_check_mode(const char* uuid) { } int normal_check_device(const char* uuid) { + int i = 0; idevice_t device = NULL; char* product_type = NULL; plist_t product_type_node = NULL; @@ -87,30 +88,25 @@ int normal_check_device(const char* uuid) { return -1; } + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; + if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) { - if (product_type_node) - plist_free(product_type_node); - lockdownd_client_free(lockdown); - idevice_free(device); + if (product_type_node) plist_free(product_type_node); return -1; } plist_get_string_val(product_type_node, &product_type); plist_free(product_type_node); - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; - - int i = 0; - for (i = 0; idevicerestore_products[i] != NULL; i++) { - if (!strcmp(product_type, idevicerestore_products[i])) { - idevicerestore_device = i; + for (i = 0; idevicerestore_devices[i].product != NULL; i++) { + if (!strcmp(product_type, idevicerestore_devices[i].product)) { break; } } - return idevicerestore_device; + return idevicerestore_devices[i].device_id; } int normal_enter_recovery(const char* uuid) { @@ -166,7 +162,7 @@ int normal_enter_recovery(const char* uuid) { return -1; } - idevicerestore_mode = RECOVERY_MODE; + idevicerestore_mode = MODE_RECOVERY; irecv_close(recovery); recovery = NULL; return 0; diff --git a/src/recovery.c b/src/recovery.c index a0a1151..e67b10d 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -132,15 +132,15 @@ int recovery_open_with_timeout(irecv_client_t* client) { int i = 0; int attempts = 10; irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; + irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; for (i = 1; i <= attempts; i++) { - recovery_error = irecv_open(client); + recovery_error = irecv_open(&recovery); if (recovery_error == IRECV_E_SUCCESS) { break; } - if (i == attempts) { + if (i >= attempts) { error("ERROR: Unable to connect to device in recovery mode\n"); return -1; } diff --git a/src/restore.c b/src/restore.c index ce9d41b..46a509a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -80,6 +80,64 @@ int restore_check_mode(const char* uuid) { return 0; } +int restore_check_device(const char* uuid) { + int i = 0; + char* type = NULL; + char* model = NULL; + plist_t node = NULL; + uint64_t version = 0; + idevice_t device = NULL; + restored_client_t restore = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + restored_error_t restore_error = RESTORE_E_SUCCESS; + + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + restore_error = restored_client_new(device, &restore, "idevicerestore"); + if (restore_error != RESTORE_E_SUCCESS) { + idevice_free(device); + return -1; + } + + restore_error = restored_query_type(restore, &type, &version); + if (restore_error != RESTORE_E_SUCCESS) { + restored_client_free(restore); + idevice_free(device); + return -1; + } + + restore_error = restored_get_value(restore, "HardwareModel", &node); + if(restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to get HardwareModel from restored\n"); + restored_client_free(restore); + idevice_free(device); + return -1; + } + + restored_client_free(restore); + idevice_free(device); + restore = NULL; + device = NULL; + + if (!node || plist_get_node_type(node) != PLIST_STRING) { + error("ERROR: Unable to get HardwareModel information\n"); + if(node) plist_free(node); + return -1; + } + plist_get_string_val(node, &model); + + for(i = 0; idevicerestore_devices[i].model != NULL; i++) { + if(!strcasecmp(model, idevicerestore_devices[i].model)) { + break; + } + } + + return idevicerestore_devices[i].device_id; +} + void restore_device_callback(const idevice_event_t* event, void* user_data) { if (event->event == IDEVICE_DEVICE_ADD) { restore_device_connected = 1; diff --git a/src/restore.h b/src/restore.h index 99ba80b..6614355 100644 --- a/src/restore.h +++ b/src/restore.h @@ -27,6 +27,7 @@ #include int restore_check_mode(const char* uuid); +int restore_check_device(const char* uuid); const char* restore_progress_string(unsigned int operation); void restore_close(idevice_t device, restored_client_t restore); int restore_handle_status_msg(restored_client_t client, plist_t msg); -- cgit v1.1-32-gdbae From a274554b753880dd7042b6013d0158a0b81124c7 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 7 Jun 2010 14:24:08 +0800 Subject: I really need to put more descriptive messages here, but im doing stuff all over the place --- src/idevicerestore.c | 7 ++++--- src/idevicerestore.h | 14 ++++++++++++++ src/ipsw.c | 8 ++++++-- src/recovery.c | 11 ++++++++++- src/restore.c | 2 +- 5 files changed, 35 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 0e77447..a1faeac 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -137,11 +137,12 @@ int main(int argc, char* argv[]) { } // discover the device type - idevicerestore_device = check_device(uuid); - if (idevicerestore_device < 0) { + int id = check_device(uuid); + if (id < 0) { error("ERROR: Unable to discover device type\n"); return -1; } + idevicerestore_device = &idevicerestore_devices[id]; // extract buildmanifest plist_t buildmanifest = NULL; @@ -178,7 +179,7 @@ int main(int argc, char* argv[]) { // devices that come after iPod2g require personalized firmwares plist_t tss_request = NULL; plist_t tss = NULL; - if (idevicerestore_device > DEVICE_IPOD2G) { + if (idevicerestore_device->device_id > DEVICE_IPOD2G) { info("Creating TSS request\n"); // fetch the device's ECID for the TSS request if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index af66892..f92aad2 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -111,4 +111,18 @@ inline static void debug_plist(plist_t plist) { free(data); } +inline static void print_progress_bar(const char* operation, double progress) { + int i = 0; + if(progress < 0) return; + if(progress > 100) progress = 100; + info("\r%s [", operation); + for(i = 0; i < 50; i++) { + if(i < progress / 2) info("="); + else info(" "); + } + info("] %3.1f%%", progress); + if(progress == 100) info("\n"); + fflush(stdout); +} + #endif diff --git a/src/ipsw.c b/src/ipsw.c index 6c5d504..7ded33e 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -95,7 +95,9 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi int i = 0; int size = 0; + int bytes = 0; int count = 0; + double progress = 0; for (i = zstat.size; i > 0; i -= count) { if (i < BUFSIZE) size = i; @@ -109,9 +111,11 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi return -1; } fwrite(buffer, 1, count, fd); - debug("."); + + bytes += size; + progress = ((double) bytes/ (double) zstat.size) * 100.0; + print_progress_bar("Extracting", progress); } - debug("\n"); fclose(fd); zip_fclose(zfile); diff --git a/src/recovery.c b/src/recovery.c index e67b10d..52f4802 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -31,6 +31,13 @@ #include "recovery.h" #include "idevicerestore.h" +int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { + if (event->type == IRECV_PROGRESS) { + print_progress_bar(event->data, event->progress); + } + return 0; +} + int recovery_check_mode() { irecv_client_t recovery = NULL; irecv_error_t recovery_error = IRECV_E_SUCCESS; @@ -92,8 +99,9 @@ int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { error("ERROR: Unable to connect to device in restore mode\n"); return -1; } - restore_close(device, restore); + restore_close(device, restore); + idevicerestore_mode = MODE_RESTORE; return 0; } @@ -149,6 +157,7 @@ int recovery_open_with_timeout(irecv_client_t* client) { debug("Retrying connection...\n"); } + irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); *client = recovery; return 0; } diff --git a/src/restore.c b/src/restore.c index 46a509a..b5eea66 100644 --- a/src/restore.c +++ b/src/restore.c @@ -208,7 +208,7 @@ void restore_close(idevice_t device, restored_client_t restore) { restored_client_free(restore); if (device) idevice_free(device); - idevice_event_unsubscribe(); + //idevice_event_unsubscribe(); } const char* restore_progress_string(unsigned int operation) { -- cgit v1.1-32-gdbae From 7d6207c33c44648cf9056ddd31ce51ac834563ab Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 7 Jun 2010 17:17:30 +0800 Subject: More small fixes and updated the TODO list --- src/idevicerestore.c | 9 ++++++++- src/idevicerestore.h | 7 ++++--- src/restore.h | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/idevicerestore.c b/src/idevicerestore.c index a1faeac..cc97e2c 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -144,6 +144,13 @@ int main(int argc, char* argv[]) { } idevicerestore_device = &idevicerestore_devices[id]; + if (idevicerestore_mode == MODE_RESTORE) { + if (restore_reboot(uuid) < 0) { + error("ERROR: Unable to exit restore mode\n"); + return -1; + } + } + // extract buildmanifest plist_t buildmanifest = NULL; info("Extracting BuildManifest from IPSW\n"); @@ -590,7 +597,7 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst return 0; } -int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { img3_file* img3 = NULL; uint32_t component_size = 0; char* component_data = NULL; diff --git a/src/idevicerestore.h b/src/idevicerestore.h index f92aad2..e4186c9 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -1,5 +1,5 @@ /* - * idevicerestore.g + * idevicerestore.h * Restore device firmware and filesystem * * Copyright (c) 2010 Joshua Hill. All Rights Reserved. @@ -22,7 +22,8 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H -#include +#include +#include #include #define info(...) printf(__VA_ARGS__) @@ -101,7 +102,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); int write_file(const char* filename, const void* data, size_t size); int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); +int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); inline static void debug_plist(plist_t plist) { int size = 0; diff --git a/src/restore.h b/src/restore.h index 6614355..7a2e27e 100644 --- a/src/restore.h +++ b/src/restore.h @@ -26,6 +26,7 @@ #include #include +int restore_reboot(const char* uuid); int restore_check_mode(const char* uuid); int restore_check_device(const char* uuid); const char* restore_progress_string(unsigned int operation); -- cgit v1.1-32-gdbae From 02773da6a2daa0d00780cac4707917360b81b6c9 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 16:14:29 +0800 Subject: Added a new asr.c file to stick all stuff related to filesystem and abstract the restore process to allow for easier porting --- src/Makefile.am | 2 +- src/asr.c | 275 ++++++++++++++++++++++++++++++ src/asr.h | 35 ++++ src/idevicerestore.c | 62 +++++-- src/idevicerestore.h | 29 +++- src/ipsw.c | 2 +- src/restore.c | 464 ++++++++++++++++++++++----------------------------- src/restore.h | 2 +- 8 files changed, 587 insertions(+), 284 deletions(-) create mode 100644 src/asr.c create mode 100644 src/asr.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index b641d00..a44640f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c +idevicerestore_SOURCES = idevicerestore.c dfu.c asr.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file diff --git a/src/asr.c b/src/asr.c new file mode 100644 index 0000000..658f03f --- /dev/null +++ b/src/asr.c @@ -0,0 +1,275 @@ +/* + * dfu.h + * Functions for handling idevices in normal mode + * + * Copyright (c) 2010 Joshua Hill. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "asr.h" +#include "idevicerestore.h" + +#define ASR_PORT 12345 +#define ASR_BUFFER_SIZE 65536 + +int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr) { + int i = 0; + int attempts = 10; + idevice_connection_t connection = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + + *asr = NULL; + + if (device == NULL) { + return -1; + } + + debug("Connecting to ASR\n"); + for (i = 1; i <= attempts; i++) { + device_error = idevice_connect(device, ASR_PORT, &connection); + if (device_error == IDEVICE_E_SUCCESS) { + break; + } + + if (i >= attempts) { + error("ERROR: Unable to connect to ASR client\n"); + return -1; + } + + sleep(2); + debug("Retrying connection...\n"); + } + + *asr = connection; + return 0; +} + +int asr_receive(idevice_connection_t asr, plist_t* data) { + uint32_t size = 0; + char* buffer = NULL; + plist_t request = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + + *data = NULL; + + buffer = (char*) malloc(ASR_BUFFER_SIZE); + if (buffer == NULL) { + error("ERROR: Unable to allocate memory for ASR receive buffer\n"); + return -1; + } + memset(buffer, '\0', ASR_BUFFER_SIZE); + + device_error = idevice_connection_receive(asr, buffer, ASR_BUFFER_SIZE, &size); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to receive data from ASR\n"); + free(buffer); + return -1; + } + plist_from_xml(buffer, size, &request); + + *data = request; + + debug("Received %d bytes:\n%s\n", size, buffer); + free(buffer); + return 0; +} + +int asr_send(idevice_connection_t asr, plist_t* data) { + uint32_t size = 0; + char* buffer = NULL; + + plist_to_xml(data, &buffer, &size); + if (asr_send_buffer(asr, buffer, size) < 0) { + error("ERROR: Unable to send plist to ASR\n"); + free(buffer); + return -1; + } + + free(buffer); + return 0; +} + +int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size) { + uint32_t bytes = 0; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + + device_error = idevice_connection_send(asr, data, size, &bytes); + if (device_error != IDEVICE_E_SUCCESS || bytes != size) { + error("ERROR: Unable to send data to ASR\n"); + return -1; + } + + debug("Sent %d bytes:\n%s", bytes, data); + return 0; +} + +void asr_close(idevice_connection_t asr) { + if (asr != NULL) { + idevice_disconnect(asr); + asr = NULL; + } +} + +int asr_perform_validation(idevice_connection_t asr, const char* filesystem) { + FILE* file = NULL; + uint64_t length = 0; + char* command = NULL; + plist_t node = NULL; + plist_t packet = NULL; + plist_t packet_info = NULL; + plist_t payload_info = NULL; + + file = fopen(filesystem, "rb"); + if (file == NULL) { + return -1; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, 0, SEEK_SET); + + payload_info = plist_new_dict(); + plist_dict_insert_item(payload_info, "Port", plist_new_uint(1)); + plist_dict_insert_item(payload_info, "Size", plist_new_uint(length)); + + packet_info = plist_new_dict(); + plist_dict_insert_item(packet_info, "FEC Slice Stride", plist_new_uint(40)); + plist_dict_insert_item(packet_info, "Packet Payload Size", plist_new_uint(1450)); + plist_dict_insert_item(packet_info, "Packets Per FEC", plist_new_uint(25)); + plist_dict_insert_item(packet_info, "Payload", payload_info); + plist_dict_insert_item(packet_info, "Stream ID", plist_new_uint(1)); + plist_dict_insert_item(packet_info, "Version", plist_new_uint(1)); + + if (asr_send(asr, packet_info)) { + error("ERROR: Unable to sent packet information to ASR\n"); + plist_free(packet_info); + return -1; + } + plist_free(packet_info); + + char* oob_data = NULL; + uint64_t oob_offset = 0; + uint64_t oob_length = 0; + plist_t oob_length_node = NULL; + plist_t oob_offset_node = NULL; + do { + if (asr_receive(asr, &packet) < 0) { + error("ERROR: Unable to receive validation packet\n"); + return -1; + } + + node = plist_dict_get_item(packet, "Command"); + if (!node || plist_get_node_type(node) != PLIST_STRING) { + error("ERROR: Unable to find command node in validation request\n"); + return -1; + } + plist_get_string_val(node, &command); + + if (!strcmp(command, "OOBData")) { + oob_length_node = plist_dict_get_item(packet, "OOB Length"); + if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { + error("ERROR: Unable to find OOB data length\n"); + return -1; + } + plist_get_uint_val(oob_length_node, &oob_length); + + oob_offset_node = plist_dict_get_item(packet, "OOB Offset"); + if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { + error("ERROR: Unable to find OOB data offset\n"); + return -1; + } + plist_get_uint_val(oob_offset_node, &oob_offset); + + oob_data = (char*) malloc(oob_length); + if (oob_data == NULL) { + error("ERROR: Out of memory\n"); + plist_free(packet); + return -1; + } + + fseek(file, oob_offset, SEEK_SET); + if (fread(oob_data, 1, oob_length, file) != oob_length) { + error("ERROR: Unable to read OOB data from filesystem offset\n"); + plist_free(packet); + free(oob_data); + return -1; + } + + if (asr_send_buffer(asr, oob_data, oob_length) < 0) { + error("ERROR: Unable to send OOB data to ASR\n"); + plist_free(packet); + free(oob_data); + return -1; + } + + plist_free(packet); + free(oob_data); + + } + + } while (strcmp(packet, "Payload")); +} + +int asr_send_payload(idevice_connection_t asr, const char* filesystem) { + int i = 0; + char data[1450]; + FILE* file = NULL; + uint32_t bytes = 0; + uint32_t count = 0; + uint32_t length = 0; + double progress = 0; + + file = fopen(filesystem, "rb"); + if (file == NULL) { + return -1; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, 0, SEEK_SET); + + for(i = length; i > 0; i -= 1450) { + int size = 1450; + if (i < 1450) { + size = i; + } + + if (fread(data, 1, size, file) != (unsigned int) size) { + error("Error reading filesystem\n"); + fclose(file); + return -1; + } + + if (asr_send_buffer(asr, data, size) < 0) { + error("ERROR: Unable to send filesystem payload\n"); + fclose(file); + return -1; + } + + bytes += size; + progress = ((double) bytes/ (double) length) * 100.0; + print_progress_bar("Extracting", progress); + + } + + fclose(file); + return 0; +} diff --git a/src/asr.h b/src/asr.h new file mode 100644 index 0000000..151c1d0 --- /dev/null +++ b/src/asr.h @@ -0,0 +1,35 @@ +/* + * dfu.h + * Functions for handling idevices in normal mode + * + * Copyright (c) 2010 Joshua Hill. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IDEVICERESTORE_ASR_H +#define IDEVICERESTORE_ASR_H + +#include + +int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr); +int asr_send(idevice_connection_t asr, plist_t* data); +int asr_receive(idevice_connection_t asr, plist_t* data); +int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size); +void asr_close(idevice_connection_t asr); +int asr_perform_validation(idevice_connection_t asr, const char* filesystem); +int asr_send_payload(idevice_connection_t asr, const char* filesystem); + +#endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index cc97e2c..69363fb 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -602,23 +602,28 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** uint32_t component_size = 0; char* component_data = NULL; char* component_blob = NULL; + char* component_name = NULL; - info("Extracting %s from %s\n", path, ipsw); + component_name = strrchr(path, '/'); + if (component_name != NULL) component_name++; + else component_name = (char*) path; + + info("Extracting %s\n", component_name); if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", path, ipsw); + error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); return -1; } img3 = img3_parse_file(component_data, component_size); if (img3 == NULL) { - error("ERROR: Unable to parse IMG3: %s\n", path); + error("ERROR: Unable to parse IMG3: %s\n", component_name); free(component_data); return -1; } free(component_data); if (tss_get_blob_by_path(tss, path, &component_blob) < 0) { - error("ERROR: Unable to get SHSH blob for TSS %s entry\n", path); + error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name); img3_free(img3); return -1; } @@ -641,13 +646,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** img3_free(img3); if (idevicerestore_debug) { - char* out = strrchr(path, '/'); - if (out != NULL) { - out++; - } else { - out = (char*) path; - } - write_file(out, component_data, component_size); + write_file(component_name, component_data, component_size); } *data = component_data; @@ -676,3 +675,44 @@ int write_file(const char* filename, const void* data, size_t size) { return size; } + +int read_file(const char* filename, char** data, uint32_t* size) { + size_t bytes = 0; + size_t length = 0; + FILE* file = NULL; + char* buffer = NULL; + debug("Reading data from %s\n", filename); + + *size = 0; + *data = NULL; + + file = fopen(filename, "rb"); + if (file == NULL) { + error("read_file: File %s not found\n", filename); + return -1; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + rewind(file); + + buffer = (char*) malloc(length); + if(buffer == NULL) { + error("ERROR: Out of memory\n"); + fclose(file); + return -1; + } + bytes = fread(buffer, 1, length, file); + fclose(file); + + if(bytes != length) { + error("ERROR: Unable to read entire file\n"); + free(buffer); + return -1; + } + + *size = length; + *data = buffer; + return 0; +} + diff --git a/src/idevicerestore.h b/src/idevicerestore.h index e4186c9..20578a9 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -63,6 +63,16 @@ #define DEVICE_IPOD3G 5 #define DEVICE_IPAD1G 6 +typedef struct idevicerestore_entry { + char* name; + char* path; + char* filename; + char* blob_data; + uint32_t blob_size; + struct idevicerestore_entry* next; + struct idevicerestore_entry* prev; +} idevicerestore_entry_t; + typedef struct { int device_id; const char* product; @@ -70,7 +80,21 @@ typedef struct { int board_id; int chip_id; } idevicerestore_device_t; - +/* +typedef struct { + int mode; + idevice_t device; + irecv_client_t recovery; + restored_client_t restore; + lockdownd_client_t lockdown; + int erase; // 1 + int custom; // 2 + int exclude; // 4 + int verbose; // 8 + idevicerestore_device_t* idevicerestore_device; + idevicerestore_entry_t** entries; +} idevicerestore_context_t; +*/ static idevicerestore_device_t idevicerestore_devices[] = { { 0, "iPhone1,1", "M68AP", 0, 8900 }, { 1, "iPod1,1", "N45AP", 2, 8900 }, @@ -79,6 +103,7 @@ static idevicerestore_device_t idevicerestore_devices[] = { { 4, "iPhone2,1", "N88AP", 0, 8920 }, { 5, "iPod3,1", "N18AP", 2, 8922 }, { 6, "iPad1,1", "K48AP", 2, 8930 }, + { 6, "iPhone4,1", "XXXAP", 0, 0 }, { -1, NULL, NULL, -1, -1 } }; @@ -90,6 +115,7 @@ extern int idevicerestore_custom; extern int idevicerestore_exclude; extern int idevicerestore_verbose; extern idevicerestore_device_t* idevicerestore_device; +extern idevicerestore_entry_t** idevicerestore_entries; int check_mode(const char* uuid); int check_device(const char* uuid); @@ -100,6 +126,7 @@ int get_cpid(const char* uuid, uint32_t* cpid); int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); int write_file(const char* filename, const void* data, size_t size); +int read_file(const char* filename, char** data, uint32_t* size); int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); diff --git a/src/ipsw.c b/src/ipsw.c index 7ded33e..adbaea0 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -98,7 +98,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi int bytes = 0; int count = 0; double progress = 0; - for (i = zstat.size; i > 0; i -= count) { + for(i = zstat.size; i > 0; i -= count) { if (i < BUFSIZE) size = i; else diff --git a/src/restore.c b/src/restore.c index b5eea66..fc22b75 100644 --- a/src/restore.c +++ b/src/restore.c @@ -24,12 +24,11 @@ #include #include +#include "asr.h" #include "tss.h" #include "restore.h" #include "idevicerestore.h" -#define ASR_PORT 12345 - #define CREATE_PARTITION_MAP 12 #define CREATE_FILESYSTEM 13 #define RESTORE_IMAGE 14 @@ -110,7 +109,7 @@ int restore_check_device(const char* uuid) { } restore_error = restored_get_value(restore, "HardwareModel", &node); - if(restore_error != RESTORE_E_SUCCESS) { + if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to get HardwareModel from restored\n"); restored_client_free(restore); idevice_free(device); @@ -124,13 +123,14 @@ int restore_check_device(const char* uuid) { if (!node || plist_get_node_type(node) != PLIST_STRING) { error("ERROR: Unable to get HardwareModel information\n"); - if(node) plist_free(node); + if (node) + plist_free(node); return -1; } plist_get_string_val(node, &model); - for(i = 0; idevicerestore_devices[i].model != NULL; i++) { - if(!strcasecmp(model, idevicerestore_devices[i].model)) { + for (i = 0; idevicerestore_devices[i].model != NULL; i++) { + if (!strcasecmp(model, idevicerestore_devices[i].model)) { break; } } @@ -147,11 +147,31 @@ void restore_device_callback(const idevice_event_t* event, void* user_data) { } } +int restore_reboot(const char* uuid) { + idevice_t device = NULL; + restored_client_t restore = NULL; + restored_error_t restore_error = RESTORE_E_SUCCESS; + if (restore_open_with_timeout(uuid, &device, &restore) < 0) { + error("ERROR: Unable to open device in restore mode\n"); + return -1; + } + + restore_error = restored_reboot(restore); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to reboot the device from restore mode\n"); + restore_close(device, restore); + return -1; + } + + restore_close(device, restore); + restore = NULL; + device = NULL; + return 0; +} + int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) { int i = 0; - int attempt = 10; - char* type = NULL; - uint64_t version = 0; + int attempts = 10; idevice_t context = NULL; restored_client_t client = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; @@ -166,12 +186,12 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie return -1; } - for (i = 1; i <= attempt; i++) { + for (i = 1; i <= attempts; i++) { if (restore_device_connected == 1) { break; } - if (i == attempt) { + if (i == attempts) { error("ERROR: Unable to connect to device in restore mode\n"); } @@ -190,7 +210,7 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie return -1; } - restore_error = restored_query_type(client, &type, &version); + restore_error = restored_query_type(client, NULL, NULL); if (restore_error != RESTORE_E_SUCCESS) { restored_client_free(client); idevice_event_unsubscribe(); @@ -208,7 +228,6 @@ void restore_close(idevice_t device, restored_client_t restore) { restored_client_free(restore); if (device) idevice_free(device); - //idevice_event_unsubscribe(); } const char* restore_progress_string(unsigned int operation) { @@ -262,202 +281,83 @@ const char* restore_progress_string(unsigned int operation) { int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_t node = NULL; - uint64_t operation = 0; - uint64_t uprogress = 0; uint64_t progress = 0; + uint64_t operation = 0; node = plist_dict_get_item(msg, "Operation"); - if (node && PLIST_UINT == plist_get_node_type(node)) { - plist_get_uint_val(node, &operation); - } else { + if (!node || plist_get_node_type(node) != PLIST_UINT) { debug("Failed to parse operation from ProgressMsg plist\n"); - return 0; + return -1; } + plist_get_uint_val(node, &operation); node = plist_dict_get_item(msg, "Progress"); - if (node && PLIST_UINT == plist_get_node_type(node)) { - plist_get_uint_val(node, &uprogress); - progress = uprogress; - } else { + if (!node || plist_get_node_type(node) != PLIST_UINT) { debug("Failed to parse progress from ProgressMsg plist \n"); - return 0; + return -1; } + plist_get_uint_val(node, &progress); + + if ((progress > 0) && (progress < 100)) { + print_progress_bar(restore_progress_string(operation), (double) progress); - if ((progress > 0) && (progress < 100)) - info("%s - Progress: %llu%%\n", restore_progress_string(operation), progress); - else + } else { info("%s\n", restore_progress_string(operation)); + } return 0; } int restore_handle_status_msg(restored_client_t client, plist_t msg) { info("Got status message\n"); + debug_plist(msg); return 0; } -int restore_send_filesystem(idevice_t device, restored_client_t client, const char* filesystem) { +int restore_send_filesystem(idevice_t device, const char* filesystem) { int i = 0; - char buffer[0x1000]; - uint32_t recv_bytes = 0; - memset(buffer, '\0', 0x1000); - idevice_connection_t connection = NULL; - idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; - - for (i = 0; i < 5; i++) { - ret = idevice_connect(device, ASR_PORT, &connection); - if (ret == IDEVICE_E_SUCCESS) - break; + FILE* file = NULL; + plist_t data = NULL; + idevice_connection_t asr = NULL; + idevice_error_t device_error = IDEVICE_E_UNKNOWN_ERROR; - else - sleep(1); - } - - if (ret != IDEVICE_E_SUCCESS) - return ret; - - memset(buffer, '\0', 0x1000); - ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); - if (ret != IDEVICE_E_SUCCESS) { - idevice_disconnect(connection); - return ret; - } - info("Received %d bytes\n", recv_bytes); - info("%s", buffer); - - FILE* fd = fopen(filesystem, "rb"); - if (fd == NULL) { - idevice_disconnect(connection); - return ret; + if (asr_open_with_timeout(device, &asr) < 0) { + error("ERROR: Unable to connect to ASR\n"); + return -1; } - - fseek(fd, 0, SEEK_END); - uint64_t len = ftell(fd); - fseek(fd, 0, SEEK_SET); - info("Connected to ASR\n"); - plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40)); - plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450)); - plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25)); - - plist_t payload = plist_new_dict(); - plist_dict_insert_item(payload, "Port", plist_new_uint(1)); - plist_dict_insert_item(payload, "Size", plist_new_uint(len)); - plist_dict_insert_item(dict, "Payload", payload); - - plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1)); - plist_dict_insert_item(dict, "Version", plist_new_uint(1)); - char* xml = NULL; - unsigned int dict_size = 0; - unsigned int sent_bytes = 0; - plist_to_xml(dict, &xml, &dict_size); - - ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes); - if (ret != IDEVICE_E_SUCCESS) { - idevice_disconnect(connection); - return ret; + // we don't really need to do anything with this, + // we're just clearing the output buffer + if (asr_receive(asr, &data) < 0) { + error("ERROR: Unable to receive data from ASR\n"); + asr_close(asr); + return -1; } + plist_free(data); - info("Sent %d bytes\n", sent_bytes); - info("%s", xml); - plist_free(dict); - free(xml); - - char* command = NULL; - do { - memset(buffer, '\0', 0x1000); - ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); - if (ret != IDEVICE_E_SUCCESS) { - idevice_disconnect(connection); - return ret; - } - info("Received %d bytes\n", recv_bytes); - info("%s", buffer); - - plist_t request = NULL; - plist_from_xml(buffer, recv_bytes, &request); - plist_t command_node = plist_dict_get_item(request, "Command"); - if (command_node && PLIST_STRING == plist_get_node_type(command_node)) { - plist_get_string_val(command_node, &command); - if (!strcmp(command, "OOBData")) { - plist_t oob_length_node = plist_dict_get_item(request, "OOB Length"); - if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { - error("Error fetching OOB Length\n"); - idevice_disconnect(connection); - return IDEVICE_E_UNKNOWN_ERROR; - } - uint64_t oob_length = 0; - plist_get_uint_val(oob_length_node, &oob_length); - - plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset"); - if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { - error("Error fetching OOB Offset\n"); - idevice_disconnect(connection); - return IDEVICE_E_UNKNOWN_ERROR; - } - uint64_t oob_offset = 0; - plist_get_uint_val(oob_offset_node, &oob_offset); - - char* oob_data = (char*) malloc(oob_length); - if (oob_data == NULL) { - error("Out of memory\n"); - idevice_disconnect(connection); - return IDEVICE_E_UNKNOWN_ERROR; - } - - fseek(fd, oob_offset, SEEK_SET); - if (fread(oob_data, 1, oob_length, fd) != oob_length) { - error("Unable to read filesystem offset\n"); - idevice_disconnect(connection); - free(oob_data); - return ret; - } - - ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes); - if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) { - error("Unable to send %d bytes to asr\n", sent_bytes); - idevice_disconnect(connection); - free(oob_data); - return ret; - } - plist_free(request); - free(oob_data); - } - } - - } while (strcmp(command, "Payload")); - - fseek(fd, 0, SEEK_SET); - char data[1450]; - for (i = len; i > 0; i -= 1450) { - int size = 1450; - if (i < 1450) { - size = i; - } - - if (fread(data, 1, size, fd) != (unsigned int) size) { - fclose(fd); - idevice_disconnect(connection); - error("Error reading filesystem\n"); - return IDEVICE_E_UNKNOWN_ERROR; - } - - ret = idevice_connection_send(connection, data, size, &sent_bytes); - if (ret != IDEVICE_E_SUCCESS) { - fclose(fd); - } + // this step sends requested chunks of data from various offsets to asr so + // it can validate the filesystem before installing it + debug("Preparing to validate the filesystem\n"); + if (asr_perform_validation(asr, filesystem) < 0) { + error("ERROR: ASR was unable to validate the filesystem\n"); + asr_close(asr); + return -1; + } + info("Filesystem validated\n"); - if (i % (1450 * 1000) == 0) { - info("."); - } + // once the target filesystem has been validated, ASR then requests the + // entire filesystem to be sent. + debug("Preparing to send filesystem\n"); + if (asr_send_payload(asr, filesystem) < 0) { + error("ERROR: Unable to send payload to ASR\n"); + asr_close(asr); + return -1; } + info("Filesystem finished\n"); - info("Done sending filesystem\n"); - fclose(fd); - ret = idevice_disconnect(connection); - return ret; + asr_close(asr); + return 0; } int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) { @@ -550,11 +450,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { } plist_dict_insert_item(dict, "NorImageData", norimage_array); - int sz = 0; - char* xml = NULL; - plist_to_xml(dict, &xml, &sz); - debug("%s", xml); - free(xml); + debug_plist(dict); restored_error_t ret = restored_send(client, dict); if (ret != RESTORE_E_SUCCESS) { @@ -567,105 +463,135 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { return 0; } -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { - idevice_t device = NULL; - idevice_error_t device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to open device\n"); - plist_free(tss); - return -1; - } +int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { + char* type = NULL; + plist_t node = NULL; - restored_client_t restore = NULL; - restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to start restored client\n"); - plist_free(tss); - idevice_free(device); - return -1; + // checks and see what kind of data restored is requests and pass + // the request to its own handler + node = plist_dict_get_item(message, "DataType"); + if (node && PLIST_STRING == plist_get_node_type(node)) { + plist_get_string_val(node, &type); + + // this request is sent when restored is ready to receive the filesystem + if (!strcmp(type, "SystemImageData")) { + restore_send_filesystem(device, filesystem); + + } + + else if (!strcmp(type, "KernelCache")) { + int kernelcache_size = 0; + char* kernelcache_data = NULL; + char* kernelcache_path = NULL; + if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { + error("ERROR: Unable to find kernelcache path\n"); + return -1; + } + + if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { + error("ERROR: Unable to get kernelcache file\n"); + return -1; + } + restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); + free(kernelcache_data); + + } + + else if (!strcmp(type, "NORData")) { + restore_send_nor(restore, ipsw, tss); + + } else { + // Unknown DataType!! + debug("Unknown data request received\n"); + } } + return 0; +} +int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { + int error = 0; char* type = NULL; - uint64_t version = 0; - if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { - error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); - plist_free(tss); - restored_client_free(restore); - idevice_free(device); + char* kernel = NULL; + plist_t node = NULL; + plist_t message = NULL; + idevice_t device = NULL; + restored_client_t restore = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + restored_error_t restore_error = RESTORE_E_SUCCESS; + + // open our connection to the device and verify we're in restore mode + if (restore_open_with_timeout(uuid, &device, &restore) < 0) { + error("ERROR: Unable to open device in restore mode\n"); return -1; } info("Device has successfully entered restore mode\n"); - /* start restore process */ - char* kernelcache = NULL; - info("Restore protocol version is %llu.\n", version); + // start the restore process restore_error = restored_start_restore(restore); - if (restore_error == RESTORE_E_SUCCESS) { - while (!idevicerestore_quit) { - plist_t message = NULL; - restore_error = restored_receive(restore, &message); - plist_t msgtype_node = plist_dict_get_item(message, "MsgType"); - if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) { - char *msgtype = NULL; - plist_get_string_val(msgtype_node, &msgtype); - if (!strcmp(msgtype, "ProgressMsg")) { - restore_error = restore_handle_progress_msg(restore, message); - - } else if (!strcmp(msgtype, "DataRequestMsg")) { - // device is requesting data to be sent - plist_t datatype_node = plist_dict_get_item(message, "DataType"); - if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) { - char *datatype = NULL; - plist_get_string_val(datatype_node, &datatype); - if (!strcmp(datatype, "SystemImageData")) { - restore_send_filesystem(device, restore, filesystem); - - } else if (!strcmp(datatype, "KernelCache")) { - int kernelcache_size = 0; - char* kernelcache_data = NULL; - char* kernelcache_path = NULL; - if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { - error("ERROR: Unable to find kernelcache path\n"); - return -1; - } - - if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { - error("ERROR: Unable to get kernelcache file\n"); - return -1; - } - restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); - free(kernelcache_data); - - } else if (!strcmp(datatype, "NORData")) { - restore_send_nor(restore, ipsw, tss); - - } else { - // Unknown DataType!! - error("Unknown DataType\n"); - return -1; - } - } - - } else if (!strcmp(msgtype, "StatusMsg")) { - restore_error = restore_handle_status_msg(restore, message); - - } else { - info("Received unknown message type: %s\n", msgtype); - } - } + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to start the restore process\n"); + restore_close(device, restore); + return -1; + } - if (RESTORE_E_SUCCESS != restore_error) { - error("Invalid return status %d\n", restore_error); - //idevicerestore_quit = 1; - } + // this is the restore process loop, it reads each message in from + // restored and passes that data on to it's specific handler + while (!idevicerestore_quit) { + restore_error = restored_receive(restore, &message); + if (restore_error != RESTORE_E_SUCCESS) { + debug("No data to read\n"); + message = NULL; + continue; + } + // discover what kind of message has been received + node = plist_dict_get_item(message, "MsgType"); + if (!node || plist_get_node_type(node) != PLIST_STRING) { + debug("Unknown message received\n"); + debug_plist(message); plist_free(message); + message = NULL; + continue; } - } else { - error("ERROR: Could not start restore. %d\n", restore_error); + plist_get_string_val(node, &type); + + // data request messages are sent by restored whenever it requires + // files sent to the server by the client. these data requests include + // SystemImageData, KernelCache, and NORData requests + if (!strcmp(type, "DataRequestMsg")) { + error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem); + } + + // progress notification messages sent by the restored inform the client + // of it's current operation and sometimes percent of progress is complete + else if (!strcmp(type, "ProgressMsg")) { + error = restore_handle_progress_msg(restore, message); + } + + // status messages usually indicate the current state of the restored + // process or often to signal an error has been encountered + else if (!strcmp(type, "StatusMsg")) { + error = restore_handle_status_msg(restore, message); + } + + // there might be some other message types i'm not aware of, but I think + // at least the "previous error logs" messages usually end up here + else { + debug("Unknown message type received\n"); + debug_plist(message); + } + + // finally, if any of these message handlers returned -1 then we encountered + // an unrecoverable error, so we need to bail. + if (error < 0) { + error("ERROR: Unable to successfully restore device\n"); + idevicerestore_quit = 1; + } + + plist_free(message); + message = NULL; } - restored_client_free(restore); - idevice_free(device); + restore_close(device, restore); return 0; } diff --git a/src/restore.h b/src/restore.h index 7a2e27e..cf9cf51 100644 --- a/src/restore.h +++ b/src/restore.h @@ -37,6 +37,6 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss); int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len); int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client); -int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem); +int restore_send_filesystem(idevice_t device, const char* filesystem); #endif -- cgit v1.1-32-gdbae From cbac0617a78db20a5430ae49b4a3fd9e3d9009cc Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Wed, 9 Jun 2010 02:34:08 +0800 Subject: forgot to update the asr.c file header --- src/asr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/asr.c b/src/asr.c index 658f03f..4a8bb58 100644 --- a/src/asr.c +++ b/src/asr.c @@ -1,6 +1,6 @@ /* - * dfu.h - * Functions for handling idevices in normal mode + * asr.h + * Functions for handling asr connections * * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * -- cgit v1.1-32-gdbae From bd7a45ad71862da6ecd96a1156bf5b1e123e3c43 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Wed, 9 Jun 2010 04:29:51 +0800 Subject: Added debug info for recovery.c and a few minor fixes to asr.c --- src/asr.c | 106 +++++++++++++++++++++++++++++++++------------------------ src/asr.h | 5 +-- src/recovery.c | 4 +++ 3 files changed, 68 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/asr.c b/src/asr.c index 4a8bb58..30166ec 100644 --- a/src/asr.c +++ b/src/asr.c @@ -48,7 +48,7 @@ int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr) { if (device_error == IDEVICE_E_SUCCESS) { break; } - +plist_new_ if (i >= attempts) { error("ERROR: Unable to connect to ASR client\n"); return -1; @@ -103,6 +103,7 @@ int asr_send(idevice_connection_t asr, plist_t* data) { return -1; } + debug("Sent %d bytes:\n%s", bytes, debug_plist(data)); free(buffer); return 0; } @@ -117,7 +118,6 @@ int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size) { return -1; } - debug("Sent %d bytes:\n%s", bytes, data); return 0; } @@ -165,12 +165,7 @@ int asr_perform_validation(idevice_connection_t asr, const char* filesystem) { } plist_free(packet_info); - char* oob_data = NULL; - uint64_t oob_offset = 0; - uint64_t oob_length = 0; - plist_t oob_length_node = NULL; - plist_t oob_offset_node = NULL; - do { + while (1) { if (asr_receive(asr, &packet) < 0) { error("ERROR: Unable to receive validation packet\n"); return -1; @@ -184,48 +179,69 @@ int asr_perform_validation(idevice_connection_t asr, const char* filesystem) { plist_get_string_val(node, &command); if (!strcmp(command, "OOBData")) { - oob_length_node = plist_dict_get_item(packet, "OOB Length"); - if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { - error("ERROR: Unable to find OOB data length\n"); - return -1; - } - plist_get_uint_val(oob_length_node, &oob_length); - - oob_offset_node = plist_dict_get_item(packet, "OOB Offset"); - if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { - error("ERROR: Unable to find OOB data offset\n"); - return -1; - } - plist_get_uint_val(oob_offset_node, &oob_offset); - - oob_data = (char*) malloc(oob_length); - if (oob_data == NULL) { - error("ERROR: Out of memory\n"); - plist_free(packet); - return -1; - } - - fseek(file, oob_offset, SEEK_SET); - if (fread(oob_data, 1, oob_length, file) != oob_length) { - error("ERROR: Unable to read OOB data from filesystem offset\n"); - plist_free(packet); - free(oob_data); - return -1; - } - - if (asr_send_buffer(asr, oob_data, oob_length) < 0) { - error("ERROR: Unable to send OOB data to ASR\n"); - plist_free(packet); - free(oob_data); - return -1; - } + asr_handle_oob_data_request(asr, packet, file); + plist_free(packet); - free(oob_data); + } else if(!strcmp(command, "Payload")) { + plist_free(packet); + break; + + } else { + error("ERROR: Unknown command received from ASR\n"); + plist_free(packet); + return -1; } + } - } while (strcmp(packet, "Payload")); + return 0; +} + +int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file) { + char* oob_data = NULL; + uint64_t oob_offset = 0; + uint64_t oob_length = 0; + plist_t oob_length_node = NULL; + plist_t oob_offset_node = NULL; + + oob_length_node = plist_dict_get_item(packet, "OOB Length"); + if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { + error("ERROR: Unable to find OOB data length\n"); + return -1; + } + plist_get_uint_val(oob_length_node, &oob_length); + + oob_offset_node = plist_dict_get_item(packet, "OOB Offset"); + if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { + error("ERROR: Unable to find OOB data offset\n"); + return -1; + } + plist_get_uint_val(oob_offset_node, &oob_offset); + + oob_data = (char*) malloc(oob_length); + if (oob_data == NULL) { + error("ERROR: Out of memory\n"); + plist_free(packet); + return -1; + } + + fseek(file, oob_offset, SEEK_SET); + if (fread(oob_data, 1, oob_length, file) != oob_length) { + error("ERROR: Unable to read OOB data from filesystem offset\n"); + plist_free(packet); + free(oob_data); + return -1; + } + + if (asr_send_buffer(asr, oob_data, oob_length) < 0) { + error("ERROR: Unable to send OOB data to ASR\n"); + plist_free(packet); + free(oob_data); + return -1; + } + free(oob_data); + return 0; } int asr_send_payload(idevice_connection_t asr, const char* filesystem) { diff --git a/src/asr.h b/src/asr.h index 151c1d0..29210ce 100644 --- a/src/asr.h +++ b/src/asr.h @@ -1,6 +1,6 @@ /* - * dfu.h - * Functions for handling idevices in normal mode + * asr.h + * Functions for handling asr connections * * Copyright (c) 2010 Joshua Hill. All Rights Reserved. * @@ -31,5 +31,6 @@ int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size); void asr_close(idevice_connection_t asr); int asr_perform_validation(idevice_connection_t asr, const char* filesystem); int asr_send_payload(idevice_connection_t asr, const char* filesystem); +int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file); #endif diff --git a/src/recovery.c b/src/recovery.c index 52f4802..361ce11 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -157,6 +157,10 @@ int recovery_open_with_timeout(irecv_client_t* client) { debug("Retrying connection...\n"); } + if (idevicerestore_debug) { + irecv_set_debug(recovery, idevicerestore_debug); + } + irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); *client = recovery; return 0; -- cgit v1.1-32-gdbae From b39abb66ffa5e26f38cb2ba03562d091decafc84 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Wed, 9 Jun 2010 04:31:59 +0800 Subject: ooops, should of tested that last commit before pushing --- src/asr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/asr.c b/src/asr.c index 30166ec..c7b6147 100644 --- a/src/asr.c +++ b/src/asr.c @@ -48,7 +48,7 @@ int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr) { if (device_error == IDEVICE_E_SUCCESS) { break; } -plist_new_ + if (i >= attempts) { error("ERROR: Unable to connect to ASR client\n"); return -1; @@ -103,7 +103,8 @@ int asr_send(idevice_connection_t asr, plist_t* data) { return -1; } - debug("Sent %d bytes:\n%s", bytes, debug_plist(data)); + debug("Sent %d bytes:\n", size); + debug_plist(data); free(buffer); return 0; } -- cgit v1.1-32-gdbae