From 4d74cd31751165b671eba9a1b0936718b7f39b52 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 1 Jun 2010 16:13:25 -0400 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(-) 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 95d83e38a95c9cf28ffa59611149fbba242449c4 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Thu, 3 Jun 2010 17:03:33 -0400 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(-) 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 26e7635460c7369be07455a7bcc7621cf53cdd2d Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Fri, 4 Jun 2010 16:02:05 -0400 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(-) 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 7e9d37959d7db900528d68d44445509f4abc6fdf Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Fri, 4 Jun 2010 16:05:16 -0400 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 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 0966c00988477450691c8c9bce47a3fb30eff6da Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Fri, 4 Jun 2010 23:17:05 -0400 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(-) 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 5fe87e252c9c28a67277e21febb19027feb32372 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 05:11:41 -0400 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(-) 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 255b285d22056dde283d33511c14387ea92e28c0 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sat, 5 Jun 2010 18:09:06 -0400 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(-) 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 a91e336c24a0d741e47be7adf0cd0b2beb20e5ab Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 7 Jun 2010 02:24:08 -0400 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(-) 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 5346ce8f7cefe7b33dd8abc44e27cb0e0816f78b Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 7 Jun 2010 05:17:30 -0400 Subject: More small fixes and updated the TODO list --- TODO | 35 ++++++++++++++++------------------- src/idevicerestore.c | 9 ++++++++- src/idevicerestore.h | 7 ++++--- src/restore.h | 1 + 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/TODO b/TODO index 80e336c..9e77cef 100644 --- a/TODO +++ b/TODO @@ -1,19 +1,16 @@ -x Unzip IPSW -x Parse BuildManifest.plist -x Build TSS request -x Submit TSS request to apple -X Stitch new signatures onto firmware -X Connect to iBoot -X Upload iBEC and execute go -X Reconnect to iBEC -X Upload devicetree and execute devicetree -X Upload ramdisk and execute ramdisk -X Upload kernelcache and execute bootx -X Send QueryType request -X Send StartRestore request -X Send source verification packets -X Send filesystem payload -X Send kernelcache payload -X Send NOR firmware payload -* Fetch activation ticket from apple -* Send activation ticket to device \ No newline at end of file +TODO List +------------------------------------------------ + +1) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) +2) Also img3 should be updated to be able to fetch tags from each image such as the VERS tag to be able to compare with the current iBoot version. +3) Many of idevicerestore options can probably be compiled into one flags structure. +4) need to implement restore_reboot(). +5) Need to update restore progress notifications to use print_progress_bar(). +6) Need to add 8900 file support into img3.c. +7) Cacheing TSS and activation info locally so the program doesn't need to query apple/cydia servers everytime would be nice. +8) Need to add support to handle and display status messages correctly. +9) Writing restore logs to an external file for debugging would be a great help. +10) Need to change some info progresses to only display the component name rather then the full path which can be messy. +11) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. +12) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. +13) restore.c is still very ugly and can be cleaned up \ No newline at end of file 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 51b56ba5bf01af40835a43ad1104a7eff3160127 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 04:14:29 -0400 Subject: Added a new asr.c file to stick all stuff related to filesystem and abstract the restore process to allow for easier porting --- TODO | 27 +-- 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 +- 9 files changed, 601 insertions(+), 297 deletions(-) create mode 100644 src/asr.c create mode 100644 src/asr.h diff --git a/TODO b/TODO index 9e77cef..c631123 100644 --- a/TODO +++ b/TODO @@ -1,16 +1,17 @@ TODO List ------------------------------------------------ -1) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) -2) Also img3 should be updated to be able to fetch tags from each image such as the VERS tag to be able to compare with the current iBoot version. -3) Many of idevicerestore options can probably be compiled into one flags structure. -4) need to implement restore_reboot(). -5) Need to update restore progress notifications to use print_progress_bar(). -6) Need to add 8900 file support into img3.c. -7) Cacheing TSS and activation info locally so the program doesn't need to query apple/cydia servers everytime would be nice. -8) Need to add support to handle and display status messages correctly. -9) Writing restore logs to an external file for debugging would be a great help. -10) Need to change some info progresses to only display the component name rather then the full path which can be messy. -11) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. -12) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. -13) restore.c is still very ugly and can be cleaned up \ No newline at end of file +o) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) +o) Also img3 should be updated to be able to fetch tags from each image such as the VERS tag to be able to compare with the current iBoot version. +o) Many of idevicerestore options can probably be compiled into one flags structure. +o) Need to add 8900 file support into img3.c. +o) Cacheing TSS and activation info locally so the program doesn't need to query apple/cydia servers everytime would be nice. +o) Need to add support to handle and display status messages correctly. +o) Writing restore logs to an external file for debugging would be a great help. +o) Need to change some info progresses to only display the component name rather then the full path which can be messy. +o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. +o) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. +o) Clean up restore_send_kernelcache +o) Clean up restore_send_nor +o) Finishing cleaning up asr_perform_validation +o) Double check to make sure asr_send_payload looks clean \ No newline at end of file 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 21769c5e13add34ddf38ffdd1ea38a4212c34cf9 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 14:34:08 -0400 Subject: forgot to update the asr.c file header --- src/asr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 04f32540c4e73c19281c2e7710b51d21ace6010b Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 16:29:51 -0400 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(-) 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 ebc6622cec840d5a7310e27864773ee600034bd4 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 16:31:59 -0400 Subject: ooops, should of tested that last commit before pushing --- src/asr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 From 59fdd010aa845557b0eb90b98959c0cd112b638c Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 8 Jun 2010 20:34:28 -0400 Subject: started to add support multiple build identities --- src/idevicerestore.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------- src/recovery.c | 2 +- src/restore.c | 7 +++++- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 69363fb..ca02dfa 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -73,6 +73,33 @@ void usage(int argc, char* argv[]) { printf("\n"); } +int get_build_count(plist_t buildmanifest) { + // 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 -1; + } + + // check and make sure this identity exists in buildmanifest + return plist_array_get_size(build_identities_array); +} + +const char* get_build_name(plist build_identity, int identity) { + 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); + return NULL; + } + + 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; + } +} + int main(int argc, char* argv[]) { int opt = 0; int optindex = 0; @@ -159,6 +186,18 @@ int main(int argc, char* argv[]) { return -1; } + // devices are listed in order from oldest to newest + // so we'll need their ECID + 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) { + error("ERROR: Unable to find device ECID\n"); + return -1; + } + debug("Found ECID %llu\n", ecid); + } + // choose whether this is an upgrade or a restore (default to upgrade) plist_t build_identity = NULL; if (idevicerestore_erase) { @@ -170,15 +209,20 @@ int main(int argc, char* argv[]) { } } 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; + // loop through all build identities in the build manifest + // and list the valid ones + int valid_builds = 0; + int build_count = get_build_count(buildmanifest); + for(i = 0; i < build_count; i++) { + if (idevicerestore_device->device_id > DEVICE_IPOD2G) { + if (get_shsh_blobs(ecid, i, &tss) < 0) { + // if this fails then no SHSH blobs have been saved + // for this build identity, so check the next one + continue; + } + info("[%d] %s\n" i, get_build_name(buildmanifest, i)); + valid_builds++; } - info("No upgrade ramdisk found, default to full restore\n"); } } @@ -514,7 +558,6 @@ 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) { diff --git a/src/recovery.c b/src/recovery.c index 361ce11..cc523f5 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -131,8 +131,8 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis free(data); return -1; } - free(data); + free(data); return 0; } diff --git a/src/restore.c b/src/restore.c index fc22b75..fa2ccdd 100644 --- a/src/restore.c +++ b/src/restore.c @@ -144,6 +144,7 @@ void restore_device_callback(const idevice_event_t* event, void* user_data) { } else if (event->event == IDEVICE_DEVICE_REMOVE) { restore_device_connected = 0; + idevicerestore_quit = 1; } } @@ -498,7 +499,11 @@ int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, } else if (!strcmp(type, "NORData")) { - restore_send_nor(restore, ipsw, tss); + if(!idevicerestore_exclude) { + restore_send_nor(restore, ipsw, tss); + } else { + idevicerestore_quit = 1; + } } else { // Unknown DataType!! -- cgit v1.1-32-gdbae From 2a2934ca1568dffe69da9a20420c7c0c71376bce Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sun, 20 Jun 2010 22:12:31 -0400 Subject: fixed a few build errors within buildmanifest parsing --- src/idevicerestore.c | 15 ++++++++------- src/recovery.c | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ca02dfa..c801266 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -85,19 +85,19 @@ int get_build_count(plist_t buildmanifest) { return plist_array_get_size(build_identities_array); } -const char* get_build_name(plist build_identity, int identity) { +const char* get_build_name(plist_t build_identity, int identity) { 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); return NULL; } - plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); + plist_t filesystem_info_node = plist_dict_get_item(manifest_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; + return NULL; } + return NULL; } int main(int argc, char* argv[]) { @@ -199,6 +199,7 @@ int main(int argc, char* argv[]) { } // choose whether this is an upgrade or a restore (default to upgrade) + plist_t tss = NULL; plist_t build_identity = NULL; if (idevicerestore_erase) { build_identity = get_build_identity(buildmanifest, 0); @@ -211,16 +212,17 @@ int main(int argc, char* argv[]) { } else { // loop through all build identities in the build manifest // and list the valid ones + int i = 0; int valid_builds = 0; int build_count = get_build_count(buildmanifest); for(i = 0; i < build_count; i++) { if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - if (get_shsh_blobs(ecid, i, &tss) < 0) { + if (get_shsh_blobs(ecid, buildmanifest, &tss) < 0) { // if this fails then no SHSH blobs have been saved // for this build identity, so check the next one continue; } - info("[%d] %s\n" i, get_build_name(buildmanifest, i)); + info("[%d] %s\n", i, get_build_name(buildmanifest, i)); valid_builds++; } } @@ -229,7 +231,6 @@ 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 = NULL; if (idevicerestore_device->device_id > DEVICE_IPOD2G) { info("Creating TSS request\n"); // fetch the device's ECID for the TSS request diff --git a/src/recovery.c b/src/recovery.c index cc523f5..88d385f 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -158,7 +158,7 @@ int recovery_open_with_timeout(irecv_client_t* client) { } if (idevicerestore_debug) { - irecv_set_debug(recovery, idevicerestore_debug); + irecv_set_debug_level(idevicerestore_debug); } irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); -- cgit v1.1-32-gdbae From 24afafe06f902bfd9f5652beb8797f24033c68bc Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Sun, 20 Jun 2010 22:02:18 -0400 Subject: Archived for historical reasons --- TODO | 4 +- src/activate.h | 13 ++- src/asr.c | 2 +- src/asr.h | 9 ++ src/common.c | 108 ++++++++++++++++++ src/common.h | 151 +++++++++++++++++++++++++ src/dfu.c | 84 +++++++++++--- src/dfu.h | 24 +++- src/idevicerestore.c | 306 +++++++++++++++++++++++---------------------------- src/idevicerestore.h | 146 ++++-------------------- src/img3.h | 9 ++ src/ipsw.c | 2 +- src/ipsw.h | 8 ++ src/normal.c | 48 +++++++- src/normal.h | 17 +++ src/recovery.c | 47 ++++++-- src/recovery.h | 20 +++- src/restore.c | 219 ++++++++++++++++++++++-------------- src/restore.h | 32 +++++- src/tss.h | 9 ++ 20 files changed, 839 insertions(+), 419 deletions(-) create mode 100644 src/common.c create mode 100644 src/common.h diff --git a/TODO b/TODO index c631123..6223afe 100644 --- a/TODO +++ b/TODO @@ -11,7 +11,7 @@ o) Writing restore logs to an external file for debugging would be a great help. o) Need to change some info progresses to only display the component name rather then the full path which can be messy. o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. o) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. -o) Clean up restore_send_kernelcache -o) Clean up restore_send_nor +o) Clean up refactor restore_send_kernelcache() +o) Clean up and refactor restore_send_nor() o) Finishing cleaning up asr_perform_validation o) Double check to make sure asr_send_payload looks clean \ No newline at end of file diff --git a/src/activate.h b/src/activate.h index f992d4f..00510d3 100644 --- a/src/activate.h +++ b/src/activate.h @@ -19,8 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ACTIVATE_H -#define ACTIVATE_H +#ifndef IDEVICERESTORE_ACTIVATE_H +#define IDEVICERESTORE_ACTIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif #include #include @@ -29,4 +33,9 @@ int activate_device(const char* uuid); int activate_check_status(const char* uuid); int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/asr.c b/src/asr.c index c7b6147..2331660 100644 --- a/src/asr.c +++ b/src/asr.c @@ -283,7 +283,7 @@ int asr_send_payload(idevice_connection_t asr, const char* filesystem) { bytes += size; progress = ((double) bytes/ (double) length) * 100.0; - print_progress_bar("Extracting", progress); + print_progress_bar(progress); } diff --git a/src/asr.h b/src/asr.h index 29210ce..1423496 100644 --- a/src/asr.h +++ b/src/asr.h @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_ASR_H #define IDEVICERESTORE_ASR_H +#ifdef __cplusplus +extern "C" { +#endif + #include int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr); @@ -33,4 +37,9 @@ 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); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..07a7075 --- /dev/null +++ b/src/common.c @@ -0,0 +1,108 @@ +/* + * common.c + * Misc functions used in idevicerestore + * + * 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 "common.h" + +int idevicerestore_debug = 0; + +int write_file(const char* filename, const void* data, size_t size) { + size_t bytes = 0; + FILE* file = NULL; + + debug("Writing data to %s\n", filename); + file = fopen(filename, "wb"); + if (file == NULL) { + error("read_file: Unable to open file %s\n", filename); + return -1; + } + + bytes = fwrite(data, 1, size, file); + fclose(file); + + if (bytes != size) { + error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size); + return -1; + } + + return size; +} + +int read_file(const char* filename, void** data, size_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; +} + +void debug_plist(plist_t plist) { + int size = 0; + char* data = NULL; + plist_to_xml(plist, &data, &size); + info("%s", data); + free(data); +} + +void print_progress_bar(double progress) { + int i = 0; + if(progress < 0) return; + if(progress > 100) progress = 100; + info("\r["); + for(i = 0; i < 50; i++) { + if(i < progress / 2) info("="); + else info(" "); + } + info("] %3.1f%%", progress); + if(progress == 100) info("\n"); + fflush(stdout); +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..cb774a5 --- /dev/null +++ b/src/common.h @@ -0,0 +1,151 @@ +/* + * common.h + * Misc functions used in idevicerestore + * + * 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_COMMON_H +#define IDEVICERESTORE_COMMON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define info(...) printf(__VA_ARGS__) +#define error(...) fprintf(stderr, __VA_ARGS__) +#define debug(...) if(idevicerestore_debug) fprintf(stderr, __VA_ARGS__) + +#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 + +#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 + +#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 + +#define MODE_UNKNOWN -1 +#define MODE_DFU 0 +#define MODE_RECOVERY 1 +#define MODE_RESTORE 2 +#define MODE_NORMAL 3 + +#define FLAG_QUIT 1 +#define FLAG_DEBUG 2 +#define FLAG_ERASE 4 +#define FLAG_CUSTOM 8 +#define FLAG_EXCLUDE 16 + +struct dfu_client_t; +struct normal_client_t; +struct restore_clien_t; +struct recovery_client_t; + +struct idevicerestore_mode_t { + int index; + const char* string; +}; + +struct idevicerestore_entry_t { + char* name; + char* path; + char* filename; + char* blob_data; + uint32_t blob_size; + struct idevicerestore_entry* next; + struct idevicerestore_entry* prev; +}; + +struct idevicerestore_device_t { + int index; + const char* product; + const char* model; + uint32_t board_id; + uint32_t chip_id; +}; + +struct idevicerestore_client_t { + int flags; + plist_t tss; + uint64_t ecid; + const char* uuid; + const char* ipsw; + const char* filesystem; + struct dfu_client_t* dfu; + struct normal_client_t* normal; + struct restore_client_t* restore; + struct recovery_client_t* recovery; + struct idevicerestore_device_t* device; + struct idevicerestore_entry_t** entries; + struct idevicerestore_mode_t* mode; +}; + +static struct idevicerestore_mode_t idevicerestore_modes[] = { + { 0, "DFU" }, + { 1, "Recovery" }, + { 2, "Restore" }, + { 3, "Normal" }, + { -1, NULL } +}; + +static struct 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 }, + { 6, "iPhone3,1", "XXXAP", 0, 0 }, + { -1, NULL, NULL, -1, -1 } +}; + +extern int idevicerestore_debug; + +void debug_plist(plist_t plist); +void print_progress_bar(double progress); +int read_file(const char* filename, void** data, size_t* size); +int write_file(const char* filename, const void* data, size_t size); + +extern struct idevicerestore_client_t* idevicerestore; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dfu.c b/src/dfu.c index 1b0e8e7..b53803e 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -24,29 +24,87 @@ #include #include "dfu.h" -#include "recovery.h" +//#include "recovery.h" #include "idevicerestore.h" -int dfu_check_mode() { - irecv_client_t dfu = NULL; - irecv_error_t dfu_error = IRECV_E_SUCCESS; +int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) { + if (event->type == IRECV_PROGRESS) { + print_progress_bar(event->progress); + } + return 0; +} - dfu_error = irecv_open(&dfu); - if (dfu_error != IRECV_E_SUCCESS) { +int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout) { + struct dfu_client_t* dfu = NULL; + if(client == NULL) { return -1; } - if (dfu->mode != kDfuMode) { - irecv_close(dfu); + if(client->dfu) { + dfu_client_free(client); + } + + dfu = (struct dfu_client_t*) malloc(sizeof(struct dfu_client_t)); + if (dfu == NULL) { + error("ERROR: Out of memory\n"); return -1; } - irecv_close(dfu); - dfu = NULL; + if (dfu_open_with_timeout(dfu, timeout) < 0) { + dfu_client_free(client); + return -1; + } + + if(dfu->client->mode != kDfuMode) { + dfu_client_free(client); + return -1; + } + + client->dfu = dfu; + return 0; +} + +void dfu_client_free(struct idevicerestore_client_t* client) { + struct dfu_client_t* dfu = NULL; + if(client != NULL) { + dfu = client->dfu; + if (dfu != NULL) { + if(dfu->client != NULL) { + irecv_close(dfu->client); + dfu->client = NULL; + } + free(dfu); + } + client->dfu = NULL; + } +} + +int dfu_open_with_timeout(struct idevicerestore_client_t* client, uint32_t timeout) { + int i = 0; + irecv_client_t recovery = NULL; + irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; + + for (i = 1; i <= timeout; i++) { + recovery_error = irecv_open(&recovery); + if (recovery_error == IRECV_E_SUCCESS) { + break; + } + + if (i == timeout) { + error("ERROR: Unable to connect to device in DFU mode\n"); + return -1; + } + + sleep(1); + debug("Retrying connection...\n"); + } + + irecv_event_subscribe(recovery, IRECV_PROGRESS, &dfu_progress_callback, NULL); + client->dfu = recovery; return 0; } -int dfu_enter_recovery(const char* ipsw, plist_t tss) { +int dfu_enter_recovery(struct idevicerestore_client_t* client) { irecv_client_t dfu = NULL; const char* component = "iBSS"; irecv_error_t dfu_error = IRECV_E_SUCCESS; @@ -57,7 +115,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) { return -1; } - if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) { + if (recovery_send_signed_component(dfu, client->ipsw, client->tss, "iBSS") < 0) { error("ERROR: Unable to send %s to device\n", component); irecv_close(dfu); return -1; @@ -80,7 +138,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) { return -1; } - idevicerestore_mode = MODE_RECOVERY; + client->mode = &idevicerestore_modes[MODE_RECOVERY]; irecv_close(dfu); dfu = NULL; return 0; diff --git a/src/dfu.h b/src/dfu.h index 3577888..0e20448 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -22,10 +22,26 @@ #ifndef IDEVICERESTORE_DFU_H #define IDEVICERESTORE_DFU_H -#include -#include +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "common.h" + +struct dfu_client_t { + irecv_client_t client; + const char* ipsw; + plist_t tss; +}; -int dfu_check_mode(); -int dfu_enter_recovery(const char* ipsw, plist_t tss); +int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout); +void dfu_client_free(struct idevicerestore_client_t* client); +int dfu_enter_recovery(struct idevicerestore_client_t* client); + + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index c801266..cdbff27 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -25,38 +25,25 @@ #include #include #include -#include -#include -#include -#include -#include "dfu.h" -#include "tss.h" +#include "idevicerestore.h" +//#include "recovery.h" +#include "restore.h" +#include "common.h" +#include "normal.h" #include "img3.h" #include "ipsw.h" -#include "normal.h" -#include "restore.h" -#include "recovery.h" -#include "idevicerestore.h" +#include "dfu.h" +#include "tss.h" -int idevicerestore_quit = 0; -int idevicerestore_debug = 0; -int idevicerestore_erase = 0; -int idevicerestore_custom = 0; -int idevicerestore_verbose = 0; -int idevicerestore_exclude = 0; -int idevicerestore_mode = MODE_UNKNOWN; -idevicerestore_device_t* idevicerestore_device = NULL; - -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} +static struct option longopts[] = { + { "uuid", required_argument, NULL, 'u' }, + { "debug", no_argument, NULL, 'd' }, + { "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[]) { @@ -65,7 +52,6 @@ void usage(int argc, char* argv[]) { printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\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"); @@ -106,30 +92,36 @@ int main(int argc, char* argv[]) { char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { + + // create an instance of our context + struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t)); + if (client == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + memset(client, '\0', sizeof(struct idevicerestore_client_t)); + idevicerestore = client; + + while ((opt = getopt_long(argc, argv, "dhcexu:", longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv); break; case 'd': - idevicerestore_debug = 1; + client->flags &= FLAG_DEBUG; break; case 'e': - idevicerestore_erase = 1; + client->flags &= FLAG_ERASE; break; case 'c': - idevicerestore_custom = 1; + client->flags &= FLAG_CUSTOM; break; case 'x': - idevicerestore_exclude = 1; - break; - - case 'v': - idevicerestore_verbose = 1; + client->flags &= FLAG_EXCLUDE; break; case 'u': @@ -152,27 +144,30 @@ int main(int argc, char* argv[]) { return -1; } - if(idevicerestore_debug) { - idevice_set_debug_level(5); + if (client->flags & FLAG_DEBUG) { + idevice_set_debug_level(1); + irecv_set_debug_level(1); } + client->uuid = uuid; + client->ipsw = ipsw; + // check which mode the device is currently in so we know where to start - idevicerestore_mode = check_mode(uuid); - if (idevicerestore_mode < 0) { + if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) { error("ERROR: Unable to discover current device state\n"); return -1; } + info("Found device in %s mode\n", client->mode->string); // discover the device type - int id = check_device(uuid); - if (id < 0) { + if (check_device(client) < 0 || client->device->index == DEVICE_UNKNOWN) { error("ERROR: Unable to discover device type\n"); return -1; } - idevicerestore_device = &idevicerestore_devices[id]; + info("Identified device as %s\n", client->device->product); - if (idevicerestore_mode == MODE_RESTORE) { - if (restore_reboot(uuid) < 0) { + if (client->mode->index == MODE_RESTORE) { + if (restore_reboot(client) < 0) { error("ERROR: Unable to exit restore mode\n"); return -1; } @@ -181,28 +176,28 @@ int main(int argc, char* argv[]) { // extract buildmanifest plist_t buildmanifest = NULL; info("Extracting BuildManifest from IPSW\n"); - if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { + if (extract_buildmanifest(client, ipsw, &buildmanifest) < 0) { error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); return -1; } // devices are listed in order from oldest to newest // so we'll need their ECID - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - info("Creating TSS request\n"); + if (client->device->index > DEVICE_IPOD2G) { + debug("Creating TSS request\n"); // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + if (get_ecid(client, &client->ecid) < 0) { error("ERROR: Unable to find device ECID\n"); return -1; } - debug("Found ECID %llu\n", ecid); + debug("Found ECID %llu\n", client->ecid); } // choose whether this is an upgrade or a restore (default to upgrade) plist_t tss = NULL; plist_t build_identity = NULL; - if (idevicerestore_erase) { - build_identity = get_build_identity(buildmanifest, 0); + if (client->flags & FLAG_ERASE) { + build_identity = get_build_identity(client, buildmanifest, 0); if (build_identity == NULL) { error("ERROR: Unable to find build any identities\n"); plist_free(buildmanifest); @@ -215,9 +210,10 @@ int main(int argc, char* argv[]) { int i = 0; int valid_builds = 0; int build_count = get_build_count(buildmanifest); - for(i = 0; i < build_count; i++) { - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - if (get_shsh_blobs(ecid, buildmanifest, &tss) < 0) { + for (i = 0; i < build_count; i++) { + if (client->device->index > DEVICE_IPOD2G) { + build_identity = get_build_identity(client, buildmanifest, i); + if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) { // if this fails then no SHSH blobs have been saved // for this build identity, so check the next one continue; @@ -231,29 +227,29 @@ 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; - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { + if (client->device->index > DEVICE_IPOD2G) { info("Creating TSS request\n"); // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + if (get_ecid(client, &ecid) < 0 || ecid == 0) { error("ERROR: Unable to find device ECID\n"); return -1; } - info("Found ECID %llu\n", ecid); + debug("Found ECID %llu\n", ecid); // fetch the SHSH blobs for this build identity - if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { + if (get_shsh_blobs(client, 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) { + if (client->flags & FLAG_ERASE > 0) { info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); - build_identity = get_build_identity(buildmanifest, 0); + build_identity = get_build_identity(client, 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 (get_shsh_blobs(client, 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); @@ -270,7 +266,7 @@ int main(int argc, char* argv[]) { // Extract filesystem from IPSW and return its name char* filesystem = NULL; - if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) { + if (extract_filesystem(client, ipsw, build_identity, &filesystem) < 0) { error("ERROR: Unable to extract filesystem from IPSW\n"); if (tss) plist_free(tss); @@ -279,7 +275,7 @@ int main(int argc, char* argv[]) { } // if the device is in normal mode, place device into recovery mode - if (idevicerestore_mode == MODE_NORMAL) { + if (client->mode->index == MODE_NORMAL) { info("Entering recovery mode...\n"); if (normal_enter_recovery(uuid) < 0) { error("ERROR: Unable to place device into recovery mode\n"); @@ -291,8 +287,8 @@ int main(int argc, char* argv[]) { } // if the device is in DFU mode, place device into recovery mode - if (idevicerestore_mode == MODE_DFU) { - if (dfu_enter_recovery(ipsw, tss) < 0) { + if (client->mode->index == MODE_DFU) { + if (dfu_enter_recovery(client) < 0) { error("ERROR: Unable to place device into recovery mode\n"); plist_free(buildmanifest); if (tss) @@ -302,7 +298,7 @@ int main(int argc, char* argv[]) { } // if the device is in recovery mode, place device into restore mode - if (idevicerestore_mode == MODE_RECOVERY) { + if (client->mode->index == MODE_RECOVERY) { if (recovery_enter_restore(uuid, ipsw, tss) < 0) { error("ERROR: Unable to place device into restore mode\n"); plist_free(buildmanifest); @@ -313,16 +309,16 @@ int main(int argc, char* argv[]) { } // device is finally in restore mode, let's do this - if (idevicerestore_mode == MODE_RESTORE) { + if (client->mode->index == MODE_RESTORE) { info("Restoring device... \n"); - if (restore_device(uuid, ipsw, tss, filesystem) < 0) { + if (restore_device(client, 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 == MODE_NORMAL) { + if (client->mode->index == MODE_NORMAL) { info("Checking activation status\n"); int activation = activate_check_status(uuid); if (activation < 0) { @@ -347,7 +343,7 @@ int main(int argc, char* argv[]) { return 0; } -int check_mode(const char* uuid) { +int check_mode(struct idevicerestore_client_t* client) { int mode = MODE_UNKNOWN; if (recovery_check_mode() == 0) { @@ -360,34 +356,35 @@ int check_mode(const char* uuid) { mode = MODE_DFU; } - else if (normal_check_mode(uuid) == 0) { + else if (normal_check_mode(client->uuid) == 0) { info("Found device in normal mode\n"); mode = MODE_NORMAL; } - else if (restore_check_mode(uuid) == 0) { + else if (restore_check_mode(client->uuid) == 0) { info("Found device in restore mode\n"); mode = MODE_RESTORE; } + client->mode = &idevicerestore_modes[mode]; return mode; } -int check_device(const char* uuid) { +int check_device(struct idevicerestore_client_t* client) { int device = DEVICE_UNKNOWN; uint32_t bdid = 0; uint32_t cpid = 0; - switch (idevicerestore_mode) { + switch (client->mode->index) { case MODE_RESTORE: - device = restore_check_device(uuid); + device = restore_check_device(client->uuid); if (device < 0) { device = DEVICE_UNKNOWN; } break; case MODE_NORMAL: - device = normal_check_device(uuid); + device = normal_check_device(client->uuid); if (device < 0) { device = DEVICE_UNKNOWN; } @@ -395,7 +392,7 @@ int check_device(const char* uuid) { case MODE_DFU: case MODE_RECOVERY: - if (get_cpid(uuid, &cpid) < 0) { + if (get_cpid(client, &cpid) < 0) { error("ERROR: Unable to get device CPID\n"); break; } @@ -404,7 +401,7 @@ int check_device(const char* uuid) { 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) { + if (get_bdid(client, &bdid) < 0) { error("ERROR: Unable to get device BDID\n"); break; } @@ -456,22 +453,23 @@ int check_device(const char* uuid) { } + client->device = &idevicerestore_devices[device]; return device; } -int get_bdid(const char* uuid, uint32_t* bdid) { - switch (idevicerestore_mode) { +int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_bdid(uuid, bdid) < 0) { - *bdid = -1; + if (normal_get_bdid(client->uuid, &client->device->board_id) < 0) { + client->device->board_id = -1; return -1; } break; case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_bdid(bdid) < 0) { - *bdid = -1; + if (recovery_get_bdid(&client->device->board_id) < 0) { + client->device->board_id = -1; return -1; } break; @@ -484,19 +482,19 @@ int get_bdid(const char* uuid, uint32_t* bdid) { return 0; } -int get_cpid(const char* uuid, uint32_t* cpid) { - switch (idevicerestore_mode) { +int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_cpid(uuid, cpid) < 0) { - *cpid = 0; + if (normal_get_cpid(client->uuid, &client->device->chip_id) < 0) { + client->device->chip_id = -1; return -1; } break; case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_cpid(cpid) < 0) { - *cpid = 0; + if (recovery_get_cpid(&client->device->chip_id) < 0) { + client->device->chip_id = -1; return -1; } break; @@ -509,10 +507,15 @@ int get_cpid(const char* uuid, uint32_t* cpid) { return 0; } -int get_ecid(const char* uuid, uint64_t* ecid) { - switch (idevicerestore_mode) { +int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { + if(client->device->index <= DEVICE_IPOD2G) { + *ecid = 0; + return 0; + } + + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_ecid(uuid, ecid) < 0) { + if (normal_get_ecid(client->uuid, ecid) < 0) { *ecid = 0; return -1; } @@ -534,10 +537,10 @@ int get_ecid(const char* uuid, uint64_t* ecid) { return 0; } -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { +int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest) { int size = 0; char* data = NULL; - int device = idevicerestore_device->device_id; + int device = client->device->index; 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) { @@ -558,7 +561,7 @@ int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { return 0; } -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { +plist_t get_build_identity(struct idevicerestore_client_t* client, 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) { @@ -580,7 +583,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { return plist_copy(build_identity); } -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { +int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss) { plist_t request = NULL; plist_t response = NULL; *tss = NULL; @@ -603,7 +606,33 @@ int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { return 0; } -int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { +int get_build_count(plist_t buildmanifest) { + // 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 -1; + } + + // check and make sure this identity exists in buildmanifest + return plist_array_get_size(build_identities_array); +} + +const char* get_build_name(plist_t build_identity, int identity) { + 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"); + return NULL; + } + + plist_t filesystem_info_node = plist_dict_get_item(manifest_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 NULL; + } +} + +int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); @@ -641,7 +670,7 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst return 0; } -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int get_signed_component(struct idevicerestore_client_t* client, 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; @@ -649,8 +678,10 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** char* component_name = NULL; component_name = strrchr(path, '/'); - if (component_name != NULL) component_name++; - else component_name = (char*) 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) { @@ -672,7 +703,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** return -1; } - if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { + if (client->device->index > DEVICE_IPOD2G && (client->flags & FLAG_CUSTOM) == 0) { if (img3_replace_signature(img3, component_blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); free(component_blob); @@ -689,7 +720,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** } img3_free(img3); - if (idevicerestore_debug) { + if (client->flags & FLAG_DEBUG) { write_file(component_name, component_data, component_size); } @@ -697,66 +728,3 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** *size = component_size; return 0; } - -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 = fopen(filename, "wb"); - if (file == NULL) { - error("read_file: Unable to open file %s\n", filename); - return -1; - } - - 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 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 20578a9..7e5873b 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -22,135 +22,31 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H -#include -#include -#include - -#define info(...) printf(__VA_ARGS__) -#define error(...) fprintf(stderr, __VA_ARGS__) -#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) - -#define MODE_UNKNOWN -1 -#define MODE_DFU 0 -#define MODE_RECOVERY 1 -#define MODE_RESTORE 2 -#define MODE_NORMAL 3 - -#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 - -#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 - -#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 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; +#ifdef __cplusplus +extern "C" { +#endif -typedef struct { - int device_id; - const char* product; - const char* model; - 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 }, - { 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 }, - { 6, "iPhone4,1", "XXXAP", 0, 0 }, - { -1, NULL, NULL, -1, -1 } -}; +#include +#include -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_device_t* idevicerestore_device; -extern idevicerestore_entry_t** idevicerestore_entries; +#include +#include "common.h" -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 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); - -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); -} - -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); +int check_mode(struct idevicerestore_client_t* client); +int check_device(struct idevicerestore_client_t* client); +const char* get_build_name(plist_t build_identity, int identity); +int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); +int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); +int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); +int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest); +plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity); +int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss); +int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t buildmanifest, char** filesystem); +int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); + +#ifdef __cplusplus } +#endif #endif diff --git a/src/img3.h b/src/img3.h index 5fddbfc..796a8e1 100644 --- a/src/img3.h +++ b/src/img3.h @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_IMG3_H #define IDEVICERESTORE_IMG3_H +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { kNorContainer = 0x696D6733, // img3 kImg3Container = 0x496D6733, // Img3 @@ -86,4 +90,9 @@ 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); + +#ifdef __cplusplus +}s +#endif + #endif diff --git a/src/ipsw.c b/src/ipsw.c index adbaea0..f08e2fd 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -114,7 +114,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi bytes += size; progress = ((double) bytes/ (double) zstat.size) * 100.0; - print_progress_bar("Extracting", progress); + print_progress_bar(progress); } fclose(fd); diff --git a/src/ipsw.h b/src/ipsw.h index aa0fd1d..cd11406 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_IPSW_H #define IDEVICERESTORE_IPSW_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include @@ -35,4 +39,8 @@ typedef struct { int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize); void ipsw_free_file(ipsw_file* file); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/normal.c b/src/normal.c index b9270d8..7ae4774 100644 --- a/src/normal.c +++ b/src/normal.c @@ -25,9 +25,49 @@ #include #include +#include "common.h" #include "normal.h" -#include "recovery.h" -#include "idevicerestore.h" +//#include "recovery.h" + +int normal_client_new(struct normal_client_t** normal) { + struct normal_client_t* client = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); + if (client == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + + if (normal_open_with_timeout(client) < 0) { + normal_client_free(client); + return -1; + } + + if(normal_check_mode(client) < 0) { + normal_client_free(client); + return -1; + } + + *normal = client; + return client; +} + +void normal_client_free(struct idevicerestore_client_t* client) { + struct normal_client_t* normal = NULL; + if (client) { + normal = client->normal; + if(normal) { + if(normal->client) { + lockdownd_client_free(normal->client); + normal->client = NULL; + } + if(normal->device) { + idevice_free(normal->device); + normal->device = NULL; + } + } + free(normal); + client->normal = NULL; + } +} int normal_check_mode(const char* uuid) { char* type = NULL; @@ -106,7 +146,7 @@ int normal_check_device(const char* uuid) { } } - return idevicerestore_devices[i].device_id; + return idevicerestore_devices[i].index; } int normal_enter_recovery(const char* uuid) { @@ -162,7 +202,7 @@ int normal_enter_recovery(const char* uuid) { return -1; } - idevicerestore_mode = MODE_RECOVERY; + //client->mode = &idevicerestore_modes[MODE_RECOVERY]; irecv_close(recovery); recovery = NULL; return 0; diff --git a/src/normal.h b/src/normal.h index cdc29ba..352e643 100644 --- a/src/normal.h +++ b/src/normal.h @@ -22,7 +22,20 @@ #ifndef IDEVICERESTORE_NORMAL_H #define IDEVICERESTORE_NORMAL_H +#ifdef __cplusplus +extern "C" { +#endif + #include +#include +#include + +struct normal_client_t { + idevice_t device; + lockdownd_client_t client; + const char* ipsw; + plist_t tss; +}; int normal_check_mode(const char* uuid); int normal_check_device(const char* uuid); @@ -31,4 +44,8 @@ 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); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/recovery.c b/src/recovery.c index 88d385f..bacfac7 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -28,16 +28,51 @@ #include "tss.h" #include "img3.h" +#include "common.h" #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); + print_progress_bar(event->progress); } return 0; } +int recovery_client_new(struct idevicerestore_client_t* client) { + struct recovery_client_t* recovery = (struct recovery_client_t*) malloc(sizeof(struct recovery_client_t)); + if (recovery == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + + if (recovery_open_with_timeout(recovery) < 0) { + recovery_client_free(recovery); + return -1; + } + + if(recovery_check_mode(recovery) < 0) { + recovery_client_free(recovery); + return -1; + } + + client->recovery = recovery; + return 0; +} + +void recovery_client_free(struct idevicerestore_client_t* client) { + struct recovery_client_t* recovery = client->recovery; + if (recovery) { + if(recovery->client) { + irecv_close(recovery); + recovery = NULL; + } + free(recovery); + client->recovery = NULL; + + } +} + int recovery_check_mode() { irecv_client_t recovery = NULL; irecv_error_t recovery_error = IRECV_E_SUCCESS; @@ -101,11 +136,11 @@ int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { } restore_close(device, restore); - idevicerestore_mode = MODE_RESTORE; + client->mode = &idevicerestore_modes[MODE_RESTORE]; return 0; } -int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) { +int recovery_send_signed_component(struct idevicerestore_client_t client, const char* ipsw, plist_t tss, char* component) { int size = 0; char* data = NULL; char* path = NULL; @@ -117,7 +152,7 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis return -1; } - if (get_signed_component(ipsw, tss, path, &data, &size) < 0) { + if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { error("ERROR: Unable to get signed component: %s\n", component); free(path); return -1; @@ -157,10 +192,6 @@ int recovery_open_with_timeout(irecv_client_t* client) { debug("Retrying connection...\n"); } - if (idevicerestore_debug) { - irecv_set_debug_level(idevicerestore_debug); - } - irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); *client = recovery; return 0; diff --git a/src/recovery.h b/src/recovery.h index 1953c6a..6cd467c 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -22,12 +22,24 @@ #ifndef IDEVICERESTORE_RECOVERY_H #define IDEVICERESTORE_RECOVERY_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include +#include + +struct recovery_client_t { + irecv_client_t client; + const char* ipsw; + plist_t tss; +}; int recovery_check_mode(); -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); +int recovery_client_new(struct idevicerestore_client_t* client); +void recovery_client_free(struct idevicerestore_client_t* client); +int recovery_send_signed_component(struct idevicerestore_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); int recovery_send_applelogo(const char* ipsw, plist_t tss); @@ -38,4 +50,8 @@ int recovery_get_ecid(uint64_t* ecid); int recovery_get_cpid(uint32_t* cpid); int recovery_get_bdid(uint32_t* bdid); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/restore.c b/src/restore.c index fa2ccdd..b4cf0b2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -26,8 +26,8 @@ #include "asr.h" #include "tss.h" +#include "common.h" #include "restore.h" -#include "idevicerestore.h" #define CREATE_PARTITION_MAP 12 #define CREATE_FILESYSTEM 13 @@ -46,6 +46,39 @@ static int restore_device_connected = 0; +int restore_client_new(struct idevicerestore_client_t* client) { + struct restore_client_t* restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); + if (restore == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + + if (restore_open_with_timeout(client) < 0) { + restore_client_free(client); + return -1; + } + + client->restore = restore; + return 0; +} + +void restore_client_free(struct idevicerestore_client_t* client) { + if (client) { + if(client->restore) { + if(client->restore->client) { + restored_client_free(client->restore->client); + client->restore->client = NULL; + } + if(client->restore->device) { + idevice_free(client->restore->device); + client->restore->device = NULL; + } + free(client->restore); + client->restore = NULL; + } + } +} + int restore_check_mode(const char* uuid) { char* type = NULL; uint64_t version = 0; @@ -135,51 +168,61 @@ int restore_check_device(const char* uuid) { } } - return idevicerestore_devices[i].device_id; + return idevicerestore_devices[i].index; } -void restore_device_callback(const idevice_event_t* event, void* user_data) { +void restore_device_callback(const idevice_event_t* event, void* userdata) { + struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata; if (event->event == IDEVICE_DEVICE_ADD) { restore_device_connected = 1; } else if (event->event == IDEVICE_DEVICE_REMOVE) { restore_device_connected = 0; - idevicerestore_quit = 1; + client->flags &= FLAG_QUIT; } } -int restore_reboot(const char* uuid) { +int restore_reboot(struct idevicerestore_client_t* client) { 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; + if(!client->restore) { + if (restore_open_with_timeout(client) < 0) { + error("ERROR: Unable to open device in restore mode\n"); + return -1; + } } - restore_error = restored_reboot(restore); + restore_error = restored_reboot(client); 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 restore_open_with_timeout(struct idevicerestore_client_t* client) { int i = 0; int attempts = 10; - idevice_t context = NULL; - restored_client_t client = NULL; + idevice_t device = NULL; + restored_client_t restored = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; restored_error_t restore_error = RESTORE_E_SUCCESS; - *device = NULL; - *restore = NULL; + // no context exists so bail + if(client == NULL) { + return -1; + } + + // create our restore client if it doesn't yet exist + if(client->restore == NULL) { + client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); + if(client->restore == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + } device_error = idevice_event_subscribe(&restore_device_callback, NULL); if (device_error != IDEVICE_E_SUCCESS) { @@ -194,43 +237,37 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie if (i == attempts) { error("ERROR: Unable to connect to device in restore mode\n"); + return -1; } sleep(2); } - device_error = idevice_new(&context, uuid); + device_error = idevice_new(&device, client->uuid); if (device_error != IDEVICE_E_SUCCESS) { return -1; } - restore_error = restored_client_new(context, &client, "idevicerestore"); + restore_error = restored_client_new(device, &restored, "idevicerestore"); if (restore_error != RESTORE_E_SUCCESS) { - idevice_event_unsubscribe(); - idevice_free(context); + //idevice_event_unsubscribe(); + idevice_free(device); return -1; } - restore_error = restored_query_type(client, NULL, NULL); + restore_error = restored_query_type(restored, NULL, NULL); if (restore_error != RESTORE_E_SUCCESS) { - restored_client_free(client); - idevice_event_unsubscribe(); - idevice_free(context); + restored_client_free(restored); + //idevice_event_unsubscribe(); + idevice_free(device); return -1; } - *device = context; - *restore = client; + client->restore->device = device; + client->restore->client = restored; return 0; } -void restore_close(idevice_t device, restored_client_t restore) { - if (restore) - restored_client_free(restore); - if (device) - idevice_free(device); -} - const char* restore_progress_string(unsigned int operation) { switch (operation) { case CREATE_PARTITION_MAP: @@ -300,7 +337,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_get_uint_val(node, &progress); if ((progress > 0) && (progress < 100)) { - print_progress_bar(restore_progress_string(operation), (double) progress); + print_progress_bar((double) progress); } else { info("%s\n", restore_progress_string(operation)); @@ -361,16 +398,32 @@ int restore_send_filesystem(idevice_t device, const char* filesystem) { return 0; } -int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) { +int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss) { + int size = 0; + char* data = NULL; + char* path = NULL; + plist_t blob = NULL; + plist_t dict = NULL; + restored_error_t restore_error = RESTORE_E_SUCCESS; + info("Sending kernelcache\n"); + if (tss_get_entry_path(tss, "KernelCache", &path) < 0) { + error("ERROR: Unable to find kernelcache path\n"); + return -1; + } - plist_t kernelcache_node = plist_new_data(kernel_data, len); + if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { + error("ERROR: Unable to get kernelcache file\n"); + return -1; + } - plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node); - restored_error_t ret = restored_send(client, dict); - if (ret != RESTORE_E_SUCCESS) { + dict = plist_new_dict(); + blob = plist_new_data(data, size); + plist_dict_insert_item(dict, "KernelCacheFile", blob); + + restore_error = restored_send(client, dict); + if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); return -1; @@ -378,52 +431,61 @@ int restore_send_kernelcache(restored_client_t client, char* kernel_data, int le info("Done sending kernelcache\n"); plist_free(dict); + free(data); return 0; } int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { char* llb_path = NULL; + char* llb_filename = NULL; + char firmware_path[256]; + char manifest_file[256]; + int manifest_size = 0; + char* manifest_data = NULL; + char firmware_filename[256]; + int llb_size = 0; + char* llb_data = NULL; + plist_t dict = NULL; + char* filename = NULL; + int nor_size = 0; + char* nor_data = NULL; + plist_t norimage_array = NULL; + restored_error_t ret = RESTORE_E_SUCCESS; + 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"); + llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { error("ERROR: Unable to extract firmware path from LLB filename\n"); free(llb_path); return -1; } - char firmware_path[256]; memset(firmware_path, '\0', sizeof(firmware_path)); memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path); info("Found firmware path %s\n", firmware_path); - char manifest_file[256]; memset(manifest_file, '\0', sizeof(manifest_file)); snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); info("Getting firmware manifest %s\n", manifest_file); - int manifest_size = 0; - char* manifest_data = NULL; 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); return -1; } - char firmware_filename[256]; memset(firmware_filename, '\0', sizeof(firmware_filename)); - int llb_size = 0; - char* llb_data = NULL; - plist_t dict = plist_new_dict(); - char* filename = strtok(manifest_data, "\n"); + dict = plist_new_dict(); + filename = strtok(manifest_data, "\n"); 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(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + if (get_signed_component(client, ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } @@ -431,14 +493,12 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size)); } - int nor_size = 0; - char* nor_data = NULL; filename = strtok(NULL, "\n"); - plist_t norimage_array = plist_new_array(); + norimage_array = plist_new_array(); 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(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + if (get_signed_component(client, ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } @@ -453,7 +513,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { debug_plist(dict); - restored_error_t ret = restored_send(client, dict); + ret = restored_send(client, dict); if (ret != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); @@ -464,7 +524,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { return 0; } -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) { +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, 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; @@ -476,44 +536,39 @@ int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, // 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"); + if(restore_send_filesystem(device, filesystem) < 0) { + error("ERROR: Unable to send filesystem\n"); return -1; } + } - if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { - error("ERROR: Unable to get kernelcache file\n"); + else if (!strcmp(type, "KernelCache")) { + if(restore_send_kernelcache(restore, ipsw, tss) < 0) { + error("ERROR: Unable to send kernelcache\n"); return -1; } - restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); - free(kernelcache_data); - } else if (!strcmp(type, "NORData")) { - if(!idevicerestore_exclude) { - restore_send_nor(restore, ipsw, tss); + if(client->flags & FLAG_EXCLUDE > 0) { + if(restore_send_nor(restore, ipsw, tss) < 0) { + error("ERROR: Unable to send NOR data\n"); + return -1; + } } else { - idevicerestore_quit = 1; + client->flags &= 1; } } else { // Unknown DataType!! debug("Unknown data request received\n"); + debug_plist(message); } } return 0; } -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { +int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { int error = 0; char* type = NULL; char* kernel = NULL; @@ -525,7 +580,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* 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) { + if (restore_open_with_timeout(client) < 0) { error("ERROR: Unable to open device in restore mode\n"); return -1; } @@ -541,7 +596,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // 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) { + while ((client->flags & FLAG_QUIT) == 0) { restore_error = restored_receive(restore, &message); if (restore_error != RESTORE_E_SUCCESS) { debug("No data to read\n"); @@ -564,7 +619,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // 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); + error = restore_handle_data_request_msg(client, device, restore, message, tss, ipsw, filesystem); } // progress notification messages sent by the restored inform the client @@ -590,7 +645,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // an unrecoverable error, so we need to bail. if (error < 0) { error("ERROR: Unable to successfully restore device\n"); - idevicerestore_quit = 1; + client->flags &= FLAG_QUIT; } plist_free(message); diff --git a/src/restore.h b/src/restore.h index cf9cf51..5446aa8 100644 --- a/src/restore.h +++ b/src/restore.h @@ -1,4 +1,4 @@ -/* + /* * restore.h * Functions for handling idevices in restore mode * @@ -22,21 +22,41 @@ #ifndef IDEVICERESTORE_RESTORE_H #define IDEVICERESTORE_RESTORE_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include #include -int restore_reboot(const char* uuid); +struct restore_client_t { + plist_t tss; + idevice_t device; + const char* uuid; + unsigned int operation; + const char* filesystem; + restored_client_t client; +}; + int restore_check_mode(const char* uuid); int restore_check_device(const char* uuid); +int restore_client_new(struct idevicerestore_client_t* client); +void restore_client_free(struct idevicerestore_client_t* client); +int restore_reboot(struct idevicerestore_client_t* client); 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_handle_progress_msg(restored_client_t client, plist_t msg); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem); 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_kernelcache(restored_client_t client, const char* ipsw, plist_t tss); +int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); +int restore_open_with_timeout(struct idevicerestore_client_t* client); int restore_send_filesystem(idevice_t device, const char* filesystem); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/tss.h b/src/tss.h index ff60da0..d45c74c 100644 --- a/src/tss.h +++ b/src/tss.h @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_TSS_H #define IDEVICERESTORE_TSS_H +#ifdef __cplusplus +extern "C" { +#endif + #include plist_t tss_send_request(plist_t request); @@ -30,4 +34,9 @@ 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); + +#ifdef __cplusplus +} +#endif + #endif -- cgit v1.1-32-gdbae From 930f4b350474435e011b9dca18424dd1c42ea353 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 21 Jun 2010 03:47:54 -0400 Subject: Finally fixed the out of control problem --- src/Makefile.am | 2 +- src/common.c | 2 + src/common.h | 4 +- src/dfu.c | 29 ++++---- src/idevicerestore.c | 23 +++--- src/idevicerestore.h | 1 - src/img3.c | 1 + src/normal.c | 100 ++++++++++++++++++++++---- src/normal.h | 4 ++ src/recovery.c | 197 ++++++++++++++++++++------------------------------- src/recovery.h | 26 ++++--- src/restore.c | 6 +- 12 files changed, 221 insertions(+), 174 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index a44640f..009f2dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c dfu.c asr.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c +idevicerestore_SOURCES = idevicerestore.c common.c tss.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c activate.c idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file diff --git a/src/common.c b/src/common.c index 07a7075..8e76697 100644 --- a/src/common.c +++ b/src/common.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "common.h" int idevicerestore_debug = 0; diff --git a/src/common.h b/src/common.h index cb774a5..50f682f 100644 --- a/src/common.h +++ b/src/common.h @@ -22,12 +22,12 @@ #ifndef IDEVICERESTORE_COMMON_H #define IDEVICERESTORE_COMMON_H -#include - #ifdef __cplusplus extern "C" { #endif +#include + #define info(...) printf(__VA_ARGS__) #define error(...) fprintf(stderr, __VA_ARGS__) #define debug(...) if(idevicerestore_debug) fprintf(stderr, __VA_ARGS__) diff --git a/src/dfu.c b/src/dfu.c index b53803e..6fd2648 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -24,7 +24,7 @@ #include #include "dfu.h" -//#include "recovery.h" +#include "recovery.h" #include "idevicerestore.h" int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) { @@ -100,46 +100,51 @@ int dfu_open_with_timeout(struct idevicerestore_client_t* client, uint32_t timeo } irecv_event_subscribe(recovery, IRECV_PROGRESS, &dfu_progress_callback, NULL); - client->dfu = recovery; + client->dfu->client = recovery; return 0; } +int dfu_check_mode() { + return -1; +} + int dfu_enter_recovery(struct idevicerestore_client_t* client) { 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) { + if (recovery_open_with_timeout(client) < 0 || dfu->mode != kDfuMode) { error("ERROR: Unable to connect to DFU device\n"); if (dfu) irecv_close(dfu); return -1; } - if (recovery_send_signed_component(dfu, client->ipsw, client->tss, "iBSS") < 0) { + if (recovery_send_signed_component(client, "iBSS") < 0) { error("ERROR: Unable to send %s to device\n", component); irecv_close(dfu); return -1; } - dfu_error = irecv_reset(dfu); + dfu_error = irecv_reset(client->dfu->client); if (dfu_error != IRECV_E_SUCCESS) { error("ERROR: Unable to reset device\n"); irecv_close(dfu); return -1; } - irecv_close(dfu); - dfu = NULL; + irecv_close(client->dfu->client); + client->dfu->client = 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) { + if (recovery_open_with_timeout(client) < 0 || client->mode->index != kDfuMode) { error("ERROR: Unable to connect to recovery device\n"); - if (dfu) - irecv_close(dfu); + if (client->dfu->client) + irecv_close(client->dfu->client); return -1; } client->mode = &idevicerestore_modes[MODE_RECOVERY]; - irecv_close(dfu); - dfu = NULL; + irecv_close(client->dfu->client); + client->dfu->client = NULL; return 0; } + diff --git a/src/idevicerestore.c b/src/idevicerestore.c index cdbff27..606062c 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -26,15 +26,15 @@ #include #include -#include "idevicerestore.h" -//#include "recovery.h" -#include "restore.h" -#include "common.h" -#include "normal.h" -#include "img3.h" -#include "ipsw.h" #include "dfu.h" #include "tss.h" +#include "img3.h" +#include "ipsw.h" +#include "common.h" +#include "normal.h" +#include "restore.h" +#include "recovery.h" +#include "idevicerestore.h" static struct option longopts[] = { { "uuid", required_argument, NULL, 'u' }, @@ -100,7 +100,6 @@ int main(int argc, char* argv[]) { return -1; } memset(client, '\0', sizeof(struct idevicerestore_client_t)); - idevicerestore = client; while ((opt = getopt_long(argc, argv, "dhcexu:", longopts, &optindex)) > 0) { switch (opt) { @@ -277,7 +276,7 @@ int main(int argc, char* argv[]) { // if the device is in normal mode, place device into recovery mode if (client->mode->index == MODE_NORMAL) { info("Entering recovery mode...\n"); - if (normal_enter_recovery(uuid) < 0) { + if (normal_enter_recovery(client) < 0) { error("ERROR: Unable to place device into recovery mode\n"); if (tss) plist_free(tss); @@ -468,7 +467,7 @@ int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_bdid(&client->device->board_id) < 0) { + if (recovery_get_bdid(client, &client->device->board_id) < 0) { client->device->board_id = -1; return -1; } @@ -493,7 +492,7 @@ int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_cpid(&client->device->chip_id) < 0) { + if (recovery_get_cpid(client, &client->device->chip_id) < 0) { client->device->chip_id = -1; return -1; } @@ -523,7 +522,7 @@ int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_ecid(ecid) < 0) { + if (recovery_get_ecid(client, ecid) < 0) { *ecid = 0; return -1; } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 7e5873b..1fadf15 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -29,7 +29,6 @@ extern "C" { #include #include -#include #include "common.h" void usage(int argc, char* argv[]); diff --git a/src/img3.c b/src/img3.c index 5c79e54..902bea4 100644 --- a/src/img3.c +++ b/src/img3.c @@ -24,6 +24,7 @@ #include #include "img3.h" +#include "common.h" #include "idevicerestore.h" img3_file* img3_parse_file(char* data, int size) { diff --git a/src/normal.c b/src/normal.c index 7ae4774..29f3911 100644 --- a/src/normal.c +++ b/src/normal.c @@ -20,34 +20,43 @@ */ #include -#include +#include +#include #include #include #include #include "common.h" #include "normal.h" -//#include "recovery.h" +#include "recovery.h" -int normal_client_new(struct normal_client_t** normal) { - struct normal_client_t* client = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); - if (client == NULL) { - error("ERROR: Out of memory\n"); - return -1; +static int normal_device_connected = 0; + +void normal_device_callback(const idevice_event_t* event, void* userdata) { + struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata; + if (event->event == IDEVICE_DEVICE_ADD) { + normal_device_connected = 1; + + } else if (event->event == IDEVICE_DEVICE_REMOVE) { + normal_device_connected = 0; + client->flags &= FLAG_QUIT; } +} - if (normal_open_with_timeout(client) < 0) { - normal_client_free(client); +int normal_client_new(struct idevicerestore_client_t* client) { + struct normal_client_t* normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); + if (normal == NULL) { + error("ERROR: Out of memory\n"); return -1; } - if(normal_check_mode(client) < 0) { + if (normal_open_with_timeout(client) < 0) { normal_client_free(client); return -1; } - *normal = client; - return client; + client->normal = normal; + return 0; } void normal_client_free(struct idevicerestore_client_t* client) { @@ -101,6 +110,73 @@ int normal_check_mode(const char* uuid) { return 0; } +int normal_open_with_timeout(struct idevicerestore_client_t* client) { + int i = 0; + int attempts = 10; + idevice_t device = NULL; + lockdownd_client_t lockdownd = NULL; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdownd_error = LOCKDOWN_E_SUCCESS; + + // no context exists so bail + if(client == NULL) { + return -1; + } + + // create our normal client if it doesn't yet exist + if(client->normal == NULL) { + client->normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); + if(client->normal == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + } + + device_error = idevice_event_subscribe(&normal_device_callback, NULL); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to subscribe to device events\n"); + return -1; + } + + for (i = 1; i <= attempts; i++) { + if (normal_device_connected == 1) { + break; + } + + if (i == attempts) { + error("ERROR: Unable to connect to device in normal mode\n"); + return -1; + } + + sleep(2); + } + + device_error = idevice_new(&device, client->uuid); + if (device_error != IDEVICE_E_SUCCESS) { + return -1; + } + + lockdownd_error = lockdownd_client_new(device, &lockdownd, "idevicerestore"); + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + //idevice_event_unsubscribe(); + idevice_free(device); + return -1; + } + + char* type = NULL; + lockdownd_error = lockdownd_query_type(lockdownd, &type); + if (lockdownd_error != LOCKDOWN_E_SUCCESS) { + lockdownd_client_free(lockdownd); + //idevice_event_unsubscribe(); + idevice_free(device); + return -1; + } + + client->normal->device = device; + client->normal->client = lockdownd; + return 0; +} + int normal_check_device(const char* uuid) { int i = 0; idevice_t device = NULL; diff --git a/src/normal.h b/src/normal.h index 352e643..836d495 100644 --- a/src/normal.h +++ b/src/normal.h @@ -37,8 +37,12 @@ struct normal_client_t { plist_t tss; }; + int normal_check_mode(const char* uuid); int normal_check_device(const char* uuid); +int normal_client_new(struct idevicerestore_client_t* client); +void normal_client_free(struct idevicerestore_client_t* client); +int normal_open_with_timeout(struct idevicerestore_client_t* client); 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 bacfac7..290f368 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include "tss.h" #include "img3.h" #include "common.h" +#include "restore.h" #include "recovery.h" #include "idevicerestore.h" @@ -46,13 +46,8 @@ int recovery_client_new(struct idevicerestore_client_t* client) { return -1; } - if (recovery_open_with_timeout(recovery) < 0) { - recovery_client_free(recovery); - return -1; - } - - if(recovery_check_mode(recovery) < 0) { - recovery_client_free(recovery); + if (recovery_open_with_timeout(client) < 0) { + recovery_client_free(client); return -1; } @@ -61,16 +56,42 @@ int recovery_client_new(struct idevicerestore_client_t* client) { } void recovery_client_free(struct idevicerestore_client_t* client) { - struct recovery_client_t* recovery = client->recovery; - if (recovery) { - if(recovery->client) { - irecv_close(recovery); - recovery = NULL; + if(client) { + if (client->recovery) { + if(client->recovery->client) { + irecv_close(client->recovery->client); + client->recovery->client = NULL; + } + free(client->recovery); + client->recovery = NULL; + } + } +} + +int recovery_open_with_timeout(struct idevicerestore_client_t* client) { + int i = 0; + int attempts = 10; + irecv_client_t recovery = NULL; + irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; + + for (i = 1; i <= attempts; i++) { + recovery_error = irecv_open(&recovery); + if (recovery_error == IRECV_E_SUCCESS) { + break; } - free(recovery); - client->recovery = NULL; + if (i >= attempts) { + error("ERROR: Unable to connect to device in recovery mode\n"); + return -1; + } + + sleep(2); + debug("Retrying connection...\n"); } + + irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); + client->recovery->client = recovery; + return 0; } int recovery_check_mode() { @@ -92,28 +113,28 @@ int recovery_check_mode() { return 0; } -int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { +int recovery_enter_restore(struct idevicerestore_client_t* client) { idevice_t device = NULL; restored_client_t restore = NULL; // upload data to make device boot restore mode - if (recovery_send_ibec(ipsw, tss) < 0) { + if (recovery_send_ibec(client) < 0) { error("ERROR: Unable to send iBEC\n"); return -1; } sleep(1); - if (recovery_send_applelogo(ipsw, tss) < 0) { + if (recovery_send_applelogo(client) < 0) { error("ERROR: Unable to send AppleLogo\n"); return -1; } - if (recovery_send_devicetree(ipsw, tss) < 0) { + if (recovery_send_devicetree(client) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } - if (recovery_send_ramdisk(ipsw, tss) < 0) { + if (recovery_send_ramdisk(client) < 0) { error("ERROR: Unable to send Ramdisk\n"); return -1; } @@ -124,35 +145,35 @@ int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { printf("Hit any key to continue..."); getchar(); - if (recovery_send_kernelcache(ipsw, tss) < 0) { + if (recovery_send_kernelcache(client) < 0) { error("ERROR: Unable to send KernelCache\n"); return -1; } info("Waiting for device to enter restore mode\n"); - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { + if (restore_open_with_timeout(client) < 0) { error("ERROR: Unable to connect to device in restore mode\n"); return -1; } - restore_close(device, restore); + restore_client_free(client); client->mode = &idevicerestore_modes[MODE_RESTORE]; return 0; } -int recovery_send_signed_component(struct idevicerestore_client_t client, const char* ipsw, plist_t tss, char* component) { +int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* component) { int size = 0; char* data = NULL; char* path = NULL; char* blob = NULL; irecv_error_t error = 0; - if (tss_get_entry_path(tss, component, &path) < 0) { + if (tss_get_entry_path(client->tss, component, &path) < 0) { error("ERROR: Unable to get component path\n"); return -1; } - if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { + if (get_signed_component(client, client->ipsw, client->tss, path, &data, &size) < 0) { error("ERROR: Unable to get signed component: %s\n", component); free(path); return -1; @@ -160,7 +181,7 @@ int recovery_send_signed_component(struct idevicerestore_client_t client, const free(path); info("Sending %s...\n", component); - error = irecv_send_buffer(client, data, size); + error = irecv_send_buffer(client->recovery->client, data, size); if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to send component: %s\n", component); free(data); @@ -171,84 +192,47 @@ int recovery_send_signed_component(struct idevicerestore_client_t client, const return 0; } -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_UNKNOWN_ERROR; - - for (i = 1; i <= attempts; i++) { - recovery_error = irecv_open(&recovery); - 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); - debug("Retrying connection...\n"); - } - - irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); - *client = recovery; - return 0; -} - -int recovery_send_ibec(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; +int recovery_send_ibec(struct idevicerestore_client_t* client) { const char* component = "iBEC"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { - return -1; - } - - recovery_error = irecv_send_command(recovery, "setenv auto-boot true"); + recovery_error = irecv_send_command(client->recovery->client, "setenv auto-boot true"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set auto-boot environmental variable\n"); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "saveenv"); + recovery_error = irecv_send_command(client->recovery->client, "saveenv"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to save environmental variable\n"); - irecv_close(recovery); return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "iBEC") < 0) { + if (recovery_send_signed_component(client, "iBEC") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "go"); + recovery_error = irecv_send_command(client->recovery->client, "go"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); return -1; } - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_send_applelogo(const char* ipsw, plist_t tss) { +int recovery_send_applelogo(struct idevicerestore_client_t* client) { irecv_client_t recovery = NULL; const char* component = "applelogo"; irecv_error_t recovery_error = IRECV_E_SUCCESS; info("Sending %s...\n", component); - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "AppleLogo") < 0) { + if (recovery_send_signed_component(client, "AppleLogo") < 0) { error("ERROR: Unable to send %s to device.\n", component); irecv_close(recovery); return -1; @@ -273,141 +257,114 @@ int recovery_send_applelogo(const char* ipsw, plist_t tss) { return 0; } -int recovery_send_devicetree(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; +int recovery_send_devicetree(struct idevicerestore_client_t* client) { const char* component = "devicetree"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreDeviceTree") < 0) { + if (recovery_send_signed_component(client, "RestoreDeviceTree") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "devicetree"); + recovery_error = irecv_send_command(client->recovery->client, "devicetree"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); return -1; } - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_send_ramdisk(const char* ipsw, plist_t tss) { +int recovery_send_ramdisk(struct idevicerestore_client_t* client) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - irecv_client_t recovery = NULL; const char *component = "ramdisk"; - recovery_error = recovery_open_with_timeout(&recovery); + recovery_error = recovery_open_with_timeout(client); if (recovery_error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreRamDisk") < 0) { + if (recovery_send_signed_component(client, "RestoreRamDisk") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "ramdisk"); + recovery_error = irecv_send_command(client->recovery->client, "ramdisk"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); return -1; } - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_send_kernelcache(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; +int recovery_send_kernelcache(struct idevicerestore_client_t* client) { const char* component = "kernelcache"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreKernelCache") < 0) { + if (recovery_send_signed_component(client, "RestoreKernelCache") < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "bootx"); + recovery_error = irecv_send_command(client->recovery->client, "bootx"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); return -1; } - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_get_ecid(uint64_t* ecid) { - irecv_client_t recovery = NULL; +int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - recovery_error = irecv_get_ecid(recovery, ecid); + recovery_error = irecv_get_ecid(client->recovery->client, ecid); if (recovery_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; +int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - recovery_error = irecv_get_cpid(recovery, cpid); + recovery_error = irecv_get_cpid(client->recovery->client, cpid); if (recovery_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; +int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - recovery_error = irecv_get_bdid(recovery, bdid); + recovery_error = irecv_get_bdid(client->recovery->client, bdid); if (recovery_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 6cd467c..5d1129f 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -28,8 +28,11 @@ extern "C" { #include #include -#include +#include "common.h" + +struct irecv_client; +typedef struct irecv_client* irecv_client_t; struct recovery_client_t { irecv_client_t client; const char* ipsw; @@ -37,18 +40,19 @@ struct recovery_client_t { }; int recovery_check_mode(); +int recovery_open_with_timeout(struct idevicerestore_client_t* client); int recovery_client_new(struct idevicerestore_client_t* client); void recovery_client_free(struct idevicerestore_client_t* client); -int recovery_send_signed_component(struct idevicerestore_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); -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); +int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* component); +int recovery_send_ibec(struct idevicerestore_client_t* client); +int recovery_send_applelogo(struct idevicerestore_client_t* client); +int recovery_send_devicetree(struct idevicerestore_client_t* client); +int recovery_send_ramdisk(struct idevicerestore_client_t* client); +int recovery_send_kernelcache(struct idevicerestore_client_t* client); +int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); +int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); +int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); + #ifdef __cplusplus } diff --git a/src/restore.c b/src/restore.c index b4cf0b2..bf4b62f 100644 --- a/src/restore.c +++ b/src/restore.c @@ -193,7 +193,7 @@ int restore_reboot(struct idevicerestore_client_t* client) { } } - restore_error = restored_reboot(client); + restore_error = restored_reboot(client->restore->client); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to reboot the device from restore mode\n"); return -1; @@ -590,7 +590,7 @@ int restore_device(struct idevicerestore_client_t* client, const char* uuid, con restore_error = restored_start_restore(restore); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to start the restore process\n"); - restore_close(device, restore); + restore_client_free(client); return -1; } @@ -652,6 +652,6 @@ int restore_device(struct idevicerestore_client_t* client, const char* uuid, con message = NULL; } - restore_close(device, restore); + restore_client_free(client); return 0; } -- cgit v1.1-32-gdbae From 7edbc8417b760179337b507a6d957882b71dde2e Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 21 Jun 2010 04:50:40 -0400 Subject: Fixed a few more compile errors, everything should compile fine now, but i'm not sure if it will run yet --- src/idevicerestore.c | 69 ++-------------------------------------------------- src/idevicerestore.h | 1 + src/normal.c | 6 ++--- src/normal.h | 2 +- 4 files changed, 7 insertions(+), 71 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 606062c..3e346fc 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -59,33 +59,6 @@ void usage(int argc, char* argv[]) { printf("\n"); } -int get_build_count(plist_t buildmanifest) { - // 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 -1; - } - - // check and make sure this identity exists in buildmanifest - return plist_array_get_size(build_identities_array); -} - -const char* get_build_name(plist_t build_identity, int identity) { - 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"); - return NULL; - } - - plist_t filesystem_info_node = plist_dict_get_item(manifest_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 NULL; - } - return NULL; -} - int main(int argc, char* argv[]) { int opt = 0; int optindex = 0; @@ -223,46 +196,6 @@ 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; - if (client->device->index > DEVICE_IPOD2G) { - info("Creating TSS request\n"); - // fetch the device's ECID for the TSS request - if (get_ecid(client, &ecid) < 0 || ecid == 0) { - error("ERROR: Unable to find device ECID\n"); - return -1; - } - debug("Found ECID %llu\n", ecid); - - // fetch the SHSH blobs for this build identity - if (get_shsh_blobs(client, 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 (client->flags & FLAG_ERASE > 0) { - info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); - build_identity = get_build_identity(client, buildmanifest, 0); - if (build_identity == NULL) { - error("ERROR: Unable to find restore identity\n"); - plist_free(buildmanifest); - return -1; - } - - if (get_shsh_blobs(client, 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(client, ipsw, build_identity, &filesystem) < 0) { @@ -629,8 +562,10 @@ const char* get_build_name(plist_t build_identity, int identity) { error("ERROR: Unable to find filesystem info node\n"); return NULL; } + return NULL; } + int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 1fadf15..d3d89a0 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -34,6 +34,7 @@ extern "C" { void usage(int argc, char* argv[]); int check_mode(struct idevicerestore_client_t* client); int check_device(struct idevicerestore_client_t* client); +int get_build_count(plist_t buildmanifest); const char* get_build_name(plist_t build_identity, int identity); int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); diff --git a/src/normal.c b/src/normal.c index 29f3911..c9a1b45 100644 --- a/src/normal.c +++ b/src/normal.c @@ -225,7 +225,7 @@ int normal_check_device(const char* uuid) { return idevicerestore_devices[i].index; } -int normal_enter_recovery(const char* uuid) { +int normal_enter_recovery(struct idevicerestore_client_t* client) { idevice_t device = NULL; irecv_client_t recovery = NULL; lockdownd_client_t lockdown = NULL; @@ -233,7 +233,7 @@ int normal_enter_recovery(const char* uuid) { idevice_error_t device_error = IDEVICE_E_SUCCESS; lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; - device_error = idevice_new(&device, uuid); + device_error = idevice_new(&device, client->uuid); if (device_error != IDEVICE_E_SUCCESS) { error("ERROR: Unable to find device\n"); return -1; @@ -259,7 +259,7 @@ int normal_enter_recovery(const char* uuid) { lockdown = NULL; device = NULL; - if (recovery_open_with_timeout(&recovery) < 0) { + if (recovery_open_with_timeout(client) < 0) { error("ERROR: Unable to enter recovery mode\n"); return -1; } diff --git a/src/normal.h b/src/normal.h index 836d495..e86bf14 100644 --- a/src/normal.h +++ b/src/normal.h @@ -43,7 +43,7 @@ int normal_check_device(const char* uuid); int normal_client_new(struct idevicerestore_client_t* client); void normal_client_free(struct idevicerestore_client_t* client); int normal_open_with_timeout(struct idevicerestore_client_t* client); -int normal_enter_recovery(const char* uuid); +int normal_enter_recovery(struct idevicerestore_client_t* client); 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); -- cgit v1.1-32-gdbae From b27dd3c4bbe2915fd7c35383ef283e222b422829 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Mon, 21 Jun 2010 04:58:13 -0400 Subject: Update TODO --- TODO | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index 6223afe..efd9e9b 100644 --- a/TODO +++ b/TODO @@ -1,17 +1,24 @@ TODO List ------------------------------------------------ -o) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) +o) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) (in progress...) o) Also img3 should be updated to be able to fetch tags from each image such as the VERS tag to be able to compare with the current iBoot version. -o) Many of idevicerestore options can probably be compiled into one flags structure. o) Need to add 8900 file support into img3.c. o) Cacheing TSS and activation info locally so the program doesn't need to query apple/cydia servers everytime would be nice. o) Need to add support to handle and display status messages correctly. o) Writing restore logs to an external file for debugging would be a great help. -o) Need to change some info progresses to only display the component name rather then the full path which can be messy. -o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. +o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. (in progress...) o) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. -o) Clean up refactor restore_send_kernelcache() +o) Double check restore_send_kernelcache() o) Clean up and refactor restore_send_nor() o) Finishing cleaning up asr_perform_validation -o) Double check to make sure asr_send_payload looks clean \ No newline at end of file +o) Double check asr_send_payload() +o) Cleanup dfu.c/dfu.h +o) Cleanup recovery.c/recovery.h +o) Cleanup normal.c/normal.h +o) Cleanup restore.c/restore.h +o) Cleanup tss.c/tss.h +o) Cleanup img3.c/img3.h +o) Cleanup ipsw.c/ipsw.h +o) Make ipsw.c a proxy to tss.c and img3.c +o) Make all components only have access to their own context instead of a single global application context (less coupling) \ No newline at end of file -- cgit v1.1-32-gdbae From 9ac5edef25cf7e084a639c2e70f9f7e963d96152 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 22 Jun 2010 03:08:45 -0400 Subject: Added info for iPhone4 and fixed a few runtime errors --- src/common.h | 5 ++++- src/idevicerestore.c | 4 ++-- src/recovery.c | 9 +++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/common.h b/src/common.h index 50f682f..f8c0ae0 100644 --- a/src/common.h +++ b/src/common.h @@ -40,6 +40,7 @@ extern "C" { #define CPID_IPHONE3GS 8920 #define CPID_IPOD3G 8922 #define CPID_IPAD1G 8930 +#define CPID_IPHONE4 8930 #define BDID_UNKNOWN -1 #define BDID_IPHONE2G 0 @@ -49,6 +50,7 @@ extern "C" { #define BDID_IPHONE3GS 0 #define BDID_IPOD3G 2 #define BDID_IPAD1G 2 +#define BDID_IPHONE4 0 #define DEVICE_UNKNOWN -1 #define DEVICE_IPHONE2G 0 @@ -58,6 +60,7 @@ extern "C" { #define DEVICE_IPHONE3GS 4 #define DEVICE_IPOD3G 5 #define DEVICE_IPAD1G 6 +#define DEVICE_IPHONE4 7 #define MODE_UNKNOWN -1 #define MODE_DFU 0 @@ -131,7 +134,7 @@ static struct idevicerestore_device_t idevicerestore_devices[] = { { 4, "iPhone2,1", "N88AP", 0, 8920 }, { 5, "iPod3,1", "N18AP", 2, 8922 }, { 6, "iPad1,1", "K48AP", 2, 8930 }, - { 6, "iPhone3,1", "XXXAP", 0, 0 }, + { 7, "iPhone3,1", "N90AP", 0, 8930 }, { -1, NULL, NULL, -1, -1 } }; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3e346fc..456d290 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -417,7 +417,7 @@ int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_cpid(client->uuid, &client->device->chip_id) < 0) { + if (normal_get_cpid(client->uuid, cpid) < 0) { client->device->chip_id = -1; return -1; } @@ -425,7 +425,7 @@ int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_cpid(client, &client->device->chip_id) < 0) { + if (recovery_get_cpid(client, cpid) < 0) { client->device->chip_id = -1; return -1; } diff --git a/src/recovery.c b/src/recovery.c index 290f368..fbcc49c 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -45,6 +45,7 @@ int recovery_client_new(struct idevicerestore_client_t* client) { error("ERROR: Out of memory\n"); return -1; } + client->recovery = recovery; if (recovery_open_with_timeout(client) < 0) { recovery_client_free(client); @@ -74,6 +75,14 @@ int recovery_open_with_timeout(struct idevicerestore_client_t* client) { irecv_client_t recovery = NULL; irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; + if(client->recovery == NULL) { + if(recovery_client_new(client) < 0) { + error("ERROR: Unable to open device in recovery mode\n"); + return -1; + } + return 0; + } + for (i = 1; i <= attempts; i++) { recovery_error = irecv_open(&recovery); if (recovery_error == IRECV_E_SUCCESS) { -- cgit v1.1-32-gdbae From 628f5d0ee70daec242062a3dda3a7784d516dd30 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Tue, 22 Jun 2010 03:35:54 -0400 Subject: Small change to make the program use irecovery command functions rather then duplicating them --- src/recovery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/recovery.c b/src/recovery.c index fbcc49c..4240817 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -205,7 +205,8 @@ int recovery_send_ibec(struct idevicerestore_client_t* client) { const char* component = "iBEC"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - recovery_error = irecv_send_command(client->recovery->client, "setenv auto-boot true"); + //recovery_error = irecv_send_command(client->recovery->client, "setenv auto-boot true"); + recovery_error = irecv_setenv(client->recovery->client, "auto-boot", "true"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set auto-boot environmental variable\n"); return -1; -- cgit v1.1-32-gdbae From 64ad5928ac315798e0c45690d1a477f5fd3a79f3 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 14:23:43 +0200 Subject: Do not report the detected device mode twice --- src/idevicerestore.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 456d290..c338a15 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -279,22 +279,18 @@ int check_mode(struct idevicerestore_client_t* client) { int mode = MODE_UNKNOWN; if (recovery_check_mode() == 0) { - info("Found device in recovery mode\n"); mode = MODE_RECOVERY; } else if (dfu_check_mode() == 0) { - info("Found device in DFU mode\n"); mode = MODE_DFU; } else if (normal_check_mode(client->uuid) == 0) { - info("Found device in normal mode\n"); mode = MODE_NORMAL; } else if (restore_check_mode(client->uuid) == 0) { - info("Found device in restore mode\n"); mode = MODE_RESTORE; } -- cgit v1.1-32-gdbae From 5c3afed329e828342d735b4af9a9cae90fcc9a34 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 15:33:15 +0200 Subject: Use debug_plist in tss code and remove redundant code --- src/tss.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/tss.c b/src/tss.c index 6696b60..0d4422c 100644 --- a/src/tss.c +++ b/src/tss.c @@ -126,11 +126,7 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { } if (idevicerestore_debug) { - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_request, &xml, &sz); - debug("%s", xml); - free(xml); + debug_plist(tss_request); } return tss_request; @@ -207,11 +203,7 @@ plist_t tss_send_request(plist_t tss_request) { free(response); if (idevicerestore_debug) { - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_response, &xml, &sz); - debug("%s", xml); - free(xml); + debug_plist(tss_response); } return tss_response; -- cgit v1.1-32-gdbae From af07bf36689bb07a6b862deb69c0391717c73a51 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 15:35:27 +0200 Subject: Do not depend on device model to extract correct buildmanifest Since the iOS 4 IPSW contains a BuildManifest.plist even for devices that do not require personal signing, the prior code logic would fail. --- src/idevicerestore.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index c338a15..38e765d 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -469,24 +469,23 @@ int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ip int size = 0; char* data = NULL; int device = client->device->index; - 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 (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; - } + /* older devices don't require personalized firmwares and use a BuildManifesto.plist */ + if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) { + plist_from_xml(data, size, buildmanifest); + return 0; + } - } else { - return -1; + data = NULL; + size = 0; + + /* whereas newer devices do not require personalized firmwares and use a BuildManifest.plist */ + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) == 0) { + plist_from_xml(data, size, buildmanifest); + return 0; } - plist_from_xml(data, size, buildmanifest); - return 0; + return -1; } plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity) { -- cgit v1.1-32-gdbae From 89436938ba55bdac2162970b37608666a68a1bb7 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 15:38:38 +0200 Subject: Fix segfault and handling of cli arguments --- src/idevicerestore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 38e765d..37577b0 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -47,7 +47,7 @@ static struct option longopts[] = { }; void usage(int argc, char* argv[]) { - char *name = strrchr(argv[0], '/'); + 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(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); @@ -78,7 +78,7 @@ int main(int argc, char* argv[]) { switch (opt) { case 'h': usage(argc, argv); - break; + return 0; case 'd': client->flags &= FLAG_DEBUG; @@ -106,10 +106,10 @@ int main(int argc, char* argv[]) { } } - argc -= optind; - argv += optind; + if ((argc-optind) == 1) { + argc -= optind; + argv += optind; - if (argc == 1) { ipsw = argv[0]; } else { usage(argc, argv); -- cgit v1.1-32-gdbae From 410767972692ac699f7f7b40a65467fe9824a623 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 16:12:37 +0200 Subject: Remove activation code, this will be handled by the ideviceactivate tool We already handle the complex restore process, let's avoid the trouble to add up the activation complexity additionally. --- src/Makefile.am | 4 +- src/activate.c | 262 --------------------------------------------------- src/activate.h | 41 -------- src/idevicerestore.c | 18 ---- 4 files changed, 2 insertions(+), 323 deletions(-) delete mode 100644 src/activate.c delete mode 100644 src/activate.h diff --git a/src/Makefile.am b/src/Makefile.am index 009f2dd..a4c8fc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c common.c tss.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c activate.c +idevicerestore_SOURCES = idevicerestore.c common.c tss.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c idevicerestore_CFLAGS = $(AM_CFLAGS) -idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file +idevicerestore_LDFLAGS = $(AM_LDFLAGS) diff --git a/src/activate.c b/src/activate.c deleted file mode 100644 index 1fcd2e2..0000000 --- a/src/activate.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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; -} - -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 deleted file mode 100644 index 00510d3..0000000 --- a/src/activate.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 IDEVICERESTORE_ACTIVATE_H -#define IDEVICERESTORE_ACTIVATE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#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); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 37577b0..6b17ad3 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -249,24 +249,6 @@ int main(int argc, char* argv[]) { } } - // device has finished restoring, lets see if we need to activate - if (client->mode->index == MODE_NORMAL) { - 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); -- cgit v1.1-32-gdbae From 742d9e87ad40c6d338ea2bf050ea5fb527a59b58 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 19:10:00 +0200 Subject: Improve error message if a device mode can not be determined Most of the time it means that there is no device attached as we should be able to detect any mode of a device. --- src/idevicerestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 6b17ad3..2a7a96b 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -126,7 +126,7 @@ int main(int argc, char* argv[]) { // check which mode the device is currently in so we know where to start if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) { - error("ERROR: Unable to discover current device state\n"); + error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); return -1; } info("Found device in %s mode\n", client->mode->string); -- cgit v1.1-32-gdbae From 0a07525af88d5b6522809595d4c5e1eb2a6e022c Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 19:12:06 +0200 Subject: Fix segfault due to broken retrieval of board id --- src/idevicerestore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 2a7a96b..03845fe 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -370,16 +370,16 @@ int check_device(struct idevicerestore_client_t* client) { int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_bdid(client->uuid, &client->device->board_id) < 0) { - client->device->board_id = -1; + if (normal_get_bdid(client->uuid, bdid) < 0) { + *bdid = 0; return -1; } break; case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_bdid(client, &client->device->board_id) < 0) { - client->device->board_id = -1; + if (recovery_get_bdid(client, bdid) < 0) { + *bdid = 0; return -1; } break; -- cgit v1.1-32-gdbae From a92e3de475368eea3c01372ce37d758a35e2a290 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 19:12:56 +0200 Subject: Do not attempt to open another recovery session if one exists --- src/recovery.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/recovery.c b/src/recovery.c index 4240817..233224a 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -352,8 +352,10 @@ int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(client) < 0) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } recovery_error = irecv_get_cpid(client->recovery->client, cpid); @@ -367,8 +369,10 @@ int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(client) < 0) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } recovery_error = irecv_get_bdid(client->recovery->client, bdid); -- cgit v1.1-32-gdbae From 17627444b5d61449a638a7937326d852a2705a11 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 8 Jul 2010 19:14:19 +0200 Subject: Remove get_build_name() which was not working and has no real use --- src/idevicerestore.c | 17 ----------------- src/idevicerestore.h | 1 - 2 files changed, 18 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 03845fe..7312279 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -190,7 +190,6 @@ int main(int argc, char* argv[]) { // for this build identity, so check the next one continue; } - info("[%d] %s\n", i, get_build_name(buildmanifest, i)); valid_builds++; } } @@ -527,22 +526,6 @@ int get_build_count(plist_t buildmanifest) { return plist_array_get_size(build_identities_array); } -const char* get_build_name(plist_t build_identity, int identity) { - 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"); - return NULL; - } - - plist_t filesystem_info_node = plist_dict_get_item(manifest_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 NULL; - } - return NULL; -} - - int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; diff --git a/src/idevicerestore.h b/src/idevicerestore.h index d3d89a0..407c0db 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -35,7 +35,6 @@ void usage(int argc, char* argv[]); int check_mode(struct idevicerestore_client_t* client); int check_device(struct idevicerestore_client_t* client); int get_build_count(plist_t buildmanifest); -const char* get_build_name(plist_t build_identity, int identity); int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); -- cgit v1.1-32-gdbae From b472d5347406fc24e9e489b5493dd6bf134dc92c Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 9 Jul 2010 03:33:34 +0200 Subject: Set and use static idevicerestore_debug flag for debug output --- src/idevicerestore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 7312279..4a2b8ab 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -82,6 +82,7 @@ int main(int argc, char* argv[]) { case 'd': client->flags &= FLAG_DEBUG; + idevicerestore_debug = 1; break; case 'e': @@ -614,7 +615,7 @@ int get_signed_component(struct idevicerestore_client_t* client, const char* ips } img3_free(img3); - if (client->flags & FLAG_DEBUG) { + if (idevicerestore_debug) { write_file(component_name, component_data, component_size); } -- cgit v1.1-32-gdbae From d1a5f28e6d1a3b7a24e406a215b4037dd68d41c9 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 9 Jul 2010 03:36:18 +0200 Subject: Implement handling unknown img3 element for 8900 chip devices --- src/img3.c | 22 ++++++++++++++++++++++ src/img3.h | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/img3.c b/src/img3.c index 902bea4..1969ece 100644 --- a/src/img3.c +++ b/src/img3.c @@ -155,6 +155,16 @@ img3_file* img3_parse_file(char* data, int size) { debug("Parsed CERT element\n"); break; + case kUnknElement: + image->unkn_element = img3_parse_element(&data[data_offset]); + if (image->unkn_element == NULL) { + error("ERROR: Unable to parse UNKN element\n"); + img3_free(image); + return NULL; + } + debug("Parsed UNKN element\n"); + break; + default: error("ERROR: Unknown IMG3 element type\n"); img3_free(image); @@ -244,6 +254,11 @@ void img3_free(img3_file* image) { image->cert_element = NULL; } + if (image->unkn_element != NULL) { + img3_free_element(image->unkn_element); + image->unkn_element = NULL; + } + free(image); image = NULL; } @@ -336,6 +351,9 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { if (image->cert_element != NULL) { size += image->cert_element->header->full_size; } + if (image->unkn_element != NULL) { + size += image->unkn_element->header->full_size; + } char* data = (char*) malloc(size); if (data == NULL) { @@ -393,6 +411,10 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { memcpy(&data[offset], image->cert_element->data, image->cert_element->header->full_size); offset += image->cert_element->header->full_size; } + if (image->unkn_element != NULL) { + memcpy(&data[offset], image->unkn_element->data, image->unkn_element->header->full_size); + offset += image->unkn_element->header->full_size; + } if (offset != size) { error("ERROR: Incorrectly sized image data\n"); diff --git a/src/img3.h b/src/img3.h index 796a8e1..cb042b5 100644 --- a/src/img3.h +++ b/src/img3.h @@ -45,7 +45,8 @@ typedef enum { kVersElement = 0x56455253, // VERS kBordElement = 0x424F5244, // BORD kSepoElement = 0x5345504F, // SEPO - kEcidElement = 0x45434944 // ECID + kEcidElement = 0x45434944, // ECID + kUnknElement = 0x53414c54 // FIXME } img3_element_type; typedef struct { @@ -81,6 +82,7 @@ typedef struct { img3_element* ecid_element; img3_element* shsh_element; img3_element* cert_element; + img3_element* unkn_element; } img3_file; void img3_free(img3_file* image); -- cgit v1.1-32-gdbae From bfd4f97062a89d046d73f9e7439ac5e74ef8dcdc Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 9 Jul 2010 03:44:40 +0200 Subject: Add function to retrieve a component path from a build identity --- src/idevicerestore.c | 65 ++++++++++++++++++++++++++++++++++------------------ src/idevicerestore.h | 1 + 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 4a2b8ab..19ae8be 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -530,31 +530,11 @@ int get_build_count(plist_t buildmanifest) { int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; - 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(manifest_node, "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"); + if (build_identity_get_component_path(build_identity, "OS", &filename) < 0) { + error("ERROR: Unable get path for filesystem component\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"); @@ -623,3 +603,44 @@ int get_signed_component(struct idevicerestore_client_t* client, const char* ips *size = component_size; return 0; } + +int build_identity_get_component_path(plist_t build_identity, const char* component, char** path) { + char* filename = NULL; + + 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"); + if (filename) + free(filename); + return -1; + } + + plist_t component_node = plist_dict_get_item(manifest_node, component); + if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) { + error("ERROR: Unable to find component node for %s\n", component); + if (filename) + free(filename); + return -1; + } + + plist_t component_info_node = plist_dict_get_item(component_node, "Info"); + if (!component_info_node || plist_get_node_type(component_info_node) != PLIST_DICT) { + error("ERROR: Unable to find component info node for %s\n", component); + if (filename) + free(filename); + return -1; + } + + plist_t component_info_path_node = plist_dict_get_item(component_info_node, "Path"); + if (!component_info_path_node || plist_get_node_type(component_info_path_node) != PLIST_STRING) { + error("ERROR: Unable to find component info path node for %s\n", component); + if (filename) + free(filename); + return -1; + } + plist_get_string_val(component_info_path_node, &filename); + + *path = filename; + return 0; +} + diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 407c0db..3213b0c 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -43,6 +43,7 @@ plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t build int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t buildmanifest, char** filesystem); int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); +int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); #ifdef __cplusplus } -- cgit v1.1-32-gdbae From 4090b98d9e8cdaada701ac320e20f7c8b0cf88f6 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 9 Jul 2010 03:47:42 +0200 Subject: Implement handling of devices which do not require a tss request This introduces passing around the "selected" build identity and fixes code logic issues to make idevicerestore work again. --- src/dfu.c | 5 ++- src/dfu.h | 2 +- src/idevicerestore.c | 96 ++++++++++++++++++++++------------------ src/idevicerestore.h | 2 +- src/recovery.c | 121 +++++++++++++++++++++++++++++++-------------------- src/recovery.h | 12 ++--- src/restore.c | 63 ++++++++++++++++++--------- src/restore.h | 8 ++-- 8 files changed, 184 insertions(+), 125 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 6fd2648..0b3ad51 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -108,10 +108,11 @@ int dfu_check_mode() { return -1; } -int dfu_enter_recovery(struct idevicerestore_client_t* client) { +int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) { irecv_client_t dfu = NULL; const char* component = "iBSS"; irecv_error_t dfu_error = IRECV_E_SUCCESS; + if (recovery_open_with_timeout(client) < 0 || dfu->mode != kDfuMode) { error("ERROR: Unable to connect to DFU device\n"); if (dfu) @@ -119,7 +120,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client) { return -1; } - if (recovery_send_signed_component(client, "iBSS") < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device\n", component); irecv_close(dfu); return -1; diff --git a/src/dfu.h b/src/dfu.h index 0e20448..259cb6a 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -37,7 +37,7 @@ struct dfu_client_t { int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout); void dfu_client_free(struct idevicerestore_client_t* client); -int dfu_enter_recovery(struct idevicerestore_client_t* client); +int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); #ifdef __cplusplus diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 19ae8be..7982ed7 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -167,16 +167,15 @@ int main(int argc, char* argv[]) { } // choose whether this is an upgrade or a restore (default to upgrade) - plist_t tss = NULL; + client->tss = NULL; plist_t build_identity = NULL; if (client->flags & FLAG_ERASE) { build_identity = get_build_identity(client, buildmanifest, 0); if (build_identity == NULL) { - error("ERROR: Unable to find build any identities\n"); + error("ERROR: Unable to find any build identities\n"); plist_free(buildmanifest); return -1; } - } else { // loop through all build identities in the build manifest // and list the valid ones @@ -184,24 +183,33 @@ int main(int argc, char* argv[]) { int valid_builds = 0; int build_count = get_build_count(buildmanifest); for (i = 0; i < build_count; i++) { - if (client->device->index > DEVICE_IPOD2G) { - build_identity = get_build_identity(client, buildmanifest, i); - if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) { - // if this fails then no SHSH blobs have been saved - // for this build identity, so check the next one - continue; - } - valid_builds++; + build_identity = get_build_identity(client, buildmanifest, i); + valid_builds++; + } + } + + if (client->flags & FLAG_CUSTOM > 0) { + if (client->device->index > DEVICE_IPOD2G) { + if (get_shsh_blobs(client, ecid, build_identity, &client->tss) < 0) { + error("ERROR: Unable to get SHSH blobs for this device\n"); + return -1; } } + + /* verify if we have tss records if required */ + if ((client->device->index > DEVICE_IPOD2G) && (client->tss == NULL)) { + error("ERROR: Unable to proceed without a tss record.\n"); + plist_free(buildmanifest); + return -1; + } } // Extract filesystem from IPSW and return its name char* filesystem = NULL; - if (extract_filesystem(client, ipsw, build_identity, &filesystem) < 0) { + if (extract_filesystem(client, client->ipsw, build_identity, &filesystem) < 0) { error("ERROR: Unable to extract filesystem from IPSW\n"); - if (tss) - plist_free(tss); + if (client->tss) + plist_free(client->tss); plist_free(buildmanifest); return -1; } @@ -211,8 +219,8 @@ int main(int argc, char* argv[]) { info("Entering recovery mode...\n"); if (normal_enter_recovery(client) < 0) { error("ERROR: Unable to place device into recovery mode\n"); - if (tss) - plist_free(tss); + if (client->tss) + plist_free(client->tss); plist_free(buildmanifest); return -1; } @@ -220,22 +228,22 @@ int main(int argc, char* argv[]) { // if the device is in DFU mode, place device into recovery mode if (client->mode->index == MODE_DFU) { - if (dfu_enter_recovery(client) < 0) { + if (dfu_enter_recovery(client, build_identity) < 0) { error("ERROR: Unable to place device into recovery mode\n"); plist_free(buildmanifest); - if (tss) - plist_free(tss); + if (client->tss) + plist_free(client->tss); return -1; } } // if the device is in recovery mode, place device into restore mode if (client->mode->index == MODE_RECOVERY) { - if (recovery_enter_restore(uuid, ipsw, tss) < 0) { + if (recovery_enter_restore(client, build_identity) < 0) { error("ERROR: Unable to place device into restore mode\n"); plist_free(buildmanifest); - if (tss) - plist_free(tss); + if (client->tss) + plist_free(client->tss); return -1; } } @@ -243,7 +251,7 @@ int main(int argc, char* argv[]) { // device is finally in restore mode, let's do this if (client->mode->index == MODE_RESTORE) { info("Restoring device... \n"); - if (restore_device(client, uuid, ipsw, tss, filesystem) < 0) { + if (restore_device(client, build_identity, filesystem) < 0) { error("ERROR: Unable to restore device\n"); return -1; } @@ -545,7 +553,7 @@ int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, return 0; } -int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int ipsw_get_component_by_path(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; @@ -564,36 +572,40 @@ int get_signed_component(struct idevicerestore_client_t* client, const char* ips return -1; } - img3 = img3_parse_file(component_data, component_size); - if (img3 == NULL) { - error("ERROR: Unable to parse IMG3: %s\n", component_name); + if (tss) { + info("Signing img3...\n"); + img3 = img3_parse_file(component_data, component_size); + if (img3 == NULL) { + error("ERROR: Unable to parse IMG3: %s\n", component_name); + free(component_data); + return -1; + } 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", component_name); - img3_free(img3); - return -1; - } + /* sign the blob if required */ + if (tss_get_blob_by_path(tss, path, &component_blob) < 0) { + error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name); + img3_free(img3); + return -1; + } - if (client->device->index > DEVICE_IPOD2G && (client->flags & FLAG_CUSTOM) == 0) { if (img3_replace_signature(img3, component_blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); free(component_blob); img3_free(img3); return -1; } - } - free(component_blob); - if (img3_get_data(img3, &component_data, &component_size) < 0) { - error("ERROR: Unable to reconstruct IMG3\n"); + if (component_blob) + free(component_blob); + + if (img3_get_data(img3, &component_data, &component_size) < 0) { + error("ERROR: Unable to reconstruct IMG3\n"); + img3_free(img3); + return -1; + } img3_free(img3); - return -1; } - img3_free(img3); if (idevicerestore_debug) { write_file(component_name, component_data, component_size); diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 3213b0c..f529b5b 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -42,7 +42,7 @@ int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ip plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity); int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss); int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); +int ipsw_get_component_by_path(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); #ifdef __cplusplus diff --git a/src/recovery.c b/src/recovery.c index 233224a..6a38343 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -45,6 +45,7 @@ int recovery_client_new(struct idevicerestore_client_t* client) { error("ERROR: Out of memory\n"); return -1; } + client->recovery = recovery; if (recovery_open_with_timeout(client) < 0) { @@ -122,28 +123,28 @@ int recovery_check_mode() { return 0; } -int recovery_enter_restore(struct idevicerestore_client_t* client) { +int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity) { idevice_t device = NULL; restored_client_t restore = NULL; // upload data to make device boot restore mode - if (recovery_send_ibec(client) < 0) { + if (recovery_send_ibec(client, build_identity) < 0) { error("ERROR: Unable to send iBEC\n"); return -1; } - sleep(1); + sleep(2); - if (recovery_send_applelogo(client) < 0) { + if (recovery_send_applelogo(client, build_identity) < 0) { error("ERROR: Unable to send AppleLogo\n"); return -1; } - if (recovery_send_devicetree(client) < 0) { + if (recovery_send_devicetree(client, build_identity) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } - if (recovery_send_ramdisk(client) < 0) { + if (recovery_send_ramdisk(client, build_identity) < 0) { error("ERROR: Unable to send Ramdisk\n"); return -1; } @@ -154,7 +155,10 @@ int recovery_enter_restore(struct idevicerestore_client_t* client) { printf("Hit any key to continue..."); getchar(); - if (recovery_send_kernelcache(client) < 0) { + info("Resetting recovery mode connection...\n"); + irecv_reset(client->recovery->client); + + if (recovery_send_kernelcache(client, build_identity) < 0) { error("ERROR: Unable to send KernelCache\n"); return -1; } @@ -170,29 +174,42 @@ int recovery_enter_restore(struct idevicerestore_client_t* client) { return 0; } -int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* component) { - int size = 0; +int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { + uint32_t size = 0; char* data = NULL; char* path = NULL; char* blob = NULL; irecv_error_t error = 0; - if (tss_get_entry_path(client->tss, component, &path) < 0) { - error("ERROR: Unable to get component path\n"); - return -1; + if (client->tss) { + if (tss_get_entry_path(client->tss, component, &path) < 0) { + error("ERROR: Unable to get component path\n"); + return -1; + } + } else { + if (build_identity_get_component_path(build_identity, component, &path) < 0) { + error("ERROR: Unable to get component: %s\n", component); + if (path) + free(path); + return -1; + } } - if (get_signed_component(client, client->ipsw, client->tss, path, &data, &size) < 0) { - error("ERROR: Unable to get signed component: %s\n", component); + info("Resetting recovery mode connection...\n"); + irecv_reset(client->recovery->client); + + if (ipsw_get_component_by_path(client->ipsw, client->tss, path, &data, &size) < 0) { + error("ERROR: Unable to get component: %s\n", component); free(path); return -1; } - free(path); - info("Sending %s...\n", component); + info("Sending %s (%d bytes)...\n", component, size); + error = irecv_send_buffer(client->recovery->client, data, size); + free(path); if (error != IRECV_E_SUCCESS) { - error("ERROR: Unable to send component: %s\n", component); + error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(error)); free(data); return -1; } @@ -201,10 +218,8 @@ int recovery_send_signed_component(struct idevicerestore_client_t* client, const return 0; } -int recovery_send_ibec(struct idevicerestore_client_t* client) { - const char* component = "iBEC"; +static int recovery_enable_autoboot(struct idevicerestore_client_t* client) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - //recovery_error = irecv_send_command(client->recovery->client, "setenv auto-boot true"); recovery_error = irecv_setenv(client->recovery->client, "auto-boot", "true"); if (recovery_error != IRECV_E_SUCCESS) { @@ -218,7 +233,18 @@ int recovery_send_ibec(struct idevicerestore_client_t* client) { return -1; } - if (recovery_send_signed_component(client, "iBEC") < 0) { + return 0; +} + +int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "iBEC"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if (recovery_enable_autoboot(client) < 0) { + return -1; + } + + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); return -1; } @@ -232,9 +258,8 @@ int recovery_send_ibec(struct idevicerestore_client_t* client) { return 0; } -int recovery_send_applelogo(struct idevicerestore_client_t* client) { - irecv_client_t recovery = NULL; - const char* component = "applelogo"; +int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "AppleLogo"; irecv_error_t recovery_error = IRECV_E_SUCCESS; info("Sending %s...\n", component); @@ -242,40 +267,37 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client) { return -1; } - if (recovery_send_signed_component(client, "AppleLogo") < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "setpicture 1"); + recovery_error = irecv_send_command(client->recovery->client, "setpicture 1"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set %s\n", component); - irecv_close(recovery); return -1; } - recovery_error = irecv_send_command(recovery, "bgcolor 0 0 0"); + recovery_error = irecv_send_command(client->recovery->client, "bgcolor 0 0 0"); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to display %s\n", component); - irecv_close(recovery); return -1; } - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_send_devicetree(struct idevicerestore_client_t* client) { - const char* component = "devicetree"; +int recovery_send_devicetree(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "RestoreDeviceTree"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(client) < 0) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } - if (recovery_send_signed_component(client, "RestoreDeviceTree") < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); return -1; } @@ -289,16 +311,17 @@ int recovery_send_devicetree(struct idevicerestore_client_t* client) { return 0; } -int recovery_send_ramdisk(struct idevicerestore_client_t* client) { +int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_identity) { + const char *component = "RestoreRamDisk"; irecv_error_t recovery_error = IRECV_E_SUCCESS; - const char *component = "ramdisk"; - recovery_error = recovery_open_with_timeout(client); - if (recovery_error != IRECV_E_SUCCESS) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } - if (recovery_send_signed_component(client, "RestoreRamDisk") < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); return -1; } @@ -312,15 +335,15 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client) { return 0; } -int recovery_send_kernelcache(struct idevicerestore_client_t* client) { - const char* component = "kernelcache"; +int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "RestoreKernelCache"; irecv_error_t recovery_error = IRECV_E_SUCCESS; if (recovery_open_with_timeout(client) < 0) { return -1; } - if (recovery_send_signed_component(client, "RestoreKernelCache") < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); return -1; } @@ -337,8 +360,10 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client) { int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { irecv_error_t recovery_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(client) < 0) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } recovery_error = irecv_get_ecid(client->recovery->client, ecid); diff --git a/src/recovery.h b/src/recovery.h index 5d1129f..b7cc0e4 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -43,12 +43,12 @@ int recovery_check_mode(); int recovery_open_with_timeout(struct idevicerestore_client_t* client); int recovery_client_new(struct idevicerestore_client_t* client); void recovery_client_free(struct idevicerestore_client_t* client); -int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* component); -int recovery_send_ibec(struct idevicerestore_client_t* client); -int recovery_send_applelogo(struct idevicerestore_client_t* client); -int recovery_send_devicetree(struct idevicerestore_client_t* client); -int recovery_send_ramdisk(struct idevicerestore_client_t* client); -int recovery_send_kernelcache(struct idevicerestore_client_t* client); +int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); +int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_identity); +int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t build_identity); +int recovery_send_devicetree(struct idevicerestore_client_t* client, plist_t build_identity); +int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_identity); +int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t build_identity); int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); diff --git a/src/restore.c b/src/restore.c index bf4b62f..5d45296 100644 --- a/src/restore.c +++ b/src/restore.c @@ -186,7 +186,8 @@ int restore_reboot(struct idevicerestore_client_t* client) { idevice_t device = NULL; restored_client_t restore = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - if(!client->restore) { + + if(client->restore == NULL) { if (restore_open_with_timeout(client) < 0) { error("ERROR: Unable to open device in restore mode\n"); return -1; @@ -398,7 +399,7 @@ int restore_send_filesystem(idevice_t device, const char* filesystem) { return 0; } -int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss) { +int restore_send_kernelcache(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) { int size = 0; char* data = NULL; char* path = NULL; @@ -407,22 +408,31 @@ int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t restored_error_t restore_error = RESTORE_E_SUCCESS; info("Sending kernelcache\n"); - if (tss_get_entry_path(tss, "KernelCache", &path) < 0) { - error("ERROR: Unable to find kernelcache path\n"); - return -1; + + if (client->tss) { + if (tss_get_entry_path(client->tss, "KernelCache", &path) < 0) { + error("ERROR: Unable to get KernelCache path\n"); + return -1; + } + } else { + if (build_identity_get_component_path(build_identity, "KernelCache", &path) < 0) { + error("ERROR: Unable to find kernelcache path\n"); + if (path) + free(path); + return -1; + } } - if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { + if (ipsw_get_component_by_path(client->ipsw, client->tss, path, &data, &size) < 0) { error("ERROR: Unable to get kernelcache file\n"); return -1; } - dict = plist_new_dict(); blob = plist_new_data(data, size); plist_dict_insert_item(dict, "KernelCacheFile", blob); - restore_error = restored_send(client, dict); + restore_error = restored_send(restore, dict); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); @@ -435,7 +445,7 @@ int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t return 0; } -int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) { char* llb_path = NULL; char* llb_filename = NULL; char firmware_path[256]; @@ -452,9 +462,18 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { plist_t norimage_array = NULL; restored_error_t ret = RESTORE_E_SUCCESS; - if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) { - error("ERROR: Unable to get LLB info from TSS response\n"); - return -1; + if (client->tss) { + if (tss_get_entry_path(client->tss, "LLB", &llb_path) < 0) { + error("ERROR: Unable to get LLB path\n"); + return -1; + } + } else { + if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) { + error("ERROR: Unable to get component: LLB\n"); + if (llb_path) + free(llb_path); + return -1; + } } llb_filename = strstr(llb_path, "LLB"); @@ -472,7 +491,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); info("Getting firmware manifest %s\n", manifest_file); - if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { + if (ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { error("ERROR: Unable to extract firmware manifest from ipsw\n"); free(llb_path); return -1; @@ -485,7 +504,7 @@ int restore_send_nor(restored_client_t client, const 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(client, ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + if (ipsw_get_component_by_path(client->ipsw, client->tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } @@ -498,7 +517,7 @@ int restore_send_nor(restored_client_t client, const 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(client, ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + if (ipsw_get_component_by_path(client->ipsw, client->tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } @@ -513,7 +532,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { debug_plist(dict); - ret = restored_send(client, dict); + ret = restored_send(restore, dict); if (ret != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); @@ -524,7 +543,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem) { char* type = NULL; plist_t node = NULL; @@ -543,7 +562,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "KernelCache")) { - if(restore_send_kernelcache(restore, ipsw, tss) < 0) { + if(restore_send_kernelcache(restore, client, build_identity) < 0) { error("ERROR: Unable to send kernelcache\n"); return -1; } @@ -551,7 +570,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev else if (!strcmp(type, "NORData")) { if(client->flags & FLAG_EXCLUDE > 0) { - if(restore_send_nor(restore, ipsw, tss) < 0) { + if(restore_send_nor(restore, client, build_identity) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -568,7 +587,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev return 0; } -int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem) { int error = 0; char* type = NULL; char* kernel = NULL; @@ -586,6 +605,8 @@ int restore_device(struct idevicerestore_client_t* client, const char* uuid, con } info("Device has successfully entered restore mode\n"); + restore = client->restore->client; + // start the restore process restore_error = restored_start_restore(restore); if (restore_error != RESTORE_E_SUCCESS) { @@ -619,7 +640,7 @@ int restore_device(struct idevicerestore_client_t* client, const char* uuid, con // 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(client, device, restore, message, tss, ipsw, filesystem); + error = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem); } // progress notification messages sent by the restored inform the client diff --git a/src/restore.h b/src/restore.h index 5446aa8..9c11c34 100644 --- a/src/restore.h +++ b/src/restore.h @@ -47,10 +47,10 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(restored_client_t client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem); -int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss); -int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss); -int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem); +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity); +int restore_send_kernelcache(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity); +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem); int restore_open_with_timeout(struct idevicerestore_client_t* client); int restore_send_filesystem(idevice_t device, const char* filesystem); -- cgit v1.1-32-gdbae