Example #1
0
irecv_error_t irecv_open(irecv_client_t* pclient) {
#ifndef WIN32
	int i = 0;
	struct libusb_device* usb_device = NULL;
	struct libusb_device** usb_device_list = NULL;
	struct libusb_device_handle* usb_handle = NULL;
	struct libusb_device_descriptor usb_descriptor;

	*pclient = NULL;
	if(libirecovery_debug) {
		irecv_set_debug_level(libirecovery_debug);
	}

	irecv_error_t error = IRECV_E_SUCCESS;
	int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list);
	for (i = 0; i < usb_device_count; i++) {
		usb_device = usb_device_list[i];
		libusb_get_device_descriptor(usb_device, &usb_descriptor);
		if (usb_descriptor.idVendor == APPLE_VENDOR_ID) {
			/* verify this device is in a mode we understand */
			if (usb_descriptor.idProduct == kRecoveryMode1 ||
				usb_descriptor.idProduct == kRecoveryMode2 ||
				usb_descriptor.idProduct == kRecoveryMode3 ||
				usb_descriptor.idProduct == kRecoveryMode4 ||
				usb_descriptor.idProduct == kDfuMode) {

				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);
					libusb_close(usb_handle);
					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_close(usb_handle);
					libusb_exit(libirecovery_context);
					return IRECV_E_OUT_OF_MEMORY;
				}

				memset(client, '\0', sizeof(struct irecv_client));
				client->interface = 0;
				client->handle = usb_handle;
				client->mode = usb_descriptor.idProduct;
				

				error = irecv_set_configuration(client, 1);
				if (error != IRECV_E_SUCCESS) {
					return error;
				}
				
				if (client->mode != kDfuMode) {
					error = irecv_set_interface(client, 0, 0);
					error = irecv_set_interface(client, 1, 1);
				} else {
					error = irecv_set_interface(client, 0, 0);
				}

				if (error != IRECV_E_SUCCESS) {
					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;
			}
		}
	}

	return IRECV_E_UNABLE_TO_CONNECT;
#else
	int ret = mobiledevice_connect(pclient);
	if (ret == IRECV_E_SUCCESS) {
		irecv_get_string_descriptor_ascii(*pclient, 3, (unsigned char*) (*pclient)->serial, 255);
	}
	return ret;
#endif
}
Example #2
0
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) {
	irecv_error_t dfu_error = IRECV_E_SUCCESS;

	if (dfu_client_new(client) < 0) {
		error("ERROR: Unable to connect to DFU device\n");
		return -1;
	}

	if (client->dfu->client->mode != kDfuMode) {
		info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
		client->mode = &idevicerestore_modes[MODE_RECOVERY];
		return 0;
	}

	if (dfu_send_component(client, build_identity, "iBSS") < 0) {
		error("ERROR: Unable to send iBSS to device\n");
		irecv_close(client->dfu->client);
		return -1;
	}

	dfu_error = irecv_reset(client->dfu->client);
	if (dfu_error != IRECV_E_SUCCESS) {
		error("ERROR: Unable to reset device\n");
		irecv_close(client->dfu->client);
		return -1;
	}

	if (client->build[0] > '8') {
		/* reconnect */
		dfu_client_free(client);
		sleep(1);
		dfu_client_new(client);

		/* get nonce */
		unsigned char* nonce = NULL;
		int nonce_size = 0;
		int nonce_changed = 0;
		if (dfu_get_nonce(client, &nonce, &nonce_size) < 0) {
			error("ERROR: Unable to get nonce from device!\n");
			return -1;
		}

		if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
			nonce_changed = 1;
			if (client->nonce) {
				free(client->nonce);
			}
			client->nonce = nonce;
			client->nonce_size = nonce_size;
		} else {
			free(nonce);
		}

		info("Nonce: ");
		int i;
		for (i = 0; i < client->nonce_size; i++) {
			info("%02x ", client->nonce[i]);
		}
		info("\n");

		if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
			// Welcome iOS5. We have to re-request the TSS with our nonce.
			plist_free(client->tss);
			if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
				error("ERROR: Unable to get SHSH blobs for this device\n");
				return -1;
			}
			if (!client->tss) {
				error("ERROR: can't continue without TSS\n");
				return -1;
			}
			fixup_tss(client->tss);
		}

		if (irecv_set_configuration(client->dfu->client, 1) < 0) {
			error("ERROR: set configuration failed\n");
		}

		/* send iBEC */
		if (dfu_send_component(client, build_identity, "iBEC") < 0) {
			error("ERROR: Unable to send iBEC to device\n");
			irecv_close(client->dfu->client);
			return -1;
		}

		dfu_error = irecv_reset(client->dfu->client);
		if (dfu_error != IRECV_E_SUCCESS) {
			error("ERROR: Unable to reset device\n");
			irecv_close(client->dfu->client);
			return -1;
		}
	}

	dfu_client_free(client);

	sleep(7);

	// Reconnect to device, but this time make sure we're not still in DFU mode
	if (recovery_client_new(client) < 0 || client->recovery->client->mode == kDfuMode) {
		error("ERROR: Unable to connect to recovery device\n");
		if (client->recovery->client)
			irecv_close(client->recovery->client);
		return -1;
	}
	return 0;
}