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