summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dfu.c6
-rw-r--r--src/dfu.h2
-rw-r--r--src/idevicerestore.c62
-rw-r--r--src/libirecovery.c46
-rw-r--r--src/libirecovery.h4
-rw-r--r--src/normal.c147
-rw-r--r--src/normal.h10
-rw-r--r--src/recovery.c6
-rw-r--r--src/recovery.h2
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);