diff options
| -rw-r--r-- | src/dfu.c | 6 | ||||
| -rw-r--r-- | src/dfu.h | 2 | ||||
| -rw-r--r-- | src/idevicerestore.c | 62 | ||||
| -rw-r--r-- | src/libirecovery.c | 46 | ||||
| -rw-r--r-- | src/libirecovery.h | 4 | ||||
| -rw-r--r-- | src/normal.c | 147 | ||||
| -rw-r--r-- | src/normal.h | 10 | ||||
| -rw-r--r-- | src/recovery.c | 6 | ||||
| -rw-r--r-- | src/recovery.h | 2 | 
9 files changed, 182 insertions, 103 deletions
| @@ -51,7 +51,7 @@ int dfu_client_new(struct idevicerestore_client_t* client) {  	}  	for (i = 1; i <= attempts; i++) { -		dfu_error = irecv_open(&dfu); +		dfu_error = irecv_open(&dfu, client->ecid);  		if (dfu_error == IRECV_E_SUCCESS) {  			break;  		} @@ -83,12 +83,12 @@ void dfu_client_free(struct idevicerestore_client_t* client) {  	}  } -int dfu_check_mode(int* mode) { +int dfu_check_mode(struct idevicerestore_client_t* client, int* mode) {  	irecv_client_t dfu = NULL;  	irecv_error_t dfu_error = IRECV_E_SUCCESS;  	irecv_init(); -	dfu_error=irecv_open(&dfu); +	dfu_error=irecv_open(&dfu, client->ecid);  	if (dfu_error != IRECV_E_SUCCESS) {  		return -1; @@ -37,7 +37,7 @@ struct dfu_client_t {  int dfu_client_new(struct idevicerestore_client_t* client);  void dfu_client_free(struct idevicerestore_client_t* client); -int dfu_check_mode(int* mode); +int dfu_check_mode(struct idevicerestore_client_t* client, int* mode);  int dfu_send_buffer(struct idevicerestore_client_t* client, char* buffer, uint32_t size);  int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);  int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index c838041..0c8f427 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -45,6 +45,7 @@  int use_apple_server;  static struct option longopts[] = { +	{ "ecid",    required_argument, NULL, 'i' },  	{ "uuid",    required_argument, NULL, 'u' },  	{ "debug",   no_argument,       NULL, 'd' },  	{ "help",    no_argument,       NULL, 'h' }, @@ -61,15 +62,18 @@ 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("  -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); -	printf("  -d, --debug\t\tenable communication debugging\n"); -	printf("  -h, --help\t\tprints usage information\n"); -	printf("  -e, --erase\t\tperform a full restore, erasing all data\n"); -	printf("  -c, --custom\t\trestore with a custom firmware\n"); -	printf("  -s, --cydia\t\tuse Cydia's signature service instead of Apple's\n"); -	printf("  -x, --exclude\t\texclude nor/baseband upgrade\n"); -	printf("  -t, --shsh\t\tfetch TSS record and save to .shsh file, then exit\n"); -	printf("  -p, --pwn\t\tPut device in pwned DFU state and exit (limera1n devices only)\n"); +	printf("  -i|--ecid ECID  target specific device by its hexadecimal ECID\n"); +	printf("                  e.g. 0xaabb123456 or 00000012AABBCCDD\n"); +	printf("  -u|--uuid UUID  target specific device by its 40-digit device UUID\n"); +	printf("                  NOTE: only works with devices in normal mode.\n"); +	printf("  -d|--debug      enable communication debugging\n"); +	printf("  -h|--help       prints usage information\n"); +	printf("  -e|--erase      perform a full restore, erasing all data\n"); +	printf("  -c|--custom     restore with a custom firmware\n"); +	printf("  -s|--cydia      use Cydia's signature service instead of Apple's\n"); +	printf("  -x|--exclude    exclude nor/baseband upgrade\n"); +	printf("  -t|--shsh       fetch TSS record and save to .shsh file, then exit\n"); +	printf("  -p|--pwn        Put device in pwned DFU mode and exit (limera1n devices only)\n");  	printf("\n");  } @@ -144,7 +148,7 @@ int main(int argc, char* argv[]) {  	}  	memset(client, '\0', sizeof(struct idevicerestore_client_t)); -	while ((opt = getopt_long(argc, argv, "dhcesxtpu:", longopts, &optindex)) > 0) { +	while ((opt = getopt_long(argc, argv, "dhcesxtpi:u:", longopts, &optindex)) > 0) {  		switch (opt) {  		case 'h':  			usage(argc, argv); @@ -171,6 +175,20 @@ int main(int argc, char* argv[]) {  			client->flags |= FLAG_EXCLUDE;  			break; +		case 'i': +			if (optarg) { +				char* tail = NULL; +				client->ecid = strtoull(optarg, &tail, 16); +				if (tail && (tail[0] != '\0')) { +					client->ecid = 0; +				} +				if (client->ecid == 0) { +					error("ERROR: Could not parse ECID from '%s'\n", optarg); +					return -1; +				} +			} +			break; +  		case 'u':  			uuid = optarg;  			break; @@ -721,19 +739,19 @@ int check_mode(struct idevicerestore_client_t* client) {  	int mode = MODE_UNKNOWN;  	int dfumode = MODE_UNKNOWN; -	if (recovery_check_mode() == 0) { +	if (recovery_check_mode(client) == 0) {  		mode = MODE_RECOVERY;  	} -	else if (dfu_check_mode(&dfumode) == 0) { +	else if (dfu_check_mode(client, &dfumode) == 0) {  		mode = dfumode;  	} -	else if (normal_check_mode(client->uuid) == 0) { +	else if (normal_check_mode(client) == 0) {  		mode = MODE_NORMAL;  	} -	else if (restore_check_mode(client->uuid) == 0) { +	else if (!client->ecid && client->uuid && (restore_check_mode(client->uuid) == 0)) {  		mode = MODE_RESTORE;  	} @@ -748,14 +766,16 @@ int check_device(struct idevicerestore_client_t* client) {  	switch (client->mode->index) {  	case MODE_RESTORE: -		device = restore_check_device(client->uuid); -		if (device < 0) { -			device = DEVICE_UNKNOWN; +		if (!client->ecid && client->uuid) { +			device = restore_check_device(client->uuid); +			if (device < 0) { +				device = DEVICE_UNKNOWN; +			}  		}  		break;  	case MODE_NORMAL: -		device = normal_check_device(client->uuid); +		device = normal_check_device(client);  		if (device < 0) {  			device = DEVICE_UNKNOWN;  		} @@ -891,7 +911,7 @@ int check_device(struct idevicerestore_client_t* client) {  int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) {  	switch (client->mode->index) {  	case MODE_NORMAL: -		if (normal_get_bdid(client->uuid, bdid) < 0) { +		if (normal_get_bdid(client, bdid) < 0) {  			*bdid = 0;  			return -1;  		} @@ -916,7 +936,7 @@ int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) {  int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) {  	switch (client->mode->index) {  	case MODE_NORMAL: -		if (normal_get_cpid(client->uuid, cpid) < 0) { +		if (normal_get_cpid(client, cpid) < 0) {  			client->device->chip_id = -1;  			return -1;  		} @@ -941,7 +961,7 @@ int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) {  int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) {  	switch (client->mode->index) {  	case MODE_NORMAL: -		if (normal_get_ecid(client->uuid, ecid) < 0) { +		if (normal_get_ecid(client, ecid) < 0) {  			*ecid = 0;  			return -1;  		} diff --git a/src/libirecovery.c b/src/libirecovery.c index f02d58e..3c9889a 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -384,7 +384,7 @@ int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index,  #endif  } -irecv_error_t irecv_open(irecv_client_t* pclient) { +irecv_error_t irecv_open(irecv_client_t* pclient, unsigned long long ecid) {  #ifndef WIN32  	int i = 0;  	struct libusb_device* usb_device = NULL; @@ -411,19 +411,28 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {  				usb_descriptor.idProduct == kWTFMode ||  				usb_descriptor.idProduct == kDfuMode) { +				if ((ecid != 0) && (usb_descriptor.idProduct == kWTFMode)) { +					// we can't get ecid in WTF mode +					continue; +				} +  				debug("opening device %04x:%04x...\n", usb_descriptor.idVendor, usb_descriptor.idProduct);  				libusb_open(usb_device, &usb_handle);  				if (usb_handle == NULL) { -					libusb_free_device_list(usb_device_list, 1); +					debug("%s: can't connect to device...\n", __func__);  					libusb_close(usb_handle); +					if (ecid != 0) { +						continue; +					} +					libusb_free_device_list(usb_device_list, 1);  					libusb_exit(libirecovery_context);  					return IRECV_E_UNABLE_TO_CONNECT;  				} -				libusb_free_device_list(usb_device_list, 1);  				irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client));  				if (client == NULL) { +					libusb_free_device_list(usb_device_list, 1);  					libusb_close(usb_handle);  					libusb_exit(libirecovery_context);  					return IRECV_E_OUT_OF_MEMORY; @@ -434,6 +443,25 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {  				client->handle = usb_handle;  				client->mode = usb_descriptor.idProduct; +				/* cache usb serial */ +				irecv_get_string_descriptor_ascii(client, usb_descriptor.iSerialNumber, (unsigned char*) client->serial, 255); + +				if (ecid != 0) { +					char* ecid_string = strstr(client->serial, "ECID:"); +					if (ecid_string == NULL) { +						debug("%s: could not get ECID for device\n", __func__); +						irecv_close(client); +						continue; +					} + +					unsigned long long this_ecid = 0; +					sscanf(ecid_string, "ECID:%qX", (unsigned long long*)&this_ecid); +					if (this_ecid != ecid) { +						irecv_close(client); +						continue; +					} +					debug("found device with ECID %016llx\n", (unsigned long long)ecid); +				}  				error = irecv_set_configuration(client, 1);  				if (error != IRECV_E_SUCCESS) { @@ -453,9 +481,6 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {  					return error;  				} -				/* cache usb serial */ -				irecv_get_string_descriptor_ascii(client, usb_descriptor.iSerialNumber, (unsigned char*) client->serial, 255); -				  				*pclient = client;  				return IRECV_E_SUCCESS;  			} @@ -529,7 +554,7 @@ irecv_error_t irecv_reset(irecv_client_t client) {  	return IRECV_E_SUCCESS;  } -irecv_error_t irecv_open_attempts(irecv_client_t* pclient, int attempts) { +irecv_error_t irecv_open_attempts(irecv_client_t* pclient, unsigned long long ecid, int attempts) {  	int i;  	for (i = 0; i < attempts; i++) { @@ -537,7 +562,7 @@ irecv_error_t irecv_open_attempts(irecv_client_t* pclient, int attempts) {  			irecv_close(*pclient);  			*pclient = NULL;  		} -		if (irecv_open(pclient) != IRECV_E_SUCCESS) { +		if (irecv_open(pclient, ecid) != IRECV_E_SUCCESS) {  			debug("Connection failed. Waiting 1 sec before retry.\n");  			sleep(1);  		} else { @@ -1451,6 +1476,9 @@ irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause) {  	irecv_client_t new_client = NULL;  	irecv_event_cb_t progress_callback = client->progress_callback; +	unsigned long long ecid = 0; +	irecv_get_ecid(client, &ecid); +  	if (check_context(client) == IRECV_E_SUCCESS) {  		irecv_close(client);  	} @@ -1460,7 +1488,7 @@ irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause) {  		sleep(initial_pause);  	} -	error = irecv_open_attempts(&new_client, 10); +	error = irecv_open_attempts(&new_client, ecid, 10);  	if(error != IRECV_E_SUCCESS) {  		return NULL;  	} diff --git a/src/libirecovery.h b/src/libirecovery.h index efd5ee8..9272ab4 100644 --- a/src/libirecovery.h +++ b/src/libirecovery.h @@ -186,8 +186,8 @@ static struct irecv_device irecv_devices[] = {  void irecv_set_debug_level(int level);  const char* irecv_strerror(irecv_error_t error); -irecv_error_t irecv_open_attempts(irecv_client_t* pclient, int attempts); -irecv_error_t irecv_open(irecv_client_t* client); +irecv_error_t irecv_open_attempts(irecv_client_t* pclient, unsigned long long ecid, int attempts); +irecv_error_t irecv_open(irecv_client_t* client, unsigned long long ecid);  irecv_error_t irecv_reset(irecv_client_t client);  irecv_error_t irecv_close(irecv_client_t client);  irecv_error_t irecv_receive(irecv_client_t client); diff --git a/src/normal.c b/src/normal.c index 97cb0c1..9902597 100644 --- a/src/normal.c +++ b/src/normal.c @@ -78,35 +78,90 @@ void normal_client_free(struct idevicerestore_client_t* client) {  	}  } -int normal_check_mode(const char* uuid) { -	char* type = NULL; -	idevice_t device = NULL; -	lockdownd_client_t lockdown = NULL; -	idevice_error_t device_error = IDEVICE_E_SUCCESS; -	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; - -	device_error = idevice_new(&device, uuid); -	if (device_error != IDEVICE_E_SUCCESS) { +static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t* device) +{ +	int num_devices = 0; +	char **devices = NULL; +	idevice_get_device_list(&devices, &num_devices); +	if (num_devices == 0) {  		return -1;  	} +	*device = NULL; +	idevice_t dev = NULL; +	idevice_error_t device_error; +	lockdownd_client_t lockdown = NULL; +	int j; +	for (j = 0; j < num_devices; j++) { +		if (lockdown != NULL) { +			lockdownd_client_free(lockdown); +			lockdown = NULL; +		} +		if (dev != NULL) { +			idevice_free(dev); +			dev = NULL; +		} +		device_error = idevice_new(&dev, devices[j]); +		if (device_error != IDEVICE_E_SUCCESS) { +			error("ERROR: %s: can't open device with UUID %s", __func__, devices[j]); +			continue; +		} -	lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); -	if (lockdown_error != LOCKDOWN_E_SUCCESS) { -		idevice_free(device); -		return -1; +		if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) { +			error("ERROR: %s: can't connect to lockdownd on device with UUID %s", __func__, devices[j]); +			continue; + +		} +		char* type = NULL; +		if (lockdownd_query_type(lockdown, &type) != LOCKDOWN_E_SUCCESS) { +			continue; +		} +		if (strcmp(type, "com.apple.mobile.lockdown") != 0) { +			free(type); +			continue; +		} +		free(type); + +		if (client->ecid != 0) { +			plist_t node = NULL; +			if ((lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_UINT)){ +				if (node) { +					plist_free(node); +				} +				continue; +			} +			lockdownd_client_free(lockdown); +			lockdown = NULL; + +			uint64_t this_ecid = 0; +			plist_get_uint_val(node, &this_ecid); +			plist_free(node); + +			if (this_ecid != client->ecid) { +				continue; +			} +		} +		if (lockdown) { +			lockdownd_client_free(lockdown); +			lockdown = NULL; +		} +		client->uuid = strdup(devices[j]); +		*device = dev; +		break;  	} +	idevice_device_list_free(devices); -	lockdown_error = lockdownd_query_type(lockdown, &type); -	if (lockdown_error != LOCKDOWN_E_SUCCESS) { -		lockdownd_client_free(lockdown); -		idevice_free(device); +	return 0; +} + +int normal_check_mode(struct idevicerestore_client_t* client) { +	idevice_t device = NULL; + +	normal_idevice_new(client, &device); +	if (!device) {  		return -1;  	} +	idevice_free(device);	 -	lockdownd_client_free(lockdown); -	idevice_free(device); -	lockdown = NULL; -	device = NULL;  	return 0;  } @@ -123,6 +178,8 @@ int normal_open_with_timeout(struct idevicerestore_client_t* client) {  		return -1;  	} +	normal_device_connected = 0; +  	// create our normal client if it doesn't yet exist  	if(client->normal == NULL) {  		client->normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); @@ -132,14 +189,10 @@ int normal_open_with_timeout(struct idevicerestore_client_t* client) {  		}  	} -	device_error = idevice_event_subscribe(&normal_device_callback, NULL); -	if (device_error != IDEVICE_E_SUCCESS) { -		error("ERROR: Unable to subscribe to device events\n"); -		return -1; -	} -  	for (i = 1; i <= attempts; i++) { -		if (normal_device_connected == 1) { +		normal_idevice_new(client, &device); +		if (device) { +			normal_device_connected = 1;  			break;  		} @@ -147,37 +200,15 @@ int normal_open_with_timeout(struct idevicerestore_client_t* client) {  			error("ERROR: Unable to connect to device in normal mode\n");  			return -1;  		} -  		sleep(2);  	} -	device_error = idevice_new(&device, client->uuid); -	if (device_error != IDEVICE_E_SUCCESS) { -		return -1; -	} - -	lockdownd_error = lockdownd_client_new(device, &lockdownd, "idevicerestore"); -	if (lockdownd_error != LOCKDOWN_E_SUCCESS) { -		//idevice_event_unsubscribe(); -		idevice_free(device); -		return -1; -	} - -	char* type = NULL; -	lockdownd_error = lockdownd_query_type(lockdownd, &type); -	if (lockdownd_error != LOCKDOWN_E_SUCCESS) { -		lockdownd_client_free(lockdownd); -		//idevice_event_unsubscribe(); -		idevice_free(device); -		return -1; -	} -  	client->normal->device = device; -	client->normal->client = lockdownd; +  	return 0;  } -int normal_check_device(const char* uuid) { +int normal_check_device(struct idevicerestore_client_t* client) {  	int i = 0;  	idevice_t device = NULL;  	char* product_type = NULL; @@ -186,8 +217,8 @@ int normal_check_device(const char* uuid) {  	idevice_error_t device_error = IDEVICE_E_SUCCESS;  	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; -	device_error = idevice_new(&device, uuid); -	if (device_error != IDEVICE_E_SUCCESS) { +	normal_idevice_new(client, &device); +	if (!device) {  		return -1;  	} @@ -270,22 +301,22 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) {  	return 0;  } -int normal_get_cpid(const char* uuid, uint32_t* cpid) { +int normal_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) {  	return 0;  } -int normal_get_bdid(const char* uuid, uint32_t* bdid) { +int normal_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) {  	return 0;  } -int normal_get_ecid(const char* uuid, uint64_t* ecid) { +int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) {  	idevice_t device = NULL;  	plist_t unique_chip_node = NULL;  	lockdownd_client_t lockdown = NULL;  	idevice_error_t device_error = IDEVICE_E_SUCCESS;  	lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; -	device_error = idevice_new(&device, uuid); +	device_error = idevice_new(&device, client->uuid);  	if (device_error != IDEVICE_E_SUCCESS) {  		return -1;  	} diff --git a/src/normal.h b/src/normal.h index e86bf14..4ca6664 100644 --- a/src/normal.h +++ b/src/normal.h @@ -38,15 +38,15 @@ struct normal_client_t {  }; -int normal_check_mode(const char* uuid); -int normal_check_device(const char* uuid); +int normal_check_mode(struct idevicerestore_client_t* client); +int normal_check_device(struct idevicerestore_client_t* client);  int normal_client_new(struct idevicerestore_client_t* client);  void normal_client_free(struct idevicerestore_client_t* client);  int normal_open_with_timeout(struct idevicerestore_client_t* client);  int normal_enter_recovery(struct idevicerestore_client_t* client); -int normal_get_cpid(const char* uuid, uint32_t* cpid); -int normal_get_bdid(const char* uuid, uint32_t* cpid); -int normal_get_ecid(const char* uuid, uint64_t* ecid); +int normal_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); +int normal_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); +int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);  #ifdef __cplusplus  } diff --git a/src/recovery.c b/src/recovery.c index 41ed4fb..9f4f200 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -69,7 +69,7 @@ int recovery_client_new(struct idevicerestore_client_t* client) {  	}  	for (i = 1; i <= attempts; i++) { -		recovery_error = irecv_open(&recovery); +		recovery_error = irecv_open(&recovery, client->ecid);  		if (recovery_error == IRECV_E_SUCCESS) {  			break;  		} @@ -98,12 +98,12 @@ int recovery_client_new(struct idevicerestore_client_t* client) {  	return 0;  } -int recovery_check_mode() { +int recovery_check_mode(struct idevicerestore_client_t* client) {  	irecv_client_t recovery = NULL;  	irecv_error_t recovery_error = IRECV_E_SUCCESS;  	irecv_init(); -	recovery_error=irecv_open(&recovery); +	recovery_error=irecv_open(&recovery, client->ecid);  	if (recovery_error != IRECV_E_SUCCESS) {  		return -1; diff --git a/src/recovery.h b/src/recovery.h index edb036a..ecb8e8e 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -41,7 +41,7 @@ struct recovery_client_t {  	plist_t tss;  }; -int recovery_check_mode(); +int recovery_check_mode(struct idevicerestore_client_t* client);  int recovery_client_new(struct idevicerestore_client_t* client);  void recovery_client_free(struct idevicerestore_client_t* client);  int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); | 
