From 87de88ccc570b98040a356a411ed6a47f58a4d72 Mon Sep 17 00:00:00 2001 From: Joshua Hill Date: Wed, 26 May 2010 17:12:20 -0400 Subject: Implemented NOR data request, it's ugly but it works! Successfully restored 4.0b4 to my device --- src/idevicerestore.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++---- src/ipsw.c | 10 +- src/tss.c | 25 ++--- 3 files changed, 253 insertions(+), 36 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index a5ada17..5f83816 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -51,9 +51,11 @@ int irecv_send_applelogo(char* ipsw, plist_t tss); int irecv_send_devicetree(char* ipsw, plist_t tss); int irecv_send_ramdisk(char* ipsw, plist_t tss); int irecv_send_kernelcache(char* ipsw, plist_t tss); -int get_tss_data(plist_t tss, const char* entry, char** path, char** blob); +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(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); +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; @@ -290,6 +292,8 @@ int main(int argc, char* argv[]) { 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(); @@ -302,8 +306,9 @@ int main(int argc, char* argv[]) { 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(2); + sleep(1); } device_error = idevice_new(&device, uuid); @@ -350,7 +355,7 @@ int main(int argc, char* argv[]) { restore_error = restored_handle_progress_msg(restore, message); } else if (!strcmp(msgtype, "DataRequestMsg")) { - //restore_error = restored_handle_data_request_msg(device, restore, message, filesystem); + // 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; @@ -361,7 +366,7 @@ int main(int argc, char* argv[]) { } else if (!strcmp(datatype, "KernelCache")) { int kernelcache_size = 0; char* kernelcache_data = NULL; - if(get_signed_component(ipsw, tss_response, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { + 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; } @@ -369,7 +374,7 @@ int main(int argc, char* argv[]) { free(kernelcache_data); } else if (!strcmp(datatype, "NORData")) { - send_nor_data(device, restore); + send_nor_data(restore, ipsw, tss_response); } else { // Unknown DataType!! @@ -388,6 +393,7 @@ int main(int argc, char* argv[]) { if (RESTORE_E_SUCCESS != restore_error) { error("Invalid return status %d\n", restore_error); + quit_flag = 1; } plist_free(message); @@ -635,8 +641,93 @@ int restored_send_kernelcache(restored_client_t client, char *kernel_data, int l return 0; } -int send_nor_data(idevice_t device, restored_client_t client) { - info("Not implemented\n"); +int send_nor_data(restored_client_t client, char* ipsw, plist_t tss) { + char* llb_path = NULL; + 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 extrac firmware path from LLB filename\n"); + free(llb_path); + free(llb_blob); + return -1; + } + + char firmware_path[256]; + memset(firmware_path, '\0', sizeof(firmware_path)); + memcpy(firmware_path, llb_path, (llb_filename-1) - llb_path); + info("Found firmware path %s\n", firmware_path); + + char manifest_file[256]; + memset(manifest_file, '\0', sizeof(manifest_file)); + snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); + info("Getting firmware manifest %s\n", manifest_file); + + int manifest_size = 0; + char* manifest_data = NULL; + 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; + } + + char firmware_filename[256]; + memset(firmware_filename, '\0', sizeof(firmware_filename)); + + int llb_size = 0; + char* llb_data = NULL; + plist_t dict = plist_new_dict(); + char* filename = strtok(manifest_data, "\n"); + 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_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + error("ERROR: Unable to get signed LLB\n"); + return -1; + } + + plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t)llb_size)); + } + + int nor_size = 0; + char* nor_data = NULL; + filename = strtok(NULL, "\n"); + plist_t norimage_array = plist_new_array(); + 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_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + error("ERROR: Unable to get signed firmware %s\n", firmware_filename); + break; + } + + plist_array_append_item(norimage_array, plist_new_data(nor_data, (uint64_t)nor_size)); + free(nor_data); + nor_data = NULL; + nor_size = 0; + filename = strtok(NULL, "\n"); + } + plist_dict_insert_item(dict, "NorImageData", norimage_array); + + 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) { + error("ERROR: Unable to send kernelcache data\n"); + plist_free(dict); + return -1; + } + + plist_free(dict); return 0; } @@ -659,7 +750,53 @@ int write_file(const char* filename, char* data, int size) { return size; } -int get_tss_data(plist_t tss, const char* entry, char** ppath, char** pblob) { +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; + } + + 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); + free(path); + return -1; + } + plist_get_data_val(blob_node, &blob, &blob_size); + *pname = key; + *pblob = blob; + return 0; + } + + free(key); + } + plist_free(tss_entry); + + return -1; +} + +int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) { *ppath = NULL; *pblob = NULL; @@ -672,7 +809,7 @@ int get_tss_data(plist_t tss, const char* entry, char** ppath, char** pblob) { 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", entry); + error("ERROR: Unable to find %s path in entry\n", path); return -1; } plist_get_string_val(path_node, &path); @@ -681,7 +818,7 @@ int get_tss_data(plist_t tss, const char* entry, char** ppath, char** pblob) { 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", entry); + error("ERROR: Unable to find %s blob in entry\n", path); free(path); return -1; } @@ -692,7 +829,7 @@ int get_tss_data(plist_t tss, const char* entry, char** ppath, char** pblob) { return 0; } -int get_signed_component(char* ipsw, plist_t tss, char* component, char** pdata, int* psize) { +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; @@ -701,7 +838,7 @@ int get_signed_component(char* ipsw, plist_t tss, char* component, char** pdata, irecv_error_t error = 0; info("Extracting %s from TSS response\n", component); - if (get_tss_data(tss, component, &path, &blob) < 0) { + 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; } @@ -741,6 +878,16 @@ int get_signed_component(char* ipsw, plist_t tss, char* component, char** pdata, return -1; } + if (idevicerestore_debug) { + char* out = strrchr(path, '/'); + if (out != NULL) { + out++; + } else { + out = path; + } + write_file(out, data, size); + } + if (img3) { img3_free(img3); img3 = NULL; @@ -759,19 +906,55 @@ int get_signed_component(char* ipsw, plist_t tss, char* component, char** pdata, return 0; } -static int irecv_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component) { +int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize) { int size = 0; char* data = NULL; - char* path = NULL; + char* name = NULL; char* blob = NULL; img3_file* img3 = NULL; irecv_error_t error = 0; - if (get_signed_component(ipsw, tss, component, &data, &size) < 0) { - error("ERROR: Unable to get signed component: %s\n", component); + 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; } -/* + + 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; + } + + 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 (img3_replace_signature(img3, blob) < 0) { + error("ERROR: Unable to replace IMG3 signature\n"); + free(name); + free(blob); + return -1; + } + + if (img3_get_data(img3, &data, &size) < 0) { + error("ERROR: Unable to reconstruct IMG3\n"); + img3_free(img3); + free(name); + return -1; + } + if (idevicerestore_debug) { char* out = strrchr(path, '/'); if (out != NULL) { @@ -781,7 +964,38 @@ static int irecv_send_signed_component(irecv_client_t client, char* ipsw, plist_ } write_file(out, data, size); } -*/ + + if (img3) { + img3_free(img3); + img3 = NULL; + } + if (blob) { + free(blob); + blob = NULL; + } + if (path) { + free(name); + name = NULL; + } + + *pdata = data; + *psize = size; + return 0; +} + +static int irecv_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 (get_signed_component_by_name(ipsw, tss, component, &data, &size) < 0) { + error("ERROR: Unable to get signed component: %s\n", component); + return -1; + } + info("Sending %s...\n", component); error = irecv_send_buffer(client, data, size); if (error != IRECV_E_SUCCESS) { @@ -885,7 +1099,7 @@ int irecv_send_applelogo(char* ipsw, plist_t tss) { } error = irecv_send_command(client, "setpicture 1"); - if(error != IRECV_E_SUCCESS) { + if (error != IRECV_E_SUCCESS) { error("ERROR: Unable to set %s\n", component); irecv_close(client); client = NULL; diff --git a/src/ipsw.c b/src/ipsw.c index f602d16..ca28596 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -74,7 +74,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi } char* buffer = (char*) malloc(BUFSIZE); - if(buffer == NULL) { + if (buffer == NULL) { error("ERROR: Unable to allocate memory\n"); return -1; } @@ -86,7 +86,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi } FILE* fd = fopen(outfile, "wb"); - if(fd == NULL) { + if (fd == NULL) { error("ERROR: Unable to open output file: %s\n", outfile); zip_fclose(zfile); return -1; @@ -96,8 +96,10 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi int size = 0; int count = 0; for (i = zstat.size; i > 0; i -= count) { - if(i < BUFSIZE) size = i; - else size = BUFSIZE; + if (i < BUFSIZE) + size = i; + else + size = BUFSIZE; count = zip_fread(zfile, buffer, size); if (count < 0) { error("ERROR: zip_fread: %s\n", infile); diff --git a/src/tss.c b/src/tss.c index 81b0658..4fc8b57 100644 --- a/src/tss.c +++ b/src/tss.c @@ -125,7 +125,8 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { plist_dict_new_iter(manifest_node, &iter); while (1) { plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) break; + if (key == NULL) + break; if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { error("ERROR: Unable to fetch BuildManifest entry\n"); free(tss_request); @@ -148,15 +149,15 @@ plist_t tss_create_request(plist_t buildmanifest, uint64_t ecid) { } size_t tss_write_callback(char* data, size_t size, size_t nmemb, tss_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; - } - - return total; + 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; + } + + return total; } plist_t tss_send_request(plist_t tss_request) { @@ -196,7 +197,7 @@ plist_t tss_send_request(plist_t tss_request) { } curl_global_cleanup(); - if(strstr(response->content, "MESSAGE=SUCCESS") == NULL) { + if (strstr(response->content, "MESSAGE=SUCCESS") == NULL) { error("ERROR: Unable to get signature from this firmware\n"); free(response->content); free(response); @@ -204,7 +205,7 @@ plist_t tss_send_request(plist_t tss_request) { } char* tss_data = strstr(response->content, "content); free(response); -- cgit v1.1-32-gdbae