diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libirecovery.c | 485 |
1 files changed, 233 insertions, 252 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c index f189838..604a9c4 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -49,7 +49,7 @@ struct irecv_client_private { int interface; int alt_interface; unsigned int mode; - char serial[256]; + struct irecv_device_info device_info; #ifndef WIN32 libusb_device_handle* handle; #else @@ -191,6 +191,191 @@ static unsigned int dfu_hash_t1[256] = { #define dfu_hash_step(a,b) \ a = (dfu_hash_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8)) +static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { +#ifndef WIN32 + return libusb_get_string_descriptor_ascii(client->handle, desc_index, buffer, size); +#else + irecv_error_t ret; + unsigned short langid = 0; + unsigned char data[255]; + int di, si; + memset(data, 0, sizeof(data)); + memset(buffer, 0, size); + + ret = irecv_usb_control_transfer(client, 0x80, 0x06, (0x03 << 8) | desc_index, langid, data, sizeof(data), USB_TIMEOUT); + + if (ret < 0) return ret; + if (data[1] != 0x03) return IRECV_E_UNKNOWN_ERROR; + if (data[0] > ret) return IRECV_E_UNKNOWN_ERROR; + + for (di = 0, si = 2; si < data[0]; si += 2) { + if (di >= (size - 1)) break; + if (data[si + 1]) { + /* high byte */ + buffer[di++] = '?'; + } else { + buffer[di++] = data[si]; + } + } + buffer[di] = 0; + + return di; +#endif +} + +static void irecv_load_device_info_from_iboot_string(irecv_client_t client, const char* iboot_string) +{ + if (!client || !iboot_string) { + return; + } + + memset(&client->device_info, '\0', sizeof(struct irecv_device_info)); + + char* ptr; + + ptr = strstr(iboot_string, "CPID:"); + if (ptr != NULL) { + sscanf(ptr, "CPID:%x", &client->device_info.cpid); + } + + ptr = strstr(iboot_string, "CPRV:"); + if (ptr != NULL) { + sscanf(ptr, "CPRV:%x", &client->device_info.cprv); + } + + ptr = strstr(iboot_string, "CPFM:"); + if (ptr != NULL) { + sscanf(ptr, "CPFM:%x", &client->device_info.cpfm); + } + + ptr = strstr(iboot_string, "SCEP:"); + if (ptr != NULL) { + sscanf(ptr, "SCEP:%x", &client->device_info.scep); + } + + ptr = strstr(iboot_string, "BDID:"); + if (ptr != NULL) { + sscanf(ptr, "BDID:%x", &client->device_info.bdid); + } + + ptr = strstr(iboot_string, "ECID:"); + if (ptr != NULL) { + sscanf(ptr, "ECID:" _FMT_qX, &client->device_info.ecid); + } + + ptr = strstr(iboot_string, "IBFL:"); + if (ptr != NULL) { + sscanf(ptr, "IBFL:%x", &client->device_info.ibfl); + } + + char tmp[256]; + tmp[0] = '\0'; + ptr = strstr(iboot_string, "SRNM:["); + if(ptr != NULL) { + sscanf(ptr, "SRNM:[%s]", tmp); + ptr = strrchr(tmp, ']'); + if(ptr != NULL) { + *ptr = '\0'; + } + client->device_info.srnm = strdup(tmp); + } + + tmp[0] = '\0'; + ptr = strstr(iboot_string, "IMEI:["); + if(ptr != NULL) { + sscanf(ptr, "IMEI:[%s]", tmp); + ptr = strrchr(tmp, ']'); + if(ptr != NULL) { + *ptr = '\0'; + } + client->device_info.imei = strdup(tmp); + } +} + +static void irecv_copy_nonce_with_tag(irecv_client_t client, const char* tag, unsigned char** nonce, unsigned int* nonce_size) +{ + if (!client || !tag) { + return; + } + + char buf[255]; + int len; + + *nonce = NULL; + *nonce_size = 0; + + len = irecv_get_string_descriptor_ascii(client, 1, (unsigned char*) buf, 255); + debug("%s: got length: %d\n", __func__, len); + if (len < 0) { + return; + } + + buf[len] = 0; + debug("%s: buf='%s' tag='%s'\n", __func__, buf, tag); + + int taglen = strlen(tag); + int nlen = 0; + char* nonce_string = NULL; + char* p = buf; + char* colon = NULL; + do { + colon = strchr(p, ':'); + if (!colon) + break; + if (colon-taglen < p) { + break; + } + char *space = strchr(colon, ' '); + if (strncmp(colon-taglen, tag, taglen) == 0) { + p = colon+1; + if (!space) { + nlen = strlen(p); + } else { + nlen = space-p; + } + nonce_string = p; + nlen/=2; + break; + } else { + if (!space) { + break; + } else { + p = space+1; + } + } + } while (colon); + + if (nlen == 0) { + debug("%s: ERROR: couldn't find tag %s in string %s\n", __func__, tag, buf); + return; + } + + unsigned char *nn = malloc(nlen); + if (!nn) { + return; + } + + int i = 0; + for (i = 0; i < nlen; i++) { + int val = 0; + if (sscanf(nonce_string+(i*2), "%02X", &val) == 1) { + nn[i] = (unsigned char)val; + } else { + debug("%s: ERROR: unexpected data in nonce result (%2s)\n", __func__, nonce_string+(i*2)); + break; + } + } + + if (i != nlen) { + debug("%s: ERROR: unable to parse nonce\n", __func__); + free(nn); + return; + } + + *nonce = nn; + *nonce_size = nlen; +} + #ifdef WIN32 static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}}; static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; @@ -262,37 +447,31 @@ irecv_error_t mobiledevice_connect(irecv_client_t* client, unsigned long long ec continue; } - _client->serial[0] = '\0'; - if ((sscanf(result, "\\\\?\\usb#vid_%*04x&pid_%*04x#%s#", _client->serial) != 1) || (_client->serial[0] == '\0')) { + char* serial_str[256]; + serial_str[0] = '\0'; + if ((sscanf(result, "\\\\?\\usb#vid_%*04x&pid_%*04x#%s#", serial_str) != 1) || (serial_str[0] == '\0')) { mobiledevice_closepipes(_client); continue; } - char* p = strchr(_client->serial, '#'); + char* p = strchr(serial_str, '#'); if (p) { *p = '\0'; } int j; - for (j = 0; j < strlen(_client->serial); j++) { - if (_client->serial[j] == '_') { - _client->serial[j] = ' '; + for (j = 0; j < strlen(serial_str); j++) { + if (serial_str[j] == '_') { + serial_str[j] = ' '; } else { - _client->serial[j] = toupper(_client->serial[j]); + serial_str[j] = toupper(serial_str[j]); } } - if (ecid != 0) { - char* ecid_string = strstr(_client->serial, "ECID:"); - if (ecid_string == NULL) { - debug("%s: could not get ECID for device\n", __func__); - mobiledevice_closepipes(_client); - continue; - } + irecv_load_device_info_from_iboot_string(_client, serial_str); - unsigned long long this_ecid = 0; - sscanf(ecid_string, "ECID:" _FMT_qX, (unsigned long long*)&this_ecid); - if (this_ecid != ecid) { + if (ecid != 0) { + if (_client->device_info.ecid != ecid) { mobiledevice_closepipes(_client); continue; } @@ -344,37 +523,29 @@ irecv_error_t mobiledevice_connect(irecv_client_t* client, unsigned long long ec continue; } - _client->serial[0] = '\0'; - if ((sscanf(result, "\\\\?\\usb#vid_%*04x&pid_%*04x#%s#", _client->serial) != 1) || (_client->serial[0] == '\0')) { + char serial_str[256]; + serial_str[0] = '\0'; + if ((sscanf(result, "\\\\?\\usb#vid_%*04x&pid_%*04x#%s#", serial_str) != 1) || (serial_str[0] == '\0')) { mobiledevice_closepipes(_client); continue; } - char* p = strchr(_client->serial, '#'); + char* p = strchr(serial_str, '#'); if (p) { *p = '\0'; } int j; - for (j = 0; j < strlen(_client->serial); j++) { - if (_client->serial[j] == '_') { - _client->serial[j] = ' '; + for (j = 0; j < strlen(serial_str); j++) { + if (serial_str[j] == '_') { + serial_str[j] = ' '; } else { - _client->serial[j] = toupper(_client->serial[j]); + serial_str[j] = toupper(serial_str[j]); } } if (ecid != 0) { - char* ecid_string = strstr(_client->serial, "ECID:"); - if (ecid_string == NULL) { - debug("%s: could not get ECID for device\n", __func__); - mobiledevice_closepipes(_client); - continue; - } - - unsigned long long this_ecid = 0; - sscanf(ecid_string, "ECID:" _FMT_qX, (unsigned long long*)&this_ecid); - if (this_ecid != ecid) { + if (_client->device_info.ecid != ecid) { mobiledevice_closepipes(_client); continue; } @@ -538,38 +709,6 @@ int irecv_usb_bulk_transfer(irecv_client_t client, return ret; } -static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { -#ifndef WIN32 - return libusb_get_string_descriptor_ascii(client->handle, desc_index, buffer, size); -#else - irecv_error_t ret; - unsigned short langid = 0; - unsigned char data[255]; - int di, si; - memset(data, 0, sizeof(data)); - memset(buffer, 0, size); - - ret = irecv_usb_control_transfer(client, 0x80, 0x06, (0x03 << 8) | desc_index, langid, data, sizeof(data), USB_TIMEOUT); - - if (ret < 0) return ret; - if (data[1] != 0x03) return IRECV_E_UNKNOWN_ERROR; - if (data[0] > ret) return IRECV_E_UNKNOWN_ERROR; - - for (di = 0, si = 2; si < data[0]; si += 2) { - if (di >= (size - 1)) break; - if (data[si + 1]) { - /* high byte */ - buffer[di++] = '?'; - } else { - buffer[di++] = data[si]; - } - } - buffer[di] = 0; - - return di; -#endif -} - irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { if(libirecovery_debug) { irecv_set_debug_level(libirecovery_debug); @@ -637,11 +776,16 @@ irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long e 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); + char serial_str[256]; + irecv_get_string_descriptor_ascii(client, usb_descriptor.iSerialNumber, (unsigned char*)serial_str, 255); + + irecv_load_device_info_from_iboot_string(client, serial_str); + + irecv_copy_nonce_with_tag(client, "NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size); + irecv_copy_nonce_with_tag(client, "SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size); if (ecid != 0) { - char* ecid_string = strstr(client->serial, "ECID:"); + char* ecid_string = strstr(serial_str, "ECID:"); if (ecid_string == NULL) { debug("%s: could not get ECID for device\n", __func__); irecv_close(client); @@ -870,6 +1014,18 @@ irecv_error_t irecv_close(irecv_client_t client) { } mobiledevice_closepipes(client); #endif + if (client->device_info.srnm) { + free(client->device_info.srnm); + } + if (client->device_info.imei) { + free(client->device_info.imei); + } + if (client->device_info.ap_nonce) { + free(client->device_info.ap_nonce); + } + if (client->device_info.sep_nonce) { + free(client->device_info.sep_nonce); + } free(client); client = NULL; } @@ -1216,186 +1372,12 @@ irecv_error_t irecv_get_mode(irecv_client_t client, int* mode) { return IRECV_E_SUCCESS; } -irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid) { +const struct irecv_device_info* irecv_get_device_info(irecv_client_t client) +{ if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - if (client->mode == IRECV_K_WTF_MODE) { - char s_cpid[8] = {0,}; - strncpy(s_cpid, client->serial, 4); - if (sscanf(s_cpid, "%x", cpid) != 1) { - *cpid = 0; - return IRECV_E_UNKNOWN_ERROR; - } - - return IRECV_E_SUCCESS; - } - - char* cpid_string = strstr(client->serial, "CPID:"); - if (cpid_string == NULL) { - *cpid = 0; - return IRECV_E_UNKNOWN_ERROR; - } - sscanf(cpid_string, "CPID:%x", cpid); - - return IRECV_E_SUCCESS; -} - -irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid) { - if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - char* bdid_string = strstr(client->serial, "BDID:"); - if (bdid_string == NULL) { - *bdid = 0; - return IRECV_E_UNKNOWN_ERROR; - } - sscanf(bdid_string, "BDID:%x", bdid); - - return IRECV_E_SUCCESS; -} - -irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) { - if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - char* ecid_string = strstr(client->serial, "ECID:"); - if (ecid_string == NULL) { - *ecid = 0; - return IRECV_E_UNKNOWN_ERROR; - } - sscanf(ecid_string, "ECID:" _FMT_qX, ecid); - - return IRECV_E_SUCCESS; -} - -irecv_error_t irecv_get_srnm(irecv_client_t client, char* srnm) { - if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - char* srnmp; - char* srnm_string = strstr(client->serial, "SRNM:["); - if(srnm_string == NULL) { - *srnm = 0; - return IRECV_E_UNKNOWN_ERROR; - } - - sscanf(srnm_string, "SRNM:[%s]", srnm); - srnmp = strrchr(srnm, ']'); - if(srnmp != NULL) { - *srnmp = '\0'; - } - - return IRECV_E_SUCCESS; -} - -irecv_error_t irecv_get_imei(irecv_client_t client, char* imei) { - if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - char* imeip; - char* imei_string = strstr(client->serial, "IMEI:["); - if (imei_string == NULL) { - *imei = 0; - return IRECV_E_UNKNOWN_ERROR; - } - - - sscanf(imei_string, "IMEI:[%s]", imei); - imeip = strrchr(imei, ']'); - if(imeip != NULL) { - *imeip = '\0'; - } - - return IRECV_E_SUCCESS; -} - -irecv_error_t irecv_get_nonce_with_tag(irecv_client_t client, const char* tag, unsigned char** nonce, int* nonce_size) { - if (check_context(client) != IRECV_E_SUCCESS) - return IRECV_E_NO_DEVICE; - - if (tag == NULL) { - return IRECV_E_INVALID_INPUT; - } - - char buf[255]; - int len; - - *nonce = NULL; - *nonce_size = 0; - - len = irecv_get_string_descriptor_ascii(client, 1, (unsigned char*) buf, 255); - debug("%s: got length: %d\n", __func__, len); - if (len < 0) { - return len; - } - - buf[len] = 0; - debug("%s: buf='%s' tag='%s'\n", __func__, buf, tag); - - int taglen = strlen(tag); - int nlen = 0; - char* nonce_string = NULL; - char* p = buf; - char* colon = NULL; - do { - colon = strchr(p, ':'); - if (!colon) - break; - if (colon-taglen < p) { - break; - } - char *space = strchr(colon, ' '); - if (strncmp(colon-taglen, tag, taglen) == 0) { - p = colon+1; - if (!space) { - nlen = strlen(p); - } else { - nlen = space-p; - } - nonce_string = p; - nlen/=2; - break; - } else { - if (!space) { - break; - } else { - p = space+1; - } - } - } while (colon); - - if (nlen == 0) { - debug("%s: ERROR: couldn't find tag %s in string %s\n", __func__, tag, buf); - return IRECV_E_UNKNOWN_ERROR; - } - - unsigned char *nn = malloc(nlen); - if (!nn) { - return IRECV_E_OUT_OF_MEMORY; - } - - int i = 0; - for (i = 0; i < nlen; i++) { - int val = 0; - if (sscanf(nonce_string+(i*2), "%02X", &val) == 1) { - nn[i] = (unsigned char)val; - } else { - debug("%s: ERROR: unexpected data in nonce result (%2s)\n", __func__, nonce_string+(i*2)); - break; - } - } - - if (i != nlen) { - debug("%s: ERROR: unable to parse nonce\n", __func__); - free(nn); - return IRECV_E_UNKNOWN_ERROR; - } - - *nonce = nn; - *nonce_size = nlen; + return NULL; - return IRECV_E_SUCCESS; + return &client->device_info; } irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) { @@ -1601,11 +1583,11 @@ irecv_error_t irecv_devices_get_device_by_client(irecv_client_t client, irecv_de *device = NULL; - if (irecv_get_cpid(client, &cpid) < 0) { + if (client->device_info.cpid == 0) { return IRECV_E_UNKNOWN_ERROR; } - if (irecv_get_bdid(client, &bdid) < 0) { + if (client->device_info.bdid == 0) { return IRECV_E_UNKNOWN_ERROR; } @@ -1660,8 +1642,7 @@ 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); + unsigned long long ecid = client->device_info.ecid; if (check_context(client) == IRECV_E_SUCCESS) { irecv_close(client); |