diff options
| -rw-r--r-- | src/idevicerestore.c | 469 | ||||
| -rw-r--r-- | src/ipsw.c | 11 | ||||
| -rw-r--r-- | src/ipsw.h | 8 | ||||
| -rw-r--r-- | src/tss.c | 8 | 
4 files changed, 401 insertions, 95 deletions
| diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 1c8b24a..ec449d9 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -41,6 +41,11 @@ int idevicerestore_debug = 0;  void usage(int argc, char* argv[]);  int write_file(const char* filename, char* data, int size); +int send_ibec(char* ipsw, plist_t tss); +int send_devicetree(char* ipsw, plist_t tss); +int send_ramdisk(char* ipsw, plist_t tss); +int send_kernelcache(char* ipsw, plist_t tss); +int get_tss_data(plist_t tss, const char* entry, char** path, char** blob);  int main(int argc, char* argv[]) {  	int opt = 0; @@ -76,7 +81,7 @@ int main(int argc, char* argv[]) {  		}  	} -	if(ipsw == NULL) { +	if (ipsw == NULL) {  		error("ERROR: Please supply an IPSW\n");  		return -1;  	} @@ -90,10 +95,10 @@ int main(int argc, char* argv[]) {  	info("Checking for device in normal mode...\n");  	device_error = idevice_new(&device, uuid); -	if(device_error != IDEVICE_E_SUCCESS) { +	if (device_error != IDEVICE_E_SUCCESS) {  		info("Checking for the device in recovery mode...\n"); -		recovery_error = irecv_open(&recovery, uuid); -		if(recovery_error != IRECV_E_SUCCESS) { +		recovery_error = irecv_open(&recovery); +		if (recovery_error != IRECV_E_SUCCESS) {  			error("ERROR: Unable to find device, is it plugged in?\n");  			return -1;  		} @@ -105,9 +110,9 @@ int main(int argc, char* argv[]) {  		mode = NORMAL_MODE;  	} -	if(mode == NORMAL_MODE) { +	if (mode == NORMAL_MODE) {  		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); -		if(lockdown_error != LOCKDOWN_E_SUCCESS) { +		if (lockdown_error != LOCKDOWN_E_SUCCESS) {  			error("ERROR: Unable to connect to lockdownd\n");  			idevice_free(device);  			return -1; @@ -115,14 +120,14 @@ int main(int argc, char* argv[]) {  		plist_t unique_chip_node = NULL;  		lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); -		if(lockdown_error != LOCKDOWN_E_SUCCESS) { +		if (lockdown_error != LOCKDOWN_E_SUCCESS) {  			error("ERROR: Unable to get UniqueChipID from lockdownd\n");  			lockdownd_client_free(lockdown);  			idevice_free(device);  			return -1;  		} -		if(!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { +		if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {  			error("ERROR: Unable to get ECID\n");  			lockdownd_client_free(lockdown);  			idevice_free(device); @@ -134,10 +139,9 @@ int main(int argc, char* argv[]) {  		idevice_free(device);  		lockdown = NULL;  		device = NULL; -	} -	else if(mode == RECOVERY_MODE) { +	} else if (mode == RECOVERY_MODE) {  		recovery_error = irecv_get_ecid(recovery, &ecid); -		if(recovery_error != IRECV_E_SUCCESS) { +		if (recovery_error != IRECV_E_SUCCESS) {  			error("ERROR: Unable to get device ECID\n");  			irecv_close(recovery);  			return -1; @@ -146,7 +150,7 @@ int main(int argc, char* argv[]) {  		recovery = NULL;  	} -	if(ecid != 0) { +	if (ecid != 0) {  		info("Found ECID %llu\n", ecid);  	} else {  		error("Unable to find device ECID\n"); @@ -154,27 +158,19 @@ int main(int argc, char* argv[]) {  	}  	info("Extracting BuildManifest.plist from IPSW\n"); -	ipsw_archive* archive = ipsw_open(ipsw); -	if(archive == NULL) { -		error("ERROR: Unable to open IPSW\n"); -		return -1; -	} - -	ipsw_file* buildmanifest = ipsw_extract_file(archive, "BuildManifest.plist"); -	if(buildmanifest == NULL) { +	ipsw_file* buildmanifest = ipsw_extract_file(ipsw, "BuildManifest.plist"); +	if (buildmanifest == NULL) {  		error("ERROR: Unable to extract BuildManifest.plist IPSW\n"); -		ipsw_close(archive);  		return -1;  	}  	plist_t manifest = NULL;  	plist_from_xml(buildmanifest->data, buildmanifest->size, &manifest);  	ipsw_free_file(buildmanifest); -	ipsw_close(archive);  	info("Creating TSS request\n");  	plist_t tss_request = tss_create_request(manifest, ecid); -	if(tss_request == NULL) { +	if (tss_request == NULL) {  		error("ERROR: Unable to create TSS request\n");  		plist_free(manifest);  		return -1; @@ -183,7 +179,7 @@ int main(int argc, char* argv[]) {  	info("Sending TSS request\n");  	plist_t tss_response = tss_send_request(tss_request); -	if(tss_response == NULL) { +	if (tss_response == NULL) {  		error("ERROR: Unable to get response from TSS server\n");  		plist_free(tss_request);  		return -1; @@ -191,18 +187,18 @@ int main(int argc, char* argv[]) {  	plist_free(tss_request);  	info("Got TSS response\n"); -	if(mode == NORMAL_MODE) { +	if (mode == NORMAL_MODE) {  		// Place the device in recovery mode  		info("Entering recovery mode...\n");  		device_error = idevice_new(&device, uuid); -		if(device_error != IDEVICE_E_SUCCESS) { +		if (device_error != IDEVICE_E_SUCCESS) {  			error("ERROR: Unable to find device\n");  			plist_free(tss_response);  			return -1;  		}  		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); -		if(lockdown_error != LOCKDOWN_E_SUCCESS) { +		if (lockdown_error != LOCKDOWN_E_SUCCESS) {  			error("ERROR: Unable to connect to lockdownd service\n");  			plist_free(tss_response);  			idevice_free(device); @@ -210,7 +206,7 @@ int main(int argc, char* argv[]) {  		}  		lockdown_error = lockdownd_enter_recovery(lockdown); -		if(lockdown_error != LOCKDOWN_E_SUCCESS) { +		if (lockdown_error != LOCKDOWN_E_SUCCESS) {  			error("ERROR: Unable to place device in recovery mode\n");  			lockdownd_client_free(lockdown);  			plist_free(tss_response); @@ -224,117 +220,212 @@ int main(int argc, char* argv[]) {  		device = NULL;  	} -	recovery_error = irecv_open(&recovery, uuid); -	while(recovery_error != IRECV_E_SUCCESS) { +	if (send_ibec(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send iBEC\n"); +		return -1; +	} + +	// Reconnect to iBEC +	info("Connecting to iBEC\n"); +	recovery_error = irecv_open(&recovery); +	while (recovery_error != IRECV_E_SUCCESS) {  		sleep(1);  		info("Retrying connection...\n"); -		recovery_error = irecv_open(&recovery, uuid); -		if(recovery_error == IRECV_E_SUCCESS) { -			mode = RECOVERY_MODE; +		recovery_error = irecv_open(&recovery); +		if (recovery_error == IRECV_E_SUCCESS) {  			break;  		}  	} -	info("Extracting iBEC from IPSW\n"); -	archive = ipsw_open(ipsw); -	if(archive == NULL) { -		error("ERROR: Unable to open IPSW\n"); +	// Sending DeviceTree +	info("Extracting DeviceTree from IPSW\n"); +	plist_t devicetree_entry = plist_dict_get_item(tss_response, "RestoreDeviceTree"); +	if (!devicetree_entry || plist_get_node_type(devicetree_entry) != PLIST_DICT) { +		error("ERROR: Unable to find DeviceTree entry in TSS response\n");  		plist_free(tss_response);  		irecv_close(recovery);  		return -1;  	} -	plist_t ibec_entry = plist_dict_get_item(tss_response, "iBEC"); -	if(!ibec_entry || plist_get_node_type(ibec_entry) != PLIST_DICT) { -		error("ERROR: Unable to find iBEC entry in TSS response\n"); +	char* devicetree_path = NULL; +	plist_t devicetree_path_node = plist_dict_get_item(devicetree_entry, "Path"); +	if (!devicetree_path_node || plist_get_node_type(devicetree_path_node) != PLIST_STRING) { +		error("ERROR: Unable to find DeviceTree path in entry\n");  		plist_free(tss_response); +		plist_free(devicetree_entry);  		irecv_close(recovery); -		ipsw_close(archive); +		recovery = NULL;  		return -1;  	} +	plist_get_string_val(devicetree_path_node, &devicetree_path); -	char* ibec_path = NULL; -	plist_t ibec_path_node = plist_dict_get_item(ibec_entry, "Path"); -	if(!ibec_path_node || plist_get_node_type(ibec_path_node) != PLIST_STRING) { -		error("ERROR: Unable to find iBEC path in entry\n"); +	char* devicetree_blob = NULL; +	uint64_t devicetree_blob_size = 0; +	plist_t devicetree_blob_node = plist_dict_get_item(devicetree_entry, "Blob"); +	if (!devicetree_blob_node || plist_get_node_type(devicetree_blob_node) != PLIST_DATA) { +		error("ERROR: Unable to find DeviceTree blob in entry\n");  		plist_free(tss_response); -		plist_free(ibec_entry); +		plist_free(devicetree_entry);  		irecv_close(recovery); -		ipsw_close(archive);  		recovery = NULL;  		return -1;  	} -	plist_get_string_val(ibec_path_node, &ibec_path); +	plist_get_data_val(devicetree_blob_node, &devicetree_blob, &devicetree_blob_size); +	plist_free(devicetree_blob_node); +	plist_free(devicetree_entry); -	char* ibec_blob = NULL; -	uint64_t ibec_blob_size = 0; -	plist_t ibec_blob_node = plist_dict_get_item(ibec_entry, "Blob"); -	if(!ibec_blob_node || plist_get_node_type(ibec_blob_node) != PLIST_DATA) { -		error("ERROR: Unable to find iBEC blob in entry\n"); -		plist_free(tss_response); -		plist_free(ibec_entry); +	ipsw_file* devicetree = ipsw_extract_file(ipsw, devicetree_path); +	if (devicetree == NULL) { +		error("ERROR: Unable to extract %s from IPSW\n", devicetree_path);  		irecv_close(recovery); -		ipsw_close(archive);  		recovery = NULL;  		return -1;  	} -	plist_get_data_val(ibec_blob_node, &ibec_blob, &ibec_blob_size); -	plist_free(ibec_blob_node); -	plist_free(ibec_entry); -	ipsw_file* ibec = ipsw_extract_file(archive, ibec_path); -	if(ibec == NULL) { -		error("ERROR: Unable to extract %s from IPSW\n", ibec_path); +	img3_file* devicetree_img3 = img3_parse_file(devicetree->data, devicetree->size); +	if (devicetree_img3 == NULL) { +		error("ERROR: Unable to parse IMG3: %s\n", devicetree_path); +		irecv_close(recovery); +		ipsw_free_file(devicetree); +		recovery = NULL; +		return -1; +	} +	ipsw_free_file(devicetree); + +	img3_replace_signature(devicetree_img3, devicetree_blob); +	free(devicetree_blob); + +	int devicetree_size = 0; +	char* devicetree_data = NULL; +	img3_get_data(devicetree_img3, &devicetree_data, &devicetree_size); +	write_file("devicetree.img3", devicetree_data, devicetree_size); +	recovery_error = irecv_send_buffer(recovery, devicetree_data, devicetree_size); +	if (recovery_error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to send IMG3: %s\n", devicetree_path);  		irecv_close(recovery); -		ipsw_close(archive); +		img3_free(devicetree_img3);  		recovery = NULL;  		return -1;  	} -	ipsw_close(archive); +	img3_free(devicetree_img3); -	img3_file* ibec_img3 = img3_parse_file(ibec->data, ibec->size); -	if(ibec_img3 == NULL) { -		error("ERROR: Unable to parse IMG3: %s\n", ibec_path); +	recovery_error = irecv_send_command(recovery, "devicetree"); +	if (recovery_error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to execute DeviceTree\n");  		irecv_close(recovery); -		ipsw_free_file(ibec); +		img3_free(devicetree_img3);  		recovery = NULL;  		return -1;  	} -	ipsw_free_file(ibec); +	free(devicetree_data); +	sleep(1); + +	// Sending RestoreRamdisk +	info("Extracting Ramdisk from IPSW\n"); +	plist_t ramdisk_entry = plist_dict_get_item(tss_response, "RestoreRamDisk"); +	if (!ramdisk_entry || plist_get_node_type(ramdisk_entry) != PLIST_DICT) { +		error("ERROR: Unable to find RestoreRamDisk entry in TSS response\n"); +		plist_free(tss_response); +		irecv_close(recovery); +		return -1; +	} -	img3_replace_signature(ibec_img3, ibec_blob); +	char* ramdisk_path = NULL; +	plist_t ramdisk_path_node = plist_dict_get_item(ramdisk_entry, "Path"); +	if (!ramdisk_path_node || plist_get_node_type(ramdisk_path_node) != PLIST_STRING) { +		error("ERROR: Unable to find RestoreRamDisk path in entry\n"); +		plist_free(tss_response); +		plist_free(ramdisk_entry); +		irecv_close(recovery); +		recovery = NULL; +		return -1; +	} +	plist_get_string_val(ramdisk_path_node, &ramdisk_path); -	int ibec_size = 0; -	char* ibec_data = NULL; -	img3_get_data(ibec_img3, &ibec_data, &ibec_size); -	write_file("ibec.dfu", ibec_data, ibec_size); -	recovery_error = irecv_send_buffer(recovery, ibec_data, ibec_size); -	if(recovery_error != IRECV_E_SUCCESS) { -		error("ERROR: Unable to send IMG3: %s\n", ibec_path); +	char* ramdisk_blob = NULL; +	uint64_t ramdisk_blob_size = 0; +	plist_t ramdisk_blob_node = plist_dict_get_item(ramdisk_entry, "Blob"); +	if (!ramdisk_blob_node || plist_get_node_type(ramdisk_blob_node) != PLIST_DATA) { +		error("ERROR: Unable to find RestoreRamdisk blob in entry\n"); +		plist_free(tss_response); +		plist_free(ramdisk_entry);  		irecv_close(recovery); -		img3_free(ibec_img3);  		recovery = NULL;  		return -1;  	} +	plist_get_data_val(ramdisk_blob_node, &ramdisk_blob, &ramdisk_blob_size); +	plist_free(ramdisk_blob_node); +	plist_free(ramdisk_entry); -	recovery_error = irecv_send_command(recovery, "go"); -	if(recovery_error != IRECV_E_SUCCESS) { -		error("ERROR: Unable to execute iBEC\n"); +	ipsw_file* ramdisk = ipsw_extract_file(ipsw, ramdisk_path); +	if (ramdisk == NULL) { +		error("ERROR: Unable to extract %s from IPSW\n", ramdisk_path);  		irecv_close(recovery); -		img3_free(ibec_img3);  		recovery = NULL;  		return -1;  	} -	free(ibec_data); +	img3_file* ramdisk_img3 = img3_parse_file(ramdisk->data, ramdisk->size); +	if (ramdisk_img3 == NULL) { +		error("ERROR: Unable to parse IMG3: %s\n", ramdisk_path); +		irecv_close(recovery); +		ipsw_free_file(ramdisk); +		recovery = NULL; +		return -1; +	} +	ipsw_free_file(ramdisk); + +	img3_replace_signature(ramdisk_img3, ramdisk_blob); +	free(ramdisk_blob); + +	int ramdisk_size = 0; +	char* ramdisk_data = NULL; +	img3_get_data(ramdisk_img3, &ramdisk_data, &ramdisk_size); +	write_file("ramdisk.dmg", ramdisk_data, ramdisk_size); +	recovery_error = irecv_send_buffer(recovery, ramdisk_data, ramdisk_size); +	if (recovery_error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to send IMG3: %s\n", ramdisk_path); +		irecv_close(recovery); +		img3_free(ramdisk_img3); +		recovery = NULL; +		return -1; +	} +	img3_free(ramdisk_img3); + +	recovery_error = irecv_send_command(recovery, "ramdisk"); +	if (recovery_error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to execute DeviceTree\n"); +		irecv_close(recovery); +		recovery = NULL; +		return -1; +	} +	free(ramdisk_data); +	irecv_close(recovery); +	recovery = NULL; + +	printf("Please unplug your device, then plug it back in, hit any key to continue\n"); +	getchar(); + +	// Reconnect to iBEC +	recovery_error = irecv_open(&recovery); +	while (recovery_error != IRECV_E_SUCCESS) { +		sleep(1); +		info("Retrying connection...\n"); +		recovery_error = irecv_open(&recovery); +		if (recovery_error == IRECV_E_SUCCESS) { +			break; +		} +	} +  	irecv_close(recovery); +	recovery = NULL;  	plist_free(tss_response);  	return 0;  }  void usage(int argc, char* argv[]) {  	char *name = strrchr(argv[0], '/'); -	printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0])); +	printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0]));  	printf("Restore firmware and filesystem to iPhone/iPod Touch.\n");  	printf("  -d, \t\tenable communication debugging\n");  	printf("  -v, \t\tenable incremental levels of verboseness\n"); @@ -357,10 +448,218 @@ int write_file(const char* filename, char* data, int size) {  	int bytes = fwrite(data, 1, size, file);  	fclose(file); -	if(bytes != size) { +	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(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", entry); +		plist_free(node); +		return -1; +	} +	plist_get_string_val(path_node, &path); +	plist_free(path_node); + +	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", entry); +		plist_free(node); +		free(path); +		return -1; +	} + +	plist_get_data_val(blob_node, &blob, &blob_size); +	plist_free(blob_node); +	plist_free(node); + +	*ppath = path; +	*pblob = blob; +	return 0; +} + +int send_ibec(char* ipsw, plist_t tss) { +	int i = 0; +	irecv_client_t client = NULL; +	info("Connecting to iBoot...\n"); +	irecv_error_t error = irecv_open(&client); +	for (i = 10; i > 0; i--) { +		if (error == IRECV_E_SUCCESS) { +			irecv_send_command(client, "setenv auto-boot true"); +			irecv_send_command(client, "saveenv"); +			break; +		} +		sleep(1); +		info("Retrying connection...\n"); +		error = irecv_open(&client); +	} + +	char* path = NULL; +	char* blob = NULL; +	info("Extracting iBEC data from TSS response\n"); +	if (get_tss_data(tss, "iBEC", &path, &blob) < 0) { +		error("ERROR: Unable to get data for TSS entry\n"); +		irecv_close(client); +		client = NULL; +		return -1; +	} + +	info("Extracting %s from %s\n", path, ipsw); +	ipsw_file* ibec = ipsw_extract_file(ipsw, path); +	if (ibec == NULL) { +		error("ERROR: Unable to extract %s from %s\n", path, ipsw); +		irecv_close(client); +		client = NULL; +		free(path); +		free(blob); +		return -1; +	} + +	img3_file* img3 = img3_parse_file(ibec->data, ibec->size); +	if (img3 == NULL) { +		error("ERROR: Unable to parse IMG3: %s\n", path); +		ipsw_free_file(ibec); +		irecv_close(client); +		client = NULL; +		free(path); +		free(blob); +		return -1; +	} +	if (ibec) { +		ipsw_free_file(ibec); +		ibec = NULL; +	} + +	if (img3_replace_signature(img3, blob) < 0) { +		error("ERROR: Unable to replace IMG3 signature\n"); +		irecv_close(client); +		client = NULL; +		free(path); +		free(blob); +		return -1; +	} +	if (blob) { +		free(blob); +		blob = NULL; +	} + +	int size = 0; +	char* data = NULL; +	if (img3_get_data(img3, &data, &size) < 0) { +		error("ERROR: Unable to reconstruct IMG3\n"); +		irecv_close(client); +		img3_free(img3); +		client = NULL; +		free(path); +		return -1; +	} + +	path = strrchr(path, '/'); +	write_file(path + 1, data, size); +	error = irecv_send_buffer(client, data, size); +	if (error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to send IMG3: %s\n", path); +		irecv_close(client); +		img3_free(img3); +		client = NULL; +		free(data); +		free(path); +		return -1; +	} +	if (img3) { +		img3_free(img3); +		img3 = NULL; +	} +	if (data) { +		free(data); +		data = NULL; +	} +	if (path) { +		free(path); +		path = NULL; +	} + +	error = irecv_send_command(client, "go"); +	if (error != IRECV_E_SUCCESS) { +		error("ERROR: Unable to execute iBEC\n"); +		irecv_close(client); +		client = NULL; +		free(data); +		return -1; +	} + +	irecv_close(client); +	client = NULL; +	return 0; +} + +int send_devicetree(char* ipsw, plist_t tss) { +	int i = 0; +	info("Sending devicetree\n"); +	irecv_client_t client = NULL; +	irecv_error_t error = irecv_open(&client); +	for (i = 10; i > 0; i--) { +		if (error == IRECV_E_SUCCESS) { +			break; +		} +		sleep(1); +		info("Retrying connection...\n"); +		error = irecv_open(&client); +	} + +	irecv_close(client); +	return 0; +} + +int send_ramdisk(char* ipsw, plist_t tss) { +	int i = 0; +	info("Sending ramdisk\n"); +	irecv_client_t client = NULL; +	irecv_error_t error = irecv_open(&client); +	for (i = 10; i > 0; i--) { +		if (error == IRECV_E_SUCCESS) { +			break; +		} +		sleep(1); +		info("Retrying connection...\n"); +		error = irecv_open(&client); +	} + +	irecv_close(client); +	return 0; +} + +int send_kernelcache(char* ipsw, plist_t tss) { +	int i = 0; +	info("Sending kernelcache\n"); +	irecv_client_t client = NULL; +	irecv_error_t error = irecv_open(&client); +	for (i = 10; i > 0; i--) { +		if (error == IRECV_E_SUCCESS) { +			break; +		} +		sleep(1); +		info("Retrying connection...\n"); +		error = irecv_open(&client); +	} + +	irecv_close(client); +	return 0; +} @@ -26,6 +26,13 @@  #include "ipsw.h"  #include "idevicerestore.h" +typedef struct { +	struct zip* zip; +} ipsw_archive; + +ipsw_archive* ipsw_open(const char* ipsw); +void ipsw_close(ipsw_archive* archive); +  ipsw_archive* ipsw_open(const char* ipsw) {  	int err = 0;  	ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); @@ -44,7 +51,8 @@ ipsw_archive* ipsw_open(const char* ipsw) {  	return archive;  } -ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename) { +ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename) { +	ipsw_archive* archive = ipsw_open(ipsw);  	if(archive == NULL || archive->zip == NULL) {  		error("ERROR: Invalid archive\n");  		return NULL; @@ -95,6 +103,7 @@ ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename) {  	}  	zip_fclose(zfile); +	ipsw_close(archive);  	return file;  } @@ -25,19 +25,13 @@  #include <zip.h>  typedef struct { -	struct zip* zip; -} ipsw_archive; - -typedef struct {  	int index;  	char* name;  	unsigned int size;  	unsigned char* data;  } ipsw_file; -ipsw_archive* ipsw_open(const char* ipsw); -ipsw_file* ipsw_extract_file(ipsw_archive* archive, const char* filename); +ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename);  void ipsw_free_file(ipsw_file* file); -void ipsw_close(ipsw_archive* archive);  #endif @@ -109,6 +109,7 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) {  	plist_dict_insert_item(tss_request, "ApBoardID", plist_new_uint(board_id));  	plist_dict_insert_item(tss_request, "ApSecurityDomain", plist_new_uint(security_domain));  	plist_dict_insert_item(tss_request, "UniqueBuildID", plist_new_data(unique_build_data, unique_build_size)); +	free(unique_build_data);  	// Add all firmware files to TSS request  	plist_t manifest_node = plist_dict_get_item(restore_identity_dict, "Manifest"); @@ -135,11 +136,13 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) {  		plist_dict_insert_item(tss_request, key, tss_entry);  		free(key);  	} +	plist_free(manifest_node);  	int sz = 0;  	char* xml = NULL;  	plist_to_xml(tss_request, &xml, &sz); -	printf("%s", xml); +	debug("%s", xml); +	free(xml);  	return tss_request;  } @@ -218,7 +221,8 @@ plist_t tss_send_request(plist_t tss_request) {  	int sz = 0;  	char* xml = NULL;  	plist_to_xml(tss_response, &xml, &sz); -	printf("%s", xml); +	debug("%s", xml); +	free(xml);  	return tss_response;  } | 
