From a7dcea5c4cf995ec7fe40548afc781f7fd799210 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Feb 2012 02:39:05 +0100 Subject: add support for targeting a device by ECID --- src/dfu.c | 6 +-- src/dfu.h | 2 +- src/idevicerestore.c | 62 ++++++++++++++-------- src/libirecovery.c | 46 ++++++++++++---- src/libirecovery.h | 4 +- src/normal.c | 147 +++++++++++++++++++++++++++++++-------------------- src/normal.h | 10 ++-- src/recovery.c | 6 +-- src/recovery.h | 2 +- 9 files changed, 182 insertions(+), 103 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 3e88a1d..13c715a 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -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; diff --git a/src/dfu.h b/src/dfu.h index 7351013..8df31f3 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -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); -- cgit v1.1-32-gdbae