diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/activate.c | 262 | ||||
-rw-r--r-- | src/activate.h | 32 | ||||
-rw-r--r-- | src/asr.c | 292 | ||||
-rw-r--r-- | src/asr.h | 36 | ||||
-rw-r--r-- | src/dfu.c | 63 | ||||
-rw-r--r-- | src/dfu.h | 8 | ||||
-rw-r--r-- | src/idevicerestore.c | 971 | ||||
-rw-r--r-- | src/idevicerestore.h | 131 | ||||
-rw-r--r-- | src/img3.c | 120 | ||||
-rw-r--r-- | src/img3.h | 60 | ||||
-rw-r--r-- | src/ipsw.c | 13 | ||||
-rw-r--r-- | src/ipsw.h | 7 | ||||
-rw-r--r-- | src/normal.c | 194 | ||||
-rw-r--r-- | src/normal.h | 11 | ||||
-rw-r--r-- | src/recovery.c | 345 | ||||
-rw-r--r-- | src/recovery.h | 20 | ||||
-rw-r--r-- | src/restore.c | 564 | ||||
-rw-r--r-- | src/restore.h | 22 | ||||
-rw-r--r-- | src/tss.c | 151 | ||||
-rw-r--r-- | src/tss.h | 14 |
21 files changed, 940 insertions, 2378 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a44640f..6840a0c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,6 @@ AM_LDFLAGS =\ bin_PROGRAMS = idevicerestore -idevicerestore_SOURCES = idevicerestore.c dfu.c asr.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c +idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS)
\ No newline at end of file diff --git a/src/activate.c b/src/activate.c deleted file mode 100644 index 1fcd2e2..0000000 --- a/src/activate.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * activate.c - * Functions to fetch activation records from Apple's servers - * - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <curl/curl.h> -#include <plist/plist.h> -#include <libimobiledevice/lockdown.h> - -typedef struct { - int length; - char* content; -} activate_response; - -size_t activate_write_callback(char* data, size_t size, size_t nmemb, activate_response* response) { - size_t total = size * nmemb; - if (total != 0) { - response->content = realloc(response->content, response->length + total + 1); - memcpy(response->content + response->length, data, total); - response->content[response->length + total] = '\0'; - response->length += total; - } - //printf("%s", data); - return total; -} - -int activate_fetch_record(lockdownd_client_t client, plist_t* record) { - int size = 0; - char* request = NULL; - struct curl_httppost* post = NULL; - struct curl_httppost* last = NULL; - activate_response* response = NULL; - - char* imei = NULL; - char* imsi = NULL; - char* iccid = NULL; - char* serial_number = NULL; - char* activation_info = NULL; - - plist_t imei_node = NULL; - plist_t imsi_node = NULL; - plist_t iccid_node = NULL; - plist_t serial_number_node = NULL; - plist_t activation_info_node = NULL; - - char* device_class = NULL; - plist_t device_class_node = NULL; - lockdownd_get_value(client, NULL, "DeviceClass", &device_class_node); - if (!device_class_node || plist_get_node_type(device_class_node) != PLIST_STRING) { - fprintf(stderr, "Unable to get DeviceClass from lockdownd\n"); - return -1; - } - plist_get_string_val(device_class_node, &device_class); - plist_free(device_class_node); - - if (!strcmp(device_class, "iPhone")) { - lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &iccid_node); - if (!iccid_node || plist_get_node_type(iccid_node) != PLIST_STRING) { - fprintf(stderr, "Unable to get ICCID from lockdownd\n"); - return -1; - } - plist_get_string_val(iccid_node, &iccid); - plist_free(iccid_node); - - lockdownd_get_value(client, NULL, "InternationalMobileEquipmentIdentity", &imei_node); - if (!imei_node || plist_get_node_type(imei_node) != PLIST_STRING) { - fprintf(stderr, "Unable to get IMEI from lockdownd\n"); - return -1; - } - plist_get_string_val(imei_node, &imei); - plist_free(imei_node); - - lockdownd_get_value(client, NULL, "InternationalMobileSubscriberIdentity", &imsi_node); - if (!imsi_node || plist_get_node_type(imsi_node) != PLIST_STRING) { - fprintf(stderr, "Unable to get IMSI from lockdownd\n"); - return -1; - } - plist_get_string_val(imsi_node, &imsi); - plist_free(imsi_node); - } - - lockdownd_get_value(client, NULL, "SerialNumber", &serial_number_node); - if (!serial_number_node || plist_get_node_type(serial_number_node) != PLIST_STRING) { - fprintf(stderr, "Unable to get SerialNumber from lockdownd\n"); - return -1; - } - plist_get_string_val(serial_number_node, &serial_number); - plist_free(serial_number_node); - - lockdownd_get_value(client, NULL, "ActivationInfo", &activation_info_node); - int type = plist_get_node_type(activation_info_node); - if (!activation_info_node || plist_get_node_type(activation_info_node) != PLIST_DICT) { - fprintf(stderr, "Unable to get ActivationInfo from lockdownd\n"); - return -1; - } - //plist_get_string_val(activation_info_node, &activation_info); - - uint32_t activation_info_size = 0; - char* activation_info_data = NULL; - plist_to_xml(activation_info_node, &activation_info_data, &activation_info_size); - plist_free(activation_info_node); - //printf("%s\n\n", activation_info_data); - - char* activation_info_start = strstr(activation_info_data, "<dict>"); - if (activation_info_start == NULL) { - fprintf(stderr, "Unable to locate beginning of ActivationInfo\n"); - return -1; - } - - char* activation_info_stop = strstr(activation_info_data, "</dict>"); - if (activation_info_stop == NULL) { - fprintf(stderr, "Unable to locate end of ActivationInfo\n"); - return -1; - } - - activation_info_stop += strlen("</dict>"); - activation_info_size = activation_info_stop - activation_info_start; - activation_info = malloc(activation_info_size + 1); - memset(activation_info, '\0', activation_info_size + 1); - memcpy(activation_info, activation_info_start, activation_info_size); - free(activation_info_data); - - curl_global_init(CURL_GLOBAL_ALL); - CURL* handle = curl_easy_init(); - if (handle == NULL) { - fprintf(stderr, "Unable to initialize libcurl\n"); - curl_global_cleanup(); - return -1; - } - - curl_formadd(&post, &last, CURLFORM_COPYNAME, "machineName", CURLFORM_COPYCONTENTS, "linux", CURLFORM_END); - curl_formadd(&post, &last, CURLFORM_COPYNAME, "InStoreActivation", CURLFORM_COPYCONTENTS, "false", CURLFORM_END); - if (imei != NULL) { - curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMEI", CURLFORM_COPYCONTENTS, imei, CURLFORM_END); - free(imei); - } - - if (imsi != NULL) { - curl_formadd(&post, &last, CURLFORM_COPYNAME, "IMSI", CURLFORM_COPYCONTENTS, imsi, CURLFORM_END); - free(imsi); - } - - if (iccid != NULL) { - curl_formadd(&post, &last, CURLFORM_COPYNAME, "ICCID", CURLFORM_COPYCONTENTS, iccid, CURLFORM_END); - free(iccid); - } - - if (serial_number != NULL) { - curl_formadd(&post, &last, CURLFORM_COPYNAME, "AppleSerialNumber", CURLFORM_COPYCONTENTS, serial_number, CURLFORM_END); - free(serial_number); - } - - if (activation_info != NULL) { - curl_formadd(&post, &last, CURLFORM_COPYNAME, "activation-info", CURLFORM_COPYCONTENTS, activation_info, CURLFORM_END); - free(activation_info); - } - - struct curl_slist* header = NULL; - header = curl_slist_append(header, "X-Apple-Tz: -14400"); - header = curl_slist_append(header, "X-Apple-Store-Front: 143441-1"); - - response = malloc(sizeof(activate_response)); - if (response == NULL) { - fprintf(stderr, "Unable to allocate sufficent memory\n"); - return -1; - } - - response->length = 0; - response->content = malloc(1); - - curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &activate_write_callback); - curl_easy_setopt(handle, CURLOPT_USERAGENT, "iTunes/9.1 (Macintosh; U; Intel Mac OS X 10.5.6)"); - curl_easy_setopt(handle, CURLOPT_URL, "https://albert.apple.com/WebObjects/ALUnbrick.woa/wa/deviceActivation"); - - curl_easy_perform(handle); - curl_slist_free_all(header); - curl_easy_cleanup(handle); - curl_global_cleanup(); - - uint32_t ticket_size = response->length; - char* ticket_data = response->content; - - char* ticket_start = strstr(ticket_data, "<plist"); - if (ticket_start == NULL) { - fprintf(stderr, "Unable to locate beginning of ActivationInfo\n"); - return -1; - } - - char* ticket_stop = strstr(ticket_data, "</plist>"); - if (ticket_stop == NULL) { - fprintf(stderr, "Unable to locate end of ActivationInfo\n"); - return -1; - } - - ticket_stop += strlen("</plist>"); - ticket_size = ticket_stop - ticket_start; - char* ticket = malloc(ticket_size + 1); - memset(ticket, '\0', ticket_size + 1); - memcpy(ticket, ticket_start, ticket_size); - //free(ticket_data); - - //printf("%s\n\n", ticket); - - plist_t ticket_dict = NULL; - plist_from_xml(ticket, ticket_size, &ticket_dict); - if (ticket_dict == NULL) { - printf("Unable to convert activation ticket into plist\n"); - return -1; - } - - plist_t iphone_activation_node = plist_dict_get_item(ticket_dict, "iphone-activation"); - if (!iphone_activation_node) { - iphone_activation_node = plist_dict_get_item(ticket_dict, "device-activation"); - if (!iphone_activation_node) { - printf("Unable to find device activation node\n"); - return -1; - } - } - - plist_t activation_record = plist_dict_get_item(iphone_activation_node, "activation-record"); - if (!activation_record) { - printf("Unable to find activation record node"); - return -1; - } - - *record = plist_copy(activation_record); - - //free(response->content); - //free(response); - //free(request); - return 0; -} - -int activate_check_status(const char* uuid) { - return 1; -} - -int activate_device(const char* uuid) { - return 0; -} diff --git a/src/activate.h b/src/activate.h deleted file mode 100644 index f992d4f..0000000 --- a/src/activate.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * activate.h - * Functions to fetch activation records from Apple's servers - * - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef ACTIVATE_H -#define ACTIVATE_H - -#include <plist/plist.h> -#include <libimobiledevice/lockdown.h> - -int activate_device(const char* uuid); -int activate_check_status(const char* uuid); -int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record); - -#endif diff --git a/src/asr.c b/src/asr.c deleted file mode 100644 index c7b6147..0000000 --- a/src/asr.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * asr.h - * Functions for handling asr connections - * - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <libimobiledevice/libimobiledevice.h> - -#include "asr.h" -#include "idevicerestore.h" - -#define ASR_PORT 12345 -#define ASR_BUFFER_SIZE 65536 - -int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr) { - int i = 0; - int attempts = 10; - idevice_connection_t connection = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - - *asr = NULL; - - if (device == NULL) { - return -1; - } - - debug("Connecting to ASR\n"); - for (i = 1; i <= attempts; i++) { - device_error = idevice_connect(device, ASR_PORT, &connection); - if (device_error == IDEVICE_E_SUCCESS) { - break; - } - - if (i >= attempts) { - error("ERROR: Unable to connect to ASR client\n"); - return -1; - } - - sleep(2); - debug("Retrying connection...\n"); - } - - *asr = connection; - return 0; -} - -int asr_receive(idevice_connection_t asr, plist_t* data) { - uint32_t size = 0; - char* buffer = NULL; - plist_t request = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - - *data = NULL; - - buffer = (char*) malloc(ASR_BUFFER_SIZE); - if (buffer == NULL) { - error("ERROR: Unable to allocate memory for ASR receive buffer\n"); - return -1; - } - memset(buffer, '\0', ASR_BUFFER_SIZE); - - device_error = idevice_connection_receive(asr, buffer, ASR_BUFFER_SIZE, &size); - if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to receive data from ASR\n"); - free(buffer); - return -1; - } - plist_from_xml(buffer, size, &request); - - *data = request; - - debug("Received %d bytes:\n%s\n", size, buffer); - free(buffer); - return 0; -} - -int asr_send(idevice_connection_t asr, plist_t* data) { - uint32_t size = 0; - char* buffer = NULL; - - plist_to_xml(data, &buffer, &size); - if (asr_send_buffer(asr, buffer, size) < 0) { - error("ERROR: Unable to send plist to ASR\n"); - free(buffer); - return -1; - } - - debug("Sent %d bytes:\n", size); - debug_plist(data); - free(buffer); - return 0; -} - -int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size) { - uint32_t bytes = 0; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - - device_error = idevice_connection_send(asr, data, size, &bytes); - if (device_error != IDEVICE_E_SUCCESS || bytes != size) { - error("ERROR: Unable to send data to ASR\n"); - return -1; - } - - return 0; -} - -void asr_close(idevice_connection_t asr) { - if (asr != NULL) { - idevice_disconnect(asr); - asr = NULL; - } -} - -int asr_perform_validation(idevice_connection_t asr, const char* filesystem) { - FILE* file = NULL; - uint64_t length = 0; - char* command = NULL; - plist_t node = NULL; - plist_t packet = NULL; - plist_t packet_info = NULL; - plist_t payload_info = NULL; - - file = fopen(filesystem, "rb"); - if (file == NULL) { - return -1; - } - - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, 0, SEEK_SET); - - payload_info = plist_new_dict(); - plist_dict_insert_item(payload_info, "Port", plist_new_uint(1)); - plist_dict_insert_item(payload_info, "Size", plist_new_uint(length)); - - packet_info = plist_new_dict(); - plist_dict_insert_item(packet_info, "FEC Slice Stride", plist_new_uint(40)); - plist_dict_insert_item(packet_info, "Packet Payload Size", plist_new_uint(1450)); - plist_dict_insert_item(packet_info, "Packets Per FEC", plist_new_uint(25)); - plist_dict_insert_item(packet_info, "Payload", payload_info); - plist_dict_insert_item(packet_info, "Stream ID", plist_new_uint(1)); - plist_dict_insert_item(packet_info, "Version", plist_new_uint(1)); - - if (asr_send(asr, packet_info)) { - error("ERROR: Unable to sent packet information to ASR\n"); - plist_free(packet_info); - return -1; - } - plist_free(packet_info); - - while (1) { - if (asr_receive(asr, &packet) < 0) { - error("ERROR: Unable to receive validation packet\n"); - return -1; - } - - node = plist_dict_get_item(packet, "Command"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find command node in validation request\n"); - return -1; - } - plist_get_string_val(node, &command); - - if (!strcmp(command, "OOBData")) { - asr_handle_oob_data_request(asr, packet, file); - - - plist_free(packet); - - } else if(!strcmp(command, "Payload")) { - plist_free(packet); - break; - - } else { - error("ERROR: Unknown command received from ASR\n"); - plist_free(packet); - return -1; - } - } - - return 0; -} - -int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file) { - char* oob_data = NULL; - uint64_t oob_offset = 0; - uint64_t oob_length = 0; - plist_t oob_length_node = NULL; - plist_t oob_offset_node = NULL; - - oob_length_node = plist_dict_get_item(packet, "OOB Length"); - if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { - error("ERROR: Unable to find OOB data length\n"); - return -1; - } - plist_get_uint_val(oob_length_node, &oob_length); - - oob_offset_node = plist_dict_get_item(packet, "OOB Offset"); - if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { - error("ERROR: Unable to find OOB data offset\n"); - return -1; - } - plist_get_uint_val(oob_offset_node, &oob_offset); - - oob_data = (char*) malloc(oob_length); - if (oob_data == NULL) { - error("ERROR: Out of memory\n"); - plist_free(packet); - return -1; - } - - fseek(file, oob_offset, SEEK_SET); - if (fread(oob_data, 1, oob_length, file) != oob_length) { - error("ERROR: Unable to read OOB data from filesystem offset\n"); - plist_free(packet); - free(oob_data); - return -1; - } - - if (asr_send_buffer(asr, oob_data, oob_length) < 0) { - error("ERROR: Unable to send OOB data to ASR\n"); - plist_free(packet); - free(oob_data); - return -1; - } - free(oob_data); - return 0; -} - -int asr_send_payload(idevice_connection_t asr, const char* filesystem) { - int i = 0; - char data[1450]; - FILE* file = NULL; - uint32_t bytes = 0; - uint32_t count = 0; - uint32_t length = 0; - double progress = 0; - - file = fopen(filesystem, "rb"); - if (file == NULL) { - return -1; - } - - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, 0, SEEK_SET); - - for(i = length; i > 0; i -= 1450) { - int size = 1450; - if (i < 1450) { - size = i; - } - - if (fread(data, 1, size, file) != (unsigned int) size) { - error("Error reading filesystem\n"); - fclose(file); - return -1; - } - - if (asr_send_buffer(asr, data, size) < 0) { - error("ERROR: Unable to send filesystem payload\n"); - fclose(file); - return -1; - } - - bytes += size; - progress = ((double) bytes/ (double) length) * 100.0; - print_progress_bar("Extracting", progress); - - } - - fclose(file); - return 0; -} diff --git a/src/asr.h b/src/asr.h deleted file mode 100644 index 29210ce..0000000 --- a/src/asr.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * asr.h - * Functions for handling asr connections - * - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef IDEVICERESTORE_ASR_H -#define IDEVICERESTORE_ASR_H - -#include <libimobiledevice/libimobiledevice.h> - -int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr); -int asr_send(idevice_connection_t asr, plist_t* data); -int asr_receive(idevice_connection_t asr, plist_t* data); -int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size); -void asr_close(idevice_connection_t asr); -int asr_perform_validation(idevice_connection_t asr, const char* filesystem); -int asr_send_payload(idevice_connection_t asr, const char* filesystem); -int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file); - -#endif @@ -19,69 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdio.h> -#include <stdlib.h> -#include <libirecovery.h> +#include <stdint.h> #include "dfu.h" -#include "recovery.h" -#include "idevicerestore.h" -int dfu_check_mode() { - irecv_client_t dfu = NULL; - irecv_error_t dfu_error = IRECV_E_SUCCESS; - - dfu_error = irecv_open(&dfu); - if (dfu_error != IRECV_E_SUCCESS) { - return -1; - } - - if (dfu->mode != kDfuMode) { - irecv_close(dfu); - return -1; - } - - irecv_close(dfu); - dfu = NULL; - return 0; -} - -int dfu_enter_recovery(const char* ipsw, plist_t tss) { - irecv_client_t dfu = NULL; - const char* component = "iBSS"; - irecv_error_t dfu_error = IRECV_E_SUCCESS; - if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode != kDfuMode) { - error("ERROR: Unable to connect to DFU device\n"); - if (dfu) - irecv_close(dfu); - return -1; - } - - if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) { - error("ERROR: Unable to send %s to device\n", component); - irecv_close(dfu); - return -1; - } - - dfu_error = irecv_reset(dfu); - if (dfu_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to reset device\n"); - irecv_close(dfu); - return -1; - } - irecv_close(dfu); - dfu = NULL; - - // Reconnect to device, but this time make sure we're not still in DFU mode - if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode == kDfuMode) { - error("ERROR: Unable to connect to recovery device\n"); - if (dfu) - irecv_close(dfu); - return -1; - } - - idevicerestore_mode = MODE_RECOVERY; - irecv_close(dfu); - dfu = NULL; +int dfu_get_ecid(uint64_t* ecid) { return 0; } @@ -19,13 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_DFU_H -#define IDEVICERESTORE_DFU_H +#ifndef DFU_H +#define DFU_H #include <stdint.h> -#include <plist/plist.h> -int dfu_check_mode(); -int dfu_enter_recovery(const char* ipsw, plist_t tss); +int dfu_get_ecid(uint64_t* ecid); #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 69363fb..aaff4d6 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <getopt.h> #include <plist/plist.h> #include <libirecovery.h> #include <libimobiledevice/restore.h> @@ -39,70 +38,46 @@ #include "recovery.h" #include "idevicerestore.h" -int idevicerestore_quit = 0; -int idevicerestore_debug = 0; -int idevicerestore_erase = 0; -int idevicerestore_custom = 0; -int idevicerestore_verbose = 0; -int idevicerestore_exclude = 0; -int idevicerestore_mode = MODE_UNKNOWN; -idevicerestore_device_t* idevicerestore_device = NULL; - -static struct option long_opts[] = { - { "uuid", required_argument, NULL, 'u' }, - { "debug", no_argument, NULL, 'd' }, - { "verbose", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - { "erase", no_argument, NULL, 'e' }, - { "custom", no_argument, NULL, 'c' }, - { "exclude", no_argument, NULL, 'x' }, - { NULL, 0, NULL, 0} -}; +#define UNKNOWN_MODE 0 +#define DFU_MODE 1 +#define NORMAL_MODE 2 +#define RECOVERY_MODE 3 +#define RESTORE_MODE 4 -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(" -v, --verbose\t\tenable verbose output\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(" -x, --exclude\t\texclude nor/baseband upgrade\n"); - printf("\n"); -} +int idevicerestore_debug = 0; +static int idevicerestore_mode = 0; +static int idevicerestore_quit = 0; +static int idevicerestore_custom = 0; + +void usage(int argc, char* argv[]); +int write_file(const char* filename, char* data, int size); +int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob); +int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob); +void device_callback(const idevice_event_t* event, void *user_data); +int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); +int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize); int main(int argc, char* argv[]) { int opt = 0; - int optindex = 0; char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { + while ((opt = getopt(argc, argv, "vdhcu:")) > 0) { switch (opt) { case 'h': usage(argc, argv); break; - case 'd': - idevicerestore_debug = 1; - break; - - case 'e': - idevicerestore_erase = 1; + case 'v': + idevicerestore_debug += 1; break; case 'c': idevicerestore_custom = 1; break; - case 'x': - idevicerestore_exclude = 1; - break; - - case 'v': - idevicerestore_verbose = 1; + case 'd': + idevicerestore_debug = 3; break; case 'u': @@ -111,608 +86,604 @@ int main(int argc, char* argv[]) { default: usage(argc, argv); - return -1; + break; } } argc -= optind; argv += optind; - if (argc == 1) { + if (argc == 1) ipsw = argv[0]; - } else { - usage(argc, argv); - return -1; - } - - if(idevicerestore_debug) { - idevice_set_debug_level(5); - } - - // check which mode the device is currently in so we know where to start - idevicerestore_mode = check_mode(uuid); - if (idevicerestore_mode < 0) { - error("ERROR: Unable to discover current device state\n"); - return -1; - } - // discover the device type - int id = check_device(uuid); - if (id < 0) { - error("ERROR: Unable to discover device type\n"); + if (ipsw == NULL) { + error("ERROR: Please supply an IPSW\n"); return -1; } - idevicerestore_device = &idevicerestore_devices[id]; - if (idevicerestore_mode == MODE_RESTORE) { - if (restore_reboot(uuid) < 0) { - error("ERROR: Unable to exit restore mode\n"); + idevice_t device = NULL; + irecv_client_t recovery = NULL; + lockdownd_client_t lockdown = NULL; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + idevice_error_t device_error = IDEVICE_E_SUCCESS; + lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; + + /* determine recovery or normal mode */ + info("Checking for device in normal mode...\n"); + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + info("Checking for the device in recovery mode...\n"); + recovery_error = irecv_open(&recovery); + if (recovery_error != IRECV_E_SUCCESS) { + error("ERROR: Unable to find device, is it plugged in?\n"); return -1; } - } + info("Found device in recovery mode\n"); + idevicerestore_mode = RECOVERY_MODE; - // extract buildmanifest - plist_t buildmanifest = NULL; - info("Extracting BuildManifest from IPSW\n"); - if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { - error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); - return -1; + } else { + info("Found device in normal mode\n"); + idevicerestore_mode = NORMAL_MODE; } - // choose whether this is an upgrade or a restore (default to upgrade) - plist_t build_identity = NULL; - if (idevicerestore_erase) { - build_identity = get_build_identity(buildmanifest, 0); - if (build_identity == NULL) { - error("ERROR: Unable to find build any identities\n"); - plist_free(buildmanifest); + /* retrieve ECID */ + if (idevicerestore_mode == NORMAL_MODE) { + lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to connect to lockdownd\n"); + idevice_free(device); return -1; } - } else { - build_identity = get_build_identity(buildmanifest, 1); - if (build_identity == NULL) { - build_identity = get_build_identity(buildmanifest, 0); - if (build_identity == NULL) { - error("ERROR: Unable to find build any identities\n"); - plist_free(buildmanifest); - return -1; - } - info("No upgrade ramdisk found, default to full restore\n"); + plist_t unique_chip_node = NULL; + lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to get UniqueChipID from lockdownd\n"); + lockdownd_client_free(lockdown); + idevice_free(device); + return -1; } - } - // devices are listed in order from oldest to newest - // devices that come after iPod2g require personalized firmwares - plist_t tss_request = NULL; - plist_t tss = NULL; - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - info("Creating TSS request\n"); - // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { - error("ERROR: Unable to find device ECID\n"); + if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { + error("ERROR: Unable to get ECID\n"); + lockdownd_client_free(lockdown); + idevice_free(device); return -1; } + + plist_get_uint_val(unique_chip_node, &ecid); + lockdownd_client_free(lockdown); + plist_free(unique_chip_node); + idevice_free(device); + lockdown = NULL; + device = NULL; + + } else if (idevicerestore_mode == RECOVERY_MODE) { + recovery_error = irecv_get_ecid(recovery, &ecid); + if (recovery_error != IRECV_E_SUCCESS) { + error("ERROR: Unable to get device ECID\n"); + irecv_close(recovery); + return -1; + } + irecv_close(recovery); + recovery = NULL; + } + + if (ecid != 0) { info("Found ECID %llu\n", ecid); + } else { + error("Unable to find device ECID\n"); + return -1; + } - // fetch the SHSH blobs for this build identity - if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { - // this might fail if the TSS server doesn't have the saved blobs for the - // update identity, so go ahead and try again with the restore identity - if (idevicerestore_erase != 1) { - info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); - build_identity = get_build_identity(buildmanifest, 0); - if (build_identity == NULL) { - error("ERROR: Unable to find restore identity\n"); - plist_free(buildmanifest); - return -1; - } + /* parse buildmanifest */ + int buildmanifest_size = 0; + char* buildmanifest_data = NULL; + info("Extracting BuildManifest.plist from IPSW\n"); + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) { + error("ERROR: Unable to extract BuildManifest.plist IPSW\n"); + return -1; + } - if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { - // if this fails then no SHSH blobs have been saved for this firmware - error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); - plist_free(buildmanifest); - return -1; - } + plist_t manifest = NULL; + plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest); - } else { - error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); - plist_free(buildmanifest); - return -1; - } - } + info("Creating TSS request\n"); + plist_t tss_request = tss_create_request(manifest, ecid); + if (tss_request == NULL) { + error("ERROR: Unable to create TSS request\n"); + plist_free(manifest); + return -1; } + plist_free(manifest); - // Extract filesystem from IPSW and return its name + info("Sending TSS request\n"); + plist_t tss_response = tss_send_request(tss_request); + if (tss_response == NULL) { + error("ERROR: Unable to get response from TSS server\n"); + plist_free(tss_request); + return -1; + } + info("Got TSS response\n"); + + // Get name of filesystem DMG in IPSW char* filesystem = NULL; - if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - if (tss) - plist_free(tss); - plist_free(buildmanifest); + plist_t filesystem_node = plist_dict_get_item(tss_request, "OS"); + if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { + error("ERROR: Unable to find filesystem node\n"); + plist_free(tss_request); return -1; } - // if the device is in normal mode, place device into recovery mode - if (idevicerestore_mode == MODE_NORMAL) { - info("Entering recovery mode...\n"); - if (normal_enter_recovery(uuid) < 0) { - error("ERROR: Unable to place device into recovery mode\n"); - if (tss) - plist_free(tss); - plist_free(buildmanifest); - return -1; - } + plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); + if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { + error("ERROR: Unable to find filesystem info node\n"); + plist_free(tss_request); + return -1; } - // if the device is in DFU mode, place device into recovery mode - if (idevicerestore_mode == MODE_DFU) { - if (dfu_enter_recovery(ipsw, tss) < 0) { - error("ERROR: Unable to place device into recovery mode\n"); - plist_free(buildmanifest); - if (tss) - plist_free(tss); - return -1; - } + plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); + if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { + error("ERROR: Unable to find filesystem info path node\n"); + plist_free(tss_request); + return -1; } + plist_get_string_val(filesystem_info_path_node, &filesystem); + plist_free(tss_request); - // if the device is in recovery mode, place device into restore mode - if (idevicerestore_mode == MODE_RECOVERY) { - if (recovery_enter_restore(uuid, ipsw, tss) < 0) { - error("ERROR: Unable to place device into restore mode\n"); - plist_free(buildmanifest); - if (tss) - plist_free(tss); - return -1; - } + info("Extracting filesystem from IPSW\n"); + if (ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) { + error("ERROR: Unable to extract filesystem\n"); + return -1; } - // device is finally in restore mode, let's do this - if (idevicerestore_mode == MODE_RESTORE) { - info("Restoring device... \n"); - if (restore_device(uuid, ipsw, tss, filesystem) < 0) { - error("ERROR: Unable to restore device\n"); + /* place device into recovery mode if required */ + if (idevicerestore_mode == NORMAL_MODE) { + info("Entering recovery mode...\n"); + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to find device\n"); + plist_free(tss_response); return -1; } - } - // device has finished restoring, lets see if we need to activate - if (idevicerestore_mode == MODE_NORMAL) { - info("Checking activation status\n"); - int activation = activate_check_status(uuid); - if (activation < 0) { - error("ERROR: Unable to check activation status\n"); + lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to connect to lockdownd service\n"); + plist_free(tss_response); + idevice_free(device); return -1; } - if (activation == 0) { - info("Activating device... \n"); - if (activate_device(uuid) < 0) { - error("ERROR: Unable to activate device\n"); - return -1; - } + lockdown_error = lockdownd_enter_recovery(lockdown); + if (lockdown_error != LOCKDOWN_E_SUCCESS) { + error("ERROR: Unable to place device in recovery mode\n"); + lockdownd_client_free(lockdown); + plist_free(tss_response); + idevice_free(device); + return -1; } - } - - info("Cleaning up...\n"); - if (filesystem) - unlink(filesystem); - - info("DONE\n"); - return 0; -} -int check_mode(const char* uuid) { - int mode = MODE_UNKNOWN; + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; + } - if (recovery_check_mode() == 0) { - info("Found device in recovery mode\n"); - mode = MODE_RECOVERY; + /* upload data to make device boot restore mode */ + if (recovery_send_ibec(ipsw, tss_response) < 0) { + error("ERROR: Unable to send iBEC\n"); + plist_free(tss_response); + return -1; } + sleep(1); - else if (dfu_check_mode() == 0) { - info("Found device in DFU mode\n"); - mode = MODE_DFU; + if (recovery_send_applelogo(ipsw, tss_response) < 0) { + error("ERROR: Unable to send AppleLogo\n"); + plist_free(tss_response); + return -1; } - else if (normal_check_mode(uuid) == 0) { - info("Found device in normal mode\n"); - mode = MODE_NORMAL; + if (recovery_send_devicetree(ipsw, tss_response) < 0) { + error("ERROR: Unable to send DeviceTree\n"); + plist_free(tss_response); + return -1; } - else if (restore_check_mode(uuid) == 0) { - info("Found device in restore mode\n"); - mode = MODE_RESTORE; + if (recovery_send_ramdisk(ipsw, tss_response) < 0) { + error("ERROR: Unable to send Ramdisk\n"); + plist_free(tss_response); + return -1; } - return mode; -} + // for some reason iboot requires a hard reset after ramdisk + // or things start getting wacky + printf("Please unplug your device, then plug it back in\n"); + printf("Hit any key to continue..."); + getchar(); -int check_device(const char* uuid) { - int device = DEVICE_UNKNOWN; - uint32_t bdid = 0; - uint32_t cpid = 0; + if (recovery_send_kernelcache(ipsw, tss_response) < 0) { + error("ERROR: Unable to send KernelCache\n"); + plist_free(tss_response); + return -1; + } - switch (idevicerestore_mode) { - case MODE_RESTORE: - device = restore_check_device(uuid); - if (device < 0) { - device = DEVICE_UNKNOWN; - } - break; + idevice_event_subscribe(&device_callback, NULL); + info("Waiting for device to enter restore mode\n"); + // block program until device has entered restore mode + while (idevicerestore_mode != RESTORE_MODE) { + sleep(1); + } - case MODE_NORMAL: - device = normal_check_device(uuid); - if (device < 0) { - device = DEVICE_UNKNOWN; - } - break; + device_error = idevice_new(&device, uuid); + if (device_error != IDEVICE_E_SUCCESS) { + error("ERROR: Unable to open device\n"); + plist_free(tss_response); + return -1; + } - case MODE_DFU: - case MODE_RECOVERY: - if (get_cpid(uuid, &cpid) < 0) { - error("ERROR: Unable to get device CPID\n"); - break; - } + restored_client_t restore = NULL; + restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to start restored client\n"); + plist_free(tss_response); + idevice_free(device); + return -1; + } - switch (cpid) { - case CPID_IPHONE2G: - // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID - // so we need to check the BoardID - if (get_bdid(uuid, &bdid) < 0) { - error("ERROR: Unable to get device BDID\n"); - break; + char* type = NULL; + uint64_t version = 0; + if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { + error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); + plist_free(tss_response); + restored_client_free(restore); + idevice_free(device); + return -1; + } + info("Device has successfully entered restore mode\n"); + + /* start restore process */ + char* kernelcache = NULL; + info("Restore protocol version is %llu.\n", version); + restore_error = restored_start_restore(restore); + if (restore_error == RESTORE_E_SUCCESS) { + while (!idevicerestore_quit) { + plist_t message = NULL; + restore_error = restored_receive(restore, &message); + plist_t msgtype_node = plist_dict_get_item(message, "MsgType"); + if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) { + char *msgtype = NULL; + plist_get_string_val(msgtype_node, &msgtype); + if (!strcmp(msgtype, "ProgressMsg")) { + restore_error = restore_handle_progress_msg(restore, message); + + } else if (!strcmp(msgtype, "DataRequestMsg")) { + // device is requesting data to be sent + plist_t datatype_node = plist_dict_get_item(message, "DataType"); + if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) { + char *datatype = NULL; + plist_get_string_val(datatype_node, &datatype); + if (!strcmp(datatype, "SystemImageData")) { + asr_send_system_image_data_from_file(device, restore, filesystem); + + } else if (!strcmp(datatype, "KernelCache")) { + int kernelcache_size = 0; + char* kernelcache_data = NULL; + if (get_signed_component_by_name(ipsw, tss_response, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { + error("ERROR: Unable to get kernelcache file\n"); + return -1; + } + restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); + free(kernelcache_data); + + } else if (!strcmp(datatype, "NORData")) { + restore_send_nor_data(restore, ipsw, tss_response); + + } else { + // Unknown DataType!! + error("Unknown DataType\n"); + return -1; + } + } + + } else if (!strcmp(msgtype, "StatusMsg")) { + restore_error = restore_handle_status_msg(restore, message); + + } else { + info("Received unknown message type: %s\n", msgtype); + } } - switch (bdid) { - case BDID_IPHONE2G: - device = DEVICE_IPHONE2G; - break; - - case BDID_IPHONE3G: - device = DEVICE_IPHONE3G; - break; - - case BDID_IPOD1G: - device = DEVICE_IPOD1G; - break; - - default: - device = DEVICE_UNKNOWN; - break; + if (RESTORE_E_SUCCESS != restore_error) { + error("Invalid return status %d\n", restore_error); + //idevicerestore_quit = 1; } - break; - - case CPID_IPHONE3GS: - device = DEVICE_IPHONE3GS; - break; - - case CPID_IPOD2G: - device = DEVICE_IPOD2G; - break; - case CPID_IPOD3G: - device = DEVICE_IPOD3G; - break; - - case CPID_IPAD1G: - device = DEVICE_IPAD1G; - break; - - default: - device = DEVICE_UNKNOWN; - break; + plist_free(message); } - break; - - default: - device = DEVICE_UNKNOWN; - break; - + } else { + error("ERROR: Could not start restore. %d\n", restore_error); } - return device; + restored_client_free(restore); + plist_free(tss_response); + idevice_free(device); + unlink(filesystem); + return 0; } -int get_bdid(const char* uuid, uint32_t* bdid) { - switch (idevicerestore_mode) { - case MODE_NORMAL: - if (normal_get_bdid(uuid, bdid) < 0) { - *bdid = -1; - return -1; - } - break; - - case MODE_DFU: - case MODE_RECOVERY: - if (recovery_get_bdid(bdid) < 0) { - *bdid = -1; - return -1; - } - break; - - default: - error("ERROR: Device is in an invalid state\n"); - return -1; +void device_callback(const idevice_event_t* event, void *user_data) { + if (event->event == IDEVICE_DEVICE_ADD) { + idevicerestore_mode = RESTORE_MODE; + } else if(event->event == IDEVICE_DEVICE_REMOVE) { + idevicerestore_quit = 1; } - - return 0; } -int get_cpid(const char* uuid, uint32_t* cpid) { - switch (idevicerestore_mode) { - case MODE_NORMAL: - if (normal_get_cpid(uuid, cpid) < 0) { - *cpid = 0; - return -1; - } - break; - - case MODE_DFU: - case MODE_RECOVERY: - if (recovery_get_cpid(cpid) < 0) { - *cpid = 0; - return -1; - } - break; +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(" -d, \t\tenable communication debugging\n"); + printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n"); + printf(" -h, \t\tprints usage information\n"); + printf(" -c, \t\trestore with a custom firmware\n"); + printf(" -v, \t\tenable incremental levels of verboseness\n"); + printf("\n"); + exit(1); +} - default: - error("ERROR: Device is in an invalid state\n"); +int write_file(const char* filename, char* data, int size) { + debug("Writing data to %s\n", filename); + FILE* file = fopen(filename, "wb"); + if (file == NULL) { + error("read_file: Unable to open file %s\n", filename); return -1; } - return 0; -} - -int get_ecid(const char* uuid, uint64_t* ecid) { - switch (idevicerestore_mode) { - case MODE_NORMAL: - if (normal_get_ecid(uuid, ecid) < 0) { - *ecid = 0; - return -1; - } - break; - - case MODE_DFU: - case MODE_RECOVERY: - if (recovery_get_ecid(ecid) < 0) { - *ecid = 0; - return -1; - } - break; + int bytes = fwrite(data, 1, size, file); + fclose(file); - default: - error("ERROR: Device is in an invalid state\n"); + if (bytes != size) { + error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); return -1; } - return 0; + return size; } -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { - int size = 0; - char* data = NULL; - int device = idevicerestore_device->device_id; - if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) { - // Older devices that don't require personalized firmwares use BuildManifesto.plist - if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) { - return -1; +int get_tss_data_by_path(plist_t tss, const char* path, char** pname, char** pblob) { + *pname = NULL; + *pblob = NULL; + + char* key = NULL; + plist_t tss_entry = NULL; + plist_dict_iter iter = NULL; + plist_dict_new_iter(tss, &iter); + while (1) { + plist_dict_next_item(tss, iter, &key, &tss_entry); + if (key == NULL) + break; + + if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { + continue; } - } else if (device >= DEVICE_IPHONE3GS && device <= DEVICE_IPAD1G) { - // Whereas newer devices that do require personalized firmwares use BuildManifest.plist - if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { + char* entry_path = NULL; + plist_t entry_path_node = plist_dict_get_item(tss_entry, "Path"); + if (!entry_path_node || plist_get_node_type(entry_path_node) != PLIST_STRING) { + error("ERROR: Unable to find TSS path node in entry %s\n", key); return -1; } + plist_get_string_val(entry_path_node, &entry_path); + if (strcmp(path, entry_path) == 0) { + char* blob = NULL; + uint64_t blob_size = 0; + plist_t blob_node = plist_dict_get_item(tss_entry, "Blob"); + if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { + error("ERROR: Unable to find TSS blob node in entry %s\n", key); + return -1; + } + plist_get_data_val(blob_node, &blob, &blob_size); + *pname = key; + *pblob = blob; + return 0; + } - } else { - return -1; + free(key); } + plist_free(tss_entry); - plist_from_xml(data, size, buildmanifest); - return 0; + return -1; } -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { +int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) { + *ppath = NULL; + *pblob = NULL; - // fetch build identities array from BuildManifest - plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); - if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { - error("ERROR: Unable to find build identities node\n"); - return NULL; + plist_t node = plist_dict_get_item(tss, entry); + if (!node || plist_get_node_type(node) != PLIST_DICT) { + error("ERROR: Unable to find %s entry in TSS response\n", entry); + return -1; } - // check and make sure this identity exists in buildmanifest - if (identity >= plist_array_get_size(build_identities_array)) { - return NULL; + char* path = NULL; + plist_t path_node = plist_dict_get_item(node, "Path"); + if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { + error("ERROR: Unable to find %s path in entry\n", path); + return -1; } + plist_get_string_val(path_node, &path); - plist_t build_identity = plist_array_get_item(build_identities_array, identity); - if (!build_identity || plist_get_node_type(build_identity) != PLIST_DICT) { - error("ERROR: Unable to find build identities node\n"); - return NULL; + char* blob = NULL; + uint64_t blob_size = 0; + plist_t blob_node = plist_dict_get_item(node, "Blob"); + if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { + error("ERROR: Unable to find %s blob in entry\n", path); + free(path); + return -1; } + plist_get_data_val(blob_node, &blob, &blob_size); - return plist_copy(build_identity); + *ppath = path; + *pblob = blob; + return 0; } -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { - plist_t request = NULL; - plist_t response = NULL; - *tss = NULL; +int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize) { + int size = 0; + char* data = NULL; + char* path = NULL; + char* blob = NULL; + img3_file* img3 = NULL; + irecv_error_t error = 0; - request = tss_create_request(build_identity, ecid); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + info("Extracting %s from TSS response\n", component); + if (get_tss_data_by_name(tss, component, &path, &blob) < 0) { + error("ERROR: Unable to get data for TSS %s entry\n", component); return -1; } - info("Sending TSS request\n"); - response = tss_send_request(request); - if (response == NULL) { - plist_free(request); + info("Extracting %s from %s\n", path, ipsw); + if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { + error("ERROR: Unable to extract %s from %s\n", path, ipsw); + free(path); + free(blob); return -1; } - plist_free(request); - *tss = response; - return 0; -} - -int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { - char* filename = NULL; - - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find manifest node\n"); + img3 = img3_parse_file(data, size); + if (img3 == NULL) { + error("ERROR: Unable to parse IMG3: %s\n", path); + free(data); + free(path); + free(blob); return -1; } + if (data) { + free(data); + data = NULL; + } - plist_t filesystem_node = plist_dict_get_item(manifest_node, "OS"); - if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { - error("ERROR: Unable to find filesystem node\n"); - return -1; + if (idevicerestore_custom == 0) { + if (img3_replace_signature(img3, blob) < 0) { + error("ERROR: Unable to replace IMG3 signature\n"); + free(path); + free(blob); + return -1; + } } - plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); - if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { - error("ERROR: Unable to find filesystem info node\n"); + if (img3_get_data(img3, &data, &size) < 0) { + error("ERROR: Unable to reconstruct IMG3\n"); + img3_free(img3); + free(path); return -1; } - plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); - if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { - error("ERROR: Unable to find filesystem info path node\n"); - return -1; + if (idevicerestore_debug) { + char* out = strrchr(path, '/'); + if (out != NULL) { + out++; + } else { + out = path; + } + write_file(out, data, size); } - plist_get_string_val(filesystem_info_path_node, &filename); - info("Extracting filesystem from IPSW\n"); - if (ipsw_extract_to_file(ipsw, filename, filename) < 0) { - error("ERROR: Unable to extract filesystem\n"); - return -1; + if (img3) { + img3_free(img3); + img3 = NULL; + } + if (blob) { + free(blob); + blob = NULL; + } + if (path) { + free(path); + path = NULL; } - *filesystem = filename; + *pdata = data; + *psize = size; return 0; } -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize) { + int size = 0; + char* data = NULL; + char* name = NULL; + char* blob = NULL; img3_file* img3 = NULL; - uint32_t component_size = 0; - char* component_data = NULL; - char* component_blob = NULL; - char* component_name = NULL; - - component_name = strrchr(path, '/'); - if (component_name != NULL) component_name++; - else component_name = (char*) path; - - info("Extracting %s\n", component_name); - if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); + irecv_error_t error = 0; + + info("Extracting %s from TSS response\n", path); + if (get_tss_data_by_path(tss, path, &name, &blob) < 0) { + error("ERROR: Unable to get data for TSS %s entry\n", path); return -1; } - img3 = img3_parse_file(component_data, component_size); - if (img3 == NULL) { - error("ERROR: Unable to parse IMG3: %s\n", component_name); - free(component_data); + info("Extracting %s from %s\n", path, ipsw); + if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { + error("ERROR: Unable to extract %s from %s\n", path, ipsw); + free(path); + free(blob); return -1; } - free(component_data); - if (tss_get_blob_by_path(tss, path, &component_blob) < 0) { - error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name); - img3_free(img3); + img3 = img3_parse_file(data, size); + if (img3 == NULL) { + error("ERROR: Unable to parse IMG3: %s\n", path); + free(data); + free(path); + free(blob); return -1; } + if (data) { + free(data); + data = NULL; + } - if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { - if (img3_replace_signature(img3, component_blob) < 0) { + if (idevicerestore_custom == 0) { + if (img3_replace_signature(img3, blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); - free(component_blob); - img3_free(img3); + free(name); + free(blob); return -1; } } - free(component_blob); - if (img3_get_data(img3, &component_data, &component_size) < 0) { + if (img3_get_data(img3, &data, &size) < 0) { error("ERROR: Unable to reconstruct IMG3\n"); img3_free(img3); + free(name); return -1; } - img3_free(img3); if (idevicerestore_debug) { - write_file(component_name, component_data, component_size); - } - - *data = component_data; - *size = component_size; - return 0; -} - -int write_file(const char* filename, const void* data, size_t size) { - size_t bytes = 0; - FILE* file = NULL; - - info("Writing data to %s\n", filename); - file = fopen(filename, "wb"); - if (file == NULL) { - error("read_file: Unable to open file %s\n", filename); - return -1; - } - - bytes = fwrite(data, 1, size, file); - fclose(file); - - if (bytes != size) { - error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); - return -1; + char* out = strrchr(path, '/'); + if (out != NULL) { + out++; + } else { + out = path; + } + write_file(out, data, size); } - return size; -} - -int read_file(const char* filename, char** data, uint32_t* size) { - size_t bytes = 0; - size_t length = 0; - FILE* file = NULL; - char* buffer = NULL; - debug("Reading data from %s\n", filename); - - *size = 0; - *data = NULL; - - file = fopen(filename, "rb"); - if (file == NULL) { - error("read_file: File %s not found\n", filename); - return -1; + if (img3) { + img3_free(img3); + img3 = NULL; } - - fseek(file, 0, SEEK_END); - length = ftell(file); - rewind(file); - - buffer = (char*) malloc(length); - if(buffer == NULL) { - error("ERROR: Out of memory\n"); - fclose(file); - return -1; + if (blob) { + free(blob); + blob = NULL; } - bytes = fread(buffer, 1, length, file); - fclose(file); - - if(bytes != length) { - error("ERROR: Unable to read entire file\n"); - free(buffer); - return -1; + if (path) { + free(name); + name = NULL; } - *size = length; - *data = buffer; + *pdata = data; + *psize = size; return 0; } - diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 20578a9..3dcf1d5 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -1,5 +1,5 @@ /* - * idevicerestore.h + * idevicerestore.g * Restore device firmware and filesystem * * Copyright (c) 2010 Joshua Hill. All Rights Reserved. @@ -22,135 +22,10 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H -#include <stdio.h> -#include <stdlib.h> -#include <plist/plist.h> - -#define info(...) printf(__VA_ARGS__) #define error(...) fprintf(stderr, __VA_ARGS__) -#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) - -#define MODE_UNKNOWN -1 -#define MODE_DFU 0 -#define MODE_RECOVERY 1 -#define MODE_RESTORE 2 -#define MODE_NORMAL 3 - -#define CPID_UNKNOWN -1 -#define CPID_IPHONE2G 8900 -#define CPID_IPOD1G 8900 -#define CPID_IPHONE3G 8900 -#define CPID_IPOD2G 8720 -#define CPID_IPHONE3GS 8920 -#define CPID_IPOD3G 8922 -#define CPID_IPAD1G 8930 - -#define BDID_UNKNOWN -1 -#define BDID_IPHONE2G 0 -#define BDID_IPOD1G 2 -#define BDID_IPHONE3G 4 -#define BDID_IPOD2G 0 -#define BDID_IPHONE3GS 0 -#define BDID_IPOD3G 2 -#define BDID_IPAD1G 2 - -#define DEVICE_UNKNOWN -1 -#define DEVICE_IPHONE2G 0 -#define DEVICE_IPOD1G 1 -#define DEVICE_IPHONE3G 2 -#define DEVICE_IPOD2G 3 -#define DEVICE_IPHONE3GS 4 -#define DEVICE_IPOD3G 5 -#define DEVICE_IPAD1G 6 - -typedef struct idevicerestore_entry { - char* name; - char* path; - char* filename; - char* blob_data; - uint32_t blob_size; - struct idevicerestore_entry* next; - struct idevicerestore_entry* prev; -} idevicerestore_entry_t; +#define info(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) +#define debug(...) if(idevicerestore_debug >= 2) fprintf(stderr, __VA_ARGS__) -typedef struct { - int device_id; - const char* product; - const char* model; - int board_id; - int chip_id; -} idevicerestore_device_t; -/* -typedef struct { - int mode; - idevice_t device; - irecv_client_t recovery; - restored_client_t restore; - lockdownd_client_t lockdown; - int erase; // 1 - int custom; // 2 - int exclude; // 4 - int verbose; // 8 - idevicerestore_device_t* idevicerestore_device; - idevicerestore_entry_t** entries; -} idevicerestore_context_t; -*/ -static idevicerestore_device_t idevicerestore_devices[] = { - { 0, "iPhone1,1", "M68AP", 0, 8900 }, - { 1, "iPod1,1", "N45AP", 2, 8900 }, - { 2, "iPhone1,2", "N82AP", 4, 8900 }, - { 3, "iPod2,1", "N72AP", 0, 8720 }, - { 4, "iPhone2,1", "N88AP", 0, 8920 }, - { 5, "iPod3,1", "N18AP", 2, 8922 }, - { 6, "iPad1,1", "K48AP", 2, 8930 }, - { 6, "iPhone4,1", "XXXAP", 0, 0 }, - { -1, NULL, NULL, -1, -1 } -}; - -extern int idevicerestore_mode; -extern int idevicerestore_quit; extern int idevicerestore_debug; -extern int idevicerestore_erase; -extern int idevicerestore_custom; -extern int idevicerestore_exclude; -extern int idevicerestore_verbose; -extern idevicerestore_device_t* idevicerestore_device; -extern idevicerestore_entry_t** idevicerestore_entries; - -int check_mode(const char* uuid); -int check_device(const char* uuid); -void usage(int argc, char* argv[]); -int get_ecid(const char* uuid, uint64_t* ecid); -int get_bdid(const char* uuid, uint32_t* bdid); -int get_cpid(const char* uuid, uint32_t* cpid); -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); -int write_file(const char* filename, const void* data, size_t size); -int read_file(const char* filename, char** data, uint32_t* size); -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); -int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); - -inline static void debug_plist(plist_t plist) { - int size = 0; - char* data = NULL; - plist_to_xml(plist, &data, &size); - debug("%s", data); - free(data); -} - -inline static void print_progress_bar(const char* operation, double progress) { - int i = 0; - if(progress < 0) return; - if(progress > 100) progress = 100; - info("\r%s [", operation); - for(i = 0; i < 50; i++) { - if(i < progress / 2) info("="); - else info(" "); - } - info("] %3.1f%%", progress); - if(progress == 100) info("\n"); - fflush(stdout); -} #endif @@ -29,20 +29,20 @@ img3_file* img3_parse_file(char* data, int size) { int data_offset = 0; img3_header* header = (img3_header*) data; - if (header->signature != kImg3Container) { + if(header->signature != kImg3Container) { error("ERROR: Invalid IMG3 file\n"); return NULL; } img3_file* image = (img3_file*) malloc(sizeof(img3_file)); - if (image == NULL) { + if(image == NULL) { error("ERROR: Unable to allocate memory for IMG3 file\n"); return NULL; } memset(image, '\0', sizeof(img3_file)); image->header = (img3_header*) malloc(sizeof(img3_header)); - if (image->header == NULL) { + if(image->header == NULL) { error("ERROR: Unable to allocate memory for IMG3 header\n"); img3_free(image); return NULL; @@ -51,12 +51,12 @@ img3_file* img3_parse_file(char* data, int size) { data_offset += sizeof(img3_header); img3_element_header* current = NULL; - while (data_offset < size) { + while(data_offset < size) { current = (img3_element_header*) &data[data_offset]; - switch (current->signature) { + switch(current->signature) { case kTypeElement: image->type_element = img3_parse_element(&data[data_offset]); - if (image->type_element == NULL) { + if(image->type_element == NULL) { error("ERROR: Unable to parse TYPE element\n"); img3_free(image); return NULL; @@ -66,7 +66,7 @@ img3_file* img3_parse_file(char* data, int size) { case kDataElement: image->data_element = img3_parse_element(&data[data_offset]); - if (image->data_element == NULL) { + if(image->data_element == NULL) { error("ERROR: Unable to parse DATA element\n"); img3_free(image); return NULL; @@ -76,7 +76,7 @@ img3_file* img3_parse_file(char* data, int size) { case kVersElement: image->vers_element = img3_parse_element(&data[data_offset]); - if (image->vers_element == NULL) { + if(image->vers_element == NULL) { error("ERROR: Unable to parse VERS element\n"); img3_free(image); return NULL; @@ -86,7 +86,7 @@ img3_file* img3_parse_file(char* data, int size) { case kSepoElement: image->sepo_element = img3_parse_element(&data[data_offset]); - if (image->sepo_element == NULL) { + if(image->sepo_element == NULL) { error("ERROR: Unable to parse SEPO element\n"); img3_free(image); return NULL; @@ -96,7 +96,7 @@ img3_file* img3_parse_file(char* data, int size) { case kBordElement: image->bord_element = img3_parse_element(&data[data_offset]); - if (image->bord_element == NULL) { + if(image->bord_element == NULL) { error("ERROR: Unable to parse BORD element\n"); img3_free(image); return NULL; @@ -105,9 +105,9 @@ img3_file* img3_parse_file(char* data, int size) { break; case kKbagElement: - if (image->kbag1_element == NULL) { + if(image->kbag1_element == NULL) { image->kbag1_element = img3_parse_element(&data[data_offset]); - if (image->kbag1_element == NULL) { + if(image->kbag1_element == NULL) { error("ERROR: Unable to parse first KBAG element\n"); img3_free(image); return NULL; @@ -115,7 +115,7 @@ img3_file* img3_parse_file(char* data, int size) { } else { image->kbag2_element = img3_parse_element(&data[data_offset]); - if (image->kbag2_element == NULL) { + if(image->kbag2_element == NULL) { error("ERROR: Unable to parse second KBAG element\n"); img3_free(image); return NULL; @@ -126,7 +126,7 @@ img3_file* img3_parse_file(char* data, int size) { case kEcidElement: image->ecid_element = img3_parse_element(&data[data_offset]); - if (image->ecid_element == NULL) { + if(image->ecid_element == NULL) { error("ERROR: Unable to parse ECID element\n"); img3_free(image); return NULL; @@ -136,7 +136,7 @@ img3_file* img3_parse_file(char* data, int size) { case kShshElement: image->shsh_element = img3_parse_element(&data[data_offset]); - if (image->shsh_element == NULL) { + if(image->shsh_element == NULL) { error("ERROR: Unable to parse SHSH element\n"); img3_free(image); return NULL; @@ -146,7 +146,7 @@ img3_file* img3_parse_file(char* data, int size) { case kCertElement: image->cert_element = img3_parse_element(&data[data_offset]); - if (image->cert_element == NULL) { + if(image->cert_element == NULL) { error("ERROR: Unable to parse CERT element\n"); img3_free(image); return NULL; @@ -168,14 +168,14 @@ img3_file* img3_parse_file(char* data, int size) { img3_element* img3_parse_element(char* data) { img3_element_header* element_header = (img3_element_header*) data; img3_element* element = (img3_element*) malloc(sizeof(img3_element)); - if (element == NULL) { + if(element == NULL) { error("ERROR: Unable to allocate memory for IMG3 element\n"); return NULL; } memset(element, '\0', sizeof(img3_element)); element->data = (char*) malloc(element_header->full_size); - if (element->data == NULL) { + if(element->data == NULL) { error("ERROR: Unable to allocate memory for IMG3 element data\n"); free(element); return NULL; @@ -188,57 +188,57 @@ img3_element* img3_parse_element(char* data) { } void img3_free(img3_file* image) { - if (image != NULL) { - if (image->header != NULL) { + if(image != NULL) { + if(image->header != NULL) { free(image->header); } - if (image->type_element != NULL) { + if(image->type_element != NULL) { img3_free_element(image->type_element); image->type_element = NULL; } - if (image->data_element != NULL) { + if(image->data_element != NULL) { img3_free_element(image->data_element); image->data_element = NULL; } - if (image->vers_element != NULL) { + if(image->vers_element != NULL) { img3_free_element(image->vers_element); image->vers_element = NULL; } - if (image->sepo_element != NULL) { + if(image->sepo_element != NULL) { img3_free_element(image->sepo_element); image->sepo_element = NULL; } - if (image->bord_element != NULL) { + if(image->bord_element != NULL) { img3_free_element(image->bord_element); image->bord_element = NULL; } - if (image->kbag1_element != NULL) { + if(image->kbag1_element != NULL) { img3_free_element(image->kbag1_element); image->kbag1_element = NULL; } - if (image->kbag2_element != NULL) { + if(image->kbag2_element != NULL) { img3_free_element(image->kbag2_element); image->kbag2_element = NULL; } - if (image->ecid_element != NULL) { + if(image->ecid_element != NULL) { img3_free_element(image->ecid_element); image->ecid_element = NULL; } - if (image->shsh_element != NULL) { + if(image->shsh_element != NULL) { img3_free_element(image->shsh_element); image->shsh_element = NULL; } - if (image->cert_element != NULL) { + if(image->cert_element != NULL) { img3_free_element(image->cert_element); image->cert_element = NULL; } @@ -249,8 +249,8 @@ void img3_free(img3_file* image) { } void img3_free_element(img3_element* element) { - if (element != NULL) { - if (element->data != NULL) { + if(element != NULL) { + if(element->data != NULL) { free(element->data); element->data = NULL; } @@ -262,37 +262,37 @@ void img3_free_element(img3_element* element) { int img3_replace_signature(img3_file* image, char* signature) { int offset = 0; img3_element* ecid = img3_parse_element(&signature[offset]); - if (ecid == NULL || ecid->type != kEcidElement) { + if(ecid == NULL || ecid->type != kEcidElement) { error("ERROR: Unable to find ECID element in signature\n"); return -1; } offset += ecid->header->full_size; img3_element* shsh = img3_parse_element(&signature[offset]); - if (shsh == NULL || shsh->type != kShshElement) { + if(shsh == NULL || shsh->type != kShshElement) { error("ERROR: Unable to find SHSH element in signature\n"); return -1; } offset += shsh->header->full_size; img3_element* cert = img3_parse_element(&signature[offset]); - if (cert == NULL || cert->type != kCertElement) { + if(cert == NULL || cert->type != kCertElement) { error("ERROR: Unable to find CERT element in signature\n"); return -1; } offset += cert->header->full_size; - if (image->ecid_element != NULL) { + if(image->ecid_element != NULL) { img3_free_element(image->ecid_element); } image->ecid_element = ecid; - if (image->shsh_element != NULL) { + if(image->shsh_element != NULL) { img3_free_element(image->shsh_element); } image->shsh_element = shsh; - if (image->cert_element != NULL) { + if(image->cert_element != NULL) { img3_free_element(image->cert_element); } image->cert_element = cert; @@ -305,39 +305,39 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { int size = sizeof(img3_header); // Add up the size of the image first so we can allocate our memory - if (image->type_element != NULL) { + if(image->type_element != NULL) { size += image->type_element->header->full_size; } - if (image->data_element != NULL) { + if(image->data_element != NULL) { size += image->data_element->header->full_size; } - if (image->vers_element != NULL) { + if(image->vers_element != NULL) { size += image->vers_element->header->full_size; } - if (image->sepo_element != NULL) { + if(image->sepo_element != NULL) { size += image->sepo_element->header->full_size; } - if (image->bord_element != NULL) { + if(image->bord_element != NULL) { size += image->bord_element->header->full_size; } - if (image->kbag1_element != NULL) { + if(image->kbag1_element != NULL) { size += image->kbag1_element->header->full_size; } - if (image->kbag2_element != NULL) { + if(image->kbag2_element != NULL) { size += image->kbag2_element->header->full_size; } - if (image->ecid_element != NULL) { + if(image->ecid_element != NULL) { size += image->ecid_element->header->full_size; } - if (image->shsh_element != NULL) { + if(image->shsh_element != NULL) { size += image->shsh_element->header->full_size; } - if (image->cert_element != NULL) { + if(image->cert_element != NULL) { size += image->cert_element->header->full_size; } char* data = (char*) malloc(size); - if (data == NULL) { + if(data == NULL) { error("ERROR: Unable to allocate memory for IMG3 data\n"); return -1; } @@ -351,49 +351,49 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) { offset += sizeof(img3_header); // Copy each section over to the new buffer - if (image->type_element != NULL) { + if(image->type_element != NULL) { memcpy(&data[offset], image->type_element->data, image->type_element->header->full_size); offset += image->type_element->header->full_size; } - if (image->data_element != NULL) { + if(image->data_element != NULL) { memcpy(&data[offset], image->data_element->data, image->data_element->header->full_size); offset += image->data_element->header->full_size; } - if (image->vers_element != NULL) { + if(image->vers_element != NULL) { memcpy(&data[offset], image->vers_element->data, image->vers_element->header->full_size); offset += image->vers_element->header->full_size; } - if (image->sepo_element != NULL) { + if(image->sepo_element != NULL) { memcpy(&data[offset], image->sepo_element->data, image->sepo_element->header->full_size); offset += image->sepo_element->header->full_size; } - if (image->bord_element != NULL) { + if(image->bord_element != NULL) { memcpy(&data[offset], image->bord_element->data, image->bord_element->header->full_size); offset += image->bord_element->header->full_size; } - if (image->kbag1_element != NULL) { + if(image->kbag1_element != NULL) { memcpy(&data[offset], image->kbag1_element->data, image->kbag1_element->header->full_size); offset += image->kbag1_element->header->full_size; } - if (image->kbag2_element != NULL) { + if(image->kbag2_element != NULL) { memcpy(&data[offset], image->kbag2_element->data, image->kbag2_element->header->full_size); offset += image->kbag2_element->header->full_size; } - if (image->ecid_element != NULL) { + if(image->ecid_element != NULL) { memcpy(&data[offset], image->ecid_element->data, image->ecid_element->header->full_size); offset += image->ecid_element->header->full_size; } - if (image->shsh_element != NULL) { + if(image->shsh_element != NULL) { memcpy(&data[offset], image->shsh_element->data, image->shsh_element->header->full_size); header->shsh_offset = offset - sizeof(img3_header); offset += image->shsh_element->header->full_size; } - if (image->cert_element != NULL) { + if(image->cert_element != NULL) { memcpy(&data[offset], image->cert_element->data, image->cert_element->header->full_size); offset += image->cert_element->header->full_size; } - if (offset != size) { + if(offset != size) { error("ERROR: Incorrectly sized image data\n"); free(data); *pdata = 0; @@ -19,43 +19,43 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_IMG3_H -#define IDEVICERESTORE_IMG3_H +#ifndef IMG3_H +#define IMG3_H typedef enum { - kNorContainer = 0x696D6733, // img3 - kImg3Container = 0x496D6733, // Img3 - k8900Container = 0x30303938, // 8900 - kImg2Container = 0x494D4732 // IMG2 + kNorContainer = 0x696D6733, // img3 + kImg3Container = 0x496D6733, // Img3 + k8900Container = 0x30303938, // 8900 + kImg2Container = 0x494D4732 // IMG2 } img3_container; typedef enum { - kDataElement = 0x44415441, // DATA - kTypeElement = 0x54595045, // TYPE - kKbagElement = 0x4B424147, // KBAG - kShshElement = 0x53485348, // SHSH - kCertElement = 0x43455254, // CERT - kChipElement = 0x43484950, // CHIP - kProdElement = 0x50524F44, // PROD - kSdomElement = 0x53444F4D, // SDOM - kVersElement = 0x56455253, // VERS - kBordElement = 0x424F5244, // BORD - kSepoElement = 0x5345504F, // SEPO - kEcidElement = 0x45434944 // ECID + kDataElement = 0x44415441, // DATA + kTypeElement = 0x54595045, // TYPE + kKbagElement = 0x4B424147, // KBAG + kShshElement = 0x53485348, // SHSH + kCertElement = 0x43455254, // CERT + kChipElement = 0x43484950, // CHIP + kProdElement = 0x50524F44, // PROD + kSdomElement = 0x53444F4D, // SDOM + kVersElement = 0x56455253, // VERS + kBordElement = 0x424F5244, // BORD + kSepoElement = 0x5345504F, // SEPO + kEcidElement = 0x45434944 // ECID } img3_element_type; typedef struct { - unsigned int signature; - unsigned int full_size; - unsigned int data_size; - unsigned int shsh_offset; - unsigned int image_type; + unsigned int signature; + unsigned int full_size; + unsigned int data_size; + unsigned int shsh_offset; + unsigned int image_type; } img3_header; typedef struct { - unsigned int signature; - unsigned int full_size; - unsigned int data_size; + unsigned int signature; + unsigned int full_size; + unsigned int data_size; } img3_element_header; typedef struct { @@ -79,11 +79,11 @@ typedef struct { img3_element* cert_element; } img3_file; -void img3_free(img3_file* image); -img3_element* img3_parse_element(char* data); -void img3_free_element(img3_element* element); img3_file* img3_parse_file(char* data, int size); -int img3_get_data(img3_file* image, char** pdata, int* psize); +img3_element* img3_parse_element(char* data); int img3_replace_signature(img3_file* image, char* signature); +void img3_free(img3_file* image); +int img3_get_data(img3_file* image, char** pdata, int* psize); +void img3_free_element(img3_element* element); #endif @@ -20,7 +20,6 @@ */ #include <zip.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -95,10 +94,8 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi int i = 0; int size = 0; - int bytes = 0; int count = 0; - double progress = 0; - for(i = zstat.size; i > 0; i -= count) { + for (i = zstat.size; i > 0; i -= count) { if (i < BUFSIZE) size = i; else @@ -111,11 +108,9 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi return -1; } fwrite(buffer, 1, count, fd); - - bytes += size; - progress = ((double) bytes/ (double) zstat.size) * 100.0; - print_progress_bar("Extracting", progress); + debug("."); } + debug("\n"); fclose(fd); zip_fclose(zfile); @@ -124,7 +119,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi return 0; } -int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize) { +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize) { ipsw_archive* archive = ipsw_open(ipsw); if (archive == NULL || archive->zip == NULL) { error("ERROR: Invalid archive\n"); @@ -19,11 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_IPSW_H -#define IDEVICERESTORE_IPSW_H +#ifndef IPSW_H +#define IPSW_H #include <zip.h> -#include <stdint.h> typedef struct { int index; @@ -32,7 +31,7 @@ typedef struct { unsigned char* data; } ipsw_file; -int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize); +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize); void ipsw_free_file(ipsw_file* file); #endif diff --git a/src/normal.c b/src/normal.c index b9270d8..c7baefd 100644 --- a/src/normal.c +++ b/src/normal.c @@ -19,202 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <stdio.h> #include <stdint.h> -#include <libirecovery.h> -#include <libimobiledevice/lockdown.h> -#include <libimobiledevice/libimobiledevice.h> #include "normal.h" -#include "recovery.h" -#include "idevicerestore.h" -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) { - return -1; - } - - lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - idevice_free(device); - return -1; - } - - lockdown_error = lockdownd_query_type(lockdown, &type); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; - return 0; -} - -int normal_check_device(const char* uuid) { - int i = 0; - idevice_t device = NULL; - char* product_type = NULL; - plist_t product_type_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); - if (device_error != IDEVICE_E_SUCCESS) { - return -1; - } - - lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - idevice_free(device); - return -1; - } - - lockdown_error = lockdownd_get_value(lockdown, NULL, "ProductType", &product_type_node); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; - - if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) { - if (product_type_node) plist_free(product_type_node); - return -1; - } - plist_get_string_val(product_type_node, &product_type); - plist_free(product_type_node); - - for (i = 0; idevicerestore_devices[i].product != NULL; i++) { - if (!strcmp(product_type, idevicerestore_devices[i].product)) { - break; - } - } - - return idevicerestore_devices[i].device_id; -} - -int normal_enter_recovery(const char* uuid) { - idevice_t device = NULL; - irecv_client_t recovery = NULL; - lockdownd_client_t lockdown = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; - - device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to find device\n"); - return -1; - } - - lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to connect to lockdownd service\n"); - idevice_free(device); - return -1; - } - - lockdown_error = lockdownd_enter_recovery(lockdown); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to place device in recovery mode\n"); - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; - - if (recovery_open_with_timeout(&recovery) < 0) { - error("ERROR: Unable to enter recovery mode\n"); - return -1; - } - - recovery_error = irecv_send_command(recovery, "setenv auto-boot true"); - if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to reset auto-boot variable\n"); - irecv_close(recovery); - return -1; - } - - recovery_error = irecv_send_command(recovery, "saveenv"); - if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to save auto-boot variable\n"); - irecv_close(recovery); - return -1; - } - - idevicerestore_mode = MODE_RECOVERY; - irecv_close(recovery); - recovery = NULL; - return 0; -} - -int normal_get_cpid(const char* uuid, uint32_t* cpid) { - return 0; -} - -int normal_get_bdid(const char* uuid, uint32_t* bdid) { - return 0; -} - -int normal_get_ecid(const char* uuid, 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); - if (device_error != IDEVICE_E_SUCCESS) { - return -1; - } - - lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to connect to lockdownd\n"); - idevice_free(device); - return -1; - } - - lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to get UniqueChipID from lockdownd\n"); - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - - if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { - error("ERROR: Unable to get ECID\n"); - lockdownd_client_free(lockdown); - idevice_free(device); - return -1; - } - plist_get_uint_val(unique_chip_node, ecid); - plist_free(unique_chip_node); - - lockdownd_client_free(lockdown); - idevice_free(device); - lockdown = NULL; - device = NULL; +int normal_get_ecid(uint64_t* ecid) { return 0; } diff --git a/src/normal.h b/src/normal.h index cdc29ba..3e2868d 100644 --- a/src/normal.h +++ b/src/normal.h @@ -19,16 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_NORMAL_H -#define IDEVICERESTORE_NORMAL_H +#ifndef NORMAL_H +#define NORMAL_H #include <stdint.h> -int normal_check_mode(const char* uuid); -int normal_check_device(const char* uuid); -int normal_enter_recovery(const char* uuid); -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_ecid(uint64_t* ecid); #endif diff --git a/src/recovery.c b/src/recovery.c index 52f4802..4e2e7ad 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -23,356 +23,247 @@ #include <stdlib.h> #include <stdint.h> #include <libirecovery.h> -#include <libimobiledevice/restore.h> -#include <libimobiledevice/libimobiledevice.h> #include "tss.h" #include "img3.h" #include "recovery.h" #include "idevicerestore.h" -int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { - if (event->type == IRECV_PROGRESS) { - print_progress_bar(event->data, event->progress); - } - return 0; -} - -int recovery_check_mode() { - irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - - recovery_error = irecv_open(&recovery); - if (recovery_error != IRECV_E_SUCCESS) { - return -1; - } - - if (recovery->mode == kDfuMode) { - irecv_close(recovery); - return -1; - } - - irecv_close(recovery); - recovery = NULL; - return 0; -} - -int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { - idevice_t device = NULL; - restored_client_t restore = NULL; - - // upload data to make device boot restore mode - if (recovery_send_ibec(ipsw, tss) < 0) { - error("ERROR: Unable to send iBEC\n"); - return -1; - } - sleep(1); - - if (recovery_send_applelogo(ipsw, tss) < 0) { - error("ERROR: Unable to send AppleLogo\n"); - return -1; - } - - if (recovery_send_devicetree(ipsw, tss) < 0) { - error("ERROR: Unable to send DeviceTree\n"); - return -1; - } - - if (recovery_send_ramdisk(ipsw, tss) < 0) { - error("ERROR: Unable to send Ramdisk\n"); - return -1; - } - - // for some reason iboot requires a hard reset after ramdisk - // or things start getting wacky - printf("Please unplug your device, then plug it back in\n"); - printf("Hit any key to continue..."); - getchar(); - - if (recovery_send_kernelcache(ipsw, tss) < 0) { - error("ERROR: Unable to send KernelCache\n"); - return -1; - } - - info("Waiting for device to enter restore mode\n"); - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { - error("ERROR: Unable to connect to device in restore mode\n"); - return -1; - } - - restore_close(device, restore); - idevicerestore_mode = MODE_RESTORE; - return 0; -} - -int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) { +int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component) { int size = 0; char* data = NULL; char* path = NULL; char* blob = NULL; + img3_file* img3 = NULL; irecv_error_t error = 0; - if (tss_get_entry_path(tss, component, &path) < 0) { - error("ERROR: Unable to get component path\n"); - return -1; - } - - if (get_signed_component(ipsw, tss, path, &data, &size) < 0) { + if (get_signed_component_by_name(ipsw, tss, component, &data, &size) < 0) { error("ERROR: Unable to get signed component: %s\n", component); - free(path); return -1; } - free(path); info("Sending %s...\n", component); error = irecv_send_buffer(client, data, size); if (error != IRECV_E_SUCCESS) { - error("ERROR: Unable to send component: %s\n", component); + error("ERROR: Unable to send IMG3: %s\n", path); + img3_free(img3); free(data); + free(path); return -1; } - free(data); + + if (data) { + free(data); + data = NULL; + } return 0; } -int recovery_open_with_timeout(irecv_client_t* client) { +irecv_error_t recovery_open_with_timeout(irecv_client_t* client) { int i = 0; - int attempts = 10; - irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; - - for (i = 1; i <= attempts; i++) { - recovery_error = irecv_open(&recovery); - if (recovery_error == IRECV_E_SUCCESS) { - break; - } - - if (i >= attempts) { - error("ERROR: Unable to connect to device in recovery mode\n"); - return -1; + irecv_error_t error = 0; + for (i = 10; i > 0; i--) { + error = irecv_open(client); + if (error == IRECV_E_SUCCESS) { + return error; } sleep(2); - debug("Retrying connection...\n"); + info("Retrying connection...\n"); } - irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); - *client = recovery; - return 0; + error("ERROR: Unable to connect to recovery device.\n"); + return error; } -int recovery_send_ibec(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; - const char* component = "iBEC"; - irecv_error_t recovery_error = IRECV_E_SUCCESS; +int recovery_send_ibec(char* ipsw, plist_t tss) { + irecv_error_t error = 0; + irecv_client_t client = NULL; + char* component = "iBEC"; - if (recovery_open_with_timeout(&recovery) < 0) { + error = recovery_open_with_timeout(&client); + if (error != IRECV_E_SUCCESS) { return -1; } - recovery_error = irecv_send_command(recovery, "setenv auto-boot true"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "setenv auto-boot true"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to set auto-boot environmental variable\n"); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "saveenv"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "saveenv"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to save environmental variable\n"); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "iBEC") < 0) { + if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "go"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "go"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - irecv_close(recovery); - recovery = NULL; + if (client) { + irecv_close(client); + client = NULL; + } return 0; } -int recovery_send_applelogo(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; - const char* component = "applelogo"; - irecv_error_t recovery_error = IRECV_E_SUCCESS; +int recovery_send_applelogo(char* ipsw, plist_t tss) { + irecv_error_t error = 0; + irecv_client_t client = NULL; + char* component = "AppleLogo"; info("Sending %s...\n", component); - if (recovery_open_with_timeout(&recovery) < 0) { + + error = recovery_open_with_timeout(&client); + if (error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "AppleLogo") < 0) { + if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "setpicture 1"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "setpicture 1"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to set %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "bgcolor 0 0 0"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "bgcolor 0 0 0"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to display %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - irecv_close(recovery); - recovery = NULL; + if (client) { + irecv_close(client); + client = NULL; + } return 0; } -int recovery_send_devicetree(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; - const char* component = "devicetree"; - irecv_error_t recovery_error = IRECV_E_SUCCESS; +int recovery_send_devicetree(char* ipsw, plist_t tss) { + irecv_error_t error = 0; + irecv_client_t client = NULL; + char *component = "RestoreDeviceTree"; - if (recovery_open_with_timeout(&recovery) < 0) { + error = recovery_open_with_timeout(&client); + if (error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreDeviceTree") < 0) { + if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "devicetree"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "devicetree"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - irecv_close(recovery); - recovery = NULL; + if (client) { + irecv_close(client); + client = NULL; + } return 0; } -int recovery_send_ramdisk(const char* ipsw, plist_t tss) { - irecv_error_t recovery_error = IRECV_E_SUCCESS; - irecv_client_t recovery = NULL; - const char *component = "ramdisk"; +int recovery_send_ramdisk(char* ipsw, plist_t tss) { + irecv_error_t error = 0; + irecv_client_t client = NULL; + char *component = "RestoreRamDisk"; - recovery_error = recovery_open_with_timeout(&recovery); - if (recovery_error != IRECV_E_SUCCESS) { + error = recovery_open_with_timeout(&client); + if (error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreRamDisk") < 0) { + if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "ramdisk"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "ramdisk"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - irecv_close(recovery); - recovery = NULL; + if (client) { + irecv_close(client); + client = NULL; + } return 0; } -int recovery_send_kernelcache(const char* ipsw, plist_t tss) { - irecv_client_t recovery = NULL; - const char* component = "kernelcache"; - irecv_error_t recovery_error = IRECV_E_SUCCESS; +int recovery_send_kernelcache(char* ipsw, plist_t tss) { + irecv_error_t error = 0; + irecv_client_t client = NULL; + char *component = "RestoreKernelCache"; - if (recovery_open_with_timeout(&recovery) < 0) { + error = recovery_open_with_timeout(&client); + if (error != IRECV_E_SUCCESS) { return -1; } - if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreKernelCache") < 0) { + if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - recovery_error = irecv_send_command(recovery, "bootx"); - if (recovery_error != IRECV_E_SUCCESS) { + error = irecv_send_command(client, "bootx"); + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(recovery); + irecv_close(client); + client = NULL; return -1; } - irecv_close(recovery); - recovery = NULL; - return 0; -} - -int recovery_get_ecid(uint64_t* ecid) { - irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - - if (recovery_open_with_timeout(&recovery) < 0) { - return -1; - } - - recovery_error = irecv_get_ecid(recovery, ecid); - if (recovery_error != IRECV_E_SUCCESS) { - irecv_close(recovery); - return -1; - } - - irecv_close(recovery); - recovery = NULL; - return 0; -} - -int recovery_get_cpid(uint32_t* cpid) { - irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - - if (recovery_open_with_timeout(&recovery) < 0) { - return -1; - } - - recovery_error = irecv_get_cpid(recovery, cpid); - if (recovery_error != IRECV_E_SUCCESS) { - irecv_close(recovery); - return -1; + if (client) { + irecv_close(client); + client = NULL; } - - irecv_close(recovery); - recovery = NULL; return 0; } -int recovery_get_bdid(uint32_t* bdid) { - irecv_client_t recovery = NULL; - irecv_error_t recovery_error = IRECV_E_SUCCESS; - - if (recovery_open_with_timeout(&recovery) < 0) { - return -1; - } - - recovery_error = irecv_get_bdid(recovery, bdid); - if (recovery_error != IRECV_E_SUCCESS) { - irecv_close(recovery); - return -1; - } - irecv_close(recovery); - recovery = NULL; +int recovery_get_ecid(uint64_t* ecid) { return 0; } diff --git a/src/recovery.h b/src/recovery.h index 1953c6a..5495638 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -19,23 +19,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_RECOVERY_H -#define IDEVICERESTORE_RECOVERY_H +#ifndef RECOVERY_H +#define RECOVERY_H #include <stdint.h> #include <plist/plist.h> -int recovery_check_mode(); -int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss); -int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component); +int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component); irecv_error_t recovery_open_with_timeout(irecv_client_t* client); -int recovery_send_ibec(const char* ipsw, plist_t tss); -int recovery_send_applelogo(const char* ipsw, plist_t tss); -int recovery_send_devicetree(const char* ipsw, plist_t tss); -int recovery_send_ramdisk(const char* ipsw, plist_t tss); -int recovery_send_kernelcache(const char* ipsw, plist_t tss); +int recovery_send_ibec(char* ipsw, plist_t tss); +int recovery_send_applelogo(char* ipsw, plist_t tss); +int recovery_send_devicetree(char* ipsw, plist_t tss); +int recovery_send_ramdisk(char* ipsw, plist_t tss); +int recovery_send_kernelcache(char* ipsw, plist_t tss); int recovery_get_ecid(uint64_t* ecid); -int recovery_get_cpid(uint32_t* cpid); -int recovery_get_bdid(uint32_t* bdid); #endif diff --git a/src/restore.c b/src/restore.c index fc22b75..485df9b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -24,11 +24,11 @@ #include <string.h> #include <libimobiledevice/restore.h> -#include "asr.h" -#include "tss.h" #include "restore.h" #include "idevicerestore.h" +#define ASR_PORT 12345 + #define CREATE_PARTITION_MAP 12 #define CREATE_FILESYSTEM 13 #define RESTORE_IMAGE 14 @@ -44,194 +44,8 @@ #define WAIT_FOR_DEVICE 33 #define LOAD_NOR 36 -static int restore_device_connected = 0; - -int restore_check_mode(const char* uuid) { - char* type = NULL; - uint64_t version = 0; - idevice_t device = NULL; - restored_client_t restore = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - restored_error_t restore_error = RESTORE_E_SUCCESS; - - device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - return -1; - } - - restore_error = restored_client_new(device, &restore, "idevicerestore"); - if (restore_error != RESTORE_E_SUCCESS) { - idevice_free(device); - return -1; - } - - restore_error = restored_query_type(restore, &type, &version); - if (restore_error != RESTORE_E_SUCCESS) { - restored_client_free(restore); - idevice_free(device); - return -1; - } - - restored_client_free(restore); - idevice_free(device); - restore = NULL; - device = NULL; - return 0; -} - -int restore_check_device(const char* uuid) { - int i = 0; - char* type = NULL; - char* model = NULL; - plist_t node = NULL; - uint64_t version = 0; - idevice_t device = NULL; - restored_client_t restore = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - restored_error_t restore_error = RESTORE_E_SUCCESS; - - device_error = idevice_new(&device, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - return -1; - } - - restore_error = restored_client_new(device, &restore, "idevicerestore"); - if (restore_error != RESTORE_E_SUCCESS) { - idevice_free(device); - return -1; - } - - restore_error = restored_query_type(restore, &type, &version); - if (restore_error != RESTORE_E_SUCCESS) { - restored_client_free(restore); - idevice_free(device); - return -1; - } - - restore_error = restored_get_value(restore, "HardwareModel", &node); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to get HardwareModel from restored\n"); - restored_client_free(restore); - idevice_free(device); - return -1; - } - - restored_client_free(restore); - idevice_free(device); - restore = NULL; - device = NULL; - - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to get HardwareModel information\n"); - if (node) - plist_free(node); - return -1; - } - plist_get_string_val(node, &model); - - for (i = 0; idevicerestore_devices[i].model != NULL; i++) { - if (!strcasecmp(model, idevicerestore_devices[i].model)) { - break; - } - } - - return idevicerestore_devices[i].device_id; -} - -void restore_device_callback(const idevice_event_t* event, void* user_data) { - if (event->event == IDEVICE_DEVICE_ADD) { - restore_device_connected = 1; - - } else if (event->event == IDEVICE_DEVICE_REMOVE) { - restore_device_connected = 0; - } -} - -int restore_reboot(const char* uuid) { - idevice_t device = NULL; - restored_client_t restore = NULL; - restored_error_t restore_error = RESTORE_E_SUCCESS; - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { - error("ERROR: Unable to open device in restore mode\n"); - return -1; - } - - restore_error = restored_reboot(restore); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to reboot the device from restore mode\n"); - restore_close(device, restore); - return -1; - } - - restore_close(device, restore); - restore = NULL; - device = NULL; - return 0; -} - -int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) { - int i = 0; - int attempts = 10; - idevice_t context = NULL; - restored_client_t client = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - restored_error_t restore_error = RESTORE_E_SUCCESS; - - *device = NULL; - *restore = NULL; - - device_error = idevice_event_subscribe(&restore_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 (restore_device_connected == 1) { - break; - } - - if (i == attempts) { - error("ERROR: Unable to connect to device in restore mode\n"); - } - - sleep(2); - } - - device_error = idevice_new(&context, uuid); - if (device_error != IDEVICE_E_SUCCESS) { - return -1; - } - - restore_error = restored_client_new(context, &client, "idevicerestore"); - if (restore_error != RESTORE_E_SUCCESS) { - idevice_event_unsubscribe(); - idevice_free(context); - return -1; - } - - restore_error = restored_query_type(client, NULL, NULL); - if (restore_error != RESTORE_E_SUCCESS) { - restored_client_free(client); - idevice_event_unsubscribe(); - idevice_free(context); - return -1; - } - - *device = context; - *restore = client; - return 0; -} - -void restore_close(idevice_t device, restored_client_t restore) { - if (restore) - restored_client_free(restore); - if (device) - idevice_free(device); -} - const char* restore_progress_string(unsigned int operation) { - switch (operation) { + switch(operation) { case CREATE_PARTITION_MAP: return "Creating partition map"; @@ -279,88 +93,208 @@ const char* restore_progress_string(unsigned int operation) { } } + int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_t node = NULL; - uint64_t progress = 0; uint64_t operation = 0; + uint64_t uprogress = 0; + uint32_t progress = 0; node = plist_dict_get_item(msg, "Operation"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (node && PLIST_UINT == plist_get_node_type(node)) { + plist_get_uint_val(node, &operation); + } else { debug("Failed to parse operation from ProgressMsg plist\n"); - return -1; + return 0; } - plist_get_uint_val(node, &operation); node = plist_dict_get_item(msg, "Progress"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (node && PLIST_UINT == plist_get_node_type(node)) { + plist_get_uint_val(node, &uprogress); + progress = (uint32_t) uprogress; + } else { debug("Failed to parse progress from ProgressMsg plist \n"); - return -1; + return 0; } - plist_get_uint_val(node, &progress); - - if ((progress > 0) && (progress < 100)) { - print_progress_bar(restore_progress_string(operation), (double) progress); - } else { + if ((progress > 0) && (progress < 100)) + info("%s - Progress: %ul%%\n", restore_progress_string(operation), progress); + else info("%s\n", restore_progress_string(operation)); - } return 0; } int restore_handle_status_msg(restored_client_t client, plist_t msg) { info("Got status message\n"); - debug_plist(msg); return 0; } -int restore_send_filesystem(idevice_t device, const char* filesystem) { +int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem) { int i = 0; - FILE* file = NULL; - plist_t data = NULL; - idevice_connection_t asr = NULL; - idevice_error_t device_error = IDEVICE_E_UNKNOWN_ERROR; + char buffer[0x1000]; + uint32_t recv_bytes = 0; + memset(buffer, '\0', 0x1000); + idevice_connection_t connection = NULL; + idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; + + for (i = 0; i < 5; i++) { + ret = idevice_connect(device, ASR_PORT, &connection); + if (ret == IDEVICE_E_SUCCESS) + break; - if (asr_open_with_timeout(device, &asr) < 0) { - error("ERROR: Unable to connect to ASR\n"); - return -1; + else + sleep(1); } - info("Connected to ASR\n"); - // we don't really need to do anything with this, - // we're just clearing the output buffer - if (asr_receive(asr, &data) < 0) { - error("ERROR: Unable to receive data from ASR\n"); - asr_close(asr); - return -1; + if (ret != IDEVICE_E_SUCCESS) + return ret; + + memset(buffer, '\0', 0x1000); + ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); + if (ret != IDEVICE_E_SUCCESS) { + idevice_disconnect(connection); + return ret; } - plist_free(data); - - // this step sends requested chunks of data from various offsets to asr so - // it can validate the filesystem before installing it - debug("Preparing to validate the filesystem\n"); - if (asr_perform_validation(asr, filesystem) < 0) { - error("ERROR: ASR was unable to validate the filesystem\n"); - asr_close(asr); - return -1; + info("Received %d bytes\n", recv_bytes); + info("%s", buffer); + + FILE* fd = fopen(filesystem, "rb"); + if (fd == NULL) { + idevice_disconnect(connection); + return ret; } - info("Filesystem validated\n"); - - // once the target filesystem has been validated, ASR then requests the - // entire filesystem to be sent. - debug("Preparing to send filesystem\n"); - if (asr_send_payload(asr, filesystem) < 0) { - error("ERROR: Unable to send payload to ASR\n"); - asr_close(asr); - return -1; + + fseek(fd, 0, SEEK_END); + uint64_t len = ftell(fd); + fseek(fd, 0, SEEK_SET); + + info("Connected to ASR\n"); + plist_t dict = plist_new_dict(); + plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40)); + plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450)); + plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25)); + + plist_t payload = plist_new_dict(); + plist_dict_insert_item(payload, "Port", plist_new_uint(1)); + plist_dict_insert_item(payload, "Size", plist_new_uint(len)); + plist_dict_insert_item(dict, "Payload", payload); + + plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1)); + plist_dict_insert_item(dict, "Version", plist_new_uint(1)); + + char* xml = NULL; + unsigned int dict_size = 0; + unsigned int sent_bytes = 0; + plist_to_xml(dict, &xml, &dict_size); + + ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes); + if (ret != IDEVICE_E_SUCCESS) { + idevice_disconnect(connection); + return ret; } - info("Filesystem finished\n"); - asr_close(asr); - return 0; + info("Sent %d bytes\n", sent_bytes); + info("%s", xml); + plist_free(dict); + free(xml); + + char* command = NULL; + do { + memset(buffer, '\0', 0x1000); + ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); + if (ret != IDEVICE_E_SUCCESS) { + idevice_disconnect(connection); + return ret; + } + info("Received %d bytes\n", recv_bytes); + info("%s", buffer); + + plist_t request = NULL; + plist_from_xml(buffer, recv_bytes, &request); + plist_t command_node = plist_dict_get_item(request, "Command"); + if (command_node && PLIST_STRING == plist_get_node_type(command_node)) { + plist_get_string_val(command_node, &command); + if (!strcmp(command, "OOBData")) { + plist_t oob_length_node = plist_dict_get_item(request, "OOB Length"); + if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { + error("Error fetching OOB Length\n"); + idevice_disconnect(connection); + return IDEVICE_E_UNKNOWN_ERROR; + } + uint64_t oob_length = 0; + plist_get_uint_val(oob_length_node, &oob_length); + + plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset"); + if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { + error("Error fetching OOB Offset\n"); + idevice_disconnect(connection); + return IDEVICE_E_UNKNOWN_ERROR; + } + uint64_t oob_offset = 0; + plist_get_uint_val(oob_offset_node, &oob_offset); + + char* oob_data = (char*) malloc(oob_length); + if (oob_data == NULL) { + error("Out of memory\n"); + idevice_disconnect(connection); + return IDEVICE_E_UNKNOWN_ERROR; + } + + fseek(fd, oob_offset, SEEK_SET); + if (fread(oob_data, 1, oob_length, fd) != oob_length) { + error("Unable to read filesystem offset\n"); + idevice_disconnect(connection); + free(oob_data); + return ret; + } + + ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes); + if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) { + error("Unable to send %d bytes to asr\n", sent_bytes); + idevice_disconnect(connection); + free(oob_data); + return ret; + } + plist_free(request); + free(oob_data); + } + } + + } while (strcmp(command, "Payload")); + + fseek(fd, 0, SEEK_SET); + char data[1450]; + for (i = len; i > 0; i -= 1450) { + int size = 1450; + if (i < 1450) { + size = i; + } + + if (fread(data, 1, size, fd) != (unsigned int) size) { + fclose(fd); + idevice_disconnect(connection); + error("Error reading filesystem\n"); + return IDEVICE_E_UNKNOWN_ERROR; + } + + ret = idevice_connection_send(connection, data, size, &sent_bytes); + if (ret != IDEVICE_E_SUCCESS) { + fclose(fd); + } + + if (i % (1450 * 1000) == 0) { + info("."); + } + } + + info("Done sending filesystem\n"); + fclose(fd); + ret = idevice_disconnect(connection); + return ret; } -int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) { +int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len) { info("Sending kernelcache\n"); plist_t kernelcache_node = plist_new_data(kernel_data, len); @@ -380,17 +314,19 @@ int restore_send_kernelcache(restored_client_t client, char* kernel_data, int le return 0; } -int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { +int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss) { char* llb_path = NULL; - if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) { + char* llb_blob = NULL; + if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) { error("ERROR: Unable to get LLB info from TSS response\n"); return -1; } char* llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { - error("ERROR: Unable to extract firmware path from LLB filename\n"); + error("ERROR: Unable to extrac firmware path from LLB filename\n"); free(llb_path); + free(llb_blob); return -1; } @@ -409,6 +345,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { error("ERROR: Unable to extract firmware manifest from ipsw\n"); free(llb_path); + free(llb_blob); return -1; } @@ -422,7 +359,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { if (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + if (get_signed_component_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } @@ -437,7 +374,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { while (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + if (get_signed_component_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } @@ -450,7 +387,11 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { } plist_dict_insert_item(dict, "NorImageData", norimage_array); - debug_plist(dict); + int sz = 0; + char* xml = NULL; + plist_to_xml(dict, &xml, &sz); + debug("%s", xml); + free(xml); restored_error_t ret = restored_send(client, dict); if (ret != RESTORE_E_SUCCESS) { @@ -462,136 +403,3 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { plist_free(dict); return 0; } - -int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { - char* type = NULL; - plist_t node = NULL; - - // checks and see what kind of data restored is requests and pass - // the request to its own handler - node = plist_dict_get_item(message, "DataType"); - if (node && PLIST_STRING == plist_get_node_type(node)) { - plist_get_string_val(node, &type); - - // this request is sent when restored is ready to receive the filesystem - if (!strcmp(type, "SystemImageData")) { - restore_send_filesystem(device, filesystem); - - } - - else if (!strcmp(type, "KernelCache")) { - int kernelcache_size = 0; - char* kernelcache_data = NULL; - char* kernelcache_path = NULL; - if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { - error("ERROR: Unable to find kernelcache path\n"); - return -1; - } - - if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { - error("ERROR: Unable to get kernelcache file\n"); - return -1; - } - restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); - free(kernelcache_data); - - } - - else if (!strcmp(type, "NORData")) { - restore_send_nor(restore, ipsw, tss); - - } else { - // Unknown DataType!! - debug("Unknown data request received\n"); - } - } - return 0; -} - -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { - int error = 0; - char* type = NULL; - char* kernel = NULL; - plist_t node = NULL; - plist_t message = NULL; - idevice_t device = NULL; - restored_client_t restore = NULL; - idevice_error_t device_error = IDEVICE_E_SUCCESS; - restored_error_t restore_error = RESTORE_E_SUCCESS; - - // open our connection to the device and verify we're in restore mode - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { - error("ERROR: Unable to open device in restore mode\n"); - return -1; - } - info("Device has successfully entered restore mode\n"); - - // start the restore process - restore_error = restored_start_restore(restore); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to start the restore process\n"); - restore_close(device, restore); - return -1; - } - - // this is the restore process loop, it reads each message in from - // restored and passes that data on to it's specific handler - while (!idevicerestore_quit) { - restore_error = restored_receive(restore, &message); - if (restore_error != RESTORE_E_SUCCESS) { - debug("No data to read\n"); - message = NULL; - continue; - } - - // discover what kind of message has been received - node = plist_dict_get_item(message, "MsgType"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Unknown message received\n"); - debug_plist(message); - plist_free(message); - message = NULL; - continue; - } - plist_get_string_val(node, &type); - - // data request messages are sent by restored whenever it requires - // files sent to the server by the client. these data requests include - // SystemImageData, KernelCache, and NORData requests - if (!strcmp(type, "DataRequestMsg")) { - error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem); - } - - // progress notification messages sent by the restored inform the client - // of it's current operation and sometimes percent of progress is complete - else if (!strcmp(type, "ProgressMsg")) { - error = restore_handle_progress_msg(restore, message); - } - - // status messages usually indicate the current state of the restored - // process or often to signal an error has been encountered - else if (!strcmp(type, "StatusMsg")) { - error = restore_handle_status_msg(restore, message); - } - - // there might be some other message types i'm not aware of, but I think - // at least the "previous error logs" messages usually end up here - else { - debug("Unknown message type received\n"); - debug_plist(message); - } - - // finally, if any of these message handlers returned -1 then we encountered - // an unrecoverable error, so we need to bail. - if (error < 0) { - error("ERROR: Unable to successfully restore device\n"); - idevicerestore_quit = 1; - } - - plist_free(message); - message = NULL; - } - - restore_close(device, restore); - return 0; -} diff --git a/src/restore.h b/src/restore.h index cf9cf51..644658a 100644 --- a/src/restore.h +++ b/src/restore.h @@ -19,24 +19,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_RESTORE_H -#define IDEVICERESTORE_RESTORE_H +#ifndef RESTORED_H +#define RESTORED_H -#include <plist/plist.h> #include <libimobiledevice/restore.h> -#include <libimobiledevice/libimobiledevice.h> -int restore_reboot(const char* uuid); -int restore_check_mode(const char* uuid); -int restore_check_device(const char* uuid); -const char* restore_progress_string(unsigned int operation); -void restore_close(idevice_t device, restored_client_t restore); -int restore_handle_status_msg(restored_client_t client, plist_t msg); +#include "restore.h" + int restore_handle_progress_msg(restored_client_t client, plist_t msg); -int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss); +int restore_handle_status_msg(restored_client_t client, plist_t msg); +int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem); int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len); -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); -int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client); -int restore_send_filesystem(idevice_t device, const char* filesystem); +int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss); +const char* restore_progress_string(unsigned int operation); #endif @@ -36,10 +36,23 @@ typedef struct { char* content; } tss_response; -plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { +plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { + // Fetch build information from BuildManifest + plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); + if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { + error("ERROR: Unable to find BuildIdentities array\n"); + return NULL; + } + + plist_t restore_identity_dict = plist_array_get_item(build_identities_array, 0); + if (!restore_identity_dict || plist_get_node_type(restore_identity_dict) != PLIST_DICT) { + error("ERROR: Unable to find restore identity\n"); + return NULL; + } + uint64_t unique_build_size = 0; char* unique_build_data = NULL; - plist_t unique_build_node = plist_dict_get_item(build_identity, "UniqueBuildID"); + plist_t unique_build_node = plist_dict_get_item(restore_identity_dict, "UniqueBuildID"); if (!unique_build_node || plist_get_node_type(unique_build_node) != PLIST_DATA) { error("ERROR: Unable to find UniqueBuildID node\n"); return NULL; @@ -48,7 +61,7 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { int chip_id = 0; char* chip_id_string = NULL; - plist_t chip_id_node = plist_dict_get_item(build_identity, "ApChipID"); + plist_t chip_id_node = plist_dict_get_item(restore_identity_dict, "ApChipID"); if (!chip_id_node || plist_get_node_type(chip_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApChipID node\n"); return NULL; @@ -58,7 +71,7 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { int board_id = 0; char* board_id_string = NULL; - plist_t board_id_node = plist_dict_get_item(build_identity, "ApBoardID"); + plist_t board_id_node = plist_dict_get_item(restore_identity_dict, "ApBoardID"); if (!board_id_node || plist_get_node_type(board_id_node) != PLIST_STRING) { error("ERROR: Unable to find ApBoardID node\n"); return NULL; @@ -68,7 +81,7 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { int security_domain = 0; char* security_domain_string = NULL; - plist_t security_domain_node = plist_dict_get_item(build_identity, "ApSecurityDomain"); + plist_t security_domain_node = plist_dict_get_item(restore_identity_dict, "ApSecurityDomain"); if (!security_domain_node || plist_get_node_type(security_domain_node) != PLIST_STRING) { error("ERROR: Unable to find ApSecurityDomain node\n"); return NULL; @@ -99,7 +112,7 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { free(unique_build_data); // Add all firmware files to TSS request - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); + plist_t manifest_node = plist_dict_get_item(restore_identity_dict, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { error("ERROR: Unable to find restore manifest\n"); plist_free(tss_request); @@ -124,14 +137,13 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) { plist_dict_insert_item(tss_request, key, tss_entry); free(key); } + plist_free(manifest_node); - if (idevicerestore_debug) { - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_request, &xml, &sz); - debug("%s", xml); - free(xml); - } + int sz = 0; + char* xml = NULL; + plist_to_xml(tss_request, &xml, &sz); + debug("%s", xml); + free(xml); return tss_request; } @@ -186,6 +198,7 @@ plist_t tss_send_request(plist_t tss_request) { curl_global_cleanup(); if (strstr(response->content, "MESSAGE=SUCCESS") == NULL) { + error("ERROR: Unable to get signature from this firmware\n"); free(response->content); free(response); return NULL; @@ -206,115 +219,15 @@ plist_t tss_send_request(plist_t tss_request) { free(response->content); free(response); - if (idevicerestore_debug) { - int sz = 0; - char* xml = NULL; - plist_to_xml(tss_response, &xml, &sz); - debug("%s", xml); - free(xml); - } + int sz = 0; + char* xml = NULL; + plist_to_xml(tss_response, &xml, &sz); + debug("%s", xml); + free(xml); return tss_response; } -int tss_get_entry_path(plist_t tss, const char* entry, char** path) { - char* path_string = NULL; - plist_t path_node = NULL; - plist_t entry_node = NULL; - - *path = NULL; - - entry_node = plist_dict_get_item(tss, entry); - if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) { - error("ERROR: Unable to find %s entry in TSS response\n", entry); - return -1; - } - - path_node = plist_dict_get_item(entry_node, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - error("ERROR: Unable to find %s path in entry\n", path_string); - return -1; - } - plist_get_string_val(path_node, &path_string); - - *path = path_string; - return 0; -} - -int tss_get_blob_by_path(plist_t tss, const char* path, char** blob) { - int i = 0; - uint32_t tss_size = 0; - uint64_t blob_size = 0; - char* entry_key = NULL; - char* blob_data = NULL; - char* entry_path = NULL; - plist_t tss_entry = NULL; - plist_t blob_node = NULL; - plist_t path_node = NULL; - plist_dict_iter iter = NULL; - - *blob = NULL; - - plist_dict_new_iter(tss, &iter); - tss_size = plist_dict_get_size(tss); - for (i = 0; i < tss_size; i++) { - plist_dict_next_item(tss, iter, &entry_key, &tss_entry); - if (entry_key == NULL) - break; - - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - continue; - } - - path_node = plist_dict_get_item(tss_entry, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - error("ERROR: Unable to find TSS path node in entry %s\n", entry_key); - return -1; - } - - plist_get_string_val(path_node, &entry_path); - if (strcmp(path, entry_path) == 0) { - blob_node = plist_dict_get_item(tss_entry, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key); - return -1; - } - plist_get_data_val(blob_node, &blob_data, &blob_size); - break; - } - - free(entry_key); - } - - if (blob_data == NULL || blob_size <= 0) { - return -1; - } - - *blob = blob_data; - return 0; -} - -int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob) { - uint64_t blob_size = 0; - char* blob_data = NULL; - plist_t blob_node = NULL; - plist_t tss_entry = NULL; - - *blob = NULL; - - tss_entry = plist_dict_get_item(tss, entry); - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - error("ERROR: Unable to find %s entry in TSS response\n", entry); - return -1; - } - - blob_node = plist_dict_get_item(tss_entry, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find blob in %s entry\n", entry); - return -1; - } - plist_get_data_val(blob_node, &blob_data, &blob_size); +void tss_stitch_img3(img3_file* file, plist_t signature) { - *blob = blob_data; - return 0; } @@ -19,15 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IDEVICERESTORE_TSS_H -#define IDEVICERESTORE_TSS_H +#ifndef TSS_H +#define TSS_H #include <plist/plist.h> -plist_t tss_send_request(plist_t request); -plist_t tss_create_request(plist_t build_identity, uint64_t ecid); -int tss_get_entry_path(plist_t tss, const char* entry, char** path); -int tss_get_blob_by_path(plist_t tss, const char* path, char** blob); -int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob); +#include "img3.h" + +plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid); +plist_t tss_send_request(plist_t tss_request); +void tss_stitch_img3(img3_file* file, plist_t signature); #endif |