diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/activate.c | 8 | ||||
| -rw-r--r-- | src/activate.h | 2 | ||||
| -rw-r--r-- | src/dfu.c | 49 | ||||
| -rw-r--r-- | src/dfu.h | 5 | ||||
| -rw-r--r-- | src/idevicerestore.c | 829 | ||||
| -rw-r--r-- | src/img3.c | 120 | ||||
| -rw-r--r-- | src/img3.h | 56 | ||||
| -rw-r--r-- | src/ipsw.c | 3 | ||||
| -rw-r--r-- | src/ipsw.h | 3 | ||||
| -rw-r--r-- | src/normal.c | 13 | ||||
| -rw-r--r-- | src/normal.h | 2 | ||||
| -rw-r--r-- | src/recovery.c | 247 | ||||
| -rw-r--r-- | src/recovery.h | 2 | ||||
| -rw-r--r-- | src/restore.c | 199 | ||||
| -rw-r--r-- | src/restore.h | 15 | ||||
| -rw-r--r-- | src/tss.c | 125 | ||||
| -rw-r--r-- | src/tss.h | 8 | 
17 files changed, 885 insertions, 801 deletions
| diff --git a/src/activate.c b/src/activate.c index 2cb4452..1fcd2e2 100644 --- a/src/activate.c +++ b/src/activate.c @@ -252,3 +252,11 @@ int activate_fetch_record(lockdownd_client_t client, plist_t* record) {  	//free(request);  	return 0;  } + +int activate_check_status(const char* uuid) { +	return 1; +} + +int activate_device(const char* uuid) { +	return 0; +} diff --git a/src/activate.h b/src/activate.h index 1feb11e..f992d4f 100644 --- a/src/activate.h +++ b/src/activate.h @@ -25,6 +25,8 @@  #include <plist/plist.h>  #include <libimobiledevice/lockdown.h> +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 @@ -19,10 +19,13 @@   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA   */ -#include <stdint.h> +#include <stdio.h> +#include <stdlib.h>  #include <libirecovery.h>  #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;  } @@ -23,10 +23,9 @@  #define IDEVICERESTORE_DFU_H  #include <stdint.h> +#include <plist/plist.h>  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;  } @@ -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; @@ -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 @@ -20,6 +20,7 @@   */  #include <zip.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h> @@ -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"); @@ -23,6 +23,7 @@  #define IDEVICERESTORE_IPSW_H  #include <zip.h> +#include <stdint.h>  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 <stdint.h>  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 <stdlib.h>  #include <stdint.h>  #include <libirecovery.h> +#include <libimobiledevice/restore.h> +#include <libimobiledevice/libimobiledevice.h>  #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 <plist/plist.h>  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 <string.h>  #include <libimobiledevice/restore.h> +#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 <plist/plist.h>  #include <libimobiledevice/restore.h> - -#include "restore.h" +#include <libimobiledevice/libimobiledevice.h>  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 @@ -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;  } @@ -24,10 +24,10 @@  #include <plist/plist.h> -#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 | 
