diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/asr.c | 275 | ||||
| -rw-r--r-- | src/asr.h | 35 | ||||
| -rw-r--r-- | src/idevicerestore.c | 62 | ||||
| -rw-r--r-- | src/idevicerestore.h | 29 | ||||
| -rw-r--r-- | src/ipsw.c | 2 | ||||
| -rw-r--r-- | src/restore.c | 464 | ||||
| -rw-r--r-- | src/restore.h | 2 | 
8 files changed, 587 insertions, 284 deletions
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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libimobiledevice/libimobiledevice.h> + +#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 <libimobiledevice/libimobiledevice.h> + +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); @@ -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 <string.h>  #include <libimobiledevice/restore.h> +#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  | 
