From 65f170986d03fb536e48967cf3ffc5fb91f57a2d Mon Sep 17 00:00:00 2001 From: Munehisa Kamata Date: Sun, 17 Jul 2022 13:33:33 -0700 Subject: [PATCH 001/159] restore: use an appropriate ticket for Cryptex1 global manifest macOS 13 introduced a new global manifest for Cryptex1 and it requires tickets found in Firmware/Manifests/restore/cryptex1/macOS Customer/ inside an IPSW, but we currently do not use the tickets and end up unexpected behavior on a Mac device after restoring, e.g. bputil fails to downgrade security mode due to "Cryptex1 manifest verification failed". This adds a proper handling to use the appropriate tickets. Signed-off-by: Munehisa Kamata --- src/restore.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/restore.c b/src/restore.c index d51de03c..1a15959b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3293,7 +3293,7 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, unsigned char** pbuffer, unsigned int* psize) +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { @@ -3310,10 +3310,15 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil plist_get_string_val(device_class_node, &device_class); char *macos_variant = NULL; - int ret = extract_macos_variant(build_identity, &macos_variant); - if (ret != 0) { - free(device_class); - return -1; + int ret; + if (variant) { + macos_variant = variant; + } else { + ret = extract_macos_variant(build_identity, &macos_variant); + if (ret != 0) { + free(device_class); + return -1; + } } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. @@ -3362,7 +3367,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i info("About to send %s...\n", component_name); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); + int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); if (ret != 0) { return -1; } @@ -3488,7 +3493,19 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice info("About to send %s...\n", component_name); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); + char *variant = NULL; + plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + if (!node || plist_get_node_type(node) != PLIST_STRING) { + debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + return -1; + } + plist_get_string_val(node, &variant); + if (!variant) { + debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + return -1; + } + + int ret = extract_global_manifest(client, build_identity, variant, &data, &size); if (ret != 0) { return -1; } From d0921e4b468500874773561a341cd662e3fb73fa Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 29 Aug 2022 03:52:54 +0200 Subject: [PATCH 002/159] restore: Add support for Cryptex1LocalPolicy firmware updater --- src/restore.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/restore.c b/src/restore.c index 1a15959b..30fccbe4 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2860,10 +2860,22 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_t request = NULL; plist_t response = NULL; - /* create Timer request */ + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t device_generated_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = "Cryptex1,Ticket"; + if (PLIST_IS_ARRAY(device_generated_tags)) { + plist_t tag0 = plist_array_get_item(device_generated_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + + /* create Cryptex1 request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Cryptex1 TSS request\n"); + error("ERROR: Unable to create %s TSS request\n", s_updater_name); return NULL; } @@ -2875,7 +2887,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - /* add Timer,* tags from info dictionary to parameters */ + /* add tags from info dictionary to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); @@ -2894,18 +2906,19 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_free(parameters); - info("Sending Cryptex1 TSS request...\n"); + info("Sending %s TSS request...\n", s_updater_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Cryptex1\n"); + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); return NULL; } - if (plist_dict_get_item(response, "Cryptex1,Ticket")) { - info("Received Cryptex1,Ticket\n"); + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); } else { - error("ERROR: No 'Cryptex1,Ticket' in TSS response, this might not work\n"); + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); } return response; @@ -3034,10 +3047,10 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } - } else if (strcmp(s_updater_name, "Cryptex1") == 0) { + } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { From d97f560eb1dad839f68a2b8c970ce62432893954 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 16 Sep 2022 15:57:32 +0200 Subject: [PATCH 003/159] Fix Cryptex1 and Cryptex1LocalPolicy TSS request handling --- src/restore.c | 50 +++++++++++++++++++++++++++++++++++--------------- src/tss.c | 38 ++++++++++++++++++++++++++++++++++++++ src/tss.h | 1 + 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/restore.c b/src/restore.c index 30fccbe4..17c9b24d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2863,10 +2863,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); - plist_t device_generated_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); const char* response_ticket = "Cryptex1,Ticket"; - if (PLIST_IS_ARRAY(device_generated_tags)) { - plist_t tag0 = plist_array_get_item(device_generated_tags, 0); + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); if (tag0) { response_ticket = plist_get_string_ptr(tag0, NULL); } @@ -2881,28 +2881,48 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); - /* add manifest for current build_identity to parameters (Cryptex1 will require the manifest in a seperate message) */ - tss_parameters_add_from_manifest(parameters, build_identity, false); + /* merge data from MessageArgInfo */ + plist_dict_merge(¶meters, p_info); - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + /* add tags from manifest to parameters */ + plist_t build_identity_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "BuildIdentityTags"); + if (PLIST_IS_ARRAY(build_identity_tags)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { + plist_t node = plist_array_get_item(build_identity_tags, i); + const char* key = plist_get_string_ptr(node, NULL); + plist_t item = plist_dict_get_item(build_identity, key); + if (item) { + plist_dict_set_item(parameters, key, plist_copy(item)); + } + } + } - /* add tags from info dictionary to parameters */ + /* make sure we always have these required tags defined */ + if (!plist_dict_get_item(parameters, "ApProductionMode")) { + plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApSecurityMode")) { + plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApChipID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + } + if (!plist_dict_get_item(parameters, "ApBoardID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + } + + /* add device generated request data to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(parameters); return NULL; } - plist_dict_merge(¶meters, device_generated_request); - /* add common tags */ - tss_request_add_common_tags(request, p_info, NULL); - - /* add Cryptex1 tags */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_merge(&request, parameters); + /* add Cryptex1 tags to request */ + tss_request_add_cryptex_tags(request, parameters, NULL); plist_free(parameters); diff --git a/src/tss.c b/src/tss.c index b6980a73..e916790f 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1381,6 +1381,44 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over return 0; } +int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides) +{ + tss_request_add_common_tags(request, parameters, NULL); + + if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { + /* Cryptex1LocalPolicy */ + tss_request_add_local_policy_tags(request, parameters); + _plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); + } else { + /* Cryptex1 */ + plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); + + _plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); + _plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); + + plist_dict_iter iter = NULL; + plist_dict_new_iter(parameters, &iter); + plist_t value = NULL; + while (1) { + char *key = NULL; + plist_dict_next_item(parameters, iter, &key, &value); + if (key == NULL) + break; + if (strncmp(key, "Cryptex1", 8) == 0) { + plist_dict_set_item(request, key, plist_copy(value)); + } + free(key); + } + } + + /* apply overrides */ + if (overrides) { + plist_dict_merge(&request, overrides); + } + + return 0; +} + static size_t tss_write_callback(char* data, size_t size, size_t nmemb, tss_response* response) { size_t total = size * nmemb; diff --git a/src/tss.h b/src/tss.h index 719be818..8af2fcca 100644 --- a/src/tss.h +++ b/src/tss.h @@ -50,6 +50,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides); +int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters); int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters); From 403d2956bee60c321669421edbde29c97c238928 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 16 Sep 2022 16:00:20 +0200 Subject: [PATCH 004/159] tss: Don't add @BBTicket in tss_request_new() --- src/idevicerestore.c | 2 +- src/tss.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 23c48d5f..641eddb4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2269,7 +2269,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie tss_parameters_add_from_manifest(parameters, build_identity, true); /* create basic request */ - /* Adds @BBTicket, @HostPlatformInfo, @VersionInfo, @UUID */ + /* Adds @HostPlatformInfo, @VersionInfo, @UUID */ request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create TSS request\n"); diff --git a/src/tss.c b/src/tss.c index e916790f..c85758e0 100644 --- a/src/tss.c +++ b/src/tss.c @@ -65,7 +65,6 @@ plist_t tss_request_new(plist_t overrides) { plist_t request = plist_new_dict(); - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@HostPlatformInfo", #ifdef WIN32 plist_new_string("windows") From e9c800732b9a2be95f74b136ad6d2903d3bee56d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 20 Sep 2022 16:30:27 +0200 Subject: [PATCH 005/159] ipsw: Add some NULL checks to ipsw_extract_to_file_with_progress() --- src/ipsw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ipsw.c b/src/ipsw.c index 639ecf58..d4ee5e52 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -393,7 +393,14 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress) { int ret = 0; - ipsw_archive* archive = ipsw_open(ipsw); + ipsw_archive* archive = NULL; + + if (!ipsw || !infile || !outfile) { + error("ERROR: Invalid argument\n"); + return -1; + } + + archive = ipsw_open(ipsw); if (archive == NULL) { error("ERROR: Invalid archive\n"); return -1; @@ -468,6 +475,10 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con char *filepath = build_path(archive->path, infile); char actual_filepath[PATH_MAX+1]; char actual_outfile[PATH_MAX+1]; + if (!filepath) { + ret = -1; + goto leave; + } if (!realpath(filepath, actual_filepath)) { error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno)); ret = -1; From 6672bad275ed84a1c14e49cf24613261fe22098b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 21 Sep 2022 09:28:29 +0200 Subject: [PATCH 006/159] tss: Add NeRDEpoch to TSS requests for newer devices (iPhone 13 and up) --- src/tss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tss.c b/src/tss.c index c85758e0..d8f97891 100644 --- a/src/tss.c +++ b/src/tss.c @@ -216,6 +216,7 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); + _plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); _plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); @@ -289,6 +290,7 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) } _plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); + _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); return 0; From 96f68e6d8826a696747fb2a403a8e39297fff1b9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 21 Sep 2022 09:55:41 +0200 Subject: [PATCH 007/159] img4: Add some more component tags --- src/img4.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/img4.c b/src/img4.c index 609e80be..6cff3497 100644 --- a/src/img4.c +++ b/src/img4.c @@ -275,28 +275,37 @@ static const char *_img4_get_component_tag(const char *compname) { "ACIBT", "acib" }, { "ACIBTLPEM", "lpbt" }, { "ACIWIFI", "aciw" }, - { "Alamo", "almo" }, { "ANE", "anef" }, { "ANS", "ansf" }, { "AOP", "aopf" }, + { "AVE", "avef" }, + { "Alamo", "almo" }, + { "Ap,ANE1", "ane1" }, + { "Ap,ANE2", "ane2" }, + { "Ap,ANE3", "ane3" }, { "Ap,AudioAccessibilityBootChime", "auac" }, { "Ap,AudioBootChime", "aubt" }, { "Ap,AudioPowerAttachChime", "aupr" }, + { "Ap,BootabilityBrainTrustCache", "trbb" }, { "Ap,CIO", "ciof" }, { "Ap,HapticAssets", "hpas" }, { "Ap,LocalBoot", "lobo" }, { "Ap,LocalPolicy", "lpol" }, { "Ap,NextStageIM4MHash", "nsih" }, { "Ap,RecoveryOSPolicyNonceHash", "ronh" }, + { "Ap,RestoreANE1", "ran1" }, + { "Ap,RestoreANE2", "ran2" }, + { "Ap,RestoreANE3", "ran3" }, { "Ap,RestoreCIO", "rcio" }, { "Ap,RestoreTMU", "rtmu" }, { "Ap,Scorpius", "scpf" }, { "Ap,SystemVolumeCanonicalMetadata", "msys" }, { "Ap,TMU", "tmuf" }, { "Ap,VolumeUUID", "vuid" }, + { "Ap,rOSLogo1", "rlg1" }, + { "Ap,rOSLogo2", "rlg2" }, { "AppleLogo", "logo" }, { "AudioCodecFirmware", "acfw" }, - { "AVE", "avef" }, { "BatteryCharging", "glyC" }, { "BatteryCharging0", "chg0" }, { "BatteryCharging1", "chg1" }, @@ -305,28 +314,22 @@ static const char *_img4_get_component_tag(const char *compname) { "BatteryLow1", "bat1" }, { "BatteryPlugin", "glyP" }, { "CFELoader", "cfel" }, - { "Dali", "dali" }, + { "CrownFirmware", "crwn" }, { "DCP", "dcpf" }, + { "Dali", "dali" }, { "DeviceTree", "dtre" }, { "Diags", "diag" }, { "EngineeringTrustCache", "dtrs" }, { "ExtDCP", "edcp" }, - { "ftap", "ftap" }, - { "ftsp", "ftsp" }, { "GFX", "gfxf" }, { "Hamm", "hamf" }, { "Homer", "homr" }, - { "iBEC", "ibec" }, - { "iBoot", "ibot" }, - { "iBootData", "ibdt" }, - { "iBootTest", "itst" }, - { "iBSS", "ibss" }, - { "InputDevice", "ipdf" }, { "ISP", "ispf" }, + { "InputDevice", "ipdf" }, { "KernelCache", "krnl" }, + { "LLB", "illb" }, { "LeapHaptics", "lphp" }, { "Liquid", "liqd" }, - { "LLB", "illb" }, { "LoadableTrustCache", "ltrs" }, { "LowPowerWallet0", "lpw0" }, { "LowPowerWallet1", "lpw1" }, @@ -337,12 +340,13 @@ static const char *_img4_get_component_tag(const char *compname) { "NeedService", "nsrv" }, { "OS", "OS\0\0" }, { "OSRamdisk", "osrd" }, - { "PersonalizedDMG", "pdmg" }, { "PEHammer", "hmmr" }, { "PERTOS", "pert" }, { "PHLEET", "phlt" }, { "PMP", "pmpf" }, + { "PersonalizedDMG", "pdmg" }, { "RBM", "rmbt" }, + { "RTP", "rtpf" }, { "Rap,SoftwareBinaryDsp1", "sbd1" }, { "Rap,RTKitOS", "rkos" }, { "Rap,RestoreRTKitOS", "rrko" }, @@ -353,12 +357,10 @@ static const char *_img4_get_component_tag(const char *compname) { "RestoreExtDCP", "recp" }, { "RestoreKernelCache", "rkrn" }, { "RestoreLogo", "rlgo" }, + { "RestoreRTP", "rrtp" }, { "RestoreRamDisk", "rdsk" }, { "RestoreSEP", "rsep" }, { "RestoreTrustCache", "rtsc" }, - { "rfta", "rfta" }, - { "rfts", "rfts" }, - { "RTP", "rtpf" }, { "SCE", "scef" }, { "SCE1Firmware", "sc1f" }, { "SEP", "sepi" }, @@ -367,6 +369,16 @@ static const char *_img4_get_component_tag(const char *compname) { "SystemLocker", "lckr" }, { "SystemVolume", "isys" }, { "WCHFirmwareUpdater", "wchf" }, + { "ftap", "ftap" }, + { "ftsp", "ftsp" }, + { "iBEC", "ibec" }, + { "iBSS", "ibss" }, + { "iBoot", "ibot" }, + { "iBootData", "ibdt" }, + { "iBootDataStage1", "ibd1" }, + { "iBootTest", "itst" }, + { "rfta", "rfta" }, + { "rfts", "rfts" }, { NULL, NULL } }; int i = 0; From 88aeb4ce1313a9e89209c08efa62fb6b7eb428c4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 25 Sep 2022 11:42:35 +0200 Subject: [PATCH 008/159] tss: Make sure vinyl tags include eUICC,Gold and eUICC,Main digests ... as well as eUICC,ApProductionMode which was missing before. --- src/tss.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/tss.c b/src/tss.c index d8f97891..f162a826 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1075,10 +1075,29 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); + _plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); _plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); _plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); _plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); + if (!plist_dict_get_item(request, "eUICC,Gold")) { + plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); + if (n) { + plist_t p = plist_new_dict(); + _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_set_item(request, "eUICC,Gold", p); + } + } + + if (!plist_dict_get_item(request, "eUICC,Main")) { + plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); + if (n) { + plist_t p = plist_new_dict(); + _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_set_item(request, "eUICC,Main", p); + } + } + /* set Nonce for eUICC,Gold component */ node = plist_dict_get_item(parameters, "EUICCGoldNonce"); if (node) { From bb7f206090649933ad616baa1b9497ee978052c8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 25 Sep 2022 13:15:44 +0200 Subject: [PATCH 009/159] tss: Add preliminary code to set UID_MODE --- src/tss.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tss.c b/src/tss.c index f162a826..da4cf178 100644 --- a/src/tss.c +++ b/src/tss.c @@ -245,6 +245,11 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + node = plist_dict_get_item(build_identity, "Info"); + if (node) { + _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); + } + if (include_manifest) { /* add build identity manifest dictionary */ node = plist_dict_get_item(build_identity, "Manifest"); @@ -293,6 +298,13 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); + if (plist_dict_get_item(parameters, "UID_MODE")) { + _plist_dict_copy_item(request, parameters, "UID_MODE", NULL); + } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + // The logic here is missing why this value is expected to be 'false' + plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); + } + return 0; } From aa98e764bff59b45173a86d2587b59f5692982eb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Oct 2022 11:32:19 +0200 Subject: [PATCH 010/159] Reduce memory usage for SourceBootObjectV4 images --- src/idevicerestore.c | 2 +- src/ipsw.c | 141 +++++++++++++++++++++++++++++++++++++++++ src/ipsw.h | 2 + src/restore.c | 147 +++++++++++++++++-------------------------- 4 files changed, 201 insertions(+), 91 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 641eddb4..308c6cb2 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2278,7 +2278,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie } /* add common tags from manifest */ - /* Adds Ap,OSLongVersion, AppNonce, @ApImg4Ticket */ + /* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */ if (tss_request_add_ap_img4_tags(request, parameters) < 0) { error("ERROR: Unable to add AP IMG4 tags to TSS request\n"); plist_free(request); diff --git a/src/ipsw.c b/src/ipsw.c index d4ee5e52..5c88c0d2 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -710,6 +710,147 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** return 0; } +int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) +{ + unsigned char* buffer = NULL; + size_t done = 0; + size_t total_size = 0; + + ipsw_archive* archive = ipsw_open(ipsw); + if (archive == NULL) { + error("ERROR: Invalid archive\n"); + return -1; + } + + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); + ipsw_close(archive); + return -1; + } + + struct zip_stat zstat; + zip_stat_init(&zstat); + if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + error("ERROR: zip_stat_index: %s\n", infile); + ipsw_close(archive); + return -1; + } + + struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + if (zfile == NULL) { + error("ERROR: zip_fopen_index: %s\n", infile); + ipsw_close(archive); + return -1; + } + + total_size = zstat.size; + buffer = (unsigned char*) malloc(blocksize); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + zip_fclose(zfile); + ipsw_close(archive); + return -1; + } + + while (done < total_size) { + size_t size = total_size-done; + if (size > blocksize) size = blocksize; + zip_int64_t zr = zip_fread(zfile, buffer, size); + if (zr < 0) { + error("ERROR: %s: zip_fread: %s\n", __func__, infile); + break; + } else if (zr == 0) { + // EOF + break; + } + if (send_callback(ctx, buffer, zr) < 0) { + error("ERROR: %s: send failed\n", __func__); + break; + } + done += zr; + } + zip_fclose(zfile); + free(buffer); + } else { + char *filepath = build_path(archive->path, infile); + struct stat fst; +#ifdef WIN32 + if (stat(filepath, &fst) != 0) { +#else + if (lstat(filepath, &fst) != 0) { +#endif + error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + ipsw_close(archive); + return -1; + } + total_size = fst.st_size; + buffer = (unsigned char*)malloc(blocksize); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + free(filepath); + ipsw_close(archive); + return -1; + } + +#ifndef WIN32 + if (S_ISLNK(fst.st_mode)) { + ssize_t rl = readlink(filepath, (char*)buffer, (total_size > blocksize) ? blocksize : total_size); + if (rl < 0) { + error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + free(buffer); + ipsw_close(archive); + return -1; + } + send_callback(ctx, buffer, (size_t)rl); + } else { +#endif + FILE *f = fopen(filepath, "rb"); + if (!f) { + error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + free(buffer); + ipsw_close(archive); + return -2; + } + + while (done < total_size) { + size_t size = total_size-done; + if (size > blocksize) size = blocksize; + size_t fr = fread(buffer, 1, size, f); + if (fr != size) { + error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); + break; + } + if (send_callback(ctx, buffer, fr) < 0) { + error("ERROR: %s: send failed\n", __func__); + break; + } + done += fr; + } + fclose(f); +#ifndef WIN32 + } +#endif + free(filepath); + free(buffer); + } + ipsw_close(archive); + + if (done < total_size) { + error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); + return -1; + } + + // send a NULL buffer to mark end of transfer + send_callback(ctx, NULL, 0); + + return 0; +} + int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) { unsigned int size = 0; diff --git a/src/ipsw.h b/src/ipsw.h index 3b5da80e..84ea7a9d 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -35,6 +35,7 @@ extern "C" { int ipsw_print_info(const char* ipsw); typedef int (*ipsw_list_cb)(void *ctx, const char* ipsw, const char *name, struct stat *stat); +typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); int ipsw_is_directory(const char* ipsw); int ipsw_file_exists(const char* ipsw, const char* infile); @@ -42,6 +43,7 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size); int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress); int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); +int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx); diff --git a/src/restore.c b/src/restore.c index 17c9b24d..b0863801 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3326,18 +3326,18 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +static char* extract_global_manifest_path(plist_t build_identity, char *variant) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { error("ERROR: build identity does not contain an 'Info' element\n"); - return -1; + return NULL; } plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass"); if (!device_class_node) { error("ERROR: build identity info does not contain a DeviceClass\n"); - return -1; + return NULL; } char *device_class = NULL; plist_get_string_val(device_class_node, &device_class); @@ -3350,7 +3350,7 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil ret = extract_macos_variant(build_identity, &macos_variant); if (ret != 0) { free(device_class); - return -1; + return NULL; } } @@ -3361,7 +3361,17 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil free(device_class); free(macos_variant); - ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); + return ticket_path; +} + +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +{ + char* ticket_path = extract_global_manifest_path(build_identity, variant); + if (!ticket_path) { + error("ERROR: failed to get global manifest path\n"); + return -1; + } + int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); if (ret != 0) { free(ticket_path); error("ERROR: failed to read global manifest\n"); @@ -3372,6 +3382,26 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil return 0; } +static int _restore_send_file_data(restored_client_t restore, void* data, size_t size) +{ + plist_t dict = plist_new_dict(); + if (data != NULL) { + // Send a chunk of file data + plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); + } else { + // Send FileDataDone to mark end of transfer + plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + } + restored_error_t restore_error = restored_send(restore, dict); + if (restore_error != RESTORE_E_SUCCESS) { + plist_free(dict); + error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); + return -1; + } + plist_free(dict); + return 0; +} + int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { debug_plist(msg); @@ -3395,9 +3425,8 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); @@ -3446,7 +3475,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i return -1; } - // Personalize IMG40 + // Personalize IMG4 ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; @@ -3456,43 +3485,23 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } - // Make plist - info("Sending %s now...\n", component_name); + info("Sending %s now...\n", component); int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (_restore_send_file_data(restore, (data + size - i), blob_size) < 0) { + free(data); + error("ERROR: Unable to send component %s data\n", component); return -1; } - - plist_free(dict); - i -= blob_size; } - debug("\n"); - - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } - - plist_free(dict); free(data); - info("Done sending %s\n", component_name); + _restore_send_file_data(restore, NULL, 0); + + info("Done sending %s\n", component); return 0; } @@ -3521,9 +3530,8 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; @@ -3538,22 +3546,11 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - int ret = extract_global_manifest(client, build_identity, variant, &data, &size); - if (ret != 0) { - return -1; - } + path = extract_global_manifest_path(build_identity, variant); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); - return -1; - } + path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); - return -1; - } + path = strdup("SystemVersion.plist"); } else { // Get component path if (client->tss) { @@ -3568,53 +3565,23 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } } - - int ret = extract_component(client->ipsw, path, &data, &size); - free(path); - path = NULL; - if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); - return -1; - } } - // Make plist - info("Sending %s now...\n", component_name); - - int64_t i = size; - while (i > 0) { - int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } - - plist_free(dict); - - i -= blob_size; + if (!path) { + error("ERROR: Failed to get path for component %s\n", component); + return -1; } - debug("\n"); - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + info("Sending %s now...\n", component); - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, restore) < 0) { + free(path); + error("ERROR: Failed to send component %s\n", component); return -1; } + free(path); - plist_free(dict); - free(data); - - info("Done sending %s\n", component_name); + info("Done sending %s\n", component); return 0; } From a4f5a0c1a65c9df239a737c350d4723c2a8cbc55 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Oct 2022 13:06:20 +0200 Subject: [PATCH 011/159] img4: Add support for stitching with additional TBM data --- src/idevicerestore.c | 4 +- src/img4.c | 192 ++++++++++++++++++++++++++++++++++++++++++- src/img4.h | 2 +- 3 files changed, 191 insertions(+), 7 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 308c6cb2..62fbc09c 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2566,9 +2566,9 @@ int personalize_component(const char *component_name, const unsigned char* compo unsigned char* stitched_component = NULL; unsigned int stitched_component_size = 0; - if (tss_response && tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) { + if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ - img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size); + img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { diff --git a/src/img4.c b/src/img4.c index 6cff3497..3a74c5ef 100644 --- a/src/img4.c +++ b/src/img4.c @@ -24,6 +24,7 @@ #include "common.h" #include "img4.h" +#include "tss.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f @@ -201,7 +202,7 @@ static void asn1_write_element(unsigned char **p, unsigned int *length, unsigned } } break; default: - fprintf(stderr, "ERROR: %s: type %02x is not implemented", __func__, type); + fprintf(stderr, "ERROR: %s: type %02x is not implemented\n", __func__, type); return; } } @@ -393,7 +394,38 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size) +static void hexdump(char* data, int length) +{ + int i; + int j; + unsigned char c; + + for (i = 0; i < length; i += 16) { + fprintf(stderr, "%04x: ", i); + for (j = 0; j < 16; j++) { + if (i + j >= length) { + fprintf(stderr, " "); + continue; + } + fprintf(stderr, "%02x ", *(data + i + j) & 0xff); + } + fprintf(stderr, " | "); + for (j = 0; j < 16; j++) { + if (i + j >= length) + break; + c = *(data + i + j); + if ((c < 32) || (c > 127)) { + fprintf(stderr, "."); + continue; + } + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); +} + +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; @@ -404,8 +436,15 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo unsigned int content_size; unsigned char* outbuf; unsigned char* p; + unsigned char* blob = NULL; + unsigned int blob_size = 0; - if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) { + if (!component_name || !component_data || component_size == 0 || !tss_response || !img4_data || !img4_size) { + return -1; + } + + if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) { + error("ERROR: %s: Failed to get ApImg4Ticket from TSS response\n", __func__); return -1; } @@ -435,13 +474,152 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo } } + // check if we have a *-TBM entry for the given component + unsigned char *additional_data = NULL; + unsigned int additional_size = 0; + char *tbm_key = malloc(strlen(component_name) + 5); + sprintf(tbm_key, "%s-TBM", component_name); + plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); + free(tbm_key); + if (tbm_dict) { + plist_t dt = plist_dict_get_item(tbm_dict, "ucon"); + if (!dt) { + error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + uint64_t ucon_size = 0; + const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + if (!ucon_data) { + error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + dt = plist_dict_get_item(tbm_dict, "ucer"); + if (!dt) { + error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + uint64_t ucer_size = 0; + const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + if (!ucer_data) { + error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + + unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16); + unsigned char *p_im4rset = im4rset; + unsigned int im4rlen = 0; + + // ----------- ucon ------------ + // write priv ucon element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); + + // write ucon IA5STRING and ucon data + unsigned char ucon_seq[16]; + unsigned char *p_ucon_seq = &ucon_seq[0]; + unsigned int ucon_seq_hdr_len = 0; + asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_seq_hdr_len); + + // write ucon sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len); + + // add size to priv ucon element + asn1_write_size(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, ucon_seq, ucon_seq_hdr_len); + p_im4rset += ucon_seq_hdr_len; + im4rlen += ucon_seq_hdr_len; + memcpy(p_im4rset, ucon_data, ucon_size); + p_im4rset += ucon_size; + im4rlen += ucon_size; + + // ----------- ucer ------------ + // write priv ucer element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); + + // write ucon IA5STRING and ucer data + unsigned char ucer_seq[16]; + unsigned char *p_ucer_seq = &ucer_seq[0]; + unsigned int ucer_seq_hdr_len = 0; + asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len); + + p = &elem_seq[0]; + seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len); + + // add size to priv ucer element + asn1_write_size(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, ucer_seq, ucer_seq_hdr_len); + p_im4rset += ucer_seq_hdr_len; + im4rlen += ucer_seq_hdr_len; + memcpy(p_im4rset, ucer_data, ucer_size); + p_im4rset += ucer_size; + im4rlen += ucer_size; + + // now construct IM4R + + /* write inner set */ + unsigned char inner_set_[8]; + unsigned char *inner_set = &inner_set_[0]; + unsigned int inner_set_len = 0; + asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, im4rlen, &inner_set, &inner_set_len); + + /* write header values */ + unsigned char hdrdata_[16]; + unsigned char *hdrdata = &hdrdata_[0]; + unsigned int hdrdata_len = 0; + asn1_write_element(&hdrdata, &hdrdata_len, ASN1_IA5_STRING, (void*)"IM4R", -1); + + /* write sequence now that we know the entire size */ + unsigned char seq_[8]; + unsigned char *seq = &seq_[0]; + unsigned int seq_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, im4rlen + inner_set_len + hdrdata_len, &seq, &seq_len); + + /* write outer cont[1] */ + unsigned char cont_[8]; + unsigned char *cont = &cont_[0]; + unsigned int cont_len = 0; + asn1_write_element_header(ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, im4rlen + inner_set_len + hdrdata_len + seq_len, &cont, &cont_len); + + // now put everything together + additional_data = malloc(im4rlen + inner_set_len + hdrdata_len + seq_len + cont_len); + p = additional_data; + memcpy(p, cont_, cont_len); + p += cont_len; + memcpy(p, seq_, seq_len); + p += seq_len; + memcpy(p, hdrdata_, hdrdata_len); + p += hdrdata_len; + memcpy(p, inner_set_, inner_set_len); + p += inner_set_len; + memcpy(p, im4rset, im4rlen); + p += im4rlen; + additional_size = (unsigned int)(p - additional_data); + + free(im4rset); + } + // create element header for the "IMG4" magic asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size); // create element header for the blob (ApImg4Ticket) asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size); // calculate the size for the final IMG4 file (asn1 sequence) - content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size; + content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size + additional_size; // create element header for the final IMG4 asn1 blob asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size); @@ -457,6 +635,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo if (img4header) { free(img4header); } + free(additional_data); error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name); return -1; } @@ -475,6 +654,10 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo p += blob_header_size; memcpy(p, blob, blob_size); p += blob_size; + if (additional_size) { + memcpy(p, additional_data, additional_size); + p += additional_size; + } *img4_data = outbuf; *img4_size = (p - outbuf); @@ -488,6 +671,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo if (img4header) { free(img4header); } + free(additional_data); return 0; } diff --git a/src/img4.h b/src/img4.h index 37dea569..1056fa68 100644 --- a/src/img4.h +++ b/src/img4.h @@ -26,7 +26,7 @@ extern "C" { #endif -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size); +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest); #ifdef __cplusplus From c45f74cc3e075d3b04dd920141e82a51dc20bd9b Mon Sep 17 00:00:00 2001 From: Munehisa Kamata Date: Tue, 4 Oct 2022 21:52:20 -0700 Subject: [PATCH 012/159] recovery: set bRequest to 1 when sending bootx command In macOS 13 beta 8 or newer release, bootx seems to fail if bRequest is 0 in the control transfer setup. Then, the device fails to enter restore mode. Seems like something has changed in iBEC since beta 8 and Apple Configurator 2 has set it to 1, so do the same thing. While this could be applied for all *OS variants, it's limited to macOS for now just to be safe. Signed-off-by: Munehisa Kamata --- src/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recovery.c b/src/recovery.c index 1a9c9709..24d0c3d0 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -498,7 +498,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu recovery_error = irecv_send_command(client->recovery->client, setba); } - recovery_error = irecv_send_command(client->recovery->client, "bootx"); + recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", client->macos_variant ? 1 : 0); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; From 4e46f12b52207cae9a4733e72534a1309870351b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 7 Oct 2022 17:19:34 +0200 Subject: [PATCH 013/159] [github-actions] Fix MinGW build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a573678f..6bd25bc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" + run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" - name: make run: make - name: make install From 961077074cf4f113d685ce19f3e0b18d343a74d6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 8 Oct 2022 21:15:18 +0200 Subject: [PATCH 014/159] recovery: Send bootx with bRequest set to 1 for all platforms --- src/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recovery.c b/src/recovery.c index 24d0c3d0..59cce625 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -498,7 +498,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu recovery_error = irecv_send_command(client->recovery->client, setba); } - recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", client->macos_variant ? 1 : 0); + recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", 1); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; From f6950c2461b28333bcef84a98f2132e93b216faf Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 11 Oct 2022 12:46:12 +0200 Subject: [PATCH 015/159] recovery: Also send "go" and "reset" commands with bRequest set to 1 --- src/recovery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/recovery.c b/src/recovery.c index 59cce625..a9d6b61f 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -344,7 +344,7 @@ int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_ide return -1; } - recovery_error = irecv_send_command(client->recovery->client, "go"); + recovery_error = irecv_send_command_breq(client->recovery->client, "go", 1); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; @@ -575,7 +575,7 @@ int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char int recovery_send_reset(struct idevicerestore_client_t* client) { - irecv_send_command(client->recovery->client, "reset"); + irecv_send_command_breq(client->recovery->client, "reset", 1); return 0; } From f8a92587b656a0ef793e9057fafdb67cf00a188d Mon Sep 17 00:00:00 2001 From: Alfie Cockell Gwinnett Date: Tue, 11 Oct 2022 18:05:08 +0100 Subject: [PATCH 016/159] Check if device is limera1n-vulnerable for --pwn option --- src/idevicerestore.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 62fbc09c..186595b8 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -482,17 +482,39 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (dfu_client_new(client) < 0) { return -1; } - info("exploiting with limera1n...\n"); - // TODO: check for non-limera1n device and fail - if (limera1n_exploit(client->device, &client->dfu->client) != 0) { - error("ERROR: limera1n exploit failed\n"); + + // Check if device is vulnerable to limera1n + unsigned int cpid = 0; + dfu_get_cpid(client, &cpid); + + int limera1nDevices[] = {8920, 8922, 8930}; + int limera1nDevicesLen = sizeof limera1nDevices / sizeof limera1nDevices[0]; + int limera1nVuln = 0; + + for (int i = 0; i < limera1nDevicesLen; i++) { + if (limera1nDevices[i] == cpid) { + limera1nVuln = 1; + break; + } + } + + if (limera1nVuln == 1) { + info("exploiting with limera1n...\n"); + if (limera1n_exploit(client->device, &client->dfu->client) != 0) { + error("ERROR: limera1n exploit failed\n"); + dfu_client_free(client); + return -1; + } + dfu_client_free(client); + info("Device should be in pwned DFU state now.\n"); + + return 0; + } + else { dfu_client_free(client); + error("ERROR: This device is not supported by the limera1n exploit"); return -1; } - dfu_client_free(client); - info("Device should be in pwned DFU state now.\n"); - - return 0; } if (client->flags & FLAG_LATEST) { From d20eb2135be46a3596d4f5c97f175faa96c55929 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 18 Oct 2022 01:09:44 +0200 Subject: [PATCH 017/159] Use limera1n_is_supported instead of compatibility check added with previous commit --- src/idevicerestore.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 186595b8..3d6b65c2 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -483,22 +483,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - // Check if device is vulnerable to limera1n - unsigned int cpid = 0; - dfu_get_cpid(client, &cpid); - - int limera1nDevices[] = {8920, 8922, 8930}; - int limera1nDevicesLen = sizeof limera1nDevices / sizeof limera1nDevices[0]; - int limera1nVuln = 0; - - for (int i = 0; i < limera1nDevicesLen; i++) { - if (limera1nDevices[i] == cpid) { - limera1nVuln = 1; - break; - } - } - - if (limera1nVuln == 1) { + if (limera1n_is_supported(client->device)) { info("exploiting with limera1n...\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); @@ -1246,7 +1231,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } info("exploiting with limera1n\n"); - // TODO: check for non-limera1n device and fail if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); dfu_client_free(client); From 2a907b0eaf3549382127aa811830ca72a553ccb8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Oct 2022 05:38:59 +0200 Subject: [PATCH 018/159] restore: Only print boot object v3/v4 plist in debug mode --- src/restore.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index b0863801..e8913f54 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3404,7 +3404,10 @@ static int _restore_send_file_data(restored_client_t restore, void* data, size_t int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); + debug_plist(message); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); @@ -3507,7 +3510,10 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); + debug_plist(message); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); From 7b89019fbb81ce64e1c1d259c5746544c8e8eeea Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Oct 2022 08:32:58 +0200 Subject: [PATCH 019/159] restore: Fix compilation error due to wrong variable name --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index e8913f54..69f2f099 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3406,7 +3406,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(message); + debug_plist(msg); } char *image_name = NULL; @@ -3512,7 +3512,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(message); + debug_plist(msg); } char *image_name = NULL; From bc617712ed2fdda6338e9f057ba7396d424d88e4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 13 Apr 2023 00:33:13 +0200 Subject: [PATCH 020/159] img4: Remove unused debug code --- src/img4.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/img4.c b/src/img4.c index 3a74c5ef..c21a0753 100644 --- a/src/img4.c +++ b/src/img4.c @@ -394,37 +394,6 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -static void hexdump(char* data, int length) -{ - int i; - int j; - unsigned char c; - - for (i = 0; i < length; i += 16) { - fprintf(stderr, "%04x: ", i); - for (j = 0; j < 16; j++) { - if (i + j >= length) { - fprintf(stderr, " "); - continue; - } - fprintf(stderr, "%02x ", *(data + i + j) & 0xff); - } - fprintf(stderr, " | "); - for (j = 0; j < 16; j++) { - if (i + j >= length) - break; - c = *(data + i + j); - if ((c < 32) || (c > 127)) { - fprintf(stderr, "."); - continue; - } - fprintf(stderr, "%c", c); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); -} - int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; From d291eb107d68ca53e9b19a169725515eae72aae5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 14 Apr 2023 03:52:14 +0200 Subject: [PATCH 021/159] Allow setting custom TSS request URL through command line switch --- src/idevicerestore.c | 39 +++++++++++++++++++++++++++++++++------ src/tss.c | 1 + 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3d6b65c2..466cfe2e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -72,7 +72,7 @@ static struct option longopts[] = { { "erase", no_argument, NULL, 'e' }, { "custom", no_argument, NULL, 'c' }, { "latest", no_argument, NULL, 'l' }, - { "cydia", no_argument, NULL, 's' }, + { "server", required_argument, NULL, 's' }, { "exclude", no_argument, NULL, 'x' }, { "shsh", no_argument, NULL, 't' }, { "keep-pers", no_argument, NULL, 'k' }, @@ -132,8 +132,8 @@ static void usage(int argc, char* argv[], int err) "\n" \ "Advanced/experimental options:\n" " -c, --custom Restore with a custom firmware (requires bootrom exploit)\n" \ - " -s, --cydia Use Cydia's signature service instead of Apple's\n" \ - " -x, --exclude Exclude nor/baseband upgrade\n" \ + " -s, --server URL Override default signing server request URL\n" \ + " -x, --exclude Exclude nor/baseband upgrade (legacy devices)\n" \ " -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \ " -z, --no-restore Do not restore and end after booting to the ramdisk\n" \ " -k, --keep-pers Write personalized components to files for debugging\n" \ @@ -1617,7 +1617,7 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_INTERACTIVE; } - while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, argv, "dhces:xtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv, 0); @@ -1635,8 +1635,35 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_CUSTOM; break; - case 's': - client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2"); + case 's': { + if (!*optarg) { + error("ERROR: URL argument for --server must not be empty!\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + char *baseurl = NULL; + if (!strncmp(optarg, "http://", 7) && (strlen(optarg) > 7) && (optarg[7] != '/')) { + baseurl = optarg+7; + } else if (!strncmp(optarg, "https://", 8) && (strlen(optarg) > 8) && (optarg[8] != '/')) { + baseurl = optarg+8; + } + if (baseurl) { + char *p = strchr(baseurl, '/'); + if (!p || *(p+1) == '\0') { + // no path component, add default path + const char default_path[] = "/TSS/controller?action=2"; + char* newurl = malloc(strlen(optarg)+sizeof(default_path)); + sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path); + client->tss_url = newurl; + } else { + client->tss_url = strdup(optarg); + } + } else { + error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + } break; case 'x': diff --git a/src/tss.c b/src/tss.c index da4cf178..e1cf1f4a 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1524,6 +1524,7 @@ plist_t tss_request_send(plist_t tss_request, const char* server_url_string) curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); if (server_url_string) { curl_easy_setopt(handle, CURLOPT_URL, server_url_string); + info("Request URL set to %s\n", server_url_string); } else { int url_index = (retry - 1) % 6; curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]); From 1ec7bb430971341f16e7f0f6a8670d2f5b850ff8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 14 Apr 2023 03:53:06 +0200 Subject: [PATCH 022/159] docs: Updated man page --- docs/idevicerestore.1 | 109 +++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/docs/idevicerestore.1 b/docs/idevicerestore.1 index 8e0a8845..d1415482 100644 --- a/docs/idevicerestore.1 +++ b/docs/idevicerestore.1 @@ -1,66 +1,111 @@ .TH "idevicerestore" 1 .SH NAME -idevicerestore \- Restore IPSW firmware FILE to an iOS device +idevicerestore \- Restore IPSW firmware at PATH to an iOS device .SH SYNOPSIS .B idevicerestore -[OPTIONS] FILE +[OPTIONS] PATH .SH DESCRIPTION Restore firmware files to iOS devices while either erasing the device or updating to preserve content and settings. +\f[B]PATH\f[] can be a compressed .ipsw file or a directory containing all files extracted from an IPSW. + .SH OPTIONS .TP .B \-i, \-\-ecid ECID -target specific device by its hexadecimal ECID e.g. 0xaabb123456 or 00000012AABBCCDD. +Target specific device by its ECID, e.g. 0xaabb123456 (hex) or 1234567890 (decimal). .TP .B \-u, \-\-udid UDID -target specific device by its 40-digit device UDID. -NOTE: only works with devices in normal mode. +Target specific device by its device UDID. + +\f[B]NOTE\f[]: only works with devices in normal mode. .TP +.B \-l, \-\-latest +Use latest available firmware (with download on demand). +Before performing any action it will interactively ask +to select one of the currently signed firmware versions, +unless \f[B]\-y\f[] has been given too. + +The PATH argument is ignored when using this option. + +\f[B]DO NOT USE\f[] if you need to preserve the baseband/unlock! + +\f[B]USE WITH CARE\f[] if you want to keep a jailbreakable firmware! +.TP .B \-e, \-\-erase -perform a full restore, erasing all data (defaults to update). +Perform full restore instead of update, erasing all data + +\f[B]DO NOT USE\f[] if you want to preserve user data on the device! +.TP +.B \-y, \-\-no\-input +Non-interactive mode, do not ask for any input. + +\f[B]WARNING\f[]: This will disable certain checks/prompts that are supposed +to prevent DATA LOSS. \f[B]Use with caution\f[]. +.TP +.B \-n, \-\-no\-action +Do not perform any restore action. If combined with \f[B]\-l\f[] option +the on-demand ipsw download is performed before exiting. +.TP +.B \-\-ipsw\-info +Print information about the IPSW at PATH and exit. +.TP +.B \-h, \-\-help +Prints usage information. +.TP +.B \-C, \-\-cache\-path DIR +Use specified directory for caching extracted or other reused files. +.TP +.B \-d, \-\-debug +Enable communication debugging. +.TP +.B \-v, \-\-version +Prints version information. + +.SH ADVANCED/EXPERIMENTAL OPTIONS .TP .B \-c, \-\-custom -restore with a custom firmware. -.TP -.B \-l, \-\-latest -use latest available firmware (with download on demand). \ -DO NOT USE if you need to preserve the baseband (unlock)! \ -USE WITH CARE if you want to keep a jailbreakable firmware! \ -The FILE argument is ignored when using this option. +Restore with a custom firmware (requires bootrom exploit) .TP -.B \-s, \-\-cydia -use Cydia's signature service instead of Apple's. +.B \-s, \-\-server URL +Override the default signing server request URL. If the URL doesn't contain +a path component, the default path \f[B]/TSS/controller?action=2\f[] will be added. .TP .B \-x, \-\-exclude -exclude nor/baseband upgrade. +Exclude nor/baseband upgrade. + +\f[B]NOTE\f[]: This option only works with legacy devices and/or custom firmware. .TP .B \-t, \-\-shsh -fetch TSS record and save to .shsh file, then exit. +Fetch TSS record and save to .shsh file, then exit. .TP -.B \-p, \-\-pwn -put device in pwned DFU mode and exit (limera1n devices only). +.B \-z, \-\-no\-restore +Do not restore and end after booting to the ramdisk. .TP -.B \-n, \-\-no\-action -do not perform any restore action. If combined with -l option the on demand -IPSW download is performed before exiting. +.B \-k, \-\-keep\-pers +Write personalized components to files for debugging. .TP -.B \-\-ipsw\-info -Print information about the IPSW at PATH and exit. +.B \-p, \-\-pwn +Put device in pwned DFU mode and exit (limera1n devices only). .TP -.B \-C, \-\-cache\-path DIR -use specified directory for caching extracted or other reused files. +.B \-P, --plain-progress +Print progress as plain step and progress .TP -.B \-d, \-\-debug -enable communication debugging. +.B \-R, \-\-restore\-mode +Allow restoring from Restore mode .TP -.B \-h, \-\-help -prints usage information. +.B \-T, \-\-ticket PATH +Use file at PATH to send as AP ticket .TP -.B \-v, \-\-version -prints version information. +.B \-\-variant VARIANT +Use given VARIANT to match the build identity to use, e.g. 'Customer Erase Install (IPSW)' +.TP +.B \-\-ignore\-errors +Try to continue the restore process after certain errors (like a failed baseband update). + +\f[B]WARNING\f[]: This might render the device unable to boot or only partially functioning. \f[B]Use with caution\f[]. .SH AUTHORS Martin Szulecki From 7321192b1bd3781ca214f575d63e2df4b0fdade2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 21 Apr 2023 17:25:05 +0200 Subject: [PATCH 023/159] Updated to use latest libplist API --- configure.ac | 2 +- src/ipsw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 38152756..cadd48eb 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ fi # Minimum package versions LIBIRECOVERY_VERSION=1.0.1 LIBIMOBILEDEVICE_VERSION=1.3.0 -LIBPLIST_VERSION=2.2.0 +LIBPLIST_VERSION=2.3.0 LIMD_GLUE_VERSION=1.0.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ipsw.c b/src/ipsw.c index 5c88c0d2..fafe5830 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -134,7 +134,7 @@ int ipsw_print_info(const char* path) } plist_t manifest = NULL; - plist_from_memory(plist_buf, plist_len, &manifest); + plist_from_memory(plist_buf, plist_len, &manifest, NULL); free(plist_buf); plist_t val; From a851716c8430c7436559f3e74d7ad8cb2089fdcd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 30 Apr 2023 16:43:59 +0200 Subject: [PATCH 024/159] git-version-gen: Prevent multiple lines of output --- git-version-gen | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-version-gen b/git-version-gen index 3eb6a42e..d8689526 100755 --- a/git-version-gen +++ b/git-version-gen @@ -3,7 +3,7 @@ SRCDIR=`dirname $0` if test -n "$1"; then VER=$1 else - if test -d "${SRCDIR}/.git" && test -x "`which git`" ; then + if test -r "${SRCDIR}/.git" && test -x "`which git`" ; then git update-index -q --refresh if ! VER=`git describe --tags --dirty 2>/dev/null`; then COMMIT=`git rev-parse --short HEAD` @@ -16,4 +16,5 @@ else fi fi fi +VER=`printf %s "$VER" | head -n1` printf %s "$VER" From 163a1647dedb7ca4656c0f072e4733573f9f982b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 30 Apr 2023 16:44:23 +0200 Subject: [PATCH 025/159] Make sure git-version-gen and .tarball-version are included in dist tarball --- Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 435cb17b..c86bf426 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,4 +4,8 @@ SUBDIRS = src docs EXTRA_DIST = \ docs \ - README.md + README.md \ + git-version-gen + +dist-hook: + echo $(VERSION) > $(distdir)/.tarball-version From 609f7f058487596597e8e742088119fdd46729df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Wed, 1 Mar 2023 20:33:47 +0100 Subject: [PATCH 026/159] Use DeviceGeneratedRequest plist for SE TSS requests --- src/restore.c | 23 +++++++++++++++++------ src/tss.c | 7 +++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/restore.c b/src/restore.c index 69f2f099..486ffb56 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2105,7 +2105,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2114,6 +2114,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); @@ -2137,6 +2138,14 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id debug("DEBUG: %s: using %s\n", __func__, comp_name); } + p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!p_dgr) { + info("NOTE: %s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); + } else if (!PLIST_IS_DICT(p_dgr)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; @@ -2167,7 +2176,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_dict_merge(¶meters, p_info); /* add required tags for SE TSS request */ - tss_request_add_se_tags(request, parameters, NULL); + tss_request_add_se_tags(request, parameters, p_dgr); plist_free(parameters); @@ -2180,10 +2189,12 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return NULL; } - if (plist_dict_get_item(response, "SE,Ticket")) { - info("Received SE ticket\n"); + if (plist_dict_get_item(response, "SE2,Ticket")) { + info("Received SE2,Ticket\n"); + } else if (plist_dict_get_item(response, "SE,Ticket")) { + info("Received SE,Ticket\n"); } else { - error("ERROR: No 'SE,Ticket' in TSS response, this might not work\n"); + error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); @@ -3025,7 +3036,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; diff --git a/src/tss.c b/src/tss.c index e1cf1f4a..9fb74af3 100644 --- a/src/tss.c +++ b/src/tss.c @@ -786,9 +786,7 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid return -1; } - /* add tags indicating we want to get the SE,Ticket */ plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); if (_plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); @@ -864,6 +862,11 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid plist_dict_merge(&request, overrides); } + /* fallback in case no @SE2,Ticket or @SE,Ticket was provided */ + if (!plist_dict_get_item(request, "@SE2,Ticket") && !plist_dict_get_item(request, "@SE,Ticket")) { + plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); + } + return 0; } From 73438a6ff3fe5758e927c05d389d0e9587dcbb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 15:12:32 +0200 Subject: [PATCH 027/159] Add support for incoherent iBoot parameters Some firmwares to load during iBoot stage 1 can have both: - isLoadedByiBoot = false - isLoadedByiBootStage1 = true This allows to load it at stage 1 --- src/dfu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index cb4d2b33..0c3c480a 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -349,11 +349,13 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli uint8_t b = 0; plist_get_bool_val(iboot_node, &b); if (b) { - debug("DEBUG: %s is loaded by iBoot Stage 1.\n", key); - if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { - error("ERROR: Unable to send component '%s' to device.\n", key); - err++; - } + debug("DEBUG: %s is loaded by iBoot Stage 1 and iBoot.\n", key); + } else { + debug("DEBUG: %s is loaded by iBoot Stage 1 but not iBoot...\n", key); + } + if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { + error("ERROR: Unable to send component '%s' to device.\n", key); + err++; } } free(key); From da22dd466548a776a62208e060017aa6cdc2df52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 15:17:49 +0200 Subject: [PATCH 028/159] Display iBoot boot stage This helps debugging cases where the iDevice does not go into stage 2 because of a missing firmware --- src/dfu.c | 15 +++++++++++++++ src/recovery.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/dfu.c b/src/dfu.c index 0c3c480a..4487ade0 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -473,6 +473,21 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide return -1; } + char *value = NULL; + unsigned long boot_stage = 0; + irecv_getenv(client->dfu->client, "boot-stage", &value); + if (value) { + boot_stage = strtoul(value, NULL, 0); + } + if (boot_stage > 0) { + info("iBoot boot-stage=%s\n", value); + free(value); + value = NULL; + if (boot_stage != 1) { + error("ERROR: iBoot should be at boot stage 1, continuing anyway...\n"); + } + } + if (dfu_send_iboot_stage1_components(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBoot stage 1 components to device\n"); diff --git a/src/recovery.c b/src/recovery.c index a9d6b61f..02f56898 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -158,6 +158,20 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build free(value); value = NULL; + unsigned long boot_stage = 0; + irecv_getenv(client->recovery->client, "boot-stage", &value); + if (value) { + boot_stage = strtoul(value, NULL, 0); + } + if (boot_stage > 0) { + info("iBoot boot-stage=%s\n", value); + free(value); + value = NULL; + if (boot_stage != 2) { + error("ERROR: iBoot should be at boot stage 2, continuing anyway...\n"); + } + } + unsigned long radio_error = 0; irecv_getenv(client->recovery->client, "radio-error", &value); if (value) { From a3515134e1be6596d8a3775d6210085056885a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 18:02:07 +0200 Subject: [PATCH 029/159] Add SE,ChipID 0x2C --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 486ffb56..2fd0ad10 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2123,7 +2123,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C) { comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); From ed5463a4696a9e059562d6c2386dfa31eafa95a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 18:02:27 +0200 Subject: [PATCH 030/159] Add generic TSS request generator This uses the DeviceGeneratedRequest and DeviceGeneratedTags to generate the full TSS request. This allows to have a more future-proof approach to new firmware names they add. --- src/restore.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index 2fd0ad10..0699be7a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2611,6 +2611,61 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } +static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +{ + plist_t request = NULL; + plist_t response = NULL; + + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = NULL; + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + if (response_ticket == NULL) { + error("ERROR: Unable to determine response ticket from device generated tags"); + return NULL; + } + + /* create TSS request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create %s TSS request\n", s_updater_name); + return NULL; + } + + /* add device generated request data to request */ + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!device_generated_request) { + error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + plist_free(request); + return NULL; + } + plist_dict_merge(&request, device_generated_request); + + info("Sending %s TSS request...\n", s_updater_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + return NULL; + } + + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); + } + + return response; +} + static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) { char *comp_name = "Baobab,TCON"; @@ -3072,6 +3127,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } + } else if (strcmp(s_updater_name, "PS190") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); + goto error_out; + } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { fwdict = restore_get_timer_firmware_data(restore, client, build_identity, p_info); if (fwdict == NULL) { @@ -3085,8 +3146,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct goto error_out; } } else { - error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name); - goto error_out; + error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } free(s_updater_name); s_updater_name = NULL; From 9b9bba770bda29a09908a287c6f8b9bf15ae9a08 Mon Sep 17 00:00:00 2001 From: Daniel VanBritsom Date: Wed, 6 Sep 2023 12:38:17 +0200 Subject: [PATCH 031/159] tss: Bump auth client version to match iOS 16.5 Sourced from the iOS 16.5 UpdateBrain.dylib --- src/tss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tss.c b/src/tss.c index 9fb74af3..b8af70fe 100644 --- a/src/tss.c +++ b/src/tss.c @@ -35,7 +35,7 @@ #include "endianness.h" -#define AUTH_VERSION "850.0.2" +#define AUTH_VERSION "914.120.2" #ifdef WIN32 #define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" From c8b9f3e582d3543391f7db4cafe96051484f60a9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 6 Sep 2023 17:03:02 +0200 Subject: [PATCH 032/159] fdr: Fix a debug log message --- src/fdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fdr.c b/src/fdr.c index e3703fe8..ca9b7c75 100644 --- a/src/fdr.c +++ b/src/fdr.c @@ -575,7 +575,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) break; } if (bytes) { - debug("FDR %p got payload of %u bytes, now try to proxy it\n", fdr, bytes); + debug("FDR %p got payload of %u bytes, now trying to proxy it\n", fdr, bytes); debug("Sending %u bytes of data\n", bytes); sent = 0; while (sent < bytes) { From 4191036d58175a873c464d966d8c9e0aa1ec3494 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 13 Sep 2023 13:42:48 +0200 Subject: [PATCH 033/159] restore: Remove plist debug print for non-existent UniqueBuildID and print it in a better format if it does exist --- src/restore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 0699be7a..a7072f0a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3373,7 +3373,10 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 variant, 0); plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); - debug_plist(unique_id_node); + if (unique_id_node) { + printf("UniqueBuildID: "); + plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); + } return build_identity; } From 7943b63d3884b58169251926de03197bd510afe9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 13 Sep 2023 13:44:24 +0200 Subject: [PATCH 034/159] normal: Don't do unpair before entering recovery mode, remove pairing record afterwards instead --- src/normal.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/normal.c b/src/normal.c index 7f570dab..b7f9f9d7 100644 --- a/src/normal.c +++ b/src/normal.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "common.h" #include "normal.h" @@ -233,12 +234,6 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) return -1; } - /* unpair the device */ - lockdown_error = lockdownd_unpair(lockdown, NULL); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("WARNING: Could not unpair device\n"); - } - lockdown_error = lockdownd_enter_recovery(lockdown); if (lockdown_error == LOCKDOWN_E_SESSION_INACTIVE) { lockdownd_client_free(lockdown); @@ -285,6 +280,9 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) return -1; } + /* remove pair record for given device */ + usbmuxd_delete_pair_record(client->udid); + return 0; } From 5a00bbd88790c2542233906c458473190b41da33 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 00:10:43 +0200 Subject: [PATCH 035/159] tss: Make missing ApNonce non-fatal for IMG3 For IMG3 devices, DFU does not provide ApNonce, but a valid SHSH is needed to boot into iBSS (which then does provide ApNonce). Thanks to @tihmstar for providing the fix! --- src/tss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tss.c b/src/tss.c index b8af70fe..0fa17408 100644 --- a/src/tss.c +++ b/src/tss.c @@ -316,8 +316,7 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) } if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("ERROR: Unable to find required ApNonce in parameters\n"); - return -1; + error("WARNING: Unable to find ApNonce in parameters\n"); } plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); From 95466549006709bf37a751091ae23e989085810c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:41:01 +0200 Subject: [PATCH 036/159] [github-actions] Updated to use checkout@v3 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bd25bc5..3606be9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,7 +57,7 @@ jobs: rm -rf extract/lib sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: autogen @@ -129,7 +129,7 @@ jobs: tar -C extract -xvf $I done sudo cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install additional requirements run: | SDKDIR=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` @@ -260,7 +260,7 @@ jobs: tar -C extract -xvf $I done cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install additional requirements run: | FILENAME="libzip-1.7.1-static.tar.bz2" From cc9c68e298cadab4b5dfbb32f36fe71b2daf47e0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:48:51 +0200 Subject: [PATCH 037/159] autoconf: Link against libusbmuxd too --- configure.ac | 3 +++ src/Makefile.am | 2 ++ 2 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index cadd48eb..572e2804 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,7 @@ fi # Minimum package versions LIBIRECOVERY_VERSION=1.0.1 LIBIMOBILEDEVICE_VERSION=1.3.0 +LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.3.0 LIMD_GLUE_VERSION=1.0.0 LIBZIP_VERSION=1.0 @@ -25,6 +26,7 @@ OPENSSL_VERSION=0.9.8 AC_SUBST(LIBIRECOVERY_VERSION) AC_SUBST(LIBIMOBILEDEVICE_VERSION) +AC_SUBST(LIBUSBMUXD_VERSION) AC_SUBST(LIBPLIST_VERSION) AC_SUBST(LIMD_GLUE_VERSION) AC_SUBST(LIBZIP_VERSION) @@ -39,6 +41,7 @@ LT_INIT # Checks for libraries. PKG_CHECK_MODULES(libirecovery, libirecovery-1.0 >= $LIBIRECOVERY_VERSION) PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= $LIBIMOBILEDEVICE_VERSION) +PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION) PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION) PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) diff --git a/src/Makefile.am b/src/Makefile.am index a89a9c66..019424ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ AM_CFLAGS = \ $(LFS_CFLAGS) \ $(libirecovery_CFLAGS) \ $(libimobiledevice_CFLAGS) \ + $(libusbmuxd_CFLAGS) \ $(libplist_CFLAGS) \ $(limd_glue_CFLAGS) \ $(libzip_CFLAGS) \ @@ -14,6 +15,7 @@ AM_LDFLAGS = \ $(AC_LDFLAGS) \ $(libirecovery_LIBS) \ $(libimobiledevice_LIBS) \ + $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ $(limd_glue_LIBS) \ $(libzip_LIBS) \ From 17969ef91403f1a914d43584caf9fa0da89d649e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:55:18 +0200 Subject: [PATCH 038/159] [github-actions] Updated to use upload-artifact@v3 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3606be9b..9a92883b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,7 +72,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_${{env.target_triplet}} path: idevicerestore.tar @@ -182,7 +182,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_macOS path: idevicerestore.tar @@ -282,7 +282,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar ${{ env.dest }} - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_${{ matrix.arch }}-${{ env.dest }} path: idevicerestore.tar From dbe7313260ddef6b2eb60b3772d1595bfd91f24c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 02:34:06 +0200 Subject: [PATCH 039/159] Refactor ipsw code to transparently stream images directly from ZIP or extracted ipsw This allows flashing directly from IPSW archive without having to extract it first, and ultimately removes the "Extracting filesystem from IPSW" part. Restoring from extracted IPSW is also supported, just pass the path to the directory that has all the files from a given IPSW. --- src/asr.c | 56 +++------ src/asr.h | 9 +- src/common.h | 6 +- src/idevicerestore.c | 195 +++++-------------------------- src/idevicerestore.h | 7 +- src/ipsw.c | 269 +++++++++++++++++++++++++------------------ src/ipsw.h | 43 +++++-- src/restore.c | 35 ++++-- src/restore.h | 7 +- 9 files changed, 272 insertions(+), 355 deletions(-) diff --git a/src/asr.c b/src/asr.c index a1aba768..b2aeaf50 100644 --- a/src/asr.c +++ b/src/asr.c @@ -43,6 +43,7 @@ #include "asr.h" #include "idevicerestore.h" #include "common.h" +#include "ipsw.h" #define ASR_VERSION 1 #define ASR_STREAM_ID 1 @@ -205,9 +206,8 @@ void asr_free(asr_client_t asr) } } -int asr_perform_validation(asr_client_t asr, const char* filesystem) +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) { - FILE* file = NULL; uint64_t length = 0; char* command = NULL; plist_t node = NULL; @@ -216,20 +216,9 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem) plist_t payload_info = NULL; int attempts = 0; - file = fopen(filesystem, "rb"); - if (file == NULL) { - return -1; - } - -#ifdef WIN32 - length = _lseeki64(fileno(file), 0, SEEK_END); - _lseeki64(fileno(file), 0, SEEK_SET); - rewind(file); -#else - fseeko(file, 0, SEEK_END); - length = ftello(file); - fseeko(file, 0, SEEK_SET); -#endif + ipsw_file_seek(file, 0, SEEK_END); + length = ipsw_file_tell(file); + ipsw_file_seek(file, 0, SEEK_SET); payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); @@ -296,7 +285,7 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem) return 0; } -int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) +int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file) { char* oob_data = NULL; uint64_t oob_offset = 0; @@ -324,13 +313,8 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) return -1; } -#ifdef WIN32 - rewind(file); - _lseeki64(fileno(file), oob_offset, SEEK_SET); -#else - fseeko(file, oob_offset, SEEK_SET); -#endif - if (fread(oob_data, 1, oob_length, file) != oob_length) { + ipsw_file_seek(file, oob_offset, SEEK_SET); + if (ipsw_file_read(file, oob_data, oob_length) != oob_length) { error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno)); free(oob_data); return -1; @@ -345,28 +329,15 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) return 0; } -int asr_send_payload(asr_client_t asr, const char* filesystem) +int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) { char *data = NULL; - FILE* file = NULL; uint64_t i, length, bytes = 0; double progress = 0; - file = fopen(filesystem, "rb"); - if (file == NULL) { - error("ERROR: Unable to open filesystem image %s: %s\n", filesystem, strerror(errno)); - return -1; - } - -#ifdef WIN32 - length = _lseeki64(fileno(file), 0, SEEK_END); - _lseeki64(fileno(file), 0, SEEK_SET); - rewind(file); -#else - fseeko(file, 0, SEEK_END); - length = ftello(file); - fseeko(file, 0, SEEK_SET); -#endif + ipsw_file_seek(file, 0, SEEK_END); + length = ipsw_file_tell(file); + ipsw_file_seek(file, 0, SEEK_SET); data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); @@ -385,7 +356,7 @@ int asr_send_payload(asr_client_t asr, const char* filesystem) size = i; } - if (fread(data, 1, size, file) != (size_t)size) { + if (ipsw_file_read(file, data, size) != (int64_t)size) { error("Error reading filesystem\n"); retry--; continue; @@ -412,6 +383,5 @@ int asr_send_payload(asr_client_t asr, const char* filesystem) } free(data); - fclose(file); return 0; } diff --git a/src/asr.h b/src/asr.h index b3336a57..0d9534c2 100644 --- a/src/asr.h +++ b/src/asr.h @@ -41,15 +41,18 @@ struct asr_client { }; typedef struct asr_client *asr_client_t; +struct ipsw_file_handle; +typedef struct ipsw_file_handle* ipsw_file_handle_t; + int asr_open_with_timeout(idevice_t device, asr_client_t* asr); void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); int asr_send(asr_client_t asr, plist_t data); int asr_receive(asr_client_t asr, plist_t* data); int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size); void asr_free(asr_client_t asr); -int asr_perform_validation(asr_client_t asr, const char* filesystem); -int asr_send_payload(asr_client_t asr, const char* filesystem); -int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file); +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file); +int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file); +int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file); #ifdef __cplusplus diff --git a/src/common.h b/src/common.h index 97d5f964..5afe5abb 100644 --- a/src/common.h +++ b/src/common.h @@ -70,6 +70,9 @@ struct dfu_client_t; struct normal_client_t; struct restore_client_t; struct recovery_client_t; +struct ipsw_archive; + +typedef struct ipsw_archive* ipsw_archive_t; struct idevicerestore_mode_t { int index; @@ -101,8 +104,7 @@ struct idevicerestore_client_t { plist_t preflight_info; char* udid; char* srnm; - char* ipsw; - const char* filesystem; + ipsw_archive_t ipsw; struct dfu_client_t* dfu; struct restore_client_t* restore; struct recovery_client_t* recovery; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 466cfe2e..7b69a9f0 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -320,6 +320,8 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) } } +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw); + int idevicerestore_start(struct idevicerestore_client_t* client) { int tss_enabled = 0; @@ -424,7 +426,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) download_to_file(s_wtfurl, wtfipsw, 0); } - ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize); + ipsw_archive_t wtf_ipsw = ipsw_open(wtfipsw); + ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize); + ipsw_close(wtf_ipsw); if (!wtftmp) { error("ERROR: Could not extract WTF\n"); } @@ -601,12 +605,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) char* ipsw = NULL; res = ipsw_download_fw(fwurl, p_fwsha1, client->cache_dir, &ipsw); if (res != 0) { - if (ipsw) { - free(ipsw); - } + free(ipsw); return res; } else { - client->ipsw = ipsw; + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Failed to open ipsw '%s'\n", ipsw); + free(ipsw); + return -1; + } + free(ipsw); } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6); @@ -641,23 +649,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - // verify if ipsw file exists - if (access(client->ipsw, F_OK) < 0) { - error("ERROR: Firmware file %s does not exist.\n", client->ipsw); - return -1; - } - // extract buildmanifest if (client->flags & FLAG_CUSTOM) { info("Extracting Restore.plist from IPSW\n"); if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw); + error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } else { info("Extracting BuildManifest from IPSW\n"); if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } @@ -941,115 +943,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* check if all components we need are actually there */ info("Checking IPSW for required components...\n"); if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) { - error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw); + error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw->path); return -1; } info("All required components found in IPSW\n"); - // Get filesystem name from build identity - char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { - error("ERROR: Unable to get path for filesystem component\n"); - return -1; - } - - // check if we already have an extracted filesystem - int delete_fs = 0; - char* filesystem = NULL; - struct stat st; - memset(&st, '\0', sizeof(struct stat)); - char tmpf[1024]; - if (client->cache_dir) { - if (stat(client->cache_dir, &st) < 0) { - mkdir_with_parents(client->cache_dir, 0755); - } - strcpy(tmpf, client->cache_dir); - strcat(tmpf, "/"); - char *ipswtmp = strdup(client->ipsw); - strcat(tmpf, basename(ipswtmp)); - free(ipswtmp); - } else { - strcpy(tmpf, client->ipsw); - } - - if (!ipsw_is_directory(client->ipsw)) { - // strip off file extension if given ipsw is not a directory - char* s = tmpf + strlen(tmpf) - 1; - char* p = s; - while (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') p--; - if (s - p < 6) { - if (*p == '.') { - *p = '\0'; - } - } - } - - if (stat(tmpf, &st) < 0) { - __mkdir(tmpf, 0755); - } - strcat(tmpf, "/"); - strcat(tmpf, fsname); - - memset(&st, '\0', sizeof(struct stat)); - if (stat(tmpf, &st) == 0) { - uint64_t fssize = 0; - ipsw_get_file_size(client->ipsw, fsname, &fssize); - if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { - info("Using cached filesystem from '%s'\n", tmpf); - filesystem = strdup(tmpf); - } - } - - if (!filesystem && !(client->flags & FLAG_SHSHONLY)) { - char extfn[1024]; - strcpy(extfn, tmpf); - strcat(extfn, ".extract"); - char lockfn[1024]; - strcpy(lockfn, tmpf); - strcat(lockfn, ".lock"); - lock_info_t li; - - lock_file(lockfn, &li); - FILE* extf = NULL; - if (access(extfn, F_OK) != 0) { - extf = fopen(extfn, "wb"); - } - unlock_file(&li); - if (!extf) { - // use temp filename - filesystem = get_temp_filename("ipsw_"); - if (!filesystem) { - error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); - filesystem = strdup(fsname); - } - delete_fs = 1; - } else { - // use .extract as filename - filesystem = strdup(extfn); - fclose(extf); - } - remove(lockfn); - - // Extract filesystem from IPSW - info("Extracting filesystem from IPSW: %s\n", fsname); - if (ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - if (client->tss) - plist_free(client->tss); - info("Removing %s\n", filesystem); - unlink(filesystem); - return -1; - } - - if (strstr(filesystem, ".extract")) { - // rename .extract to - remove(tmpf); - rename(filesystem, tmpf); - free(filesystem); - filesystem = strdup(tmpf); - } - } - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2); /* retrieve shsh blobs if required */ @@ -1140,8 +1038,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (client->flags & FLAG_SHSHONLY) { @@ -1196,8 +1092,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.25); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1214,8 +1108,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1226,16 +1118,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) { info("connecting to DFU\n"); if (dfu_client_new(client) < 0) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } info("exploiting with limera1n\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); dfu_client_free(client); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } dfu_client_free(client); @@ -1245,8 +1133,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to place device into recovery mode from DFU mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } else if (client->mode == MODE_RECOVERY) { @@ -1256,8 +1142,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* send ApTicket */ if (recovery_send_ticket(client) < 0) { error("ERROR: Unable to send APTicket\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } @@ -1269,8 +1153,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (recovery_send_ibec(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBEC\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); @@ -1283,8 +1165,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } debug("Waiting for device to reconnect in recovery mode...\n"); @@ -1294,16 +1174,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } mutex_unlock(&client->device_event_mutex); } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1315,8 +1191,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); recovery_send_reset(client); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } @@ -1336,14 +1210,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_free(client->tss); if (get_tss_response(client, build_identity, &client->tss) < 0) { error("ERROR: Unable to get SHSH blobs for this device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (!client->tss) { error("ERROR: can't continue without TSS\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } fixup_tss(client->tss); @@ -1351,8 +1221,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1362,8 +1230,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to place device into restore mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); @@ -1378,8 +1244,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) mutex_unlock(&client->device_event_mutex); error("ERROR: Device failed to enter restore mode.\n"); error("Please make sure that usbmuxd is running.\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } mutex_unlock(&client->device_event_mutex); @@ -1393,19 +1257,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } client->ignore_device_add_events = 1; info("About to restore device... \n"); - result = restore_device(client, build_identity, filesystem); + result = restore_device(client, build_identity); if (result < 0) { error("ERROR: Unable to restore device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return result; } } - info("Cleaning up...\n"); - if (delete_fs && filesystem) - unlink(filesystem); - /* special handling of older AppleTVs as they enter Recovery mode on boot when plugged in to USB */ if ((strncmp(client->device->product_type, "AppleTV", 7) == 0) && (client->device->product_type[7] < '5')) { if (recovery_client_new(client) == 0) { @@ -1476,7 +1334,7 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) free(client->srnm); } if (client->ipsw) { - free(client->ipsw); + ipsw_close(client->ipsw); } if (client->version) { free(client->version); @@ -1535,11 +1393,11 @@ void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* if (!client) return; if (client->ipsw) { - free(client->ipsw); + ipsw_close(client->ipsw); client->ipsw = NULL; } if (path) { - client->ipsw = strdup(path); + client->ipsw = ipsw_open(path); } } @@ -1795,7 +1653,12 @@ int main(int argc, char* argv[]) { info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); if (ipsw) { - client->ipsw = strdup(ipsw); + // verify if ipsw file exists + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Firmware file %s cannot be opened.\n", ipsw); + return -1; + } } curl_global_init(CURL_GLOBAL_ALL); @@ -2570,7 +2433,7 @@ int build_manifest_get_identity_count(plist_t build_manifest) return plist_array_get_size(build_identities_array); } -int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) +int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) { char* component_name = NULL; if (!ipsw || !path || !component_data || !component_size) { @@ -2585,7 +2448,7 @@ int extract_component(const char* ipsw, const char* path, unsigned char** compon info("Extracting %s (%s)...\n", component_name, path); if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); + error("ERROR: Unable to extract %s from %s\n", component_name, ipsw->path); return -1; } @@ -2718,7 +2581,7 @@ void build_identity_print_information(plist_t build_identity) node = NULL; } -int build_identity_check_components_in_ipsw(plist_t build_identity, const char *ipsw) +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw) { plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 8a5736ff..880562ff 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -52,6 +52,8 @@ extern "C" { #define RESTORE_VARIANT_MACOS_RECOVERY_OS "macOS Customer" struct idevicerestore_client_t; +struct ipsw_archive; +typedef struct ipsw_archive* ipsw_archive_t; enum { RESTORE_STEP_DETECT = 0, @@ -108,11 +110,10 @@ plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, cons plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact); int build_manifest_get_build_count(plist_t build_manifest); void build_identity_print_information(plist_t build_identity); -int build_identity_check_components_in_ipsw(plist_t build_identity, const char* ipsw); int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); -int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem); -int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); +int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem); +int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest); diff --git a/src/ipsw.c b/src/ipsw.c index fafe5830..58d817c6 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -55,16 +55,8 @@ #define BUFSIZE 0x100000 -typedef struct { - struct zip* zip; - char *path; -} ipsw_archive; - static int cancel_flag = 0; -ipsw_archive* ipsw_open(const char* ipsw); -void ipsw_close(ipsw_archive* archive); - static char* build_path(const char* path, const char* file) { size_t plen = strlen(path); @@ -118,11 +110,14 @@ int ipsw_print_info(const char* path) uint32_t plist_len = 0; if (memcmp(&magic, "PK\x03\x04", 4) == 0) { + ipsw_archive_t ipsw = ipsw_open(thepath); unsigned int rlen = 0; - if (ipsw_extract_to_memory(thepath, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { + ipsw_close(ipsw); error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n"); return -1; } + ipsw_close(ipsw); plist_len = (uint32_t)rlen; } else { size_t rlen = 0; @@ -310,10 +305,10 @@ int ipsw_print_info(const char* path) return 0; } -ipsw_archive* ipsw_open(const char* ipsw) +ipsw_archive_t ipsw_open(const char* ipsw) { int err = 0; - ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); + ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct ipsw_archive)); if (archive == NULL) { error("ERROR: Out of memory\n"); return NULL; @@ -324,7 +319,6 @@ ipsw_archive* ipsw_open(const char* ipsw) error("ERROR: ipsw_open %s: %s\n", ipsw, strerror(errno)); return NULL; } - archive->path = strdup(ipsw); if (S_ISDIR(fst.st_mode)) { archive->zip = NULL; } else { @@ -335,7 +329,20 @@ ipsw_archive* ipsw_open(const char* ipsw) return NULL; } } - return archive; + archive->path = strdup(ipsw); + return (ipsw_archive_t)archive; +} + +void ipsw_close(ipsw_archive_t ipsw) +{ + if (ipsw != NULL) { + free(ipsw->path); + if (ipsw->zip) { + zip_unchange_all(ipsw->zip); + zip_close(ipsw->zip); + } + free(ipsw); + } } int ipsw_is_directory(const char* ipsw) @@ -348,37 +355,33 @@ int ipsw_is_directory(const char* ipsw) return S_ISDIR(fst.st_mode); } -int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) +int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) { - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } *size = zstat.size; } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; if (stat(filepath, &fst) != 0) { free(filepath); - ipsw_close(archive); return -1; } free(filepath); @@ -386,30 +389,22 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) *size = fst.st_size; } - ipsw_close(archive); return 0; } -int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress) +int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress) { int ret = 0; - ipsw_archive* archive = NULL; if (!ipsw || !infile || !outfile) { error("ERROR: Invalid argument\n"); return -1; } - archive = ipsw_open(ipsw); - if (archive == NULL) { - error("ERROR: Invalid archive\n"); - return -1; - } - cancel_flag = 0; - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); return -1; @@ -417,7 +412,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); return -1; } @@ -428,7 +423,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); return -1; @@ -472,7 +467,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con fclose(fd); zip_fclose(zfile); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); char actual_filepath[PATH_MAX+1]; char actual_outfile[PATH_MAX+1]; if (!filepath) { @@ -553,76 +548,66 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con leave: free(filepath); } - ipsw_close(archive); if (cancel_flag) { ret = -2; } return ret; } -int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile) +int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile) { return ipsw_extract_to_file_with_progress(ipsw, infile, outfile, 0); } -int ipsw_file_exists(const char* ipsw, const char* infile) +int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) { - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (!ipsw) { return 0; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { - ipsw_close(archive); return 0; } } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); if (access(filepath, R_OK) != 0) { free(filepath); - ipsw_close(archive); return 0; } free(filepath); } - ipsw_close(archive); - return 1; } -int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) { size_t size = 0; unsigned char* buffer = NULL; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); - ipsw_close(archive); return -1; } @@ -631,7 +616,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); - ipsw_close(archive); return -1; } @@ -639,7 +623,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: zip_fread: %s\n", infile); zip_fclose(zfile); free(buffer); - ipsw_close(archive); return -1; } @@ -647,7 +630,7 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** zip_fclose(zfile); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; #ifdef WIN32 if (stat(filepath, &fst) != 0) { @@ -656,7 +639,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** #endif error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); - ipsw_close(archive); return -1; } size = fst.st_size; @@ -664,7 +646,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** if (buffer == NULL) { error("ERROR: Out of memory\n"); free(filepath); - ipsw_close(archive); return -1; } @@ -674,7 +655,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } } else { @@ -684,7 +664,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -2; } if (fread(buffer, 1, size, f) != size) { @@ -692,7 +671,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } fclose(f); @@ -703,45 +681,40 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** free(filepath); } - ipsw_close(archive); *pbuffer = buffer; *psize = size; return 0; } -int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) +int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) { unsigned char* buffer = NULL; size_t done = 0; size_t total_size = 0; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); - ipsw_close(archive); return -1; } @@ -750,7 +723,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); - ipsw_close(archive); return -1; } @@ -771,10 +743,9 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ } done += zr; } - zip_fclose(zfile); free(buffer); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; #ifdef WIN32 if (stat(filepath, &fst) != 0) { @@ -783,7 +754,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ #endif error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); - ipsw_close(archive); return -1; } total_size = fst.st_size; @@ -791,7 +761,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ if (buffer == NULL) { error("ERROR: Out of memory\n"); free(filepath); - ipsw_close(archive); return -1; } @@ -802,7 +771,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } send_callback(ctx, buffer, (size_t)rl); @@ -813,7 +781,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -2; } @@ -838,7 +805,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ free(filepath); free(buffer); } - ipsw_close(archive); if (done < total_size) { error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); @@ -851,7 +817,7 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ return 0; } -int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) +int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled) { unsigned int size = 0; unsigned char* data = NULL; @@ -881,7 +847,7 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t return -1; } -int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) +int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist) { unsigned int size = 0; unsigned char* data = NULL; @@ -895,10 +861,10 @@ int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) return -1; } -static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, ipsw_list_cb cb, void *ctx) +static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ipsw_list_cb cb, void *ctx) { int ret = 0; - char *base = build_path(archive->path, path); + char *base = build_path(ipsw->path, path); DIR *dirp = opendir(base); @@ -936,10 +902,10 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i break; } - ret = cb(ctx, archive->path, subpath, &st); + ret = cb(ctx, ipsw, subpath, &st); if (ret >= 0 && S_ISDIR(st.st_mode)) - ipsw_list_contents_recurse(archive, subpath, cb, ctx); + ipsw_list_contents_recurse(ipsw, subpath, cb, ctx); free(fpath); free(subpath); @@ -950,21 +916,19 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i return ret; } -int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) +int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) { int ret = 0; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { - error("ERROR: Invalid archive\n"); + if (ipsw == NULL) { + error("ERROR: Invalid IPSW archive\n"); return -1; } - if (archive->zip) { - int64_t entries = zip_get_num_entries(archive->zip, 0); + if (ipsw->zip) { + int64_t entries = zip_get_num_entries(ipsw->zip, 0); if (entries < 0) { error("ERROR: zip_get_num_entries failed\n"); - ipsw_close(archive); return -1; } @@ -972,7 +936,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) zip_stat_t stat; zip_stat_init(&stat); - if (zip_stat_index(archive->zip, index, 0, &stat) < 0) { + if (zip_stat_index(ipsw->zip, index, 0, &stat) < 0) { error("ERROR: zip_stat_index failed for %s\n", stat.name); ret = -1; continue; @@ -980,7 +944,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) uint8_t opsys; uint32_t attributes; - if (zip_file_get_external_attributes(archive->zip, index, 0, &opsys, &attributes) < 0) { + if (zip_file_get_external_attributes(ipsw->zip, index, 0, &opsys, &attributes) < 0) { error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name); ret = -1; continue; @@ -1010,25 +974,12 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) break; } } else { - ret = ipsw_list_contents_recurse(archive, "", cb, ctx); + ret = ipsw_list_contents_recurse(ipsw, "", cb, ctx); } - ipsw_close(archive); return ret; } -void ipsw_close(ipsw_archive* archive) -{ - if (archive != NULL) { - free(archive->path); - if (archive->zip) { - zip_unchange_all(archive->zip); - zip_close(archive->zip); - } - free(archive); - } -} - int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares) { char url[256]; @@ -1352,3 +1303,91 @@ void ipsw_cancel(void) { cancel_flag++; } + +ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) +{ + ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, path, 0); + if (zindex < 0) { + error("ERROR: zip_name_locate: %s not found\n", path); + free(handle); + return NULL; + } + handle->zfile = zip_fopen_index(ipsw->zip, zindex, 0); + if (handle->zfile == NULL) { + error("ERROR: zip_fopen_index: %s could not be opened\n", path); + free(handle); + return NULL; + } + + } else { + char *filepath = build_path(ipsw->path, path); + handle->file = fopen(filepath, "rb"); + free(filepath); + if (!handle->file) { + error("ERROR: fopen: %s could not be opened\n", path); + free(handle); + return NULL; + } + } + return handle; +} + +void ipsw_file_close(ipsw_file_handle_t handle) +{ + if (handle && handle->zfile) { + zip_fclose(handle->zfile); + } else if (handle && handle->file) { + fclose(handle->file); + } + free(handle); +} + +int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size) +{ + if (handle && handle->zfile) { + zip_int64_t zr = zip_fread(handle->zfile, buffer, size); + return (int64_t)zr; + } else if (handle && handle->file) { + return fread(buffer, 1, size, handle->file); + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} + +int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence) +{ + if (handle && handle->zfile) { + return zip_fseek(handle->zfile, offset, whence); + } else if (handle && handle->file) { +#ifdef WIN32 + if (whence == SEEK_SET) { + rewind(handle->file); + } + return (_lseeki64(fileno(handle->file), offset, whence) < 0) ? -1 : 0; +#else + return fseeko(handle->file, offset, whence); +#endif + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} + +int64_t ipsw_file_tell(ipsw_file_handle_t handle) +{ + if (handle && handle->zfile) { + return zip_ftell(handle->zfile); + } else if (handle && handle->file) { +#ifdef WIN32 + return _lseeki64(fileno(handle->file), 0, SEEK_CUR); +#else + return ftello(handle->file); +#endif + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} diff --git a/src/ipsw.h b/src/ipsw.h index 84ea7a9d..96bcb626 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -32,21 +32,44 @@ extern "C" { #include #include +struct ipsw_archive { + struct zip* zip; + char *path; +}; +typedef struct ipsw_archive* ipsw_archive_t; + +ipsw_archive_t ipsw_open(const char* ipsw); +void ipsw_close(ipsw_archive_t ipsw); + int ipsw_print_info(const char* ipsw); -typedef int (*ipsw_list_cb)(void *ctx, const char* ipsw, const char *name, struct stat *stat); +typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat); typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); +struct ipsw_file_handle { + FILE* file; + struct zip_file* zfile; +}; +typedef struct ipsw_file_handle* ipsw_file_handle_t; + +ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path); +void ipsw_file_close(ipsw_file_handle_t handle); + +int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size); +int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence); +int64_t ipsw_file_tell(ipsw_file_handle_t handle); + int ipsw_is_directory(const char* ipsw); -int ipsw_file_exists(const char* ipsw, const char* infile); -int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size); -int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); -int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress); -int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); -int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); -int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); -int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); -int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx); + +int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile); +int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size); +int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile); +int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress); +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); +int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); +int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled); +int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist); +int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx); int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares); int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char** ipswfile); diff --git a/src/restore.c b/src/restore.c index a7072f0a..c1dd92d7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -896,13 +896,26 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem) +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) { asr_client_t asr = NULL; info("About to send filesystem...\n"); + ipsw_file_handle_t file = NULL; + char* fsname = NULL; + if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { + error("ERROR: Unable to get path for filesystem component\n"); + return -1; + } + file = ipsw_file_open(client->ipsw, fsname); + if (!file) { + error("ERROR: Unable to open '%s' in ipsw\n", fsname); + free(fsname); + } + if (asr_open_with_timeout(device, &asr) < 0) { + ipsw_file_close(file); error("ERROR: Unable to connect to ASR\n"); return -1; } @@ -913,7 +926,8 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it info("Validating the filesystem\n"); - if (asr_perform_validation(asr, filesystem) < 0) { + if (asr_perform_validation(asr, file) < 0) { + ipsw_file_close(file); error("ERROR: ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; @@ -923,11 +937,14 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // once the target filesystem has been validated, ASR then requests the // entire filesystem to be sent. info("Sending filesystem now...\n"); - if (asr_send_payload(asr, filesystem) < 0) { + if (asr_send_payload(asr, file) < 0) { + ipsw_file_close(file); error("ERROR: Unable to send payload to ASR\n"); asr_free(asr); return -1; } + ipsw_file_close(file); + info("Done sending filesystem\n"); asr_free(asr); @@ -3275,7 +3292,7 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str return 0; } -static int restore_bootability_send_one(void *ctx, const char *ipsw, const char *name, struct stat *stat) +static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat) { idevice_connection_t connection = (idevice_connection_t)ctx; const char *prefix = "BootabilityBundle/Restore/Bootability/"; @@ -3747,7 +3764,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) { plist_t node = NULL; @@ -3759,7 +3776,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3795,7 +3812,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -4038,7 +4055,7 @@ static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t s } #endif -int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem) +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity) { int err = 0; char* type = NULL; @@ -4361,7 +4378,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem); + err = restore_handle_data_request_msg(client, device, restore, message, build_identity); } // restore logs are available if a previous restore failed diff --git a/src/restore.h b/src/restore.h index ad3b7214..765f3746 100644 --- a/src/restore.h +++ b/src/restore.h @@ -38,7 +38,6 @@ struct restore_client_t { idevice_t device; char* udid; unsigned int operation; - const char* filesystem; uint64_t protocol_version; restored_client_t client; }; @@ -52,13 +51,13 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity); int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name); -int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem); +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem); +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity); int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); #ifdef __cplusplus From cf22a1c0fa5994be2f02ed431461524499b06267 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 29 Sep 2023 10:49:25 +0200 Subject: [PATCH 040/159] tss: Add Ap,SikaFuse to TSS request as seen for iPhone 14/15 devices This is currently implemented as a workaround as the evaluation of when this value should be set is unclear. Right now we set it when UID_MODE is set too. --- src/tss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tss.c b/src/tss.c index 0fa17408..5fd18045 100644 --- a/src/tss.c +++ b/src/tss.c @@ -305,6 +305,14 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); } + // FIXME: I didn't understand yet when this value is set, so for now we use a workaround + if (plist_dict_get_item(parameters, "ApSikaFuse")) { + _plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); + } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + // Workaround: We have only seen Ap,SikaFuse together with UID_MODE + plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); + } + return 0; } From c96f60b8cf4cee0d8a861bf1a924f0f240e04b07 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 15:21:38 +0200 Subject: [PATCH 041/159] restore: Handle SepStage1 (SEPPatchImageData) in NORImageData --- src/restore.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/restore.c b/src/restore.c index c1dd92d7..0fea6e3d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1396,6 +1396,31 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } + if (build_identity_has_component(build_identity, "SepStage1") && + build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + component = "SepStage1"; + ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); + free(sep_path); + if (ret < 0) { + error("ERROR: Unable to extract component: %s\n", component); + return -1; + } + + ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + free(component_data); + component_data = NULL; + component_size = 0; + if (ret < 0) { + error("ERROR: Unable to get personalized component: %s\n", component); + return -1; + } + + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + free(personalized_data); + personalized_data = NULL; + personalized_size = 0; + } + if (idevicerestore_debug) debug_plist(dict); From ca76f44bdda73cb69e3c67f85718656e96b2d56f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 18:45:55 +0200 Subject: [PATCH 042/159] restore: Attributed status code 50 with SEP load failure --- src/restore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/restore.c b/src/restore.c index 0fea6e3d..1b246f84 100644 --- a/src/restore.c +++ b/src/restore.c @@ -742,6 +742,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) case 27: info("Status: Failed to mount filesystems.\n"); break; + case 50: case 51: info("Status: Failed to load SEP Firmware.\n"); break; From 064daea982e92d425a574b20088f445d2091d582 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 18:59:43 +0200 Subject: [PATCH 043/159] restore: Add new SE,ChipID 0x36 to list of known values --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 1b246f84..05ff5af8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2166,7 +2166,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); From e4e551287d15a7d6fc9a0e9e0610e6921e53c0af Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 12:19:01 +0200 Subject: [PATCH 044/159] restore/tss: Prefer DeviceGeneratedRequest for Rose TSS request, and add missing tag --- src/restore.c | 14 ++++++++++---- src/tss.c | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/restore.c b/src/restore.c index 05ff5af8..c6e8a322 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2423,7 +2423,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2458,8 +2458,14 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - /* add Rap,* tags from info dictionary to parameters */ - plist_dict_merge(¶meters, p_info); + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request) { + /* use DeviceGeneratedRequest if present */ + plist_dict_merge(&request, device_generated_request); + } else { + /* add Rap,* tags from info dictionary to parameters */ + plist_dict_merge(¶meters, p_info); + } /* add required tags for Rose TSS request */ tss_request_add_rose_tags(request, parameters, NULL); @@ -3153,7 +3159,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; diff --git a/src/tss.c b/src/tss.c index 5fd18045..670cd0a4 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1167,6 +1167,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr _plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); _plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); _plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); + _plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; From 1405a9f501e023b7edaa2829c0a2254235332703 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 12:23:21 +0200 Subject: [PATCH 045/159] restore: Refine checkpoint log output --- src/restore.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/restore.c b/src/restore.c index c6e8a322..320d5f06 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4439,29 +4439,38 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit else if (!strcmp(type, "CheckpointMsg")) { uint64_t ckpt_id; - uint64_t ckpt_res; + int64_t ckpt_res; uint8_t ckpt_complete = 0; + const char* ckpt_name = NULL; // Get checkpoint id node = plist_dict_get_item(message, "CHECKPOINT_ID"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint id from checkpoint plist\n"); return -1; } plist_get_uint_val(node, &ckpt_id); + // Get checkpoint_name + node = plist_dict_get_item(message, "CHECKPOINT_NAME"); + ckpt_name = (node) ? plist_get_string_ptr(node, NULL) : "unknown"; // Get checkpoint result node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint result from checkpoint plist\n"); return -1; } - plist_get_uint_val(node, &ckpt_res); + plist_get_int_val(node, &ckpt_res); // Get checkpoint complete node = plist_dict_get_item(message, "CHECKPOINT_COMPLETE"); if (PLIST_IS_BOOLEAN(node)) { plist_get_bool_val(node, &ckpt_complete); } - if (ckpt_complete) - info("Checkpoint %" PRIu64 " complete with code %" PRIu64 "\n", ckpt_id, ckpt_res); + + info("Checkpoint %s id: 0x%" PRIX64 " (%s)\n", (ckpt_complete) ? "completed" : "started ", ckpt_id, ckpt_name); + if (ckpt_res != 0) { + node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); + const char* ckpt_error = (node) ? plist_get_string_ptr(node, NULL) : "(unknown)"; + info("Checkpoint FAILED id: 0x%" PRIX64 " error %"PRIi64": %s\n", ckpt_id, ckpt_res, ckpt_error); + } } // baseband update message From 7e5860d249441d0b45e50de2b46475432e3fc908 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 14:39:20 +0200 Subject: [PATCH 046/159] restore: Improve checkpoint log output again, make sure to always check for errors Turns out even with a CHECKPOINT_RESULT of 0 we can still have a CHECKPOINT_ERROR string. --- src/restore.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/restore.c b/src/restore.c index 320d5f06..26a93a02 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4465,11 +4465,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_get_bool_val(node, &ckpt_complete); } - info("Checkpoint %s id: 0x%" PRIX64 " (%s)\n", (ckpt_complete) ? "completed" : "started ", ckpt_id, ckpt_name); - if (ckpt_res != 0) { - node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); - const char* ckpt_error = (node) ? plist_get_string_ptr(node, NULL) : "(unknown)"; - info("Checkpoint FAILED id: 0x%" PRIX64 " error %"PRIi64": %s\n", ckpt_id, ckpt_res, ckpt_error); + if (ckpt_complete) { + info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); + } else { + info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); + } + node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); + if (node) { + info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } } From 523e567f16f45dc3b9a73921d700e026bcc4b94e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 12:12:27 +0200 Subject: [PATCH 047/159] restore: Skip adding FirmwareData to FirmwareResponseData for Rose --- src/restore.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/restore.c b/src/restore.c index 26a93a02..fc7ec9b7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2487,6 +2487,12 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); } + /* skip FirmwareData for newer versions */ + if (client->build_major >= 20) { + debug("DEBUG: Not adding FirmwareData.\n"); + return response; + } + comp_name = "Rap,RTKitOS"; if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); From f17f5208aa04e71915b9961f76fc6c59c454cd91 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 12:24:55 +0200 Subject: [PATCH 048/159] restore: Add Ace3 as known updater name to suppress error message --- src/restore.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/restore.c b/src/restore.c index fc7ec9b7..1d34a184 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3200,6 +3200,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } + } else if (strcmp(s_updater_name, "Ace3") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); From 6806495ca7df744f635be515c5cdf938ad49ea82 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 20:58:13 +0200 Subject: [PATCH 049/159] restore: Also print checkpoint warning messages --- src/restore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/restore.c b/src/restore.c index 1d34a184..8063f080 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4482,6 +4482,10 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } else { info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); } + node = plist_dict_get_item(message, "CHECKPOINT_WARNING"); + if (node) { + info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + } node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); if (node) { info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); From 503bdd01f5e9f16c583ebff343edee8bfaf3f572 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 7 Oct 2023 02:33:03 +0200 Subject: [PATCH 050/159] Improve debug output by suppressing libimobiledevice and libirecovery debug output by default To get libimobiledevice and libirecovery output, add -d or --debug twice. --- src/common.h | 1 + src/idevicerestore.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/common.h b/src/common.h index 5afe5abb..67089434 100644 --- a/src/common.h +++ b/src/common.h @@ -91,6 +91,7 @@ struct idevicerestore_entry_t { struct idevicerestore_client_t { int flags; + int debug_level; plist_t tss; plist_t tss_localpolicy; plist_t tss_recoveryos_root_ticket; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 7b69a9f0..56207a07 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -341,10 +341,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(1); - irecv_set_debug_level(1); + if (client->debug_level > 0) { idevicerestore_debug = 1; + if (client->debug_level > 1) { + idevice_set_debug_level(1); + irecv_set_debug_level(1); + } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); @@ -1483,6 +1485,7 @@ int main(int argc, char* argv[]) { case 'd': client->flags |= FLAG_DEBUG; + client->debug_level++; break; case 'e': From 4072cd965eab44993700b980d8848b46ec3be72e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 9 Oct 2023 11:32:30 +0200 Subject: [PATCH 051/159] tss: Add USBPortController1,* entries to parameters --- src/tss.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tss.c b/src/tss.c index 670cd0a4..5e676f4b 100644 --- a/src/tss.c +++ b/src/tss.c @@ -245,6 +245,10 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + node = plist_dict_get_item(build_identity, "Info"); if (node) { _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); From c871c591e36d2a4083e3dda4c70144a0321ce70f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 Nov 2023 12:54:47 +0100 Subject: [PATCH 052/159] Extract OS component when using older ipsw archives Older ipsw archives have the root filesystem stored in compressed format rather than just "stored". The "Verifying Filesystem" step would then fail as compressed files are not seekable in ZIP files. This commit introduces a detection for this and has the filesystem extracted should it be required. If not using a cache path, the temp file used for extraction will be deleted after the procedure is completed. --- src/asr.c | 18 ++++++----- src/common.c | 17 ++++++++++ src/common.h | 4 +++ src/idevicerestore.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ src/ipsw.c | 20 ++++++++++-- src/ipsw.h | 3 ++ src/restore.c | 17 +++++++++- 7 files changed, 143 insertions(+), 11 deletions(-) diff --git a/src/asr.c b/src/asr.c index b2aeaf50..304e8a32 100644 --- a/src/asr.c +++ b/src/asr.c @@ -216,9 +216,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) plist_t payload_info = NULL; int attempts = 0; - ipsw_file_seek(file, 0, SEEK_END); - length = ipsw_file_tell(file); - ipsw_file_seek(file, 0, SEEK_SET); + length = ipsw_file_size(file); payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); @@ -313,9 +311,14 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_hand return -1; } - ipsw_file_seek(file, oob_offset, SEEK_SET); - if (ipsw_file_read(file, oob_data, oob_length) != oob_length) { - error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno)); + if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) { + error("ERROR: Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset); + free(oob_data); + return -1; + } + int64_t ir = ipsw_file_read(file, oob_data, oob_length); + if (ir != oob_length) { + error("ERROR: Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir); free(oob_data); return -1; } @@ -335,8 +338,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) uint64_t i, length, bytes = 0; double progress = 0; - ipsw_file_seek(file, 0, SEEK_END); - length = ipsw_file_tell(file); + length = ipsw_file_size(file); ipsw_file_seek(file, 0, SEEK_SET); data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); diff --git a/src/common.c b/src/common.c index 068f2ddb..0ad775ce 100644 --- a/src/common.c +++ b/src/common.c @@ -695,3 +695,20 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * plist_dict_set_item(target_dict, key, plist_copy(node)); return 0; } + +char* path_get_basename(char* path) +{ +#ifdef WIN32 + char *p = path + strlen(path); + while (p > path) { + if ((*p == '/') || (*p == '\\')) { + return p+1; + } + p--; + } + return p; +#else + char *p = strrchr(path, '/'); + return p ? p + 1 : path; +#endif +} diff --git a/src/common.h b/src/common.h index 67089434..c2a96b0a 100644 --- a/src/common.h +++ b/src/common.h @@ -128,6 +128,8 @@ struct idevicerestore_client_t { int ignore_device_add_events; plist_t macos_variant; char* restore_variant; + char* filesystem; + int delete_fs; }; extern struct idevicerestore_mode_t idevicerestore_modes[]; @@ -193,6 +195,8 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); +char* path_get_basename(char* path); + #ifdef __cplusplus } #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 56207a07..dc7750bd 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -45,6 +45,8 @@ #define SHA384 sha384 #endif +#include + #include "dfu.h" #include "tss.h" #include "img3.h" @@ -950,6 +952,73 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } info("All required components found in IPSW\n"); + /* Get OS (filesystem) name from build identity */ + char* os_path = NULL; + if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) { + error("ERROR: Unable to get path for filesystem component\n"); + return -1; + } + + /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */ + int needs_os_extraction = 0; + if (client->ipsw->zip) { + ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path); + if (zfile) { + if (!zfile->seekable) { + needs_os_extraction = 1; + } + ipsw_file_close(zfile); + } + } + + if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) { + char* tmpf = NULL; + struct stat st; + if (client->cache_dir) { + memset(&st, '\0', sizeof(struct stat)); + if (stat(client->cache_dir, &st) < 0) { + mkdir_with_parents(client->cache_dir, 0755); + } + char* ipsw_basename = path_get_basename(client->ipsw->path); + ipsw_basename = strdup(ipsw_basename); + char* p = strrchr(ipsw_basename, '.'); + if (p && isalpha(*(p+1))) { + *p = '\0'; + } + tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL); + mkdir_with_parents(tmpf, 0755); + free(tmpf); + tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL); + free(ipsw_basename); + } else { + tmpf = get_temp_filename(NULL); + client->delete_fs = 1; + } + + /* check if we already have it extracted */ + uint64_t fssize = 0; + ipsw_get_file_size(client->ipsw, os_path, &fssize); + memset(&st, '\0', sizeof(struct stat)); + if (stat(tmpf, &st) == 0) { + if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { + info("Using cached filesystem from '%s'\n", tmpf); + client->filesystem = tmpf; + } + } + + if (!client->filesystem) { + info("Extracting filesystem from IPSW: %s\n", os_path); + if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) { + error("ERROR: Unable to extract filesystem from IPSW\n"); + info("Removing %s\n", tmpf); + unlink(tmpf); + free(tmpf); + return -1; + } + client->filesystem = tmpf; + } + } + idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2); /* retrieve shsh blobs if required */ @@ -1338,6 +1407,12 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) if (client->ipsw) { ipsw_close(client->ipsw); } + if (client->filesystem) { + if (client->delete_fs) { + unlink(client->filesystem); + } + free(client->filesystem); + } if (client->version) { free(client->version); } diff --git a/src/ipsw.c b/src/ipsw.c index 58d817c6..5b1d7323 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -1308,7 +1308,8 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) { ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, path, 0); + zip_stat_t zst; + zip_int64_t zindex = zip_name_locate(ipsw->zip, path, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s not found\n", path); free(handle); @@ -1320,8 +1321,12 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) free(handle); return NULL; } - + zip_stat_init(&zst); + zip_stat(ipsw->zip, path, 0, &zst); + handle->size = zst.size; + handle->seekable = (zst.comp_method == ZIP_CM_STORE); } else { + struct stat st; char *filepath = build_path(ipsw->path, path); handle->file = fopen(filepath, "rb"); free(filepath); @@ -1330,6 +1335,9 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) free(handle); return NULL; } + fstat(fileno(handle->file), &st); + handle->size = st.st_size; + handle->seekable = 1; } return handle; } @@ -1344,6 +1352,14 @@ void ipsw_file_close(ipsw_file_handle_t handle) free(handle); } +uint64_t ipsw_file_size(ipsw_file_handle_t handle) +{ + if (handle) { + return handle->size; + } + return 0; +} + int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size) { if (handle && handle->zfile) { diff --git a/src/ipsw.h b/src/ipsw.h index 96bcb626..56faf942 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -49,12 +49,15 @@ typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); struct ipsw_file_handle { FILE* file; struct zip_file* zfile; + uint64_t size; + int seekable; }; typedef struct ipsw_file_handle* ipsw_file_handle_t; ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path); void ipsw_file_close(ipsw_file_handle_t handle); +uint64_t ipsw_file_size(ipsw_file_handle_t handle); int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size); int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence); int64_t ipsw_file_tell(ipsw_file_handle_t handle); diff --git a/src/restore.c b/src/restore.c index 8063f080..9e0268a2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #ifdef HAVE_REVERSE_PROXY #include @@ -903,13 +904,23 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("About to send filesystem...\n"); + ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { error("ERROR: Unable to get path for filesystem component\n"); return -1; } - file = ipsw_file_open(client->ipsw, fsname); + if (client->filesystem) { + char* path = strdup(client->filesystem); + char* fsname_base = path_get_basename(path); + char* parent_dir = dirname(path); + ipsw_dummy = ipsw_open(parent_dir); + free(path); + file = ipsw_file_open(ipsw_dummy, fsname_base); + } else { + file = ipsw_file_open(client->ipsw, fsname); + } if (!file) { error("ERROR: Unable to open '%s' in ipsw\n", fsname); free(fsname); @@ -917,6 +928,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de if (asr_open_with_timeout(device, &asr) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); return -1; } @@ -929,6 +941,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("Validating the filesystem\n"); if (asr_perform_validation(asr, file) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; @@ -940,11 +953,13 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("Sending filesystem now...\n"); if (asr_send_payload(asr, file) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to send payload to ASR\n"); asr_free(asr); return -1; } ipsw_file_close(file); + ipsw_close(ipsw_dummy); info("Done sending filesystem\n"); From 8664de040b36518c2b1b76edb9cbf9e5a8613965 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 7 Nov 2023 14:45:04 +0100 Subject: [PATCH 053/159] Print device Product and Build Version and IPSW Product and Build Version It wasn't entirely clear what "Product Version" and "Product Build" would be so prefixing it with "IPSW" makes it clear it's the version being restored. --- src/common.h | 2 ++ src/idevicerestore.c | 42 ++++++++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/common.h b/src/common.h index c2a96b0a..f7b1dcd1 100644 --- a/src/common.h +++ b/src/common.h @@ -114,6 +114,8 @@ struct idevicerestore_client_t { struct idevicerestore_mode_t* mode; char* version; char* build; + char* device_version; + char* device_build; int build_major; char* restore_boot_args; char* cache_dir; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index dc7750bd..b2185103 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -478,6 +478,21 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } + if (client->mode == MODE_NORMAL) { + plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_version); + plist_free(pver); + } + pver = normal_get_lockdown_value(client, NULL, "BuildVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_build); + plist_free(pver); + } + } + info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A"); + info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); + if (client->flags & FLAG_PWN) { recovery_client_free(client); @@ -678,8 +693,8 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* print iOS information from the manifest */ build_manifest_get_version_information(client->build_manifest, client); - info("Product Version: %s\n", client->version); - info("Product Build: %s Major: %d\n", client->build, client->build_major); + info("IPSW Product Version: %s\n", client->version); + info("IPSW Product Build: %s Major: %d\n", client->build, client->build_major); client->image4supported = is_image4_supported(client); info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); @@ -872,17 +887,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { - plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); - char *device_version = NULL; - if (pver) { - plist_get_string_val(pver, &device_version); - plist_free(pver); - } - if (device_version && (compare_versions(device_version, client->version) > 0)) { + if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) { if (client->flags & FLAG_INTERACTIVE) { char input[64]; char spaces[16]; - int num_spaces = 13 - strlen(client->version) - strlen(device_version); + int num_spaces = 13 - strlen(client->version) - strlen(client->device_version); memset(spaces, ' ', num_spaces); spaces[num_spaces] = '\0'; printf("################################ [ WARNING ] #################################\n" @@ -893,7 +902,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) "# If you want to take the risk (and have a backup of your important data!) #\n" "# type YES and press ENTER to continue. You have been warned. #\n" "##############################################################################\n", - device_version, client->version, spaces); + client->device_version, client->version, spaces); while (1) { printf("> "); fflush(stdout); @@ -912,7 +921,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } } - free(device_version); } if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) { @@ -1413,12 +1421,10 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) } free(client->filesystem); } - if (client->version) { - free(client->version); - } - if (client->build) { - free(client->build); - } + free(client->version); + free(client->build); + free(client->device_version); + free(client->device_build); if (client->restore_boot_args) { free(client->restore_boot_args); } From f87ab8baee1c78ba5d3ab6dde4da44ecb93086c4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Nov 2023 11:37:38 +0100 Subject: [PATCH 054/159] .gitignore: Add src/idevicerestore.exe --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a826b421..bdfaa099 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ py-compile stamp-h1 src/.libs src/idevicerestore +src/idevicerestore.exe From 6085ed7429986c7dec579fe1f1303ae6651ea1f2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Nov 2023 01:56:08 +0100 Subject: [PATCH 055/159] Print progress for large components (e.g. Cryptex) --- src/common.c | 2 +- src/idevicerestore.h | 1 + src/ipsw.c | 8 ++++---- src/ipsw.h | 2 +- src/restore.c | 41 ++++++++++++++++++++++++++++++++++------- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/common.c b/src/common.c index 0ad775ce..bb534e22 100644 --- a/src/common.c +++ b/src/common.c @@ -467,7 +467,7 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d client->progress_cb(step, progress, client->progress_cb_data); } else { // we don't want to be too verbose in regular idevicerestore. - if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) { + if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW) || (step == RESTORE_STEP_UPLOAD_IMG)) { print_progress_bar(100.0 * progress); } } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 880562ff..e1a767cb 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -63,6 +63,7 @@ enum { RESTORE_STEP_FLASH_FW, RESTORE_STEP_FLASH_BB, RESTORE_STEP_FUD, + RESTORE_STEP_UPLOAD_IMG, RESTORE_NUM_STEPS }; diff --git a/src/ipsw.c b/src/ipsw.c index 5b1d7323..c25f61d3 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -737,7 +737,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip // EOF break; } - if (send_callback(ctx, buffer, zr) < 0) { + if (send_callback(ctx, buffer, zr, done, total_size) < 0) { error("ERROR: %s: send failed\n", __func__); break; } @@ -773,7 +773,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip free(buffer); return -1; } - send_callback(ctx, buffer, (size_t)rl); + send_callback(ctx, buffer, (size_t)rl, 0, 0); } else { #endif FILE *f = fopen(filepath, "rb"); @@ -792,7 +792,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); break; } - if (send_callback(ctx, buffer, fr) < 0) { + if (send_callback(ctx, buffer, fr, done, total_size) < 0) { error("ERROR: %s: send failed\n", __func__); break; } @@ -812,7 +812,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip } // send a NULL buffer to mark end of transfer - send_callback(ctx, NULL, 0); + send_callback(ctx, NULL, 0, done, total_size); return 0; } diff --git a/src/ipsw.h b/src/ipsw.h index 56faf942..f0e11a12 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -44,7 +44,7 @@ void ipsw_close(ipsw_archive_t ipsw); int ipsw_print_info(const char* ipsw); typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat); -typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); +typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, size_t total_size); struct ipsw_file_handle { FILE* file; diff --git a/src/restore.c b/src/restore.c index 9e0268a2..7727411d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3537,7 +3537,13 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil return 0; } -static int _restore_send_file_data(restored_client_t restore, void* data, size_t size) +struct _restore_send_file_data_ctx { + struct idevicerestore_client_t* client; + restored_client_t restore; + int last_progress; +}; + +static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) { plist_t dict = plist_new_dict(); if (data != NULL) { @@ -3547,13 +3553,21 @@ static int _restore_send_file_data(restored_client_t restore, void* data, size_t // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); } - restored_error_t restore_error = restored_send(restore, dict); + restored_error_t restore_error = restored_send(rctx->restore, dict); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); + if (total_size > 0) { + double progress = (double)done / (double)total_size; + int progress_int = (int)(progress*100.0); + if (progress_int > rctx->last_progress) { + idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress); + rctx->last_progress = progress_int; + } + } return 0; } @@ -3643,12 +3657,17 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } - info("Sending %s now...\n", component); + info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.restore = restore; + rctx.last_progress = 0; int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - if (_restore_send_file_data(restore, (data + size - i), blob_size) < 0) { + if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { free(data); error("ERROR: Unable to send component %s data\n", component); return -1; @@ -3657,7 +3676,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } free(data); - _restore_send_file_data(restore, NULL, 0); + _restore_send_file_data(&rctx, NULL, 0, size-i, size); info("Done sending %s\n", component); return 0; @@ -3733,9 +3752,17 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - info("Sending %s now...\n", component); + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); + + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.restore = restore; + rctx.last_progress = 0; - if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, restore) < 0) { + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); error("ERROR: Failed to send component %s\n", component); return -1; From 10c15d596eb54c9b97cd7e6323ac8416349ca225 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Nov 2023 20:25:38 +0100 Subject: [PATCH 056/159] Fix update restore by making sure the premanifest is properly generated --- src/idevicerestore.c | 4 ++-- src/img4.c | 11 +++++------ src/tss.c | 31 +++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index b2185103..9bc9f8b4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1981,7 +1981,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ plist_t overrides = plist_new_dict(); plist_dict_set_item(overrides, "@APTicket", plist_new_bool(1)); plist_dict_set_item(overrides, "ApProductionMode", plist_new_uint(0)); - plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(0)); + plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(1)); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(0)); plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(0)); @@ -2005,7 +2005,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ return -1; } - plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); + plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1)); /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { diff --git a/src/img4.c b/src/img4.c index c21a0753..56b04964 100644 --- a/src/img4.c +++ b/src/img4.c @@ -844,13 +844,12 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* comp = _img4_get_component_tag(key); } if (!comp) { - error("ERROR: %s: Unhandled component '%s' - can't create manifest\n", __func__, key); - free(iter); - free(buf); - return -1; + debug("DEBUG: %s: Unhandled component '%s'\n", __func__, key); + _manifest_write_component(&p, &length, key, val); + } else { + debug("DEBUG: found component %s (%s)\n", comp, key); + _manifest_write_component(&p, &length, comp, val); } - debug("DEBUG: found component %s (%s)\n", comp, key); - _manifest_write_component(&p, &length, comp, val); } free(key); } while (val); diff --git a/src/tss.c b/src/tss.c index 5e676f4b..e9d68f39 100644 --- a/src/tss.c +++ b/src/tss.c @@ -582,8 +582,15 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ continue; } - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key); + if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") + && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + && !_plist_dict_get_bool(info_dict, "IsFUDFirmware") + && !_plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + && !_plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + && !_plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + && !_plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) + { + debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; } } @@ -679,14 +686,26 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } } - if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + int is_fw_payload = _plist_dict_get_bool(info_dict, "IsFirmwarePayload") + || _plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + || _plist_dict_get_bool(info_dict, "IsFUDFirmware") + || _plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + || _plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + || _plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + || _plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); + + if (_plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { + if (!_plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { + debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); + continue; + } + } else if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } - - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key); + if (!is_fw_payload) { + debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; } } From 85ea3378255cc15e3f39365018f45a42d7469375 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:14:43 +0100 Subject: [PATCH 057/159] asr: Fix sending payload without checksum --- src/asr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/asr.c b/src/asr.c index 304e8a32..bf15dc21 100644 --- a/src/asr.c +++ b/src/asr.c @@ -349,11 +349,12 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) SHA1_Init(&sha1); } - int size = 0; i = length; int retry = 3; while(i > 0 && retry >= 0) { - size = ASR_PAYLOAD_CHUNK_SIZE; + uint32_t size = ASR_PAYLOAD_CHUNK_SIZE; + uint32_t sendsize = 0; + if (i < ASR_PAYLOAD_CHUNK_SIZE) { size = i; } @@ -364,11 +365,12 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) continue; } + sendsize = size; if (asr->checksum_chunks) { SHA1((unsigned char*)data, size, (unsigned char*)(data+size)); + sendsize += 20; } - - if (asr_send_buffer(asr, data, size+20) < 0) { + if (asr_send_buffer(asr, data, sendsize) < 0) { error("ERROR: Unable to send filesystem payload\n"); retry--; continue; From 83600e92240cd2538cd82f90ed03601731b1b0d9 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:41:21 +0100 Subject: [PATCH 058/159] restore: Fix UaF `fsname_base` points inside the dynamically allocated `path` which is freed before `fsname_base` is used, creating a use-after-free condition. This commits makes sure to free `path` only after it is no longer needed. --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index 7727411d..7fa104bc 100644 --- a/src/restore.c +++ b/src/restore.c @@ -913,11 +913,11 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de } if (client->filesystem) { char* path = strdup(client->filesystem); - char* fsname_base = path_get_basename(path); + const char* fsname_base = path_get_basename(path); char* parent_dir = dirname(path); ipsw_dummy = ipsw_open(parent_dir); - free(path); file = ipsw_file_open(ipsw_dummy, fsname_base); + free(path); } else { file = ipsw_file_open(client->ipsw, fsname); } From acecac3cb8b66fddd9dc811c920c6b7dfb969895 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:45:53 +0100 Subject: [PATCH 059/159] Change path_get_basename()'s return type to const char* This makes it clear that the return value is immutable and moreover suggests that the return vale is not allocated and thus should be treated carefully. --- src/common.c | 6 +++--- src/common.h | 2 +- src/idevicerestore.c | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/common.c b/src/common.c index bb534e22..c3c9d685 100644 --- a/src/common.c +++ b/src/common.c @@ -696,10 +696,10 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * return 0; } -char* path_get_basename(char* path) +const char* path_get_basename(char* path) { #ifdef WIN32 - char *p = path + strlen(path); + const char *p = path + strlen(path); while (p > path) { if ((*p == '/') || (*p == '\\')) { return p+1; @@ -708,7 +708,7 @@ char* path_get_basename(char* path) } return p; #else - char *p = strrchr(path, '/'); + const char *p = strrchr(path, '/'); return p ? p + 1 : path; #endif } diff --git a/src/common.h b/src/common.h index f7b1dcd1..974d5054 100644 --- a/src/common.h +++ b/src/common.h @@ -197,7 +197,7 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -char* path_get_basename(char* path); +const char* path_get_basename(char* path); #ifdef __cplusplus } diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 9bc9f8b4..064c5030 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -987,8 +987,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (stat(client->cache_dir, &st) < 0) { mkdir_with_parents(client->cache_dir, 0755); } - char* ipsw_basename = path_get_basename(client->ipsw->path); - ipsw_basename = strdup(ipsw_basename); + char* ipsw_basename = strdup(path_get_basename(client->ipsw->path)); char* p = strrchr(ipsw_basename, '.'); if (p && isalpha(*(p+1))) { *p = '\0'; From ecae6c6e8ca6b6bad080a1c73f10ffd0e67d75a7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 15 Nov 2023 13:29:16 +0100 Subject: [PATCH 060/159] Change path_get_basename arg to const too --- src/common.c | 2 +- src/common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common.c b/src/common.c index c3c9d685..9a739940 100644 --- a/src/common.c +++ b/src/common.c @@ -696,7 +696,7 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * return 0; } -const char* path_get_basename(char* path) +const char* path_get_basename(const char* path) { #ifdef WIN32 const char *p = path + strlen(path); diff --git a/src/common.h b/src/common.h index 974d5054..493b1df4 100644 --- a/src/common.h +++ b/src/common.h @@ -197,7 +197,7 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -const char* path_get_basename(char* path); +const char* path_get_basename(const char* path); #ifdef __cplusplus } From c6a9359f7f1bd532d51fbab79f47e230afe6f5f5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 21 Nov 2023 00:33:48 +0100 Subject: [PATCH 061/159] Update libzip API usage to use non-deprecated functions --- src/restore.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/restore.c b/src/restore.c index 7fa104bc..772f57fd 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1515,7 +1515,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned uint64_t fsize = 0; uint64_t blob_size = 0; int zerr = 0; - int zindex = -1; + int64_t zindex = -1; struct zip_stat zstat; struct zip_file* zfile = NULL; struct zip* za = NULL; @@ -1537,7 +1537,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } int is_fls = 0; - int signed_file_idxs[16]; + int64_t signed_file_idxs[16]; int signed_file_count = 0; char* key = NULL; plist_t node = NULL; @@ -1566,13 +1566,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1652,7 +1652,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update signed '%s' in archive\n", signfn); goto leave; } @@ -1670,9 +1670,10 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(iter); // remove everything but required files - int i, j, keep, numf = zip_get_num_files(za); + int64_t i, numf = zip_get_num_entries(za, 0); for (i = 0; i < numf; i++) { - keep = 0; + int j; + int keep = 0; // check for signed file index for (j = 0; j < signed_file_count; j++) { if (i == signed_file_idxs[j]) { @@ -1706,13 +1707,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1771,7 +1772,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update archive with ticketed ebl.fls\n"); goto leave; } @@ -1792,7 +1793,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } blob = NULL; - if (zip_add(za, "bbticket.der", zs) == -1) { + if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { error("ERROR: could not add bbticket.der to archive\n"); goto leave; } From 8a5abb99170b324b0fc5a00928ba2ac78a7afc98 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 27 Nov 2023 00:14:27 +0800 Subject: [PATCH 062/159] restore: Only print progress bar for images larger than 16 MB --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 772f57fd..1261147f 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3561,7 +3561,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return -1; } plist_free(dict); - if (total_size > 0) { + if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; int progress_int = (int)(progress*100.0); if (progress_int > rctx->last_progress) { From 14fc14a2a0e9ba0e224b6bc318b8fa773a8dad8c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 13 Jan 2024 12:12:30 +0100 Subject: [PATCH 063/159] [github-actions] Windows: build with static libcurl --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a92883b..75eac9a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" + run: ./autogen.sh CC=gcc CXX=g++ libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="-I/${{env.dest}}/include -DCURL_STATICLIB" libcurl_LIBS="/${{env.dest}}/lib/libcurl.a /${{env.dest}}/lib/libssh2.a /${{env.dest}}/lib/libpsl.a /${{env.dest}}/lib/libidn2.a /${{env.dest}}/lib/libunistring.a /${{env.dest}}/lib/libnghttp2.a /${{env.dest}}/lib/libbrotlidec.a /${{env.dest}}/lib/libbrotlicommon.a /${{env.dest}}/lib/libiconv.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" - name: make run: make - name: make install From a2b8443b48dd885a9059e6e051ff0d6c36ef8f46 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jan 2024 00:29:49 +0100 Subject: [PATCH 064/159] libcurl build --- .github/workflows/curl.yml | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/curl.yml diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml new file mode 100644 index 00000000..a2974762 --- /dev/null +++ b/.github/workflows/curl.yml @@ -0,0 +1,58 @@ +name: build-libcurl-static + +on: [push] + +jobs: + build-windows: + runs-on: windows-2019 + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + include: [ + { msystem: MINGW64, arch: x86_64 }, + { msystem: MINGW32, arch: i686 } + ] + steps: + - uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.msystem }} + release: false + update: false + install: >- + base-devel + git + mingw-w64-${{ matrix.arch }}-gcc + make + libtool + autoconf + automake-wrapper + liblzma + - name: prepare environment + run: | + dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]` + echo "dest=$dest" >> $GITHUB_ENV + echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV + - name: fetch curl source + run: | + curl -Ls -o curl-8.1.0.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_1_0/curl-8.1.0.tar.bz2 + tar xjf curl-8.1.0.tar.bz2 + - name: configure curl + run: | + cd curl-8.1.0 + ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-bindlocal --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl + - name: build libcurl + run: | + CURDIR=`pwd` + cd curl-8.1.0/lib + make + cp .libs/libcurl.a . + cd .. + tar cf $CURDIR/libcurl-static.tar lib/libcurl.a include/curl/*.h + - name: publish artifact + uses: actions/upload-artifact@v3 + with: + name: libcurl_${{ matrix.arch }}-${{ env.dest }} + path: libcurl-static.tar From cba2d5e0a918184c0145e371eb3dd9e4ae52cd7b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jan 2024 00:59:16 +0100 Subject: [PATCH 065/159] update build --- .github/workflows/build.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 75eac9a3..696dcda8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -270,8 +270,17 @@ jobs: tar -C deps -xjf $FILENAME echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV + FILENAME="libcurl-8.1.0-static.tar.bz2" + curl -o $FILENAME.b64 -Ls "https://gist.github.com/nikias/6c397a0a2f4f4eafd91b81cccd22b761/raw/85216e60af6787f3b351291165eb91bd585ff09a/libcurl-8.1.0-static-${{matrix.arch}}-${{env.dest}}.tar.bz2" + base64 -d < $FILENAME.b64 > $FILENAME + tar -C deps -xjf $FILENAME + echo "LIBCURL_CFLAGS=-I`pwd`/deps/include -DCURL_STATICLIB" >> $GITHUB_ENV + echo "LIBCURL_LIBS=`pwd`/deps/lib/libcurl.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="-I/${{env.dest}}/include -DCURL_STATICLIB" libcurl_LIBS="/${{env.dest}}/lib/libcurl.a /${{env.dest}}/lib/libssh2.a /${{env.dest}}/lib/libpsl.a /${{env.dest}}/lib/libidn2.a /${{env.dest}}/lib/libunistring.a /${{env.dest}}/lib/libnghttp2.a /${{env.dest}}/lib/libbrotlidec.a /${{env.dest}}/lib/libbrotlicommon.a /${{env.dest}}/lib/libiconv.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" + run: | + ./autogen.sh CC=gcc CXX=g++ \ + libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" \ + zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="${{env.LIBCURL_CFLAGS}}" libcurl_LIBS="$LIBCURL_LIBS" - name: make run: make - name: make install From fdbf383a52111014f7e41fde0f1e8ee209679412 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 8 Mar 2024 12:23:03 +0100 Subject: [PATCH 066/159] Make sure to extract the build manifest before doing restore mode checks Otherwise we could set tss_enabled to 0 but the extraction would re-enable it. --- src/idevicerestore.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 064c5030..af5dbf3e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -642,6 +642,21 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return 0; } + // extract buildmanifest + if (client->flags & FLAG_CUSTOM) { + info("Extracting Restore.plist from IPSW\n"); + if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { + error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } else { + info("Extracting BuildManifest from IPSW\n"); + if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } + if (client->mode == MODE_RESTORE) { if (client->flags & FLAG_ALLOW_RESTORE_MODE) { tss_enabled = 0; @@ -668,20 +683,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - // extract buildmanifest - if (client->flags & FLAG_CUSTOM) { - info("Extracting Restore.plist from IPSW\n"); - if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); - return -1; - } - } else { - info("Extracting BuildManifest from IPSW\n"); - if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); - return -1; - } - } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8); /* check if device type is supported by the given build manifest */ From 012e0aa3d458a44ae3808707b9d5b6038d9095a6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 00:49:55 +0100 Subject: [PATCH 067/159] Fix some variable types for more consistency --- src/dfu.c | 6 +++--- src/dfu.h | 4 ++-- src/idevicerestore.c | 14 +++++++------- src/idevicerestore.h | 4 ++-- src/normal.c | 8 ++++---- src/normal.h | 4 ++-- src/recovery.c | 4 ++-- src/recovery.h | 4 ++-- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 4487ade0..8602bc0c 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -238,7 +238,7 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } -int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -263,7 +263,7 @@ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** non return 0; } -int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -417,7 +417,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide /* get nonce */ unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get ApNonce from device!\n"); diff --git a/src/dfu.h b/src/dfu.h index 67124429..f6174abb 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -44,8 +44,8 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); int dfu_is_image4_supported(struct idevicerestore_client_t* client); -int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index af5dbf3e..e71dea4e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1064,7 +1064,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->build_major > 8) { unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { /* the first nonce request with older firmware releases can fail and it's OK */ info("NOTE: Unable to get nonce from device\n"); @@ -1265,7 +1265,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!client->image4supported && (client->build_major > 8)) { // we need another tss request with nonce. unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); @@ -1810,7 +1810,7 @@ int is_image4_supported(struct idevicerestore_client_t* client) return res; } -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -1861,7 +1861,7 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, return 0; } -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -2102,7 +2102,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { @@ -2226,7 +2226,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); /* ApSepNonce */ @@ -2405,7 +2405,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index e1a767cb..5afcf1af 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -93,8 +93,8 @@ const char* idevicerestore_get_error(void); irecv_device_t get_irecv_device(struct idevicerestore_client_t* client); int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); int is_image4_supported(struct idevicerestore_client_t* client); -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int get_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); diff --git a/src/normal.c b/src/normal.c index b7f9f9d7..efe8f03d 100644 --- a/src/normal.c +++ b/src/normal.c @@ -323,7 +323,7 @@ plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const return node; } -static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, int* nonce_size) +static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, unsigned int* nonce_size) { plist_t nonce_node = normal_get_lockdown_value(client, NULL, key); @@ -334,18 +334,18 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const uint64_t n_size = 0; plist_get_data_val(nonce_node, (char**)nonce, &n_size); - *nonce_size = (int)n_size; + *nonce_size = (unsigned int)n_size; plist_free(nonce_node); return 0; } -int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { return normal_get_nonce_by_key(client, "SEPNonce", nonce, nonce_size); } -int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { return normal_get_nonce_by_key(client, "ApNonce", nonce, nonce_size); } diff --git a/src/normal.h b/src/normal.h index 85464dbc..7741ac5f 100644 --- a/src/normal.h +++ b/src/normal.h @@ -36,8 +36,8 @@ int normal_check_mode(struct idevicerestore_client_t* client); irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client); int normal_enter_recovery(struct idevicerestore_client_t* client); int normal_is_image4_supported(struct idevicerestore_client_t* client); -int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const char* domain, const char* key); int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest); diff --git a/src/recovery.c b/src/recovery.c index 02f56898..e3fb4d19 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -537,7 +537,7 @@ int recovery_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } -int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->recovery == NULL) { if (recovery_client_new(client) < 0) { @@ -562,7 +562,7 @@ int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char* return 0; } -int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->recovery == NULL) { if (recovery_client_new(client) < 0) { diff --git a/src/recovery.h b/src/recovery.h index 92214af3..d7413e0c 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -55,8 +55,8 @@ int recovery_send_reset(struct idevicerestore_client_t* client); int recovery_send_ticket(struct idevicerestore_client_t* client); int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable); int recovery_is_image4_supported(struct idevicerestore_client_t* client); -int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); #ifdef __cplusplus From babf9add7f1f5df7d8093e7d26d73b674ecd246b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 01:06:37 +0100 Subject: [PATCH 068/159] tss: Update libauthinstall verison string --- src/tss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tss.c b/src/tss.c index e9d68f39..80591e7f 100644 --- a/src/tss.c +++ b/src/tss.c @@ -35,7 +35,7 @@ #include "endianness.h" -#define AUTH_VERSION "914.120.2" +#define AUTH_VERSION "973.40.2" #ifdef WIN32 #define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" From e4a5ac4114177293e3a1b555ee767377b21d4432 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 04:25:21 +0100 Subject: [PATCH 069/159] Add support for Port DFU device restore --- configure.ac | 4 +- src/Makefile.am | 1 + src/ace3.c | 244 +++++++++++++++++++++++++++++++++++++++++++ src/ace3.h | 17 +++ src/common.c | 1 + src/common.h | 2 + src/dfu.c | 83 +++++++++++++++ src/dfu.h | 4 + src/idevicerestore.c | 157 ++++++++++++++++++++++++++++ 9 files changed, 511 insertions(+), 2 deletions(-) create mode 100644 src/ace3.c create mode 100644 src/ace3.h diff --git a/configure.ac b/configure.ac index 572e2804..1cd58444 100644 --- a/configure.ac +++ b/configure.ac @@ -15,11 +15,11 @@ if test -z $PACKAGE_VERSION; then fi # Minimum package versions -LIBIRECOVERY_VERSION=1.0.1 +LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.3.0 -LIMD_GLUE_VERSION=1.0.0 +LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 diff --git a/src/Makefile.am b/src/Makefile.am index 019424ba..722487a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,7 @@ idevicerestore_SOURCES = \ restore.c restore.h \ asr.c asr.h \ fdr.c fdr.h \ + ace3.c ace3.h \ limera1n_payload.h \ limera1n.c limera1n.h \ download.c download.h \ diff --git a/src/ace3.c b/src/ace3.c new file mode 100644 index 00000000..b96e6b4f --- /dev/null +++ b/src/ace3.c @@ -0,0 +1,244 @@ +/* + * ace3.c + * Functions to handle Ace3/uarp firmware format + * + * Copyright (c) 2024 Nikias Bassen, 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 +#include +#include +#include + +#include "common.h" +#include "ace3.h" +#include "endianness.h" + +static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, unsigned int salt) +{ + uint32_t result; + unsigned int i; + unsigned int j; + + if ( !buffer ) + return 0xFFFFFFFF; + result = salt; + for (i = 0; i < bufsize; ++i) { + for (j = 0; j != 8; ++j) { + unsigned int tmp0 = 2 * result; + unsigned int tmp1 = *(unsigned char*)(buffer + i); + unsigned int tmp2 = ((unsigned int)result >> 31) ^ ((tmp1 >> j) & 1); + result = (tmp2 + 2 * result) ^ 0x4C11DB6; + if (!tmp2) + result = tmp0; + } + } + return result; +} + +int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size) +{ + struct ace3bin_header { + uint32_t magic; // 0xACE00003 + uint32_t unk4; // 0x00203400 + uint32_t unk8; // 0x00002800 + uint32_t header_size; // 0x00000040 + uint32_t data1_size; + uint32_t data2_size; + uint32_t im4m_offset; + uint32_t im4m_dl_size; + uint32_t content_size; + uint32_t crc; + uint64_t fill1; // 0xFFFFFFFFFFFFFFFF + uint64_t fill2; // 0xFFFFFFFFFFFFFFFF + uint64_t fill3; // 0xFFFFFFFFFFFFFFFF + }; + + struct uarp_header { + uint32_t unk_00; // BE 0x00000002 + uint32_t header_size; // BE usually 0x0000002C + uint32_t plist_offset; // BE + uint32_t unk_0c; // 0 + uint32_t unk_10; // 0 + uint32_t unk_14; // 0 + uint32_t unk_18; // 0 + uint32_t c_offset; // BE + uint32_t unk_20; // 0 + uint32_t toc_offset; // BE usually 0x0000002c + uint32_t toc_size; // BE + }; + struct uarp_toc_entry { + uint32_t this_size; // BE usually 0x28 + uint32_t fourcc; // 'PT01' or similar + uint32_t index; // BE starting with 0, increment+1 for each entry + uint32_t unk_0c; // BE usually not zero + uint32_t unk_10; // BE usually 0 + uint32_t unk_14; // BE usually 0 + uint32_t unk_18; // BE other offset, not sure + uint32_t unk_1c; // BE usually 0 + uint32_t offset; // BE + uint32_t size; // + }; + + plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); + uint64_t im4m_size = 0; + const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + + struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; + uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); + uint32_t plist_offset = be32toh(uarp_hdr->plist_offset); + uint32_t plist_size = uarp_size - plist_offset; + nskeyedarchive_t ka = nskeyedarchive_new_from_data(uarp_fw + plist_offset, plist_size); + if (!ka) { + return -1; + } + plist_t uarp_dict = nskeyedarchive_to_plist(ka); + nskeyedarchive_free(ka); + + // find the corresponding entries for given BoardID+PREV + + char* payload_4cc = NULL; + char* data_payload_4ccs = NULL; + + plist_t sb_payloads = plist_dict_get_item(uarp_dict, "SuperBinary Payloads"); + if (PLIST_IS_ARRAY(sb_payloads)) { + plist_array_iter iter = NULL; + plist_array_new_iter(sb_payloads, &iter); + plist_t payload = NULL; + do { + plist_array_next_item(sb_payloads, iter, &payload); + if (!payload) { + break; + } + plist_t meta = plist_dict_get_item(payload, "Payload MetaData"); + if (!PLIST_IS_DICT(meta)) { + continue; + } + plist_t prefix = plist_dict_get_item(meta, "Personalization Manifest Prefix"); + if (!PLIST_IS_STRING(prefix)) { + continue; + } + if (strcmp(plist_get_string_ptr(prefix, NULL), "USBPortController") != 0) { + continue; + } + plist_t p_boardid = plist_dict_get_item(meta, "Personalization Board ID (64 bits)"); + if (!PLIST_IS_INT(p_boardid)) { + continue; + } + uint64_t boardid = 0; + plist_get_uint_val(p_boardid, &boardid); + if (boardid == bdid) { + plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC"); + plist_get_string_val(p4cc, &payload_4cc); + plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data"); + if (PLIST_IS_ARRAY(matching)) { + plist_array_iter iter2 = NULL; + plist_array_new_iter(matching, &iter2); + plist_t match = NULL; + do { + plist_array_next_item(matching, iter2, &match); + if (!PLIST_IS_DICT(match)) { + break; + } + uint64_t minrev = 0; + plist_t p_min = plist_dict_get_item(match, "Personalization Matching Data Product Revision Minimum"); + plist_get_uint_val(p_min, &minrev); + uint64_t maxrev = 0; + plist_t p_max = plist_dict_get_item(match, "Personalization Matching Data Product Revision Maximum"); + plist_get_uint_val(p_max, &maxrev); + if (prev >= minrev && prev <= maxrev) { + plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags"); + plist_get_string_val(tags, &data_payload_4ccs); + break; + } + } while (match); + plist_mem_free(iter2); + } + break; + } + } while (payload); + plist_mem_free(iter); + } + if (!payload_4cc) { + printf("Failed to get payload 4cc\n"); + return -1; + } + if (!data_payload_4ccs) { + printf("Failed to get data payload 4ccs\n"); + return -1; + } + + // now find the blobs in UARP data + uint32_t dl_offset = 0; + uint32_t dl_size = 0; + uint32_t data1_offset = 0; + uint32_t data1_size = 0; + uint32_t data2_offset = 0; + uint32_t data2_size = 0; + uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); + uint32_t toc_size = be32toh(uarp_hdr->toc_size); + const unsigned char* p = uarp_fw + uarp_hdr_size; + while (p < uarp_fw + toc_size) { + struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p; + uint32_t te_size = be32toh(entry->this_size); + if (strncmp((char*)&(entry->fourcc), payload_4cc, 4) == 0) { + dl_offset = be32toh(entry->offset); + dl_size = be32toh(entry->size); + } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs, 4) == 0) { + data1_offset = be32toh(entry->offset); + data1_size = be32toh(entry->size); + } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs+5, 4) == 0) { + data2_offset = be32toh(entry->offset); + data2_size = be32toh(entry->size); + } + p += te_size; + } + + uint32_t content_size = data1_size + data2_size + im4m_size + dl_size; + + *bin_out = (unsigned char*)malloc(0x40 + content_size); + struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out); + hdr->magic = htole32(0xACE00003); + hdr->unk4 = htole32(0x00203400); + hdr->unk8 = htole32(0x00002800); + hdr->header_size = htole32(0x40); + hdr->data1_size = htole32(data1_size); + hdr->data2_size = htole32(data2_size);; + hdr->im4m_offset = htole32(0x40 + data1_size + data2_size); + hdr->im4m_dl_size = htole32(im4m_size + dl_size); + hdr->content_size = htole32(content_size); + hdr->crc = 0; + hdr->fill1 = 0xFFFFFFFFFFFFFFFFLL; + hdr->fill2 = 0xFFFFFFFFFFFFFFFFLL; + hdr->fill3 = 0xFFFFFFFFFFFFFFFFLL; + + // write data1 payload + memcpy(*bin_out + 0x40, uarp_fw + data1_offset, data1_size); + // write data2 payload + memcpy(*bin_out + 0x40 + data1_size, uarp_fw + data2_offset, data2_size); + // write IM4M + memcpy(*bin_out + 0x40 + data1_size + data2_size, im4m, im4m_size); + // write dl payload + memcpy(*bin_out + 0x40 + data1_size + data2_size + im4m_size, uarp_fw + dl_offset, dl_size); + + // calculate CRC and update header + hdr->crc = htole32(crc_buffer(*bin_out + 0x40, content_size, 0xFFFFFFFF)); + + *bin_size = 0x40 + content_size; + + return 0; +} diff --git a/src/ace3.h b/src/ace3.h new file mode 100644 index 00000000..2ef65a7c --- /dev/null +++ b/src/ace3.h @@ -0,0 +1,17 @@ +#ifndef IDEVICERESTORE_ACE3_H +#define IDEVICERESTORE_ACE3_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common.c b/src/common.c index 9a739940..499509d3 100644 --- a/src/common.c +++ b/src/common.c @@ -63,6 +63,7 @@ struct idevicerestore_mode_t idevicerestore_modes[] = { { 3, "Recovery" }, { 4, "Restore" }, { 5, "Normal" }, + { 6, "Port DFU" }, }; int idevicerestore_debug = 0; diff --git a/src/common.h b/src/common.h index 493b1df4..9b3c1e3b 100644 --- a/src/common.h +++ b/src/common.h @@ -47,6 +47,7 @@ extern "C" { #define _MODE_RECOVERY 3 #define _MODE_RESTORE 4 #define _MODE_NORMAL 5 +#define _MODE_PORTDFU 6 #define MODE_UNKNOWN &idevicerestore_modes[_MODE_UNKNOWN] #define MODE_WTF &idevicerestore_modes[_MODE_WTF] @@ -54,6 +55,7 @@ extern "C" { #define MODE_RECOVERY &idevicerestore_modes[_MODE_RECOVERY] #define MODE_RESTORE &idevicerestore_modes[_MODE_RESTORE] #define MODE_NORMAL &idevicerestore_modes[_MODE_NORMAL] +#define MODE_PORTDFU &idevicerestore_modes[_MODE_PORTDFU] #define FLAG_QUIT 1 diff --git a/src/dfu.c b/src/dfu.c index 8602bc0c..62a3dc09 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -118,6 +118,21 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe return 0; } +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) +{ + irecv_error_t err = 0; + + info("Sending data (%d bytes)...\n", size); + + err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); + if (err != IRECV_E_SUCCESS) { + error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); + return -1; + } + + return 0; +} + int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { char* path = NULL; @@ -204,6 +219,24 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide return 0; } +int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + + *bdid = device_info->bdid; + + return 0; +} + int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) { if(client->dfu == NULL) { @@ -222,6 +255,27 @@ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) return 0; } +int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + char* ptr = strstr(device_info->serial_string, "PREV:"); + if (ptr) { + sscanf(ptr, "PREV:%x", prev); + return 0; + } + return -1; +} + + int dfu_is_image4_supported(struct idevicerestore_client_t* client) { if(client->dfu == NULL) { @@ -238,6 +292,35 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } +int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + + if (device_info->ap_nonce && device_info->ap_nonce_size > 0) { + *nonce = (unsigned char*)malloc(device_info->ap_nonce_size); + if (!*nonce) { + return -1; + } + *nonce_size = device_info->ap_nonce_size; + // The nonce is backwards, so we have to swap the bytes + unsigned int i = 0; + for (i = 0; i < *nonce_size; i++) { + (*nonce)[(*nonce_size)-1-i] = device_info->ap_nonce[i]; + } + } + + return 0; +} + int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { diff --git a/src/dfu.h b/src/dfu.h index f6174abb..4590dbd7 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -41,9 +41,13 @@ int dfu_client_new(struct idevicerestore_client_t* client); void dfu_client_free(struct idevicerestore_client_t* client); irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client); int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size); +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options); int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); +int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid); int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); +int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev); int dfu_is_image4_supported(struct idevicerestore_client_t* client); +int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index e71dea4e..ad02f7fd 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -47,6 +47,7 @@ #include +#include "ace3.h" #include "dfu.h" #include "tss.h" #include "img3.h" @@ -298,6 +299,9 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) case IRECV_K_DFU_MODE: client->mode = MODE_DFU; break; + case IRECV_K_PORT_DFU_MODE: + client->mode = MODE_PORTDFU; + break; case IRECV_K_RECOVERY_MODE_1: case IRECV_K_RECOVERY_MODE_2: case IRECV_K_RECOVERY_MODE_3: @@ -316,6 +320,12 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) mutex_lock(&client->device_event_mutex); client->mode = MODE_UNKNOWN; debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A"); + if (event->mode == IRECV_K_PORT_DFU_MODE) { + // We have to reset the ECID here if a port DFU device disconnects, + // because when the device reconnects in a different mode, it will + // have the actual device ECID and wouldn't get detected. + client->ecid = 0; + } cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } @@ -683,6 +693,152 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } + if (client->mode == MODE_PORTDFU) { + unsigned int pdfu_bdid = 0; + unsigned int pdfu_cpid = 0; + unsigned int prev = 0; + + if (dfu_get_bdid(client, &pdfu_bdid) < 0) { + error("ERROR: Failed to get bdid for Port DFU device!\n"); + return -1; + } + if (dfu_get_cpid(client, &pdfu_cpid) < 0) { + error("ERROR: Failed to get cpid for Port DFU device!\n"); + return -1; + } + if (dfu_get_prev(client, &prev) < 0) { + error("ERROR: Failed to get PREV for Port DFU device!\n"); + return -1; + } + + unsigned char* pdfu_nonce = NULL; + unsigned int pdfu_nsize = 0; + if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) { + error("ERROR: Failed to get nonce for Port DFU device!\n"); + return -1; + } + + plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0); + if (!build_identity) { + error("ERORR: Failed to get build identity\n"); + return -1; + } + + unsigned int b_pdfu_cpid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); + if (b_pdfu_cpid != pdfu_cpid) { + error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); + return -1; + } + unsigned int b_pdfu_bdid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); + if (b_pdfu_bdid != pdfu_bdid) { + error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); + return -1; + } + + plist_t parameters = plist_new_dict(); + plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid)); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); + plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); + if (!usbf) { + plist_free(parameters); + error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n"); + return -1; + } + plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path"); + if (!p_fwpath) { + plist_free(parameters); + error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n"); + return -1; + } + const char* fwpath = plist_get_string_ptr(p_fwpath, NULL); + if (!fwpath) { + plist_free(parameters); + error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n"); + return -1; + } + unsigned char* uarp_buf = NULL; + unsigned int uarp_size = 0; + if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) { + plist_free(parameters); + error("ERROR: Unable to extract '%s' from IPSW\n", fwpath); + return -1; + } + usbf = plist_copy(usbf); + plist_dict_remove_item(usbf, "Info"); + plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); + + plist_t request = tss_request_new(NULL); + if (request == NULL) { + plist_free(parameters); + error("ERROR: Unable to create TSS request\n"); + return -1; + } + plist_dict_merge(&request, parameters); + plist_free(parameters); + + // send request and grab response + plist_t response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to send TSS request\n"); + return -1; + } + info("Received USBPortController1,Ticket\n"); + + info("Creating Ace3Binary\n"); + unsigned char* ace3bin = NULL; + size_t ace3bin_size = 0; + if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) { + error("ERROR: Could not create Ace3Binary\n"); + return -1; + } + plist_free(response); + free(uarp_buf); + + if (idevicerestore_keep_pers) { + write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size); + } + + if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) { + error("ERROR: Could not send Ace3Buffer to device\n"); + return -1; + } + + debug("Waiting for device to disconnect...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not disconnect. Port DFU failed.\n"); + } + return -2; + } + debug("Waiting for device to reconnect in DFU mode...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n"); + } + return -2; + } + mutex_unlock(&client->device_event_mutex); + + if (client->flags & FLAG_NOACTION) { + info("Port DFU restore successful.\n"); + return 0; + } else { + info("Port DFU restore successful. Continuing.\n"); + } + } + idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8); /* check if device type is supported by the given build manifest */ @@ -1773,6 +1929,7 @@ irecv_device_t get_irecv_device(struct idevicerestore_client_t *client) return normal_get_irecv_device(client); case _MODE_DFU: + case _MODE_PORTDFU: case _MODE_RECOVERY: return dfu_get_irecv_device(client); From d50698e38c0e1ddfef94f7a84a34d779e4f8caba Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+VisualEhrmanntraut@users.noreply.github.com> Date: Wed, 3 Apr 2024 22:16:45 +0300 Subject: [PATCH 070/159] Fix restore mode component personalisation --- src/idevicerestore.c | 54 +++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ad02f7fd..fc8b153f 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -667,14 +667,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } + if (client->flags & FLAG_CUSTOM) { + // prevent attempt to sign custom firmware + tss_enabled = 0; + info("Custom firmware requested; TSS has been disabled.\n"); + } + if (client->mode == MODE_RESTORE) { - if (client->flags & FLAG_ALLOW_RESTORE_MODE) { - tss_enabled = 0; - if (!client->root_ticket) { - client->root_ticket = (void*)strdup(""); - client->root_ticket_len = 0; - } - } else { + if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) { if (restore_reboot(client) < 0) { error("ERROR: Unable to exit restore mode\n"); return -2; @@ -856,12 +856,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) client->image4supported = is_image4_supported(client); info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); - if (client->flags & FLAG_CUSTOM) { - /* prevent signing custom firmware */ - tss_enabled = 0; - info("Custom firmware requested. Disabled TSS request.\n"); - } - // choose whether this is an upgrade or a restore (default to upgrade) client->tss = NULL; plist_t build_identity = NULL; @@ -1241,20 +1235,34 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); - return -1; - } - if (client->macos_variant) { - if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + if (client->mode == MODE_RESTORE && client->root_ticket) { + plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len); + if (!ap_ticket) { + error("ERROR: Failed to create ApImg4Ticket node value.\n"); return -1; } - if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < - 0) { - error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + client->tss = plist_new_dict(); + if (!client->tss) { + error("ERROR: Failed to create ApImg4Ticket node.\n"); + return -1; + } + plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket); + } else { + if (get_tss_response(client, build_identity, &client->tss) < 0) { + error("ERROR: Unable to get SHSH blobs for this device\n"); return -1; } + if (client->macos_variant) { + if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + return -1; + } + if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < + 0) { + error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + return -1; + } + } } if (stashbag_commit_required) { From d8f8cb126571f1db53b7638bc2cd170716571144 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 4 Apr 2024 09:29:02 +0200 Subject: [PATCH 071/159] Remove annoying linebreak --- src/idevicerestore.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fc8b153f..fdb340e4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1257,8 +1257,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); return -1; } - if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < - 0) { + if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) { error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); return -1; } From 6d40d0ab626eb0ffee4f005b7fdc915bc561deb9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 4 Apr 2024 09:30:06 +0200 Subject: [PATCH 072/159] dfu: A little code optimization --- src/dfu.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 62a3dc09..cc8e1fbf 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -103,13 +103,13 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) return device; } -int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) { irecv_error_t err = 0; info("Sending data (%d bytes)...\n", size); - err = irecv_send_buffer(client->dfu->client, buffer, size, 1); + err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); return -1; @@ -118,19 +118,9 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe return 0; } -int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) +int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) { - irecv_error_t err = 0; - - info("Sending data (%d bytes)...\n", size); - - err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); - if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); - return -1; - } - - return 0; + return dfu_send_buffer_with_options(client, buffer, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); } int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) @@ -208,7 +198,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide info("Sending %s (%d bytes)...\n", component, size); - irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1); + irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); free(data); From 71ca0f0451c523fb47e80f53b45560e7a7b0c9b1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:08:20 +0200 Subject: [PATCH 073/159] [github-actions] Updated actions in build workflow --- .github/workflows/build.yml | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 696dcda8..1fc2be97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,35 +14,35 @@ jobs: run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{env.target_triplet}} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -57,7 +57,7 @@ jobs: rm -rf extract/lib sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: autogen @@ -72,7 +72,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_${{env.target_triplet}} path: idevicerestore.tar @@ -88,35 +88,35 @@ jobs: fi shell: bash - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_macOS repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_macOS repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_macOS repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_macOS repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -129,7 +129,7 @@ jobs: tar -C extract -xvf $I done sudo cp -r extract/* / - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install additional requirements run: | SDKDIR=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` @@ -182,7 +182,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_macOS path: idevicerestore.tar @@ -219,35 +219,35 @@ jobs: echo "dest=$dest" >> $GITHUB_ENV echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -260,7 +260,7 @@ jobs: tar -C extract -xvf $I done cp -r extract/* / - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install additional requirements run: | FILENAME="libzip-1.7.1-static.tar.bz2" @@ -291,7 +291,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar ${{ env.dest }} - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_${{ matrix.arch }}-${{ env.dest }} path: idevicerestore.tar From d95b43d7bef9163491f41910855e6f34bd13d88b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:12:43 +0200 Subject: [PATCH 074/159] [github-actions] Only allow curl workflow to be triggered manually --- .github/workflows/curl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml index a2974762..87e4459b 100644 --- a/.github/workflows/curl.yml +++ b/.github/workflows/curl.yml @@ -1,6 +1,6 @@ name: build-libcurl-static -on: [push] +on: workflow_dispatch jobs: build-windows: From 0548d9f20d2937d1e122d0b405cb60219ec4fa0f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:16:27 +0200 Subject: [PATCH 075/159] [github-actions] Fix build for macOS --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1fc2be97..76d4a0b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,7 +161,7 @@ jobs: base64 -D < $FILENAME.b64 > $FILENAME tar -C deps -xjf $FILENAME echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV - echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a -Xlinker /usr/lib/libbz2.dylib -Xlinker /usr/lib/liblzma.dylib -lz" >> $GITHUB_ENV + echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a -Xlinker ${SDKDIR}/usr/lib/libbz2.tbd -Xlinker ${SDKDIR}/usr/lib/liblzma.tbd -lz" >> $GITHUB_ENV - name: autogen run: | export CFLAGS="${{env.BUILD_CFLAGS}} -Wno-nullability-completeness -Wno-expansion-to-defined" From e6d8c0b9d53e5f3c9100cfc8c88626be45c98b85 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 5 May 2024 04:01:12 +0200 Subject: [PATCH 076/159] Updated to use libplist 2.5.0 API --- configure.ac | 2 +- src/ace3.c | 2 +- src/common.c | 139 --------------- src/common.h | 8 - src/idevicerestore.c | 56 +++---- src/img4.c | 18 +- src/normal.c | 12 +- src/restore.c | 88 +++++----- src/tss.c | 392 +++++++++++++++++++++---------------------- 9 files changed, 285 insertions(+), 432 deletions(-) diff --git a/configure.ac b/configure.ac index 1cd58444..4c39d42d 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ fi LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 -LIBPLIST_VERSION=2.3.0 +LIBPLIST_VERSION=2.5.0 LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ace3.c b/src/ace3.c index b96e6b4f..d280196c 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -96,7 +96,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); uint64_t im4m_size = 0; - const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + const uint8_t* im4m = plist_get_data_ptr(p_im4m, &im4m_size); struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); diff --git a/src/common.c b/src/common.c index 499509d3..e5ee07b9 100644 --- a/src/common.c +++ b/src/common.c @@ -558,145 +558,6 @@ void get_user_input(char *buf, int maxlen, int secure) buf[len] = 0; } -uint64_t _plist_dict_get_uint(plist_t dict, const char *key) -{ - uint64_t uintval = 0; - char *strval = NULL; - uint64_t strsz = 0; - plist_t node = plist_dict_get_item(dict, key); - if (!node) { - return uintval; - } - switch (plist_get_node_type(node)) { - case PLIST_UINT: - plist_get_uint_val(node, &uintval); - break; - case PLIST_STRING: - plist_get_string_val(node, &strval); - if (strval) { - uintval = strtoull(strval, NULL, 0); - free(strval); - } - break; - case PLIST_DATA: - plist_get_data_val(node, &strval, &strsz); - if (strval) { - if (strsz == 8) { - uintval = le64toh(*(uint64_t*)strval); - } else if (strsz == 4) { - uintval = le32toh(*(uint32_t*)strval); - } else if (strsz == 2) { - uintval = le16toh(*(uint16_t*)strval); - } else if (strsz == 1) { - uintval = strval[0]; - } else { - error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz); - } - free(strval); - } - break; - default: - break; - } - return uintval; -} - -uint8_t _plist_dict_get_bool(plist_t dict, const char *key) -{ - uint8_t bval = 0; - uint64_t uintval = 0; - char *strval = NULL; - uint64_t strsz = 0; - plist_t node = plist_dict_get_item(dict, key); - if (!node) { - return 0; - } - switch (plist_get_node_type(node)) { - case PLIST_BOOLEAN: - plist_get_bool_val(node, &bval); - break; - case PLIST_UINT: - plist_get_uint_val(node, &uintval); - bval = (uint8_t)uintval; - break; - case PLIST_STRING: - plist_get_string_val(node, &strval); - if (strval) { - if (strcmp(strval, "true")) { - bval = 1; - } else if (strcmp(strval, "false")) { - bval = 0; - } - free(strval); - } - break; - case PLIST_DATA: - plist_get_data_val(node, &strval, &strsz); - if (strval) { - if (strsz == 1) { - bval = strval[0]; - } else { - error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz); - } - free(strval); - } - break; - default: - break; - } - return bval; -} - -int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) { - return -1; - } - uint64_t u64val = _plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key); - plist_dict_set_item(target_dict, key, plist_new_uint(u64val)); - return 0; -} - -int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) { - return -1; - } - uint64_t bval = _plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key); - plist_dict_set_item(target_dict, key, plist_new_bool(bval)); - return 0; -} - -int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!PLIST_IS_DATA(node)) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - -int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!PLIST_IS_STRING(node)) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - -int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!node) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - const char* path_get_basename(const char* path) { #ifdef WIN32 diff --git a/src/common.h b/src/common.h index 9b3c1e3b..766a3853 100644 --- a/src/common.h +++ b/src/common.h @@ -191,14 +191,6 @@ char* realpath(const char *filename, char *resolved_name); void get_user_input(char *buf, int maxlen, int secure); -uint8_t _plist_dict_get_bool(plist_t dict, const char *key); -uint64_t _plist_dict_get_uint(plist_t dict, const char *key); -int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); - const char* path_get_basename(const char* path); #ifdef __cplusplus diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fdb340e4..ece455ed 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -724,12 +724,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - unsigned int b_pdfu_cpid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); + unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); if (b_pdfu_cpid != pdfu_cpid) { error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); return -1; } - unsigned int b_pdfu_bdid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); + unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); if (b_pdfu_bdid != pdfu_bdid) { error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); return -1; @@ -738,9 +738,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1)); plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid)); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); @@ -771,7 +771,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) usbf = plist_copy(usbf); plist_dict_remove_item(usbf, "Info"); plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); - plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data(pdfu_nonce, pdfu_nsize)); plist_t request = tss_request_new(NULL); if (request == NULL) { @@ -2263,14 +2263,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2331,20 +2331,20 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t pinfo = NULL; normal_get_preflight_info(client, &pinfo); if (pinfo) { - _plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); - _plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); - _plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); - _plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); + plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); + plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); + plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); + plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); /* add baseband parameters */ tss_request_add_baseband_tags(request, parameters, NULL); - _plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); - if (_plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { - _plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); - _plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); - _plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); - _plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); + plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); + if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { + plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); + plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); + plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); + plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); /* add vinyl parameters */ tss_request_add_vinyl_tags(request, parameters, NULL); @@ -2387,7 +2387,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApNonce */ if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; @@ -2395,7 +2395,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApSepNonce */ if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2496,12 +2496,12 @@ int get_recovery_os_local_policy_tss_response( uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); - _plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL); - _plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL); + plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL); + plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL); plist_t vol_uuid_node = plist_dict_get_item(args, "Ap,VolumeUUID"); char* vol_uuid_str = NULL; @@ -2518,7 +2518,7 @@ int get_recovery_os_local_policy_tss_response( for (i = 0; i < 16; i++) { vol_uuid[i] = (unsigned char)vuuid[i]; } - plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data((char*)vol_uuid, 16)); + plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data(vol_uuid, 16)); /* create basic request */ request = tss_request_new(NULL); @@ -2566,14 +2566,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2591,7 +2591,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2603,7 +2603,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; SHA384(ticket, ticket_length, hash); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data(hash, SHA384_DIGEST_LENGTH)); /* create basic request */ request = tss_request_new(NULL); diff --git a/src/img4.c b/src/img4.c index 56b04964..2d1cc43a 100644 --- a/src/img4.c +++ b/src/img4.c @@ -457,7 +457,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucon_size = 0; - const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + const uint8_t* ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -468,7 +468,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucer_size = 0; - const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + const uint8_t* ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -705,7 +705,7 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "Digest"); if (node) { - char *digest = NULL; + uint8_t *digest = NULL; uint64_t digest_len = 0; plist_get_data_val(node, &digest, &digest_len); if (digest_len > 0) { @@ -740,7 +740,7 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "TBMDigests"); if (node) { - char *data = NULL; + uint8_t *data = NULL; uint64_t datalen = 0; plist_get_data_val(node, &data, &datalen); const char *tbmtag = NULL; @@ -798,22 +798,22 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* unsigned int tmp_len = 0; /* write manifest properties */ - uintval = _plist_dict_get_uint(request, "ApBoardID"); + uintval = plist_dict_get_uint(request, "ApBoardID"); _manifest_write_key_value(&tmp, &tmp_len, "BORD", ASN1_INTEGER, &uintval, -1); uintval = 0; _manifest_write_key_value(&tmp, &tmp_len, "CEPO", ASN1_INTEGER, &uintval, -1); - uintval = _plist_dict_get_uint(request, "ApChipID"); + uintval = plist_dict_get_uint(request, "ApChipID"); _manifest_write_key_value(&tmp, &tmp_len, "CHIP", ASN1_INTEGER, &uintval, -1); - boolval = _plist_dict_get_bool(request, "ApProductionMode"); + boolval = plist_dict_get_bool(request, "ApProductionMode"); _manifest_write_key_value(&tmp, &tmp_len, "CPRO", ASN1_BOOLEAN, &boolval, -1); boolval = 0; _manifest_write_key_value(&tmp, &tmp_len, "CSEC", ASN1_BOOLEAN, &boolval, -1); - uintval = _plist_dict_get_uint(request, "ApSecurityDomain"); + uintval = plist_dict_get_uint(request, "ApSecurityDomain"); _manifest_write_key_value(&tmp, &tmp_len, "SDOM", ASN1_INTEGER, &uintval, -1); /* create manifest properties set */ @@ -907,7 +907,7 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* length += hdr_len; - *manifest = plist_new_data((char*)buf, length); + *manifest = plist_new_data(buf, length); free(buf); diff --git a/src/normal.c b/src/normal.c index efe8f03d..8070982b 100644 --- a/src/normal.c +++ b/src/normal.c @@ -333,7 +333,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const } uint64_t n_size = 0; - plist_get_data_val(nonce_node, (char**)nonce, &n_size); + plist_get_data_val(nonce_node, nonce, &n_size); *nonce_size = (unsigned int)n_size; plist_free(nonce_node); @@ -462,13 +462,13 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ } else { plist_t node; - if (_plist_dict_get_bool(pl, "Skip")) { + if (plist_dict_get_bool(pl, "Skip")) { result = 0; info("Device does not require stashbag.\n"); break; } - if (_plist_dict_get_bool(pl, "ShowDialog")) { + if (plist_dict_get_bool(pl, "ShowDialog")) { info("Device requires stashbag.\n"); printf("******************************************************************************\n" "* Please enter your passcode on the device. The device will store a token *\n" @@ -491,13 +491,13 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ plist_free(pl); break; } - if (_plist_dict_get_bool(pl, "Timeout")) { + if (plist_dict_get_bool(pl, "Timeout")) { error("ERROR: Timeout while waiting for user to enter passcode.\n"); result = -2; plist_free(pl); break; } - if (_plist_dict_get_bool(pl, "HideDialog")) { + if (plist_dict_get_bool(pl, "HideDialog")) { plist_free(pl); /* hide dialog */ result = 1; @@ -588,7 +588,7 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ } error("ERROR: Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)"); free(strval); - } else if (_plist_dict_get_bool(pl, "StashbagCommitComplete")) { + } else if (plist_dict_get_bool(pl, "StashbagCommitComplete")) { info("Stashbag committed!\n"); result = 0; } else { diff --git a/src/restore.c b/src/restore.c index 1261147f..0e553389 100644 --- a/src/restore.c +++ b/src/restore.c @@ -976,7 +976,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1000,7 +1000,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1029,7 +1029,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1053,7 +1053,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1118,7 +1118,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } dict = plist_new_dict(); - blob = plist_new_data((char*)data, size); + blob = plist_new_data(data, size); char compkeyname[256]; sprintf(compkeyname, "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); @@ -1279,7 +1279,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } dict = plist_new_dict(); - plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size)); + plist_dict_set_item(dict, "LlbImageData", plist_new_data(llb_data, llb_size)); free(llb_data); if (flash_version_1) { @@ -1339,13 +1339,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_size = 0; if (flash_version_1) { - plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_dict_set_item(norimage, component, plist_new_data(nor_data, nor_size)); } else { /* make sure iBoot is the first entry in the array */ if (!strncmp("iBoot", component, 5)) { - plist_array_insert_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size), 0); + plist_array_insert_item(norimage, plist_new_data(nor_data, nor_size), 0); } else { - plist_array_append_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_array_append_item(norimage, plist_new_data(nor_data, nor_size)); } } @@ -1381,7 +1381,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1406,7 +1406,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1431,7 +1431,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1609,7 +1609,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob = NULL; blob_size = 0; - plist_get_data_val(node, (char**)&blob, &blob_size); + plist_get_data_val(node, &blob, &blob_size); if (!blob) { error("ERROR: could not get %s-Blob data\n", key); goto leave; @@ -1742,7 +1742,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + plist_get_data_val(bbticket, &blob, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1780,7 +1780,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // add BBTicket as bbticket.der blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + plist_get_data_val(bbticket, &blob, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1839,7 +1839,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer uint64_t bb_nonce_size = 0; uint64_t bb_chip_id = 0; plist_t response = NULL; - char* buffer = NULL; + uint8_t* buffer = NULL; char* bbfwtmp = NULL; plist_t dict = NULL; @@ -1860,11 +1860,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } plist_t bb_snum_node = plist_dict_get_item(arguments, "ChipSerialNo"); if (bb_snum_node && plist_get_node_type(bb_snum_node) == PLIST_DATA) { - plist_get_data_val(bb_snum_node, (char**)&bb_snum, &bb_snum_size); + plist_get_data_val(bb_snum_node, &bb_snum, &bb_snum_size); } plist_t bb_nonce_node = plist_dict_get_item(arguments, "Nonce"); if (bb_nonce_node && plist_get_node_type(bb_nonce_node) == PLIST_DATA) { - plist_get_data_val(bb_nonce_node, (char**)&bb_nonce, &bb_nonce_size); + plist_get_data_val(bb_nonce_node, &bb_nonce, &bb_nonce_size); } } @@ -1873,11 +1873,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (bb_nonce) { - plist_dict_set_item(parameters, "BbNonce", plist_new_data((const char*)bb_nonce, bb_nonce_size)); + plist_dict_set_item(parameters, "BbNonce", plist_new_data(bb_nonce, bb_nonce_size)); } plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id)); plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); - plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); + plist_dict_set_item(parameters, "BbSNUM", plist_new_data(bb_snum, bb_snum_size)); tss_parameters_add_from_manifest(parameters, build_identity, true); @@ -1970,7 +1970,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer // send file dict = plist_new_dict(); - plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, (uint64_t)sz)); + plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, sz)); free(buffer); buffer = NULL; @@ -2034,7 +2034,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest int want_image_list = 0; arguments = plist_dict_get_item(message, "Arguments"); - want_image_list = _plist_dict_get_bool(arguments, image_list_k); + want_image_list = plist_dict_get_bool(arguments, image_list_k); node = plist_dict_get_item(arguments, "ImageName"); if (node) { plist_get_string_val(node, &image_name); @@ -2109,7 +2109,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest error("ERROR: Unable to get personalized component: %s\n", component); } - plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); + plist_dict_set_item(data_dict, component, plist_new_data(data, size)); free(data); } } @@ -2256,7 +2256,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } - plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2347,7 +2347,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc *(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size); component_size += 16; - plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2429,7 +2429,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru comp_name = NULL; plist_t firmware_data = plist_new_dict(); - plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data(component_data, component_size)); plist_dict_set_item(response, "FirmwareData", firmware_data); free(component_data); @@ -2578,7 +2578,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2676,7 +2676,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_to_bin(fw_map, &bin_plist, &bin_size); plist_free(fw_map); - plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, (uint64_t)bin_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((uint8_t*)bin_plist, bin_size)); free(bin_plist); return response; @@ -2798,7 +2798,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2851,7 +2851,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } else { plist_t info_dict = plist_array_get_item(info_array, 0); plist_t hwid = plist_dict_get_item(info_dict, "HardwareID"); - tag = (uint32_t)_plist_dict_get_uint(info_dict, "TagNumber"); + tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber"); char key[64]; plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag)); @@ -2862,25 +2862,25 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } sprintf(key, "Timer,ChipID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ChipID"); + plist_dict_copy_uint(parameters, hwid, key, "ChipID"); sprintf(key, "Timer,BoardID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "BoardID"); + plist_dict_copy_uint(parameters, hwid, key, "BoardID"); sprintf(key, "Timer,ECID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ECID"); + plist_dict_copy_uint(parameters, hwid, key, "ECID"); sprintf(key, "Timer,Nonce,%u", tag); - _plist_dict_copy_data(parameters, hwid, key, "Nonce"); + plist_dict_copy_data(parameters, hwid, key, "Nonce"); sprintf(key, "Timer,SecurityMode,%u", tag); - _plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); + plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); sprintf(key, "Timer,SecurityDomain,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); + plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); sprintf(key, "Timer,ProductionMode,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); + plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); if (!ap_info) { @@ -2983,7 +2983,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -3043,10 +3043,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); } if (!plist_dict_get_item(parameters, "ApChipID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); } if (!plist_dict_get_item(parameters, "ApBoardID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); } /* add device generated request data to parameters */ @@ -3461,7 +3461,7 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) { plist_t args = plist_dict_get_item(msg, "Arguments"); - return restore_get_build_identity(client, _plist_dict_get_bool(args, "IsRecoveryOS")); + return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS")); } int extract_macos_variant(plist_t build_identity, char** output) @@ -3549,7 +3549,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi plist_t dict = plist_new_dict(); if (data != NULL) { // Send a chunk of file data - plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); + plist_dict_set_item(dict, "FileData", plist_new_data(data, size)); } else { // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); @@ -3806,7 +3806,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer } plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); + plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data(data, size)); int restore_error = restored_send(restore, dict); if (restore_error != RESTORE_E_SUCCESS) { @@ -4289,7 +4289,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "BBUpdaterState", bbus); - _plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); + plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); diff --git a/src/tss.c b/src/tss.c index 80591e7f..04d51087 100644 --- a/src/tss.c +++ b/src/tss.c @@ -92,39 +92,39 @@ int tss_request_add_local_policy_tags(plist_t request, plist_t parameters) { plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - if (_plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { error("ERROR: Unable to find required Ap,LocalBoot in parameters\n"); return -1; } - if (_plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { + if (plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n"); return -1; } - if (_plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n"); return -1; } - _plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); - _plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); - _plist_dict_copy_uint(request, parameters, "ApECID", NULL); - _plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - _plist_dict_copy_data(request, parameters, "ApNonce", NULL); + plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); + plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); + plist_dict_copy_uint(request, parameters, "ApECID", NULL); + plist_dict_copy_uint(request, parameters, "ApChipID", NULL); + plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); + plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); + plist_dict_copy_data(request, parameters, "ApNonce", NULL); if (!plist_dict_get_item(request, "ApSecurityMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { error("ERROR: Unable to find required ApSecurityMode in parameters\n"); return -1; } } if (!plist_dict_get_item(request, "ApProductionMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } @@ -137,121 +137,121 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, { plist_t node = NULL; - if (_plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { error("ERROR: Unable to find UniqueBuildID node\n"); return -1; } - _plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); + plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); - if (_plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; + if (plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; error("ERROR: Unable to find ApChipID node\n"); return -1; } - if (_plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { + if (plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { error("ERROR: Unable to find ApBoardID node\n"); return -1; } - _plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); - _plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); + plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); - if (_plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { + if (plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { debug("NOTE: Unable to find BbChipID node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbActivationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n"); } /* BbSkeyId - Used by XMM 6180/GSM */ - if (_plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { debug("NOTE: Unable to find BbSkeyId node\n"); } /* SE,ChipID - Used for SE firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); /* Savage,ChipID - Used for Savage firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); /* add Savage,PatchEpoch - Used for Savage firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); + plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); /* Yonkers,BoardID - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); /* Yonkers,ChipID - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); - _plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); - - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); - - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); + + plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); + + plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); + plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); + + plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + + plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); node = plist_dict_get_item(build_identity, "Info"); if (node) { - _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); + plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); } if (include_manifest) { @@ -274,9 +274,9 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) return -1; } - _plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); + plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); - if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { error("ERROR: Unable to find required ApNonce in parameters\n"); return -1; } @@ -285,34 +285,34 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) if (!plist_dict_get_item(request, "ApSecurityMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { error("ERROR: Unable to find required ApSecurityMode in parameters\n"); return -1; } } if (!plist_dict_get_item(request, "ApProductionMode")) { /* ApProductionMode */ - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } } - _plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); - _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); - _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); + plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); + plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); + plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); if (plist_dict_get_item(parameters, "UID_MODE")) { - _plist_dict_copy_item(request, parameters, "UID_MODE", NULL); - } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + plist_dict_copy_item(request, parameters, "UID_MODE", NULL); + } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { // The logic here is missing why this value is expected to be 'false' plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); } // FIXME: I didn't understand yet when this value is set, so for now we use a workaround if (plist_dict_get_item(parameters, "ApSikaFuse")) { - _plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); - } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); + } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { // Workaround: We have only seen Ap,SikaFuse together with UID_MODE plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); } @@ -327,28 +327,28 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) return -1; } - if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { error("WARNING: Unable to find ApNonce in parameters\n"); } plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); - if (_plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { error("ERROR: Unable to find required ApBoardID in request\n"); return -1; } - if (_plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { error("ERROR: Unable to find required ApChipID in request\n"); return -1; } - if (_plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { error("ERROR: Unable to find required ApSecurityDomain in request\n"); return -1; } - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } @@ -358,11 +358,11 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) { - _plist_dict_copy_uint(request, parameters, "ApECID", NULL); - _plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); - _plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); + plist_dict_copy_uint(request, parameters, "ApECID", NULL); + plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); + plist_dict_copy_uint(request, parameters, "ApChipID", NULL); + plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); + plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); /* apply overrides */ if (overrides) { @@ -576,19 +576,19 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ continue; } - if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { + if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") - && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - && !_plist_dict_get_bool(info_dict, "IsFUDFirmware") - && !_plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - && !_plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - && !_plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - && !_plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) + if (!plist_dict_get_bool(info_dict, "IsFirmwarePayload") + && !plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + && !plist_dict_get_bool(info_dict, "IsFUDFirmware") + && !plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + && !plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + && !plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + && !plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) { debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; @@ -609,7 +609,7 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", key); plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); } @@ -679,28 +679,28 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid continue; } - if (_plist_dict_get_bool(parameters, "ApSupportsImg4")) { + if (plist_dict_get_bool(parameters, "ApSupportsImg4")) { if (!plist_dict_get_item(info_dict, "RestoreRequestRules")) { debug("DEBUG: %s: Skipping '%s' as it doesn't have RestoreRequestRules\n", __func__, key); continue; } } - int is_fw_payload = _plist_dict_get_bool(info_dict, "IsFirmwarePayload") - || _plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - || _plist_dict_get_bool(info_dict, "IsFUDFirmware") - || _plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - || _plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - || _plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - || _plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); + int is_fw_payload = plist_dict_get_bool(info_dict, "IsFirmwarePayload") + || plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + || plist_dict_get_bool(info_dict, "IsFUDFirmware") + || plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + || plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + || plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + || plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); - if (_plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { + if (plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); continue; } - } else if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { + } else if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } @@ -711,7 +711,7 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } /* skip components with IsFTAB:true */ - if (_plist_dict_get_bool(info_dict, "IsFTAB")) { + if (plist_dict_get_bool(info_dict, "IsFTAB")) { debug("DEBUG: %s: Skipping FTAB component '%s'\n", __func__, key); continue; } @@ -730,7 +730,7 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", key); plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); } @@ -755,22 +755,22 @@ int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t o plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "BbChipID", NULL); - _plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); + plist_dict_copy_uint(request, parameters, "BbChipID", NULL); + plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */ - _plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); /* BbSkeyId - Used by XMM 6180/GSM */ - _plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); - _plist_dict_copy_data(request, parameters, "BbNonce", NULL); - _plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); + plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); + plist_dict_copy_data(request, parameters, "BbNonce", NULL); + plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); - uint64_t bb_chip_id = _plist_dict_get_uint(request, "BbChipID"); - int32_t bb_cert_id = (int32_t)_plist_dict_get_uint(request, "BbGoldCertId"); + uint64_t bb_chip_id = plist_dict_get_uint(request, "BbChipID"); + int32_t bb_cert_id = (int32_t)plist_dict_get_uint(request, "BbGoldCertId"); - if (_plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { error("ERROR: Unable to find required BbSNUM in parameters\n"); return -1; } @@ -818,28 +818,28 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - if (_plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__); return -1; } /* 'IsDev' determines whether we have Production or Development */ - uint8_t is_dev = _plist_dict_get_bool(parameters, "SE,IsDev"); + uint8_t is_dev = plist_dict_get_bool(parameters, "SE,IsDev"); /* add SE,* components from build manifest to request */ char* key = NULL; @@ -914,7 +914,7 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1)); - if (_plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); return -1; } @@ -929,33 +929,33 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove plist_dict_set_item(dict, "Digest", plist_copy(node)); plist_dict_set_item(request, "SEP", dict); - if (_plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); return -1; } - if (_plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); return -1; } const char *comp_name = NULL; - uint8_t isprod = _plist_dict_get_bool(request, "Savage,ProductionMode"); + uint8_t isprod = plist_dict_get_bool(request, "Savage,ProductionMode"); /* get the right component name */ comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; @@ -963,7 +963,7 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove if (node && (plist_get_node_type(node) == PLIST_DATA)) { unsigned char *savage_rev = NULL; uint64_t savage_rev_len = 0; - plist_get_data_val(node, (char**)&savage_rev, &savage_rev_len); + plist_get_data_val(node, &savage_rev, &savage_rev_len); if (savage_rev_len > 0) { if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; @@ -988,12 +988,12 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove *component_name = strdup(comp_name); } - if (_plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); return -1; } @@ -1045,8 +1045,8 @@ int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t ov char *comp_name = NULL; plist_t comp_node = NULL; - uint8_t isprod = _plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); - uint64_t fabrevision = _plist_dict_get_uint(parameters, "Yonkers,FabRevision"); + uint8_t isprod = plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); + uint64_t fabrevision = plist_dict_get_uint(parameters, "Yonkers,FabRevision"); plist_dict_iter iter = NULL; plist_dict_new_iter(manifest_node, &iter); @@ -1120,16 +1120,16 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); - _plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); - _plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); - _plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); - _plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); + plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); + plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); + plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); + plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); if (!plist_dict_get_item(request, "eUICC,Gold")) { plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); if (n) { plist_t p = plist_new_dict(); - _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_copy_data(p, n, "Digest", NULL); plist_dict_set_item(request, "eUICC,Gold", p); } } @@ -1138,7 +1138,7 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); if (n) { plist_t p = plist_new_dict(); - _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_copy_data(p, n, "Digest", NULL); plist_dict_set_item(request, "eUICC,Main", p); } } @@ -1183,14 +1183,14 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Rap,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); - _plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); - _plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); - _plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); - _plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); + plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); + plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); + plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); + plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); + plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); + plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); + plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1214,7 +1214,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); } @@ -1250,11 +1250,11 @@ int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t o plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@BMU,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); - _plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); - _plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); - _plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); + plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); + plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); + plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); + plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1278,7 +1278,7 @@ int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t o } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); } @@ -1314,16 +1314,16 @@ int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overr plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Baobab,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); - _plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); - _plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); - _plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); + plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); + plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); + plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); - uint8_t isprod = _plist_dict_get_bool(parameters, "Baobab,ProductionMode"); + uint8_t isprod = plist_dict_get_bool(parameters, "Baobab,ProductionMode"); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1380,28 +1380,28 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, key, plist_new_bool(1)); - tag = (uint32_t)_plist_dict_get_uint(parameters, "TagNumber"); + tag = (uint32_t)plist_dict_get_uint(parameters, "TagNumber"); sprintf(key, "Timer,BoardID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,ChipID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,SecurityDomain,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,SecurityMode,%u", tag); - _plist_dict_copy_bool(request, parameters, key, NULL); + plist_dict_copy_bool(request, parameters, key, NULL); sprintf(key, "Timer,ProductionMode,%u", tag); - _plist_dict_copy_bool(request, parameters, key, NULL); + plist_dict_copy_bool(request, parameters, key, NULL); sprintf(key, "Timer,ECID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,Nonce,%u", tag); - _plist_dict_copy_data(request, parameters, key, NULL); + plist_dict_copy_data(request, parameters, key, NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1425,7 +1425,7 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); } @@ -1454,13 +1454,13 @@ int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t ov if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { /* Cryptex1LocalPolicy */ tss_request_add_local_policy_tags(request, parameters); - _plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); + plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); } else { /* Cryptex1 */ plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); - _plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); - _plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); + plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); + plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); plist_dict_iter iter = NULL; plist_dict_new_iter(parameters, &iter); @@ -1659,7 +1659,7 @@ static int tss_response_get_data_by_key(plist_t response, const char* name, unsi return -1; } - char *data = NULL; + uint8_t* data = NULL; uint64_t len = 0; plist_get_data_val(node, &data, &len); if (data) { @@ -1718,7 +1718,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** uint32_t tss_size = 0; uint64_t blob_size = 0; char* entry_key = NULL; - char* blob_data = NULL; + uint8_t* blob_data = NULL; char* entry_path = NULL; plist_t tss_entry = NULL; plist_t blob_node = NULL; @@ -1772,7 +1772,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) { uint64_t blob_size = 0; - char* blob_data = NULL; + uint8_t* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; From 653349a1eac8c52776dcfd17cb82bbeac272fb71 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 14 May 2024 09:36:42 +0200 Subject: [PATCH 077/159] Require libplist 2.6.0 --- configure.ac | 2 +- src/ace3.c | 2 +- src/idevicerestore.c | 24 +++++++-------- src/img4.c | 18 +++++------ src/restore.c | 73 +++++++++++++++++++------------------------- src/tss.c | 10 +++--- 6 files changed, 57 insertions(+), 72 deletions(-) diff --git a/configure.ac b/configure.ac index 4c39d42d..0b5fcea2 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ fi LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 -LIBPLIST_VERSION=2.5.0 +LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ace3.c b/src/ace3.c index d280196c..b96e6b4f 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -96,7 +96,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); uint64_t im4m_size = 0; - const uint8_t* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ece455ed..f27c3572 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -771,7 +771,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) usbf = plist_copy(usbf); plist_dict_remove_item(usbf, "Info"); plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); - plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data(pdfu_nonce, pdfu_nsize)); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); plist_t request = tss_request_new(NULL); if (request == NULL) { @@ -1236,7 +1236,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->mode == MODE_RESTORE && client->root_ticket) { - plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len); + plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len); if (!ap_ticket) { error("ERROR: Failed to create ApImg4Ticket node value.\n"); return -1; @@ -2263,14 +2263,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2387,7 +2387,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApNonce */ if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; @@ -2395,7 +2395,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApSepNonce */ if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2496,7 +2496,7 @@ int get_recovery_os_local_policy_tss_response( uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2518,7 +2518,7 @@ int get_recovery_os_local_policy_tss_response( for (i = 0; i < 16; i++) { vol_uuid[i] = (unsigned char)vuuid[i]; } - plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data(vol_uuid, 16)); + plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data((char*)vol_uuid, 16)); /* create basic request */ request = tss_request_new(NULL); @@ -2566,14 +2566,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2591,7 +2591,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2603,7 +2603,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; SHA384(ticket, ticket_length, hash); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data(hash, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); /* create basic request */ request = tss_request_new(NULL); diff --git a/src/img4.c b/src/img4.c index 2d1cc43a..9a0cb29f 100644 --- a/src/img4.c +++ b/src/img4.c @@ -457,7 +457,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucon_size = 0; - const uint8_t* ucon_data = plist_get_data_ptr(dt, &ucon_size); + const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -468,7 +468,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucer_size = 0; - const uint8_t* ucer_data = plist_get_data_ptr(dt, &ucer_size); + const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -705,13 +705,11 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "Digest"); if (node) { - uint8_t *digest = NULL; uint64_t digest_len = 0; - plist_get_data_val(node, &digest, &digest_len); + const char *digest = plist_get_data_ptr(node, &digest_len); if (digest_len > 0) { - _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, digest, digest_len); + _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, (void*)digest, digest_len); } - free(digest); } node = plist_dict_get_item(comp, "Trusted"); @@ -740,9 +738,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "TBMDigests"); if (node) { - uint8_t *data = NULL; uint64_t datalen = 0; - plist_get_data_val(node, &data, &datalen); + const char *data = plist_get_data_ptr(node, &datalen); const char *tbmtag = NULL; if (!strcmp(tag, "sepi")) { tbmtag = "tbms"; @@ -752,9 +749,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c if (!tbmtag) { error("ERROR: Unexpected TMBDigests for comp '%s'\n", tag); } else { - _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, data, datalen); + _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, (void*)data, datalen); } - free(data); } asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, tmp_len, &inner_start, &inner_length); @@ -907,7 +903,7 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* length += hdr_len; - *manifest = plist_new_data(buf, length); + *manifest = plist_new_data((char*)buf, length); free(buf); diff --git a/src/restore.c b/src/restore.c index 0e553389..050ee3b2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -976,7 +976,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1000,7 +1000,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1029,7 +1029,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1053,7 +1053,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1118,7 +1118,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } dict = plist_new_dict(); - blob = plist_new_data(data, size); + blob = plist_new_data((char*)data, size); char compkeyname[256]; sprintf(compkeyname, "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); @@ -1279,7 +1279,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } dict = plist_new_dict(); - plist_dict_set_item(dict, "LlbImageData", plist_new_data(llb_data, llb_size)); + plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, llb_size)); free(llb_data); if (flash_version_1) { @@ -1339,13 +1339,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_size = 0; if (flash_version_1) { - plist_dict_set_item(norimage, component, plist_new_data(nor_data, nor_size)); + plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, nor_size)); } else { /* make sure iBoot is the first entry in the array */ if (!strncmp("iBoot", component, 5)) { - plist_array_insert_item(norimage, plist_new_data(nor_data, nor_size), 0); + plist_array_insert_item(norimage, plist_new_data((char*)nor_data, nor_size), 0); } else { - plist_array_append_item(norimage, plist_new_data(nor_data, nor_size)); + plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size)); } } @@ -1381,7 +1381,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1406,7 +1406,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1431,7 +1431,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1510,7 +1510,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } unsigned char* buffer = NULL; - unsigned char* blob = NULL; + const unsigned char* blob = NULL; unsigned char* fdata = NULL; uint64_t fsize = 0; uint64_t blob_size = 0; @@ -1607,9 +1607,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(buffer); buffer = NULL; - blob = NULL; blob_size = 0; - plist_get_data_val(node, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size); if (!blob) { error("ERROR: could not get %s-Blob data\n", key); goto leave; @@ -1626,8 +1625,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } } - free(blob); - blob = NULL; fsize = (is_fls ? fls->size : mbn->size); fdata = (unsigned char*)malloc(fsize); @@ -1740,9 +1737,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1752,8 +1748,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned error("ERROR: could not insert BBTicket to ebl.fls\n"); goto leave; } - free(blob); - blob = NULL; fsize = fls->size; fdata = (unsigned char*)malloc(fsize); @@ -1778,20 +1772,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } else { // add BBTicket as bbticket.der - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; } - zs = zip_source_buffer(za, blob, blob_size, 1); + zs = zip_source_buffer(za, blob, blob_size, 0); if (!zs) { error("ERROR: out of memory\n"); goto leave; } - blob = NULL; if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { error("ERROR: could not add bbticket.der to archive\n"); @@ -1824,7 +1816,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned mbn_free(mbn); fls_free(fls); free(buffer); - free(blob); return res; } @@ -1839,7 +1830,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer uint64_t bb_nonce_size = 0; uint64_t bb_chip_id = 0; plist_t response = NULL; - uint8_t* buffer = NULL; + char* buffer = NULL; char* bbfwtmp = NULL; plist_t dict = NULL; @@ -1860,11 +1851,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } plist_t bb_snum_node = plist_dict_get_item(arguments, "ChipSerialNo"); if (bb_snum_node && plist_get_node_type(bb_snum_node) == PLIST_DATA) { - plist_get_data_val(bb_snum_node, &bb_snum, &bb_snum_size); + plist_get_data_val(bb_snum_node, (char**)&bb_snum, &bb_snum_size); } plist_t bb_nonce_node = plist_dict_get_item(arguments, "Nonce"); if (bb_nonce_node && plist_get_node_type(bb_nonce_node) == PLIST_DATA) { - plist_get_data_val(bb_nonce_node, &bb_nonce, &bb_nonce_size); + plist_get_data_val(bb_nonce_node, (char**)&bb_nonce, &bb_nonce_size); } } @@ -1873,11 +1864,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (bb_nonce) { - plist_dict_set_item(parameters, "BbNonce", plist_new_data(bb_nonce, bb_nonce_size)); + plist_dict_set_item(parameters, "BbNonce", plist_new_data((const char*)bb_nonce, bb_nonce_size)); } plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id)); plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); - plist_dict_set_item(parameters, "BbSNUM", plist_new_data(bb_snum, bb_snum_size)); + plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); tss_parameters_add_from_manifest(parameters, build_identity, true); @@ -2109,7 +2100,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest error("ERROR: Unable to get personalized component: %s\n", component); } - plist_dict_set_item(data_dict, component, plist_new_data(data, size)); + plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); free(data); } } @@ -2256,7 +2247,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2347,7 +2338,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc *(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size); component_size += 16; - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2429,7 +2420,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru comp_name = NULL; plist_t firmware_data = plist_new_dict(); - plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data(component_data, component_size)); + plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char*)component_data, component_size)); plist_dict_set_item(response, "FirmwareData", firmware_data); free(component_data); @@ -2578,7 +2569,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2676,7 +2667,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_to_bin(fw_map, &bin_plist, &bin_size); plist_free(fw_map); - plist_dict_set_item(response, "FirmwareData", plist_new_data((uint8_t*)bin_plist, bin_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, bin_size)); free(bin_plist); return response; @@ -2798,7 +2789,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2983,7 +2974,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -3549,7 +3540,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi plist_t dict = plist_new_dict(); if (data != NULL) { // Send a chunk of file data - plist_dict_set_item(dict, "FileData", plist_new_data(data, size)); + plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); } else { // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); @@ -3806,7 +3797,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer } plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data(data, size)); + plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); int restore_error = restored_send(restore, dict); if (restore_error != RESTORE_E_SUCCESS) { diff --git a/src/tss.c b/src/tss.c index 04d51087..99781ef7 100644 --- a/src/tss.c +++ b/src/tss.c @@ -961,9 +961,8 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; node = plist_dict_get_item(parameters, "Savage,Revision"); if (node && (plist_get_node_type(node) == PLIST_DATA)) { - unsigned char *savage_rev = NULL; uint64_t savage_rev_len = 0; - plist_get_data_val(node, &savage_rev, &savage_rev_len); + const unsigned char *savage_rev = (const unsigned char*)plist_get_data_ptr(node, &savage_rev_len); if (savage_rev_len > 0) { if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; @@ -971,7 +970,6 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch"; } } - free(savage_rev); } /* add Savage,B?-*-Patch */ @@ -1659,7 +1657,7 @@ static int tss_response_get_data_by_key(plist_t response, const char* name, unsi return -1; } - uint8_t* data = NULL; + char* data = NULL; uint64_t len = 0; plist_get_data_val(node, &data, &len); if (data) { @@ -1718,7 +1716,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** uint32_t tss_size = 0; uint64_t blob_size = 0; char* entry_key = NULL; - uint8_t* blob_data = NULL; + char* blob_data = NULL; char* entry_path = NULL; plist_t tss_entry = NULL; plist_t blob_node = NULL; @@ -1772,7 +1770,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) { uint64_t blob_size = 0; - uint8_t* blob_data = NULL; + char* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; From c4c7d2339e9ceeeddb9f9465ff5cdd160a6a9358 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 18 May 2024 23:42:00 +0200 Subject: [PATCH 078/159] automake: Prevent `dist` or `distcheck` when uncommitted changes are present --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index c86bf426..efaae8e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,4 +8,5 @@ EXTRA_DIST = \ git-version-gen dist-hook: + @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi echo $(VERSION) > $(distdir)/.tarball-version From 56d2c01505479b85e9aeddf58cd4237bf4242c2c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 18 May 2024 23:50:02 +0200 Subject: [PATCH 079/159] Add missing cast to silence compiler warning --- src/normal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/normal.c b/src/normal.c index 8070982b..e699bbe6 100644 --- a/src/normal.c +++ b/src/normal.c @@ -333,7 +333,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const } uint64_t n_size = 0; - plist_get_data_val(nonce_node, nonce, &n_size); + plist_get_data_val(nonce_node, (char**)nonce, &n_size); *nonce_size = (unsigned int)n_size; plist_free(nonce_node); From 04a3f49132522f514ef36117dd908990e278dbbc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 23 May 2024 23:22:06 +0200 Subject: [PATCH 080/159] Link against the new libtatsu and remove tss code --- configure.ac | 3 + src/Makefile.am | 3 +- src/dfu.c | 3 +- src/idevicerestore.c | 3 +- src/img4.c | 3 +- src/recovery.c | 3 +- src/restore.c | 2 +- src/tss.c | 1794 ------------------------------------------ src/tss.h | 76 -- 9 files changed, 14 insertions(+), 1876 deletions(-) delete mode 100644 src/tss.c delete mode 100644 src/tss.h diff --git a/configure.ac b/configure.ac index 0b5fcea2..4686e199 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 +LIBTATSU_VERSION=1.0.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 @@ -29,6 +30,7 @@ AC_SUBST(LIBIMOBILEDEVICE_VERSION) AC_SUBST(LIBUSBMUXD_VERSION) AC_SUBST(LIBPLIST_VERSION) AC_SUBST(LIMD_GLUE_VERSION) +AC_SUBST(LIBTATSU_VERSION) AC_SUBST(LIBZIP_VERSION) AC_SUBST(LIBCURL_VERSION) AC_SUBST(OPENSSL_VERSION) @@ -44,6 +46,7 @@ PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= $LIBIMOBILEDEVICE_VE PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION) PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION) +PKG_CHECK_MODULES(libtatsu, libtatsu-1.0 >= $LIBTATSU_VERSION) PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) PKG_CHECK_MODULES(libcurl, libcurl >= $LIBCURL_VERSION) PKG_CHECK_MODULES(zlib, zlib) diff --git a/src/Makefile.am b/src/Makefile.am index 722487a2..88602e50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ AM_CFLAGS = \ $(libusbmuxd_CFLAGS) \ $(libplist_CFLAGS) \ $(limd_glue_CFLAGS) \ + $(libtatsu_CFLAGS) \ $(libzip_CFLAGS) \ $(zlib_CFLAGS) \ $(openssl_CFLAGS) \ @@ -18,6 +19,7 @@ AM_LDFLAGS = \ $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ $(limd_glue_LIBS) \ + $(libtatsu_LIBS) \ $(libzip_LIBS) \ $(zlib_LIBS) \ $(openssl_LIBS) \ @@ -31,7 +33,6 @@ idevicerestore_SOURCES = \ idevicerestore.c idevicerestore.h \ endianness.h \ common.c common.h \ - tss.c tss.h \ fls.c fls.h \ mbn.c mbn.h \ img3.c img3.h \ diff --git a/src/dfu.c b/src/dfu.c index cc8e1fbf..8557c292 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -27,8 +27,9 @@ #include #include +#include + #include "dfu.h" -#include "tss.h" #include "recovery.h" #include "idevicerestore.h" #include "common.h" diff --git a/src/idevicerestore.c b/src/idevicerestore.c index f27c3572..0b517b9f 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -46,10 +46,10 @@ #endif #include +#include #include "ace3.h" #include "dfu.h" -#include "tss.h" #include "img3.h" #include "img4.h" #include "ipsw.h" @@ -359,6 +359,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevice_set_debug_level(1); irecv_set_debug_level(1); } + tss_set_debug_level(client->debug_level); } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); diff --git a/src/img4.c b/src/img4.c index 9a0cb29f..cfd3c934 100644 --- a/src/img4.c +++ b/src/img4.c @@ -22,9 +22,10 @@ #include #include +#include + #include "common.h" #include "img4.h" -#include "tss.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f diff --git a/src/recovery.c b/src/recovery.c index e3fb4d19..afda4a97 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -29,8 +29,9 @@ #include #include +#include + #include "idevicerestore.h" -#include "tss.h" #include "img3.h" #include "restore.h" #include "recovery.h" diff --git a/src/restore.c b/src/restore.c index 050ee3b2..efb03f93 100644 --- a/src/restore.c +++ b/src/restore.c @@ -38,6 +38,7 @@ #endif #include #include +#include #include "idevicerestore.h" #include "asr.h" @@ -45,7 +46,6 @@ #include "fls.h" #include "mbn.h" #include "ftab.h" -#include "tss.h" #include "ipsw.h" #include "restore.h" #include "common.h" diff --git a/src/tss.c b/src/tss.c deleted file mode 100644 index 99781ef7..00000000 --- a/src/tss.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* - * tss.c - * Functions for communicating with Apple's TSS server - * - * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. - * 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 -#include -#include -#include -#include -#include - -#include "tss.h" -#include "img3.h" -#include "common.h" -#include "idevicerestore.h" - -#include "endianness.h" - -#define AUTH_VERSION "973.40.2" - -#ifdef WIN32 -#define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" -#else -#define TSS_CLIENT_VERSION_STRING "libauthinstall-"AUTH_VERSION"" -#endif -#define ECID_STRSIZE 0x20 - -typedef struct { - int length; - char* content; -} tss_response; - -char* ecid_to_string(uint64_t ecid) -{ - char* ecid_string = malloc(ECID_STRSIZE); - memset(ecid_string, '\0', ECID_STRSIZE); - if (ecid == 0) { - error("ERROR: Invalid ECID passed.\n"); - return NULL; - } - snprintf(ecid_string, ECID_STRSIZE, "%"PRIu64, ecid); - return ecid_string; -} - -plist_t tss_request_new(plist_t overrides) -{ - plist_t request = plist_new_dict(); - - plist_dict_set_item(request, "@HostPlatformInfo", -#ifdef WIN32 - plist_new_string("windows") -#else - plist_new_string("mac") -#endif - ); - - plist_dict_set_item(request, "@VersionInfo", plist_new_string(TSS_CLIENT_VERSION_STRING)); - char* guid = generate_guid(); - if (guid) { - plist_dict_set_item(request, "@UUID", plist_new_string(guid)); - free(guid); - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return request; -} - -int tss_request_add_local_policy_tags(plist_t request, plist_t parameters) -{ - plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - - if (plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { - error("ERROR: Unable to find required Ap,LocalBoot in parameters\n"); - return -1; - } - - if (plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { - error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n"); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { - error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n"); - return -1; - } - - plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); - plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); - plist_dict_copy_uint(request, parameters, "ApECID", NULL); - plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - plist_dict_copy_data(request, parameters, "ApNonce", NULL); - - if (!plist_dict_get_item(request, "ApSecurityMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityMode in parameters\n"); - return -1; - } - } - if (!plist_dict_get_item(request, "ApProductionMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - } - - return 0; -} - -int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest) -{ - plist_t node = NULL; - - if (plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { - error("ERROR: Unable to find UniqueBuildID node\n"); - return -1; - } - - plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); - - if (plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; - error("ERROR: Unable to find ApChipID node\n"); - return -1; - } - - if (plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { - error("ERROR: Unable to find ApBoardID node\n"); - return -1; - } - - plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); - plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); - - if (plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { - debug("NOTE: Unable to find BbChipID node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbActivationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n"); - } - - /* BbSkeyId - Used by XMM 6180/GSM */ - if (plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { - debug("NOTE: Unable to find BbSkeyId node\n"); - } - - /* SE,ChipID - Used for SE firmware request */ - plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); - - /* Savage,ChipID - Used for Savage firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); - - /* add Savage,PatchEpoch - Used for Savage firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); - - /* Yonkers,BoardID - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); - - /* Yonkers,ChipID - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); - - /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); - - plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); - - plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); - plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); - - plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); - - plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); - - node = plist_dict_get_item(build_identity, "Info"); - if (node) { - plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); - } - - if (include_manifest) { - /* add build identity manifest dictionary */ - node = plist_dict_get_item(build_identity, "Manifest"); - if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to find Manifest node\n"); - return -1; - } - plist_dict_set_item(parameters, "Manifest", plist_copy(node)); - } - - return 0; -} - -int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) -{ - if (!parameters) { - error("ERROR: Missing required AP parameters\n"); - return -1; - } - - plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); - - if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("ERROR: Unable to find required ApNonce in parameters\n"); - return -1; - } - - plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - - if (!plist_dict_get_item(request, "ApSecurityMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityMode in parameters\n"); - return -1; - } - } - if (!plist_dict_get_item(request, "ApProductionMode")) { - /* ApProductionMode */ - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - } - - plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); - plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); - plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); - - if (plist_dict_get_item(parameters, "UID_MODE")) { - plist_dict_copy_item(request, parameters, "UID_MODE", NULL); - } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { - // The logic here is missing why this value is expected to be 'false' - plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); - } - - // FIXME: I didn't understand yet when this value is set, so for now we use a workaround - if (plist_dict_get_item(parameters, "ApSikaFuse")) { - plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); - } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { - // Workaround: We have only seen Ap,SikaFuse together with UID_MODE - plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); - } - - return 0; -} - -int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) -{ - if (!parameters) { - error("ERROR: Missing required AP parameters\n"); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("WARNING: Unable to find ApNonce in parameters\n"); - } - - plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); - - if (plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { - error("ERROR: Unable to find required ApBoardID in request\n"); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { - error("ERROR: Unable to find required ApChipID in request\n"); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityDomain in request\n"); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - - return 0; -} - -int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_dict_copy_uint(request, parameters, "ApECID", NULL); - plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); - plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -static void tss_entry_apply_restore_request_rules(plist_t tss_entry, plist_t parameters, plist_t rules) -{ - if (!tss_entry || !rules) { - return; - } - if (plist_get_node_type(tss_entry) != PLIST_DICT) { - return; - } - if (plist_get_node_type(rules) != PLIST_ARRAY) { - return; - } - - uint32_t i; - for (i = 0; i < plist_array_get_size(rules); i++) { - plist_t rule = plist_array_get_item(rules, i); - plist_t conditions = plist_dict_get_item(rule, "Conditions"); - plist_dict_iter iter = NULL; - plist_dict_new_iter(conditions, &iter); - char* key = NULL; - plist_t value = NULL; - plist_t value2 = NULL; - int conditions_fulfilled = 1; - while (conditions_fulfilled) { - plist_dict_next_item(conditions, iter, &key, &value); - if (key == NULL) - break; - if (!strcmp(key, "ApRawProductionMode")) { - value2 = plist_dict_get_item(parameters, "ApProductionMode"); - } else if (!strcmp(key, "ApCurrentProductionMode")) { - value2 = plist_dict_get_item(parameters, "ApProductionMode"); - } else if (!strcmp(key, "ApRawSecurityMode")) { - value2 = plist_dict_get_item(parameters, "ApSecurityMode"); - } else if (!strcmp(key, "ApRequiresImage4")) { - value2 = plist_dict_get_item(parameters, "ApSupportsImg4"); - } else if (!strcmp(key, "ApDemotionPolicyOverride")) { - value2 = plist_dict_get_item(parameters, "DemotionPolicy"); - } else if (!strcmp(key, "ApInRomDFU")) { - value2 = plist_dict_get_item(parameters, "ApInRomDFU"); - } else { - error("WARNING: Unhandled condition '%s' while parsing RestoreRequestRules\n", key); - value2 = NULL; - } - if (value2) { - conditions_fulfilled = plist_compare_node_value(value, value2); - } else { - conditions_fulfilled = 0; - } - free(key); - } - free(iter); - iter = NULL; - - if (!conditions_fulfilled) { - continue; - } - - plist_t actions = plist_dict_get_item(rule, "Actions"); - plist_dict_new_iter(actions, &iter); - while (1) { - plist_dict_next_item(actions, iter, &key, &value); - if (key == NULL) - break; - uint8_t bv = 255; - plist_get_bool_val(value, &bv); - if (bv != 255) { - value2 = plist_dict_get_item(tss_entry, key); - if (value2) { - plist_dict_remove_item(tss_entry, key); - } - debug("DEBUG: Adding %s=%s to TSS entry\n", key, (bv) ? "true" : "false"); - plist_dict_set_item(tss_entry, key, plist_new_bool(bv)); - } - free(key); - } - } -} - -int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - /* loop over components from build manifest */ - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find restore manifest\n"); - return -1; - } - - /* add components to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - /* do not populate BaseBandFirmware, only in basebaseband request */ - if ((strcmp(key, "BasebandFirmware") == 0)) { - continue; - } - - // Compared to ac2, not needed for RecoveryOSRootTicket - if ((strcmp(key, "SE,UpdatePayload") == 0)) { - continue; - } - if ((strcmp(key, "BaseSystem") == 0)) { - continue; - } - if ((strcmp(key, "ANS") == 0)) { - continue; - } - if ((strcmp(key, "Ap,AudioBootChime") == 0)) { - continue; - } - if ((strcmp(key, "Ap,CIO") == 0)) { - continue; - } - if ((strcmp(key, "Ap,RestoreCIO") == 0)) { - continue; - } - if ((strcmp(key, "Ap,RestoreTMU") == 0)) { - continue; - } - if ((strcmp(key, "Ap,TMU") == 0)) { - continue; - } - if ((strcmp(key, "Ap,rOSLogo1") == 0)) { - continue; - } - if ((strcmp(key, "Ap,rOSLogo2") == 0)) { - continue; - } - if ((strcmp(key, "AppleLogo") == 0)) { - continue; - } - if ((strcmp(key, "DCP") == 0)) { - continue; - } - if ((strcmp(key, "LLB") == 0)) { - continue; - } - if ((strcmp(key, "RecoveryMode") == 0)) { - continue; - } - if ((strcmp(key, "RestoreANS") == 0)) { - continue; - } - if ((strcmp(key, "RestoreDCP") == 0)) { - continue; - } - if ((strcmp(key, "RestoreDeviceTree") == 0)) { - continue; - } - if ((strcmp(key, "RestoreKernelCache") == 0)) { - continue; - } - if ((strcmp(key, "RestoreLogo") == 0)) { - continue; - } - if ((strcmp(key, "RestoreRamDisk") == 0)) { - continue; - } - if ((strcmp(key, "RestoreSEP") == 0)) { - continue; - } - if ((strcmp(key, "SEP") == 0)) { - continue; - } - if ((strcmp(key, "ftap") == 0)) { - continue; - } - if ((strcmp(key, "ftsp") == 0)) { - continue; - } - if ((strcmp(key, "iBEC") == 0)) { - continue; - } - if ((strcmp(key, "iBSS") == 0)) { - continue; - } - if ((strcmp(key, "rfta") == 0)) { - continue; - } - if ((strcmp(key, "rfts") == 0)) { - continue; - } - - /* FIXME: only used with diagnostics firmware */ - if (strcmp(key, "Diags") == 0) { - continue; - } - - plist_t info_dict = plist_dict_get_item(manifest_entry, "Info"); - if (!info_dict) { - continue; - } - - if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted")) { - debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); - continue; - } - - if (!plist_dict_get_bool(info_dict, "IsFirmwarePayload") - && !plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - && !plist_dict_get_bool(info_dict, "IsFUDFirmware") - && !plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - && !plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - && !plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - && !plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) - { - debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); - continue; - } - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove obsolete Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* handle RestoreRequestRules */ - plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); - if (rules) { - debug("DEBUG: Applying restore request rules for entry %s\n", key); - tss_entry_apply_restore_request_rules(tss_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", key); - plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); - } - - /* finally add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - /* loop over components from build manifest */ - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find restore manifest\n"); - return -1; - } - - /* add components to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - /* do not populate BaseBandFirmware, only in basebaseband request */ - if ((strcmp(key, "BasebandFirmware") == 0)) { - continue; - } - - // Compared to ac2, not needed - if ((strcmp(key, "SE,UpdatePayload") == 0)) { - continue; - } - - // Compared to ac2, not needed - if ((strcmp(key, "BaseSystem") == 0)) { - continue; - } - - /* FIXME: only used with diagnostics firmware */ - if (strcmp(key, "Diags") == 0) { - continue; - } - - plist_t info_dict = plist_dict_get_item(manifest_entry, "Info"); - if (!info_dict) { - continue; - } - - if (plist_dict_get_bool(parameters, "ApSupportsImg4")) { - if (!plist_dict_get_item(info_dict, "RestoreRequestRules")) { - debug("DEBUG: %s: Skipping '%s' as it doesn't have RestoreRequestRules\n", __func__, key); - continue; - } - } - - int is_fw_payload = plist_dict_get_bool(info_dict, "IsFirmwarePayload") - || plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - || plist_dict_get_bool(info_dict, "IsFUDFirmware") - || plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - || plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - || plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - || plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); - - if (plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); - continue; - } - } else if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted")) { - debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); - continue; - } - if (!is_fw_payload) { - debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); - continue; - } - } - - /* skip components with IsFTAB:true */ - if (plist_dict_get_bool(info_dict, "IsFTAB")) { - debug("DEBUG: %s: Skipping FTAB component '%s'\n", __func__, key); - continue; - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove obsolete Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* handle RestoreRequestRules */ - plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); - if (rules) { - debug("DEBUG: Applying restore request rules for entry %s\n", key); - tss_entry_apply_restore_request_rules(tss_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", key); - plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); - } - - /* finally add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "BbChipID", NULL); - plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); - /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */ - plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); - /* BbSkeyId - Used by XMM 6180/GSM */ - plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); - plist_dict_copy_data(request, parameters, "BbNonce", NULL); - plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); - - uint64_t bb_chip_id = plist_dict_get_uint(request, "BbChipID"); - int32_t bb_cert_id = (int32_t)plist_dict_get_uint(request, "BbGoldCertId"); - - if (plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { - error("ERROR: Unable to find required BbSNUM in parameters\n"); - return -1; - } - - /* BasebandFirmware */ - node = plist_access_path(parameters, 2, "Manifest", "BasebandFirmware"); - if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to get BasebandFirmware node\n"); - return -1; - } - plist_t bbfwdict = plist_copy(node); - node = NULL; - if (plist_dict_get_item(bbfwdict, "Info")) { - plist_dict_remove_item(bbfwdict, "Info"); - } - - if (bb_chip_id == 0x68) { - /* depending on the BasebandCertId remove certain nodes */ - if (bb_cert_id == 0x26F3FACC || bb_cert_id == 0x5CF2EC4E || bb_cert_id == 0x8399785A) { - plist_dict_remove_item(bbfwdict, "PSI2-PartialDigest"); - plist_dict_remove_item(bbfwdict, "RestorePSI2-PartialDigest"); - } else { - plist_dict_remove_item(bbfwdict, "PSI-PartialDigest"); - plist_dict_remove_item(bbfwdict, "RestorePSI-PartialDigest"); - } - } - - plist_dict_set_item(request, "BasebandFirmware", bbfwdict); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - - if (plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__); - return -1; - } - - /* 'IsDev' determines whether we have Production or Development */ - uint8_t is_dev = plist_dict_get_bool(parameters, "SE,IsDev"); - - /* add SE,* components from build manifest to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - if (strncmp(key, "SE,", 3)) { - continue; - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* remove Development or Production key/hash node */ - if (is_dev) { - if (plist_dict_get_item(tss_entry, "ProductionCMAC")) - plist_dict_remove_item(tss_entry, "ProductionCMAC"); - if (plist_dict_get_item(tss_entry, "ProductionUpdatePayloadHash")) - plist_dict_remove_item(tss_entry, "ProductionUpdatePayloadHash"); - } else { - if (plist_dict_get_item(tss_entry, "DevelopmentCMAC")) - plist_dict_remove_item(tss_entry, "DevelopmentCMAC"); - if (plist_dict_get_item(tss_entry, "DevelopmentUpdatePayloadHash")) - plist_dict_remove_item(tss_entry, "DevelopmentUpdatePayloadHash"); - } - - /* add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - /* fallback in case no @SE2,Ticket or @SE,Ticket was provided */ - if (!plist_dict_get_item(request, "@SE2,Ticket") && !plist_dict_get_item(request, "@SE,Ticket")) { - plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); - } - - return 0; -} - -int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the Savage,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1)); - - if (plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); - return -1; - } - - /* add SEP */ - node = plist_access_path(manifest_node, 2, "SEP", "Digest"); - if (!node) { - error("ERROR: Unable to get SEP digest from manifest\n"); - return -1; - } - plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Digest", plist_copy(node)); - plist_dict_set_item(request, "SEP", dict); - - if (plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); - return -1; - } - - const char *comp_name = NULL; - uint8_t isprod = plist_dict_get_bool(request, "Savage,ProductionMode"); - - /* get the right component name */ - comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; - node = plist_dict_get_item(parameters, "Savage,Revision"); - if (node && (plist_get_node_type(node) == PLIST_DATA)) { - uint64_t savage_rev_len = 0; - const unsigned char *savage_rev = (const unsigned char*)plist_get_data_ptr(node, &savage_rev_len); - if (savage_rev_len > 0) { - if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { - comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; - } else if ((savage_rev[0] & 0xF0) == 0xA0) { - comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch"; - } - } - } - - /* add Savage,B?-*-Patch */ - node = plist_dict_get_item(manifest_node, comp_name); - if (!node) { - error("ERROR: Unable to get %s entry from manifest\n", comp_name); - return -1; - } - dict = plist_copy(node); - plist_dict_remove_item(dict, "Info"); - plist_dict_set_item(request, comp_name, dict); - - if (component_name) { - *component_name = strdup(comp_name); - } - - if (plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); - return -1; - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the Savage,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Yonkers,Ticket", plist_new_bool(1)); - - /* add SEP */ - node = plist_access_path(manifest_node, 2, "SEP", "Digest"); - if (!node) { - error("ERROR: Unable to get SEP digest from manifest\n"); - return -1; - } - plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Digest", plist_copy(node)); - plist_dict_set_item(request, "SEP", dict); - - { - static const char *keys[] = {"Yonkers,AllowOfflineBoot", "Yonkers,BoardID", "Yonkers,ChipID", "Yonkers,ECID", "Yonkers,Nonce", "Yonkers,PatchEpoch", "Yonkers,ProductionMode", "Yonkers,ReadECKey", "Yonkers,ReadFWKey", }; - int i; - for (i = 0; i < (int)(sizeof(keys) / sizeof(keys[0])); ++i) { - node = plist_dict_get_item(parameters, keys[i]); - if (!node) { - error("ERROR: %s: Unable to find required %s in parameters\n", __func__, keys[i]); - } - plist_dict_set_item(request, keys[i], plist_copy(node)); - node = NULL; - } - } - - char *comp_name = NULL; - plist_t comp_node = NULL; - uint8_t isprod = plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); - uint64_t fabrevision = plist_dict_get_uint(parameters, "Yonkers,FabRevision"); - - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (iter) { - node = NULL; - comp_name = NULL; - plist_dict_next_item(manifest_node, iter, &comp_name, &node); - if (comp_name == NULL) { - node = NULL; - break; - } - if (strncmp(comp_name, "Yonkers,", 8) == 0) { - int target_node = 1; - plist_t sub_node; - if ((sub_node = plist_dict_get_item(node, "EPRO")) != NULL && plist_get_node_type(sub_node) == PLIST_BOOLEAN) { - uint8_t b = 0; - plist_get_bool_val(sub_node, &b); - target_node &= ((isprod) ? b : !b); - } - if ((sub_node = plist_dict_get_item(node, "FabRevision")) != NULL && plist_get_node_type(sub_node) == PLIST_UINT) { - uint64_t v = 0; - plist_get_uint_val(sub_node, &v); - target_node &= (v == fabrevision); - } - if (target_node) { - comp_node = node; - break; - } - } - free(comp_name); - } - free(iter); - - if (comp_name == NULL) { - error("ERROR: No Yonkers node for %s/%lu\n", (isprod) ? "Production" : "Development", (unsigned long)fabrevision); - return -1; - } - - /* add Yonkers,SysTopPatch* */ - if (comp_node != NULL) { - plist_t comp_dict = plist_copy(comp_node); - plist_dict_remove_item(comp_dict, "Info"); - plist_dict_set_item(request, comp_name, comp_dict); - } - - if (component_name) { - *component_name = comp_name; - } else { - free(comp_name); - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the eUICC,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); - - plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); - plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); - plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); - plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); - - if (!plist_dict_get_item(request, "eUICC,Gold")) { - plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); - if (n) { - plist_t p = plist_new_dict(); - plist_dict_copy_data(p, n, "Digest", NULL); - plist_dict_set_item(request, "eUICC,Gold", p); - } - } - - if (!plist_dict_get_item(request, "eUICC,Main")) { - plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); - if (n) { - plist_t p = plist_new_dict(); - plist_dict_copy_data(p, n, "Digest", NULL); - plist_dict_set_item(request, "eUICC,Main", p); - } - } - - /* set Nonce for eUICC,Gold component */ - node = plist_dict_get_item(parameters, "EUICCGoldNonce"); - if (node) { - plist_t n = plist_dict_get_item(request, "eUICC,Gold"); - if (n) { - plist_dict_set_item(n, "Nonce", plist_copy(node)); - } - } - - /* set Nonce for eUICC,Main component */ - node = plist_dict_get_item(parameters, "EUICCMainNonce"); - if (node) { - plist_t n = plist_dict_get_item(request, "eUICC,Main"); - if (n) { - plist_dict_set_item(n, "Nonce", plist_copy(node)); - } - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the Rap,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Rap,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); - plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); - plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); - plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); - plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); - plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); - plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); - - char *comp_name = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (iter) { - node = NULL; - comp_name = NULL; - plist_dict_next_item(manifest_node, iter, &comp_name, &node); - if (comp_name == NULL) { - node = NULL; - break; - } - if (strncmp(comp_name, "Rap,", 4) == 0) { - plist_t manifest_entry = plist_copy(node); - - /* handle RestoreRequestRules */ - plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); - if (rules) { - debug("DEBUG: Applying restore request rules for entry %s\n", comp_name); - tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); - plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); - } - - plist_dict_remove_item(manifest_entry, "Info"); - - /* finally add entry to request */ - plist_dict_set_item(request, comp_name, manifest_entry); - } - free(comp_name); - } - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the BMU,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@BMU,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); - plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); - plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); - plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); - - char *comp_name = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (iter) { - node = NULL; - comp_name = NULL; - plist_dict_next_item(manifest_node, iter, &comp_name, &node); - if (comp_name == NULL) { - node = NULL; - break; - } - if (strncmp(comp_name, "BMU,", 4) == 0) { - plist_t manifest_entry = plist_copy(node); - - /* handle RestoreRequestRules */ - plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); - if (rules) { - debug("DEBUG: Applying restore request rules for entry %s\n", comp_name); - tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); - plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); - } - - plist_dict_remove_item(manifest_entry, "Info"); - - /* finally add entry to request */ - plist_dict_set_item(request, comp_name, manifest_entry); - } - free(comp_name); - } - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the Baobab,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Baobab,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); - plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); - plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); - plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); - - uint8_t isprod = plist_dict_get_bool(parameters, "Baobab,ProductionMode"); - - char *comp_name = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (iter) { - node = NULL; - comp_name = NULL; - plist_dict_next_item(manifest_node, iter, &comp_name, &node); - if (comp_name == NULL) { - node = NULL; - break; - } - if (strncmp(comp_name, "Baobab,", 7) == 0) { - plist_t manifest_entry = plist_copy(node); - - plist_dict_remove_item(manifest_entry, "Info"); - plist_dict_set_item(manifest_entry, "EPRO", plist_new_bool(isprod)); - - /* finally add entry to request */ - plist_dict_set_item(request, comp_name, manifest_entry); - } - free(comp_name); - } - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - return 0; -} - -int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - uint32_t tag = 0; - - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); - return -1; - } - - /* add tags indicating we want to get the Timer ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - - node = plist_dict_get_item(parameters, "TicketName"); - if (!node) { - error("ERROR: %s: Missing TicketName\n", __func__); - return -1; - } - char key[64]; - sprintf(key, "@%s", plist_get_string_ptr(node, NULL)); - - plist_dict_set_item(request, key, plist_new_bool(1)); - - tag = (uint32_t)plist_dict_get_uint(parameters, "TagNumber"); - - sprintf(key, "Timer,BoardID,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,ChipID,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,SecurityDomain,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,SecurityMode,%u", tag); - plist_dict_copy_bool(request, parameters, key, NULL); - - sprintf(key, "Timer,ProductionMode,%u", tag); - plist_dict_copy_bool(request, parameters, key, NULL); - - sprintf(key, "Timer,ECID,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,Nonce,%u", tag); - plist_dict_copy_data(request, parameters, key, NULL); - - char *comp_name = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (iter) { - node = NULL; - comp_name = NULL; - plist_dict_next_item(manifest_node, iter, &comp_name, &node); - if (comp_name == NULL) { - node = NULL; - break; - } - if (!strncmp(comp_name, "Timer,", 6)) { - plist_t manifest_entry = plist_copy(node); - - /* handle RestoreRequestRules */ - plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); - if (rules) { - debug("DEBUG: Applying restore request rules for entry %s\n", comp_name); - tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); - plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); - } - - plist_dict_remove_item(manifest_entry, "Info"); - - /* finally add entry to request */ - plist_dict_set_item(request, comp_name, manifest_entry); - } - free(comp_name); - } - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - tss_request_add_common_tags(request, parameters, NULL); - - if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { - /* Cryptex1LocalPolicy */ - tss_request_add_local_policy_tags(request, parameters); - plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); - } else { - /* Cryptex1 */ - plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); - - plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); - plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); - - plist_dict_iter iter = NULL; - plist_dict_new_iter(parameters, &iter); - plist_t value = NULL; - while (1) { - char *key = NULL; - plist_dict_next_item(parameters, iter, &key, &value); - if (key == NULL) - break; - if (strncmp(key, "Cryptex1", 8) == 0) { - plist_dict_set_item(request, key, plist_copy(value)); - } - free(key); - } - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -static 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; -} - -plist_t tss_request_send(plist_t tss_request, const char* server_url_string) -{ - if (idevicerestore_debug) { - debug_plist(tss_request); - } - - char* request = NULL; - int status_code = -1; - int retry = 0; - int max_retries = 15; - unsigned int size = 0; - char curl_error_message[CURL_ERROR_SIZE]; - - const char* urls[6] = { - "https://gs.apple.com/TSS/controller?action=2", - "https://17.171.36.30/TSS/controller?action=2", - "https://17.151.36.30/TSS/controller?action=2", - "http://gs.apple.com/TSS/controller?action=2", - "http://17.171.36.30/TSS/controller?action=2", - "http://17.151.36.30/TSS/controller?action=2" - }; - - plist_to_xml(tss_request, &request, &size); - - tss_response* response = NULL; - memset(curl_error_message, '\0', CURL_ERROR_SIZE); - - while (retry++ < max_retries) { - response = NULL; - CURL* handle = curl_easy_init(); - if (handle == NULL) { - break; - } - struct curl_slist* header = NULL; - header = curl_slist_append(header, "Cache-Control: no-cache"); - header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\""); - header = curl_slist_append(header, "Expect:"); - - response = malloc(sizeof(tss_response)); - if (response == NULL) { - fprintf(stderr, "Unable to allocate sufficient memory\n"); - return NULL; - } - - response->length = 0; - response->content = malloc(1); - response->content[0] = '\0'; - - /* disable SSL verification to allow download from untrusted https locations */ - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request); - curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING); - curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); - if (server_url_string) { - curl_easy_setopt(handle, CURLOPT_URL, server_url_string); - info("Request URL set to %s\n", server_url_string); - } else { - int url_index = (retry - 1) % 6; - curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]); - info("Request URL set to %s\n", urls[url_index]); - } - - info("Sending TSS request attempt %d... ", retry); - - curl_easy_perform(handle); - curl_slist_free_all(header); - curl_easy_cleanup(handle); - - if (strstr(response->content, "MESSAGE=SUCCESS")) { - status_code = 0; - info("response successfully received\n"); - break; - } - - if (response->length > 0) { - error("TSS server returned: %s\n", response->content); - } - - char* status = strstr(response->content, "STATUS="); - if (status) { - sscanf(status+7, "%d&%*s", &status_code); - } - if (status_code == -1) { - error("%s\n", curl_error_message); - // no status code in response. retry - free(response->content); - free(response); - response = NULL; - sleep(2); - continue; - } else if (status_code == 8) { - // server error (invalid bb request?) - break; - } else if (status_code == 49) { - // server error (invalid bb data, e.g. BbSNUM?) - break; - } else if (status_code == 69 || status_code == 94) { - // This device isn't eligible for the requested build. - break; - } else if (status_code == 100) { - // server error, most likely the request was malformed - break; - } else if (status_code == 126) { - // An internal error occured, most likely the request was malformed - break; - } else { - error("ERROR: tss_send_request: Unhandled status code %d\n", status_code); - } - } - - if (status_code != 0) { - if (response && strstr(response->content, "MESSAGE=") != NULL) { - char* message = strstr(response->content, "MESSAGE=") + strlen("MESSAGE="); - error("ERROR: TSS request failed (status=%d, message=%s)\n", status_code, message); - } else { - error("ERROR: TSS request failed: %s (status=%d)\n", curl_error_message, status_code); - } - free(request); - if (response) free(response->content); - if (response) free(response); - return NULL; - } - - char* tss_data = strstr(response->content, "content); - free(response); - return NULL; - } - - uint32_t tss_size = 0; - plist_t tss_response = NULL; - tss_size = response->length - (tss_data - response->content); - plist_from_xml(tss_data, tss_size, &tss_response); - free(response->content); - free(response); - - if (idevicerestore_debug) { - debug_plist(tss_response); - } - - free(request); - - return tss_response; -} - -static int tss_response_get_data_by_key(plist_t response, const char* name, unsigned char** buffer, unsigned int* length) -{ - plist_t node = plist_dict_get_item(response, name); - if (!node || plist_get_node_type(node) != PLIST_DATA) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, name); - return -1; - } - - char* data = NULL; - uint64_t len = 0; - plist_get_data_val(node, &data, &len); - if (data) { - *length = (unsigned int)len; - *buffer = (unsigned char*)data; - return 0; - } else { - error("ERROR: Unable to get %s data from TSS response\n", name); - return -1; - } -} - -int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "ApImg4Ticket", ticket, length); -} - -int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "APTicket", ticket, length); -} - -int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "BBTicket", ticket, length); -} - -int tss_response_get_path_by_entry(plist_t response, 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(response, entry); - if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry); - return -1; - } - - path_node = plist_dict_get_item(entry_node, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - debug("NOTE: Unable to find %s path in TSS entry\n", entry); - return -1; - } - plist_get_string_val(path_node, &path_string); - - *path = path_string; - return 0; -} - -int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob) -{ - uint32_t 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); - free(iter); - 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); - free(iter); - return -1; - } - plist_get_data_val(blob_node, &blob_data, &blob_size); - break; - } - - free(entry_key); - } - free(iter); - - if (blob_data == NULL || blob_size <= 0) { - return -1; - } - - *blob = (unsigned char*)blob_data; - return 0; -} - -int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned 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(response, entry); - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, 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); - - *blob = (unsigned char*)blob_data; - return 0; -} diff --git a/src/tss.h b/src/tss.h deleted file mode 100644 index 8af2fcca..00000000 --- a/src/tss.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * tss.h - * Definitions for communicating with Apple's TSS server. - * - * Copyright (c) 2013 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. - * 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_TSS_H -#define IDEVICERESTORE_TSS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* parameters */ -int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest); - -/* request */ -plist_t tss_request_new(plist_t overrides); - -int tss_request_add_local_policy_tags(plist_t request, plist_t parameters); -int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name); -int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name); -int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides); - -int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters); -int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters); - -/* i/o */ -plist_t tss_request_send(plist_t request, const char* server_url_string); - -/* response */ -int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_path_by_entry(plist_t response, const char* entry, char** path); -int tss_response_get_blob_by_path(plist_t response, const char* path, unsigned char** blob); -int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob); - -/* helpers */ -char* ecid_to_string(uint64_t ecid); - -#ifdef __cplusplus -} -#endif - -#endif From df06f4d859f7bb0896d1b15ade5b9d2b58626a0e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 23 May 2024 23:38:26 +0200 Subject: [PATCH 081/159] [github-actions] Update build workflow to use new libtatsu --- .github/workflows/build.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76d4a0b8..c07d02ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,6 +48,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{env.target_triplet}} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -122,6 +129,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_macOS repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_macOS + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -253,6 +267,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{ matrix.arch }}-${{ env.dest }} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract From 4ed598bdf865de7d2f202e6d6b9d1d39529f0e8d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 5 Jun 2024 18:24:16 +0200 Subject: [PATCH 082/159] Small change to align with updated libtatsu --- configure.ac | 2 +- src/idevicerestore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4686e199..545b235a 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 -LIBTATSU_VERSION=1.0.0 +LIBTATSU_VERSION=1.0.1 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 0b517b9f..538562de 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2170,7 +2170,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ return -1; } - plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1)); + plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { From 9a4266a39da9bd741dda6aa1c15464ef67bba8d4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 12 Jun 2024 15:09:23 +0200 Subject: [PATCH 083/159] Add missing linebreak to log message --- src/idevicerestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 538562de..25442218 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1495,7 +1495,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // device is finally in restore mode, let's do this if (client->mode == MODE_RESTORE) { if ((client->flags & FLAG_NO_RESTORE) != 0) { - info("Device is now in restore mode. Exiting as requested."); + info("Device is now in restore mode. Exiting as requested.\n"); return 0; } client->ignore_device_add_events = 1; From 4e95bd957981ba6bb1fc56d5f0f9781ed9fa8123 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 12 Jun 2024 19:27:38 +0200 Subject: [PATCH 084/159] Require libtatsu 1.0.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 545b235a..25d1e952 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 -LIBTATSU_VERSION=1.0.1 +LIBTATSU_VERSION=1.0.2 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 From 10cd5f7f0fe14fbf51f2142ea2df153da33d1a21 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 16 Jun 2024 15:53:29 +0200 Subject: [PATCH 085/159] Remove OpenSSL dependency in favor of libimobiledevice-glue's hash functions This also removes the sha1/sha384 code from this repository since we are using the ones from libimobiledevice-glue now. --- .github/workflows/build.yml | 12 -- configure.ac | 33 +--- src/Makefile.am | 5 - src/asr.c | 19 +-- src/fixedint.h | 72 --------- src/idevicerestore.c | 14 +- src/ipsw.c | 18 +-- src/sha1.c | 294 --------------------------------- src/sha1.h | 44 ----- src/sha512.c | 314 ------------------------------------ src/sha512.h | 32 ---- 11 files changed, 13 insertions(+), 844 deletions(-) delete mode 100644 src/fixedint.h delete mode 100644 src/sha1.c delete mode 100644 src/sha1.h delete mode 100644 src/sha512.c delete mode 100644 src/sha512.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c07d02ae..bd2bdd58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -158,18 +158,7 @@ jobs: export CFLAGS="$USEARCHS -isysroot $SDKDIR" echo "Using CFLAGS: $CFLAGS" echo "BUILD_CFLAGS=$CFLAGS" >> $GITHUB_ENV - mkdir -p lib - curl -o lib/libcrypto.35.tbd -Ls \ - https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libcrypto.35.tbd - curl -o lib/libssl.35.tbd -Ls \ - https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libssl.35.tbd - LIBRESSL_VER=2.2.7 - FILENAME="libressl-$LIBRESSL_VER.tar.gz" - curl -o $FILENAME -Ls "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$FILENAME" mkdir -p deps - tar -C deps -xzf $FILENAME - echo "LIBRESSL_CFLAGS=-I`pwd`/deps/libressl-$LIBRESSL_VER/include" >> $GITHUB_ENV - echo "LIBRESSL_LIBS=-Xlinker `pwd`/lib/libssl.35.tbd -Xlinker `pwd`/lib/libcrypto.35.tbd" >> $GITHUB_ENV FILENAME="libzip-static.tar.bz2" curl -o $FILENAME.b64 -Ls "https://gist.github.com/nikias/3da15d03120382f87b44029cd8495a02/raw/99cd8138fed99e8f6530b6f179f787342c698e1f/libzip-1.7.1_static_macOS.tar.bz2" base64 -D < $FILENAME.b64 > $FILENAME @@ -181,7 +170,6 @@ jobs: export CFLAGS="${{env.BUILD_CFLAGS}} -Wno-nullability-completeness -Wno-expansion-to-defined" echo "Using CFLAGS: $CFLAGS" ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \ - openssl_CFLAGS="$LIBRESSL_CFLAGS" openssl_LIBS="$LIBRESSL_LIBS" \ libcurl_CFLAGS="-I${{env.SDKDIR}}/usr/include" libcurl_LIBS="-lcurl" \ libzip_CFLAGS="$LIBZIP_CFLAGS" libzip_LIBS="$LIBZIP_LIBS" \ zlib_CFLAGS="-I${{env.SDKDIR}}/usr/include" zlib_LIBS="-lz" \ diff --git a/configure.ac b/configure.ac index 25d1e952..d2c7f32e 100644 --- a/configure.ac +++ b/configure.ac @@ -19,11 +19,10 @@ LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 -LIMD_GLUE_VERSION=1.2.0 +LIMD_GLUE_VERSION=1.3.0 LIBTATSU_VERSION=1.0.2 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 -OPENSSL_VERSION=0.9.8 AC_SUBST(LIBIRECOVERY_VERSION) AC_SUBST(LIBIMOBILEDEVICE_VERSION) @@ -33,7 +32,6 @@ AC_SUBST(LIMD_GLUE_VERSION) AC_SUBST(LIBTATSU_VERSION) AC_SUBST(LIBZIP_VERSION) AC_SUBST(LIBCURL_VERSION) -AC_SUBST(OPENSSL_VERSION) # Checks for programs. AC_PROG_CC @@ -51,9 +49,6 @@ PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) PKG_CHECK_MODULES(libcurl, libcurl >= $LIBCURL_VERSION) PKG_CHECK_MODULES(zlib, zlib) -# optional -PKG_CHECK_MODULES(openssl, openssl >= $OPENSSL_VERSION, have_openssl=yes, have_openssl=no) - AC_CHECK_FUNCS([strsep strcspn mkstemp realpath]) if test x$ac_cv_func_strsep != xyes; then if test x$ac_cv_func_strcspn != xyes; then @@ -156,32 +151,6 @@ fi CFLAGS="$CACHED_CFLAGS" -AC_ARG_WITH([openssl], - [AS_HELP_STRING([--without-openssl], - [Do not use OpenSSL])], - [use_openssl=$withval], - [use_openssl=$have_openssl]) - -if test "x$use_openssl" == "xyes"; then - if test "x$have_openssl" != "xyes"; then - echo "*** NOTE: --with-openssl passed but OpenSSL is not available ***" - use_openssl=no - fi -fi -if test "x$use_openssl" != "xyes"; then - echo "*** NOTE: Using internal SHA1 implementation ***" - have_openssl=no - openssl_CFLAGS= - openssl_LIBS= -fi -if test "x$have_openssl" == "xyes"; then - AC_DEFINE(HAVE_OPENSSL, [1], [Define if you have OpenSSL]) -fi -AC_SUBST(openssl_CFLAGS) -AC_SUBST(openssl_LIBS) - -AM_CONDITIONAL(USE_INTERNAL_SHA, test x$use_openssl != xyes) - AC_SUBST(GLOBAL_CFLAGS) AC_SUBST(AC_LDFLAGS) AC_SUBST(AC_LDADD) diff --git a/src/Makefile.am b/src/Makefile.am index 88602e50..80f02f20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,6 @@ AM_CFLAGS = \ $(libtatsu_CFLAGS) \ $(libzip_CFLAGS) \ $(zlib_CFLAGS) \ - $(openssl_CFLAGS) \ $(libcurl_CFLAGS) AM_LDFLAGS = \ @@ -22,7 +21,6 @@ AM_LDFLAGS = \ $(libtatsu_LIBS) \ $(libzip_LIBS) \ $(zlib_LIBS) \ - $(openssl_LIBS) \ $(libcurl_LIBS) AM_LDADD = $(AC_LDADD) @@ -50,9 +48,6 @@ idevicerestore_SOURCES = \ limera1n.c limera1n.h \ download.c download.h \ locking.c locking.h -if USE_INTERNAL_SHA -idevicerestore_SOURCES += sha1.c sha1.h sha512.c sha512.h fixedint.h -endif idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) idevicerestore_LDADD = $(AM_LDADD) diff --git a/src/asr.c b/src/asr.c index bf15dc21..aadf25a1 100644 --- a/src/asr.c +++ b/src/asr.c @@ -30,15 +30,8 @@ #include #include #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha1.h" -#define SHA_CTX SHA1_CTX -#define SHA1_Init SHA1Init -#define SHA1_Update SHA1Update -#define SHA1_Final SHA1Final -#endif + +#include #include "asr.h" #include "idevicerestore.h" @@ -343,12 +336,6 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); - SHA_CTX sha1; - - if (asr->checksum_chunks) { - SHA1_Init(&sha1); - } - i = length; int retry = 3; while(i > 0 && retry >= 0) { @@ -367,7 +354,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) sendsize = size; if (asr->checksum_chunks) { - SHA1((unsigned char*)data, size, (unsigned char*)(data+size)); + sha1((unsigned char*)data, size, (unsigned char*)(data+size)); sendsize += 20; } if (asr_send_buffer(asr, data, sendsize) < 0) { diff --git a/src/fixedint.h b/src/fixedint.h deleted file mode 100644 index 1a8745b1..00000000 --- a/src/fixedint.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - Portable header to provide the 32 and 64 bits type. - - Not a compatible replacement for , do not blindly use it as such. -*/ - -#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED) - #include - #define FIXEDINT_H_INCLUDED - - #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C) - #include - #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) - #endif -#endif - - -#ifndef FIXEDINT_H_INCLUDED - #define FIXEDINT_H_INCLUDED - - #include - - /* (u)int32_t */ - #ifndef uint32_t - #if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long uint32_t; - #elif (UINT_MAX == 0xffffffffUL) - typedef unsigned int uint32_t; - #elif (USHRT_MAX == 0xffffffffUL) - typedef unsigned short uint32_t; - #endif - #endif - - - #ifndef int32_t - #if (LONG_MAX == 0x7fffffffL) - typedef signed long int32_t; - #elif (INT_MAX == 0x7fffffffL) - typedef signed int int32_t; - #elif (SHRT_MAX == 0x7fffffffL) - typedef signed short int32_t; - #endif - #endif - - - /* (u)int64_t */ - #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L) - typedef long long int64_t; - typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif defined(__GNUC__) - __extension__ typedef long long int64_t; - __extension__ typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC) - typedef long long int64_t; - typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC) - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; - - #define UINT64_C(v) v ##UI64 - #define INT64_C(v) v ##I64 - #endif -#endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 25442218..309f2b69 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -38,13 +38,7 @@ #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha512.h" -#define SHA384 sha384 -#endif - +#include #include #include @@ -2495,7 +2489,7 @@ int get_recovery_os_local_policy_tss_response( // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); + sha384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); @@ -2590,7 +2584,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); + sha384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); @@ -2603,7 +2597,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ tss_response_get_ap_img4_ticket(client->tss, &ticket, &ticket_length); // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; - SHA384(ticket, ticket_length, hash); + sha384(ticket, ticket_length, hash); plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); /* create basic request */ diff --git a/src/ipsw.c b/src/ipsw.c index c25f61d3..6a747f40 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -34,16 +34,8 @@ #include #include #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha1.h" -#define SHA_CTX SHA1_CTX -#define SHA1_Init SHA1Init -#define SHA1_Update SHA1Update -#define SHA1_Final SHA1Final -#endif +#include #include #include @@ -1176,14 +1168,14 @@ static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) unsigned char tsha1[20]; char buf[8192]; if (!f) return 0; - SHA_CTX sha1ctx; - SHA1_Init(&sha1ctx); + sha1_context sha1ctx; + sha1_init(&sha1ctx); rewind(f); while (!feof(f)) { size_t sz = fread(buf, 1, 8192, f); - SHA1_Update(&sha1ctx, (const void*)buf, sz); + sha1_update(&sha1ctx, buf, sz); } - SHA1_Final(tsha1, &sha1ctx); + sha1_final(&sha1ctx, tsha1); return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; } diff --git a/src/sha1.c b/src/sha1.c deleted file mode 100644 index 02557ffe..00000000 --- a/src/sha1.c +++ /dev/null @@ -1,294 +0,0 @@ -/* -SHA-1 in C -By Steve Reid -100% Public Domain -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#define SHA1HANDSOFF - -#include -#include - -/* for uint32_t */ -#include - -#include "sha1.h" - - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN -#define blk0(i) block->l[i] -#else -#error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform( - uint32_t state[5], - const unsigned char buffer[64] -) -{ - uint32_t a, b, c, d, e; - - typedef union - { - unsigned char c[64]; - uint32_t l[16]; - } CHAR64LONG16; - -#ifdef SHA1HANDSOFF - CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ - CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a, b, c, d, e, 0); - R0(e, a, b, c, d, 1); - R0(d, e, a, b, c, 2); - R0(c, d, e, a, b, 3); - R0(b, c, d, e, a, 4); - R0(a, b, c, d, e, 5); - R0(e, a, b, c, d, 6); - R0(d, e, a, b, c, 7); - R0(c, d, e, a, b, 8); - R0(b, c, d, e, a, 9); - R0(a, b, c, d, e, 10); - R0(e, a, b, c, d, 11); - R0(d, e, a, b, c, 12); - R0(c, d, e, a, b, 13); - R0(b, c, d, e, a, 14); - R0(a, b, c, d, e, 15); - R1(e, a, b, c, d, 16); - R1(d, e, a, b, c, 17); - R1(c, d, e, a, b, 18); - R1(b, c, d, e, a, 19); - R2(a, b, c, d, e, 20); - R2(e, a, b, c, d, 21); - R2(d, e, a, b, c, 22); - R2(c, d, e, a, b, 23); - R2(b, c, d, e, a, 24); - R2(a, b, c, d, e, 25); - R2(e, a, b, c, d, 26); - R2(d, e, a, b, c, 27); - R2(c, d, e, a, b, 28); - R2(b, c, d, e, a, 29); - R2(a, b, c, d, e, 30); - R2(e, a, b, c, d, 31); - R2(d, e, a, b, c, 32); - R2(c, d, e, a, b, 33); - R2(b, c, d, e, a, 34); - R2(a, b, c, d, e, 35); - R2(e, a, b, c, d, 36); - R2(d, e, a, b, c, 37); - R2(c, d, e, a, b, 38); - R2(b, c, d, e, a, 39); - R3(a, b, c, d, e, 40); - R3(e, a, b, c, d, 41); - R3(d, e, a, b, c, 42); - R3(c, d, e, a, b, 43); - R3(b, c, d, e, a, 44); - R3(a, b, c, d, e, 45); - R3(e, a, b, c, d, 46); - R3(d, e, a, b, c, 47); - R3(c, d, e, a, b, 48); - R3(b, c, d, e, a, 49); - R3(a, b, c, d, e, 50); - R3(e, a, b, c, d, 51); - R3(d, e, a, b, c, 52); - R3(c, d, e, a, b, 53); - R3(b, c, d, e, a, 54); - R3(a, b, c, d, e, 55); - R3(e, a, b, c, d, 56); - R3(d, e, a, b, c, 57); - R3(c, d, e, a, b, 58); - R3(b, c, d, e, a, 59); - R4(a, b, c, d, e, 60); - R4(e, a, b, c, d, 61); - R4(d, e, a, b, c, 62); - R4(c, d, e, a, b, 63); - R4(b, c, d, e, a, 64); - R4(a, b, c, d, e, 65); - R4(e, a, b, c, d, 66); - R4(d, e, a, b, c, 67); - R4(c, d, e, a, b, 68); - R4(b, c, d, e, a, 69); - R4(a, b, c, d, e, 70); - R4(e, a, b, c, d, 71); - R4(d, e, a, b, c, 72); - R4(c, d, e, a, b, 73); - R4(b, c, d, e, a, 74); - R4(a, b, c, d, e, 75); - R4(e, a, b, c, d, 76); - R4(d, e, a, b, c, 77); - R4(c, d, e, a, b, 78); - R4(b, c, d, e, a, 79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init( - SHA1_CTX * context -) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update( - SHA1_CTX * context, - const unsigned char *data, - size_t len -) -{ - size_t i; - - size_t j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len >> 29); - j = (j >> 3) & 63; - if ((j + len) > 63) - { - memcpy(&context->buffer[j], data, (i = 64 - j)); - SHA1Transform(context->state, context->buffer); - for (; i + 63 < len; i += 64) - { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final( - unsigned char digest[20], - SHA1_CTX * context -) -{ - unsigned i; - - unsigned char finalcount[8]; - - unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) - { - uint32_t t = context->count[i]; - - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t} -#else - for (i = 0; i < 8; i++) - { - finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ - } -#endif - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) - { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) - { - digest[i] = (unsigned char) - ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} - -void SHA1( - const unsigned char *str, - size_t len, - unsigned char *hash_out -) -{ - SHA1_CTX ctx; - size_t ii; - - SHA1Init(&ctx); - for (ii=0; ii - 100% Public Domain - */ - -#include "stdint.h" - -typedef struct -{ - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform( - uint32_t state[5], - const unsigned char buffer[64] - ); - -void SHA1Init( - SHA1_CTX * context - ); - -void SHA1Update( - SHA1_CTX * context, - const unsigned char *data, - size_t len - ); - -void SHA1Final( - unsigned char digest[20], - SHA1_CTX * context - ); - -void SHA1( - const unsigned char *str, - size_t len, - unsigned char *hash_out); - -#endif /* SHA1_H */ diff --git a/src/sha512.c b/src/sha512.c deleted file mode 100644 index 8f7c59d1..00000000 --- a/src/sha512.c +++ /dev/null @@ -1,314 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ - -#include "fixedint.h" -#include "sha512.h" - -/* the K array */ -static const uint64_t K[80] = { - UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), - UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), - UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), - UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), - UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), - UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), - UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), - UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), - UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), - UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), - UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), - UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), - UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), - UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), - UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), - UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), - UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), - UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), - UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), - UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), - UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), - UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), - UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), - UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), - UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), - UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), - UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), - UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), - UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), - UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), - UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), - UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), - UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), - UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), - UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), - UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), - UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), - UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), - UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), - UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) -}; - -/* Various logical functions */ - -#define ROR64c(x, y) \ - ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \ - ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF)) - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -#define LOAD64H(x, y) \ - { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ - (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ - (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ - (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } - - -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR64c(x, n) -#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n)) -#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -#ifndef MIN - #define MIN(x, y) ( ((x)<(y))?(x):(y) ) -#endif - -/* compress 1024-bits */ -static int sha512_compress(sha512_context *md, unsigned char *buf) -{ - uint64_t S[8], W[80], t0, t1; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - - /* copy the state into 1024-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD64H(W[i], buf + (8*i)); - } - - /* fill W[16..79] */ - for (i = 16; i < 80; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - -/* Compress */ - #define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c);\ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < 80; i += 8) { - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); - } - - #undef RND - - - - /* feedback */ - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } - - return 0; -} - - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return 0 if successful -*/ -int sha512_init(sha512_context * md) { - if (md == NULL) return 1; - - md->curlen = 0; - md->length = 0; - md->state[0] = UINT64_C(0x6a09e667f3bcc908); - md->state[1] = UINT64_C(0xbb67ae8584caa73b); - md->state[2] = UINT64_C(0x3c6ef372fe94f82b); - md->state[3] = UINT64_C(0xa54ff53a5f1d36f1); - md->state[4] = UINT64_C(0x510e527fade682d1); - md->state[5] = UINT64_C(0x9b05688c2b3e6c1f); - md->state[6] = UINT64_C(0x1f83d9abfb41bd6b); - md->state[7] = UINT64_C(0x5be0cd19137e2179); - md->num_qwords = 8; - - return 0; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return 0 if successful -*/ -int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) -{ - size_t n; - size_t i; - int err; - if (md == NULL) return 1; - if (in == NULL) return 1; - if (md->curlen > sizeof(md->buf)) { - return 1; - } - while (inlen > 0) { - if (md->curlen == 0 && inlen >= 128) { - if ((err = sha512_compress (md, (unsigned char *)in)) != 0) { - return err; - } - md->length += 128 * 8; - in += 128; - inlen -= 128; - } else { - n = MIN(inlen, (128 - md->curlen)); - - for (i = 0; i < n; i++) { - md->buf[i + md->curlen] = in[i]; - } - - - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == 128) { - if ((err = sha512_compress (md, md->buf)) != 0) { - return err; - } - md->length += 8*128; - md->curlen = 0; - } - } - } - return 0; -} - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (64 bytes) - @return 0 if successful -*/ -int sha512_final(sha512_context * md, unsigned char *out) -{ - int i; - - if (md == NULL) return 1; - if (out == NULL) return 1; - - if (md->curlen >= sizeof(md->buf)) { - return 1; - } - - /* increase the length of the message */ - md->length += md->curlen * UINT64_C(8); - - /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 112 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->curlen > 112) { - while (md->curlen < 128) { - md->buf[md->curlen++] = (unsigned char)0; - } - sha512_compress(md, md->buf); - md->curlen = 0; - } - - /* pad upto 120 bytes of zeroes - * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash - * > 2^64 bits of data... :-) - */ - while (md->curlen < 120) { - md->buf[md->curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(md->length, md->buf+120); - sha512_compress(md, md->buf); - - /* copy output */ - for (i = 0; i < md->num_qwords; i++) { - STORE64H(md->state[i], out+(8*i)); - } - - return 0; -} - -int sha512(const unsigned char *message, size_t message_len, unsigned char *out) -{ - sha512_context ctx; - int ret; - if ((ret = sha512_init(&ctx))) return ret; - if ((ret = sha512_update(&ctx, message, message_len))) return ret; - if ((ret = sha512_final(&ctx, out))) return ret; - return 0; -} - -int sha384_init(sha384_context * md) { - if (md == NULL) return 1; - - md->curlen = 0; - md->length = 0; - md->state[0] = UINT64_C(0xcbbb9d5dc1059ed8); - md->state[1] = UINT64_C(0x629a292a367cd507); - md->state[2] = UINT64_C(0x9159015a3070dd17); - md->state[3] = UINT64_C(0x152fecd8f70e5939); - md->state[4] = UINT64_C(0x67332667ffc00b31); - md->state[5] = UINT64_C(0x8eb44a8768581511); - md->state[6] = UINT64_C(0xdb0c2e0d64f98fa7); - md->state[7] = UINT64_C(0x47b5481dbefa4fa4); - md->num_qwords = 6; - - return 0; -} - -int sha384_final(sha384_context * md, unsigned char* out) -{ - return sha512_final(md, out); -} - -int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen) -{ - return sha512_update(md, in, inlen); -} - -int sha384(const unsigned char *message, size_t message_len, unsigned char *out) -{ - sha384_context ctx; - int ret; - if ((ret = sha384_init(&ctx))) return ret; - if ((ret = sha384_update(&ctx, message, message_len))) return ret; - if ((ret = sha384_final(&ctx, out))) return ret; - return 0; -} diff --git a/src/sha512.h b/src/sha512.h deleted file mode 100644 index 72db47b5..00000000 --- a/src/sha512.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SHA512_H -#define SHA512_H - -#include - -#include "fixedint.h" - -/* state */ -typedef struct sha512_context_ { - uint64_t length, state[8]; - size_t curlen; - unsigned char buf[128]; - int num_qwords; -} sha512_context; - -#define SHA512_DIGEST_LENGTH 64 - -int sha512_init(sha512_context * md); -int sha512_final(sha512_context * md, unsigned char *out); -int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen); -int sha512(const unsigned char *message, size_t message_len, unsigned char *out); - -typedef sha512_context sha384_context; - -#define SHA384_DIGEST_LENGTH 48 - -int sha384_init(sha384_context * md); -int sha384_final(sha384_context * md, unsigned char *out); -int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen); -int sha384(const unsigned char *message, size_t message_len, unsigned char *out); - -#endif From 4117b894f495a929c69073fba019be1998fa5f31 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 17 Jun 2024 19:58:23 +0200 Subject: [PATCH 086/159] Require libtatsu-1.0.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d2c7f32e..d0a052f8 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.3.0 -LIBTATSU_VERSION=1.0.2 +LIBTATSU_VERSION=1.0.3 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 From a4cf7e2279f9d7ba0625b31bec2b43c957534dd3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Jun 2024 15:02:49 +0200 Subject: [PATCH 087/159] Updated README --- README.md | 223 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 178 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 3b525678..1af2d935 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,21 @@ ![](https://github.com/libimobiledevice/idevicerestore/actions/workflows/build.yml/badge.svg) +## Table of Contents +- [Features](#features) +- [Building](#building) + - [Prerequisites](#prerequisites) + - [Linux (Debian/Ubuntu based)](#linux-debianubuntu-based) + - [macOS](#macos) + - [Windows](#windows) + - [Configuring the source tree](#configuring-the-source-tree) + - [Building and installation](#building-and-installation) +- [Usage](#usage) +- [Contributing](#contributing) +- [Links](#links) +- [License](#license) +- [Credits](#credits) + ## Features The idevicerestore application is a full reimplementation of all granular steps @@ -33,56 +48,176 @@ Use with caution and make sure to backup your data before trying to restore. **In any case, usage is at your own risk.** -## Installation / Getting started - -### Debian / Ubuntu Linux +## Building + +### Prerequisites + +You need to have a working compiler (gcc/clang) and development environent +available. This project uses autotools for the build process, allowing to +have common build steps across different platforms. +Only the prerequisites differ and they are described in this section. + +#### Linux (Debian/Ubuntu based) + +* Install all required dependencies and build tools: + ```shell + sudo apt-get install \ + build-essential \ + pkg-config \ + checkinstall \ + git \ + autoconf \ + automake \ + libtool-bin \ + libreadline-dev \ + libusb-1.0-0-dev \ + libplist-dev \ + libimobiledevice-dev \ + libimobiledevice-glue-dev \ + libtatsu-dev \ + libcurl4-openssl-dev \ + libssl-dev \ + libzip-dev \ + zlib1g-dev + ``` + NOTE: [libtatsu](https://github.com/libimobiledevice/libtatsu) (and thus `libtatsu-dev`) + is a new library that was just published recently, you have to + [build it from source](https://github.com/libimobiledevice/libtatsu?tab=readme-ov-file#building). + Also, other `*-dev` packages might not be available for your distribution, + so you will have to build these packages on your own as well. + +#### macOS + +* Make sure the Xcode command line tools are installed. + + **Option 1**: + The easiest way to build and install `idevicerestore` for macOS is using + the following build script which will do the work for you, it will build + and install all required dependencies: + ```bash + mkdir -p limd-build + cd limd-build + curl -o ./limd-build-macos.sh -L https://is.gd/limdmacos + bash ./limd-build-macos.sh + ``` + Follow the prompts of the script and you should have a working `idevicerestore` + available. + + **Option 2**: + Use either [MacPorts](https://www.macports.org/) + or [Homebrew](https://brew.sh/) to install `automake`, `autoconf`, and `libtool`. + + Using MacPorts: + ```shell + sudo port install libtool autoconf automake + ``` + + Using Homebrew: + ```shell + brew install libtool autoconf automake + ``` + + `idevicerestore` has a few dependencies from the libimobiledevice project. + You will have to build and install the following: + * [libplist](https://github.com/libimobiledevice/libplist) + * [libimobiledevice-glue](https://github.com/libimobiledevice/libimobiledevice-glue) + * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd) + * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice) + * [libirecovery](https://github.com/libimobiledevice/libirecovery) + * [libtatsu](https://github.com/libimobiledevice/libtatsu) + + Check their `README.md` for building and installation instructions. + +#### Windows + +* Using [MSYS2](https://www.msys2.org/) is the official way of compiling this project on Windows. Download the MSYS2 installer + and follow the installation steps. + + It is recommended to use the _MSYS2 MinGW 64-bit_ shell. Run it and make sure the required dependencies are installed: + + ```shell + pacman -S base-devel \ + git \ + mingw-w64-x86_64-gcc \ + make \ + libtool \ + autoconf \ + automake-wrapper + ``` + NOTE: You can use a different shell and different compiler according to your needs. Adapt the above command accordingly. + + `idevicerestore` has a few dependencies from the libimobiledevice project. + You will have to build and install the following: + * [libplist](https://github.com/libimobiledevice/libplist) + * [libimobiledevice-glue](https://github.com/libimobiledevice/libimobiledevice-glue) + * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd) + * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice) + * [libirecovery](https://github.com/libimobiledevice/libirecovery) + * [libtatsu](https://github.com/libimobiledevice/libtatsu) + + Check their `README.md` for building and installation instructions. + + +### Configuring the source tree + +You can build the source code from a git checkout, or from a `.tar.bz2` release tarball from [Releases](https://github.com/libimobiledevice/idevicerestore/releases). +Before we can build it, the source tree has to be configured for building. The steps depend on where you got the source from. + +* **From git** + + If you haven't done already, clone the actual project repository and change into the directory. + ```shell + git clone https://github.com/libimobiledevice/idevicerestore.git + cd idevicerestore + ``` + + Configure the source tree for building: + ```shell + ./autogen.sh + ``` + +* **From release tarball (.tar.bz2)** + + When using an official [release tarball](https://github.com/libimobiledevice/idevicerestore/releases) (`idevicerestore-x.y.z.tar.bz2`) + the procedure is slightly different. + + Extract the tarball: + ```shell + tar xjf idevicerestore-x.y.z.tar.bz2 + cd idevicerestore-x.y.z + ``` + + Configure the source tree for building: + ```shell + ./configure + ``` + +Both `./configure` and `./autogen.sh` (which generates and calls `configure`) accept a few options, for example `--prefix` to allow +building for a different target folder. You can simply pass them like this: -First install all required dependencies and build tools: ```shell -sudo apt-get install \ - build-essential \ - pkg-config \ - checkinstall \ - git \ - autoconf \ - automake \ - libtool-bin \ - libreadline-dev \ - libusb-1.0-0-dev \ - libplist-dev \ - libimobiledevice-dev \ - libimobiledevice-glue-dev \ - libcurl4-openssl-dev \ - libssl-dev \ - libzip-dev \ - zlib1g-dev +./autogen.sh --prefix=/usr/local ``` - -Then clone, build and install [libirecovery](https://github.com/libimobiledevice/libirecovery.git) which is not yet packaged: +or ```shell -git clone https://github.com/libimobiledevice/libirecovery.git -cd libirecovery -./autogen.sh -make -sudo make install -cd .. +./configure --prefix=/usr/local ``` -If the configure processes indicates old or missing libraries, your distribution -might not have yet packaged the latest versions. In that case you will have to -clone [these libraries](https://github.com/libimobiledevice/) separately and repeat the process in order to proceed. - -Continue with cloning the actual project repository: -```shell -git clone https://github.com/libimobiledevice/idevicerestore.git -cd idevicerestore +Once the command is successful, the last few lines of output will look like this: ``` +[...] +config.status: creating config.h +config.status: config.h is unchanged +config.status: executing depfiles commands +config.status: executing libtool commands -Now you can build and install it: -```shell -./autogen.sh -make -sudo make install +Configuration for idevicerestore 1.1.0: +------------------------------------------- + + Install prefix: .........: /usr/local + + Now type 'make' to build idevicerestore 1.1.0, + and then 'make install' for installation. ``` **Important** @@ -142,8 +277,6 @@ Please make sure your contribution adheres to: * Try to split larger changes into individual commits of a common domain * Use your real name and a valid email address for your commits -We are still working on the guidelines so bear with us! - ## Links * Homepage: https://libimobiledevice.org/ @@ -166,4 +299,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2022-04-04 +README Updated on: 2024-06-19 From e0839878e760a752ebec838bc5227e32ba8650db Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 22 Jun 2024 15:36:38 +0200 Subject: [PATCH 088/159] restore: Remove `build_identity` from the parameters of the functions --- src/restore.c | 269 ++++++++++++++++++++++++++++++++------------------ src/restore.h | 9 +- 2 files changed, 178 insertions(+), 100 deletions(-) diff --git a/src/restore.c b/src/restore.c index efb03f93..d7462198 100644 --- a/src/restore.c +++ b/src/restore.c @@ -898,16 +898,21 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device) { asr_client_t asr = NULL; - - info("About to send filesystem...\n"); - ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { + + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + info("About to send filesystem...\n"); + + if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) { error("ERROR: Unable to get path for filesystem component\n"); return -1; } @@ -1072,7 +1077,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl return 0; } -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name) +int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name) { unsigned int size = 0; unsigned char* data = NULL; @@ -1081,6 +1086,11 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + if (component_name == NULL) { component_name = component; } @@ -1093,7 +1103,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } } if (!path) { - if (build_identity_get_component_path(build_identity, component, &path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) { error("ERROR: Unable to find %s path from build identity\n", component); return -1; } @@ -1136,7 +1146,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1156,6 +1166,11 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* plist_t firmware_files = NULL; int flash_version_1 = 0; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + info("About to send NORData...\n"); plist_t arguments = plist_dict_get_item(message, "Arguments"); @@ -1169,7 +1184,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } } if (llb_path == NULL) { - if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) { error("ERROR: Unable to get component path for LLB\n"); return -1; } @@ -1209,7 +1224,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } else { info("Getting firmware manifest from build identity\n"); plist_dict_iter iter = NULL; - plist_t build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + plist_t build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -1362,8 +1377,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* unsigned char* personalized_data = NULL; unsigned int personalized_size = 0; - if (build_identity_has_component(build_identity, "RestoreSEP") && - build_identity_get_component_path(build_identity, "RestoreSEP", &restore_sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "RestoreSEP") && + build_identity_get_component_path(client->restore->build_identity, "RestoreSEP", &restore_sep_path) == 0) { component = "RestoreSEP"; ret = extract_component(client->ipsw, restore_sep_path, &component_data, &component_size); free(restore_sep_path); @@ -1387,8 +1402,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } - if (build_identity_has_component(build_identity, "SEP") && - build_identity_get_component_path(build_identity, "SEP", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SEP") && + build_identity_get_component_path(client->restore->build_identity, "SEP", &sep_path) == 0) { component = "SEP"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); @@ -1412,8 +1427,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } - if (build_identity_has_component(build_identity, "SepStage1") && - build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SepStage1") && + build_identity_get_component_path(client->restore->build_identity, "SepStage1", &sep_path) == 0) { component = "SepStage1"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); @@ -1820,7 +1835,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned return res; } -static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { int res = -1; uint64_t bb_cert_id = 0; @@ -1834,6 +1849,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer char* bbfwtmp = NULL; plist_t dict = NULL; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + info("About to send BasebandData...\n"); // NOTE: this function is called 2 or 3 times! @@ -1870,7 +1890,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* create baseband request */ plist_t request = tss_request_new(NULL); @@ -1884,7 +1904,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer tss_request_add_common_tags(request, parameters, NULL); tss_request_add_baseband_tags(request, parameters, NULL); - plist_t node = plist_access_path(build_identity, 2, "Info", "FDRSupport"); + plist_t node = plist_access_path(client->restore->build_identity, 2, "Info", "FDRSupport"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { uint8_t b = 0; plist_get_bool_val(node, &b); @@ -1911,7 +1931,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } // get baseband firmware file path from build identity - plist_t bbfw_path = plist_access_path(build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); + plist_t bbfw_path = plist_access_path(client->restore->build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) { error("ERROR: Unable to get BasebandFirmware/Info/Path node\n"); plist_free(response); @@ -2011,7 +2031,7 @@ int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device) return 0; } -static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t build_identity, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) +static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) { restored_error_t restore_error; plist_t arguments; @@ -2024,6 +2044,11 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest char *image_name = NULL; int want_image_list = 0; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + arguments = plist_dict_get_item(message, "Arguments"); want_image_list = plist_dict_get_bool(arguments, image_list_k); node = plist_dict_get_item(arguments, "ImageName"); @@ -2051,7 +2076,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest data_dict = plist_new_dict(); } - build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -2083,7 +2108,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest if (!image_name) { info("Found %s component '%s'\n", image_type_k, component); } - build_identity_get_component_path(build_identity, component, &path); + build_identity_get_component_path(client->restore->build_identity, component, &path); if (path) { ret = extract_component(client->ipsw, path, &component_data, &component_size); } @@ -2155,7 +2180,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2167,6 +2192,12 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; + + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &chip_id); @@ -2177,9 +2208,9 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); - if (build_identity_has_component(build_identity, "SE,UpdatePayload")) + if (build_identity_has_component(client->restore->build_identity, "SE,UpdatePayload")) comp_name = "SE,UpdatePayload"; - else if (build_identity_has_component(build_identity, "SE,Firmware")) + else if (build_identity_has_component(client->restore->build_identity, "SE,Firmware")) comp_name = "SE,Firmware"; else { error("ERROR: Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); @@ -2196,7 +2227,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return NULL; } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2220,7 +2251,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add SE,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2255,7 +2286,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return response; } -static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2267,6 +2298,11 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2277,7 +2313,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Savage,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2310,7 +2346,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc } /* now get actual component data */ - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2346,7 +2382,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc return response; } -static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2357,6 +2393,11 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2369,7 +2410,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Yonkers,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2401,7 +2442,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2430,7 +2471,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2444,6 +2485,11 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Rose request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2455,7 +2501,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2501,7 +2547,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct } comp_name = "Rap,RTKitOS"; - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2525,8 +2571,8 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct } comp_name = "Rap,RestoreRTKitOS"; - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; @@ -2577,7 +2623,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -2588,6 +2634,11 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2599,7 +2650,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add BMU,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2624,7 +2675,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2653,7 +2704,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return NULL; } - plist_t fw_map_digest = plist_access_path(build_identity, 3, "Manifest", comp_name, "Digest"); + plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest"); if (!fw_map_digest) { plist_free(fw_map); error("ERROR: Unable to get Digest for '%s' component\n", comp_name); @@ -2673,7 +2724,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } -static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t request = NULL; plist_t response = NULL; @@ -2728,7 +2779,7 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -2739,6 +2790,11 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2750,7 +2806,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Baobab,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2775,7 +2831,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2797,7 +2853,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char comp_name[64]; char *comp_path = NULL; @@ -2813,6 +2869,11 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct uint32_t tag = 0; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2823,7 +2884,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2902,8 +2963,8 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } sprintf(comp_name, "Timer,RTKitOS,%u", tag); - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2930,8 +2991,8 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; @@ -2982,12 +3043,17 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); @@ -3019,7 +3085,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { plist_t node = plist_array_get_item(build_identity_tags, i); const char* key = plist_get_string_ptr(node, NULL); - plist_t item = plist_dict_get_item(build_identity, key); + plist_t item = plist_dict_get_item(client->restore->build_identity, key); if (item) { plist_dict_set_item(parameters, key, plist_copy(item)); } @@ -3034,10 +3100,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); } if (!plist_dict_get_item(parameters, "ApChipID")) { - plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL); } if (!plist_dict_get_item(parameters, "ApBoardID")) { - plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApBoardID", NULL); } /* add device generated request data to parameters */ @@ -3072,7 +3138,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str return response; } -static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { plist_t dict = NULL; int restore_error; @@ -3096,7 +3162,7 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st return 0; } -static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { plist_t arguments; plist_t p_type, p_updater_name, p_loop_count, p_info; @@ -3107,6 +3173,11 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct char *s_updater_name = NULL; int restore_error; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + if (idevicerestore_debug) { debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__); debug_plist(message); @@ -3153,7 +3224,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_se_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; @@ -3163,59 +3234,59 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(restore, client, build_identity, p_info2); + fwdict = restore_get_yonkers_firmware_data(restore, client, p_info2); } else { - fwdict = restore_get_savage_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_savage_firmware_data(restore, client, p_info); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_rose_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_veridian_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_tcon_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_timer_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { - fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_cryptex1_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; @@ -3246,12 +3317,17 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct return -1; } -static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) +static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client) { plist_t dict; int restore_error; - plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + plist_t manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (!manifest) { error("failed to get Manifest node from build_identity"); goto error_out; @@ -3379,7 +3455,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message, idevice_t device) +static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message, idevice_t device) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3563,7 +3639,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return 0; } -int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); @@ -3593,7 +3669,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); + int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size); if (ret != 0) { return -1; } @@ -3674,7 +3750,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i return 0; } -int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); @@ -3718,7 +3794,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - path = extract_global_manifest_path(build_identity, variant); + path = extract_global_manifest_path(client->restore->build_identity, variant); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { @@ -3842,7 +3918,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message) { plist_t node = NULL; @@ -3854,7 +3930,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { + if(restore_send_filesystem(client, device) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3868,14 +3944,14 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "PersonalizedBootObjectV3")) { - if (restore_send_personalized_boot_object_v3(restore, client, message, build_identity) < 0) { + if (restore_send_personalized_boot_object_v3(restore, client, message) < 0) { error("ERROR: Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { - if (restore_send_source_boot_object_v4(restore, client, message, build_identity) < 0) { + if (restore_send_source_boot_object_v4(restore, client, message) < 0) { error("ERROR: Unable to send SourceBootObjectV4\n"); return -1; } @@ -3890,7 +3966,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { + if(restore_send_filesystem(client, device) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3913,28 +3989,28 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } // send KernelCache else if (!strcmp(type, "KernelCache")) { - if (restore_send_component(restore, client, build_identity, "KernelCache", NULL) < 0) { + if (restore_send_component(restore, client, "KernelCache", NULL) < 0) { error("ERROR: Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { - if (restore_send_component(restore, client, build_identity, "DeviceTree", NULL) < 0) { + if (restore_send_component(restore, client, "DeviceTree", NULL) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { - if (restore_send_component(restore, client, build_identity, "SystemVolume", type) < 0) { + if (restore_send_component(restore, client, "SystemVolume", type) < 0) { error("ERROR: Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { - if (restore_send_component(restore, client, build_identity, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { + if (restore_send_component(restore, client, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); return -1; } @@ -3942,7 +4018,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, build_identity, message) < 0) { + if(restore_send_nor(restore, client, message) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -3953,7 +4029,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BasebandData")) { - if(restore_send_baseband_data(restore, client, build_identity, message) < 0) { + if(restore_send_baseband_data(restore, client, message) < 0) { error("ERROR: Unable to send baseband data\n"); return -1; } @@ -3967,49 +4043,49 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "FUDData")) { - if(restore_send_image_data(restore, client, build_identity, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { + if(restore_send_image_data(restore, client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { error("ERROR: Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { - if(restore_send_firmware_updater_preflight(restore, client, build_identity, message) < 0) { + if(restore_send_firmware_updater_preflight(restore, client, message) < 0) { error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { - if(restore_send_firmware_updater_data(restore, client, build_identity, message) < 0) { + if(restore_send_firmware_updater_data(restore, client, message) < 0) { error("ERROR: Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { - if(restore_send_image_data(restore, client, build_identity, message, "ImageList", NULL, "ImageData") < 0) { + if(restore_send_image_data(restore, client, message, "ImageList", NULL, "ImageData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { - if(restore_send_image_data(restore, client, build_identity, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { + if(restore_send_image_data(restore, client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, build_identity, message, device) < 0) { + if (restore_send_bootability_bundle_data(restore, client, message, device) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { - if (restore_send_receipt_manifest(restore, client, build_identity) < 0) { + if (restore_send_receipt_manifest(restore, client) < 0) { error("ERROR: Unable to send ReceiptManifest data\n"); return -1; } @@ -4157,6 +4233,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } info("Device %s has successfully entered restore mode\n", client->udid); + client->restore->build_identity = build_identity; restore = client->restore->client; device = client->restore->device; @@ -4456,7 +4533,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity); + err = restore_handle_data_request_msg(client, device, restore, message); } // restore logs are available if a previous restore failed diff --git a/src/restore.h b/src/restore.h index 765f3746..228de741 100644 --- a/src/restore.h +++ b/src/restore.h @@ -40,6 +40,7 @@ struct restore_client_t { unsigned int operation; uint64_t protocol_version; restored_client_t client; + plist_t build_identity; }; int restore_check_mode(struct idevicerestore_client_t* client); @@ -51,13 +52,13 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity); -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message); +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name); +int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity); +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device); int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); #ifdef __cplusplus From de1d17df224bffa4ae40e8b052c57d3af4f83dfd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 22 Jun 2024 17:08:15 +0200 Subject: [PATCH 089/159] restore: Remove `device` from the parameters of the functions --- src/restore.c | 42 ++++++++++++++++++++++++++---------------- src/restore.h | 6 +++--- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/restore.c b/src/restore.c index d7462198..6ac70b44 100644 --- a/src/restore.c +++ b/src/restore.c @@ -781,7 +781,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) return result; } -static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, idevice_t device, plist_t msg) +static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { int result = -1; plist_t node = plist_dict_get_item(msg, "DataPort"); @@ -793,9 +793,14 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + debug("Connecting to baseband updater data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -898,14 +903,14 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device) +int restore_send_filesystem(struct idevicerestore_client_t* client) { asr_client_t asr = NULL; ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; - if (!client || !client->restore || !client->restore->build_identity) { + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); return -1; } @@ -931,7 +936,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de free(fsname); } - if (asr_open_with_timeout(device, &asr) < 0) { + if (asr_open_with_timeout(client->restore->device, &asr) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); @@ -2006,7 +2011,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer return res; } -int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device) +int restore_send_fdr_trust_data(restored_client_t restore) { restored_error_t restore_error; plist_t dict; @@ -3455,7 +3460,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message, idevice_t device) +static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3471,9 +3476,14 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + debug("Connecting to BootabilityBundle data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -3918,7 +3928,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message) { plist_t node = NULL; @@ -3930,7 +3940,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device) < 0) { + if(restore_send_filesystem(client) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3966,7 +3976,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device) < 0) { + if(restore_send_filesystem(client) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -4036,7 +4046,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "FDRTrustData")) { - if(restore_send_fdr_trust_data(restore, device) < 0) { + if(restore_send_fdr_trust_data(restore) < 0) { error("ERROR: Unable to send FDR Trust data\n"); return -1; } @@ -4078,7 +4088,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, message, device) < 0) { + if (restore_send_bootability_bundle_data(restore, client, message) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } @@ -4092,7 +4102,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BasebandUpdaterOutputData")) { - if (restore_handle_baseband_updater_output_data(restore, client, device, message) < 0) { + if (restore_handle_baseband_updater_output_data(restore, client, message) < 0) { error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); return -1; } @@ -4533,7 +4543,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message); + err = restore_handle_data_request_msg(client, restore, message); } // restore logs are available if a previous restore failed @@ -4610,7 +4620,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // baseband updater output data request else if (!strcmp(type, "BasebandUpdaterOutputData")) { - err = restore_handle_baseband_updater_output_data(restore, client, device, message); + err = restore_handle_baseband_updater_output_data(restore, client, message); } // there might be some other message types i'm not aware of, but I think diff --git a/src/restore.h b/src/restore.h index 228de741..851b1813 100644 --- a/src/restore.h +++ b/src/restore.h @@ -52,14 +52,14 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message); int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device); -int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); +int restore_send_filesystem(struct idevicerestore_client_t* client); +int restore_send_fdr_trust_data(restored_client_t restore); #ifdef __cplusplus } From 28c1dab3c2c631d8bea7d0a08aa48a1e11da7eff Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 24 Jun 2024 12:42:22 +0200 Subject: [PATCH 090/159] Add support for iOS 18 restore process --- src/asr.c | 15 +- src/asr.h | 4 +- src/common.c | 36 +- src/common.h | 1 + src/idevicerestore.c | 5 +- src/restore.c | 804 +++++++++++++++++++++++++++++++++++++------ src/restore.h | 16 +- 7 files changed, 750 insertions(+), 131 deletions(-) diff --git a/src/asr.c b/src/asr.c index aadf25a1..b150e852 100644 --- a/src/asr.c +++ b/src/asr.c @@ -40,7 +40,6 @@ #define ASR_VERSION 1 #define ASR_STREAM_ID 1 -#define ASR_PORT 12345 #define ASR_BUFFER_SIZE 65536 #define ASR_FEC_SLICE_STRIDE 40 #define ASR_PACKETS_PER_FEC 25 @@ -48,7 +47,7 @@ #define ASR_PAYLOAD_CHUNK_SIZE 131072 #define ASR_CHECKSUM_CHUNK_SIZE 131072 -int asr_open_with_timeout(idevice_t device, asr_client_t* asr) +int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) { int i = 0; int attempts = 10; @@ -61,9 +60,13 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr) return -1; } - debug("Connecting to ASR\n"); + if (port == 0) { + port = ASR_DEFAULT_PORT; + } + debug("Connecting to ASR on port %u\n", port); + for (i = 1; i <= attempts; i++) { - device_error = idevice_connect(device, ASR_PORT, &connection); + device_error = idevice_connect(device, port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -358,7 +361,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) sendsize += 20; } if (asr_send_buffer(asr, data, sendsize) < 0) { - error("ERROR: Unable to send filesystem payload\n"); + error("Unable to send filesystem payload chunk, retrying...\n"); retry--; continue; } @@ -374,5 +377,5 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) } free(data); - return 0; + return (i == 0) ? 0 : -1; } diff --git a/src/asr.h b/src/asr.h index 0d9534c2..4473fbb4 100644 --- a/src/asr.h +++ b/src/asr.h @@ -30,6 +30,8 @@ extern "C" { #include +#define ASR_DEFAULT_PORT 12345 + typedef void (*asr_progress_cb_t)(double, void*); struct asr_client { @@ -44,7 +46,7 @@ typedef struct asr_client *asr_client_t; struct ipsw_file_handle; typedef struct ipsw_file_handle* ipsw_file_handle_t; -int asr_open_with_timeout(idevice_t device, asr_client_t* asr); +int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port); void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); int asr_send(asr_client_t asr, plist_t data); int asr_receive(asr_client_t asr, plist_t* data); diff --git a/src/common.c b/src/common.c index e5ee07b9..80d82560 100644 --- a/src/common.c +++ b/src/common.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -79,17 +80,31 @@ static int info_disabled = 0; static int error_disabled = 0; static int debug_disabled = 0; +static mutex_t log_mutex; +static thread_once_t init_once = THREAD_ONCE_INIT; + +static void _log_init(void) +{ + printf("******** _log_init ********\n"); + mutex_init(&log_mutex); +} + void info(const char* format, ...) { if (info_disabled) return; + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs; va_start(vargs, format); vfprintf((info_stream) ? info_stream : stdout, format, vargs); va_end(vargs); + mutex_unlock(&log_mutex); } void error(const char* format, ...) { + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs, vargs2; va_start(vargs, format); va_copy(vargs2, vargs); @@ -99,6 +114,7 @@ void error(const char* format, ...) vfprintf((error_stream) ? error_stream : stderr, format, vargs2); } va_end(vargs2); + mutex_unlock(&log_mutex); } void debug(const char* format, ...) @@ -107,10 +123,13 @@ void debug(const char* format, ...) if (!idevicerestore_debug) { return; } + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs; va_start(vargs, format); vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); va_end(vargs); + mutex_unlock(&log_mutex); } void idevicerestore_set_info_stream(FILE* strm) @@ -227,9 +246,9 @@ void debug_plist(plist_t plist) { char* data = NULL; plist_to_xml(plist, &data, &size); if (size <= MAX_PRINT_LEN) - info("%s:printing %i bytes plist:\n%s", __FILE__, size, data); + info("printing %i bytes plist:\n%s", size, data); else - info("%s:supressed printing %i bytes plist...\n", __FILE__, size); + info("supressed printing %i bytes plist...\n", size); free(data); } @@ -239,13 +258,13 @@ void print_progress_bar(double progress) { int i = 0; if(progress < 0) return; if(progress > 100) progress = 100; - info("\r["); + fprintf((info_stream) ? info_stream : stdout, "\r["); for(i = 0; i < 50; i++) { - if(i < progress / 2) info("="); - else info(" "); + if(i < progress / 2) fprintf((info_stream) ? info_stream : stdout, "="); + else fprintf((info_stream) ? info_stream : stdout, " "); } - info("] %5.1f%%", progress); - if(progress >= 100) info("\n"); + fprintf((info_stream) ? info_stream : stdout, "] %5.1f%%", progress); + if(progress >= 100) fprintf((info_stream) ? info_stream : stdout, "\n"); fflush((info_stream) ? info_stream : stdout); #endif } @@ -464,6 +483,8 @@ char *get_temp_filename(const char *prefix) void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress) { + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); if(client && client->progress_cb) { client->progress_cb(step, progress, client->progress_cb_data); } else { @@ -472,6 +493,7 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d print_progress_bar(100.0 * progress); } } + mutex_unlock(&log_mutex); } #ifndef HAVE_STRSEP diff --git a/src/common.h b/src/common.h index 766a3853..8085a1a1 100644 --- a/src/common.h +++ b/src/common.h @@ -134,6 +134,7 @@ struct idevicerestore_client_t { char* restore_variant; char* filesystem; int delete_fs; + int async_err; }; extern struct idevicerestore_mode_t idevicerestore_modes[]; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 309f2b69..8de9186d 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1514,10 +1514,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - info("DONE\n"); - if (result == 0) { + info("DONE\n"); idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0); + } else { + info("RESTORE FAILED\n"); } if (build_identity_needs_free) diff --git a/src/restore.c b/src/restore.c index 6ac70b44..a62886df 100644 --- a/src/restore.c +++ b/src/restore.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifdef HAVE_REVERSE_PROXY #include #else @@ -39,6 +41,7 @@ #include #include #include +#include #include "idevicerestore.h" #include "asr.h" @@ -633,6 +636,101 @@ const char* restore_progress_string(unsigned int operation) } } +struct restored_service_client { + +}; + +#define SERVICE_TYPE_RESTORED 1 +#define SERVICE_TYPE_PLIST 2 + +typedef struct restore_service_client { + void* client; + int type; +} *restore_service_client_t; + +static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message) +{ + if (!client || !client->restore || !client->restore->client || !PLIST_IS_DICT(message)) return NULL; + restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client)); + if (!plist_dict_get_item(message, "DataPort")) { + service->client = client->restore->client; + service->type = SERVICE_TYPE_RESTORED; + return service; + } + plist_t data_type = plist_dict_get_item(message, "DataType"); + uint16_t data_port = plist_dict_get_uint(message, "DataPort"); + const char* data_type_str = plist_get_string_ptr(data_type, NULL); + + struct lockdownd_service_descriptor svcdesc = { + data_port, + 0, + (char*)data_type_str + }; + property_list_service_client_t plclient = NULL; + info("Connecting to %s data port %u\n", data_type_str, data_port); + if (property_list_service_client_new(client->restore->device, &svcdesc, &plclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + error("ERROR: Failed to start service connection for %s on port %u\n", data_type_str, data_port); + free(service); + return NULL; + } + service->client = plclient; + service->type = SERVICE_TYPE_PLIST; + + return service; +} + +static int _restore_service_send(restore_service_client_t service, plist_t plist, plist_format_t fmt) +{ + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return restored_send((restored_client_t)service->client, plist); + case SERVICE_TYPE_PLIST: + if (fmt == PLIST_FORMAT_BINARY) { + return property_list_service_send_binary_plist((property_list_service_client_t)service->client, plist); + } + return property_list_service_send_xml_plist((property_list_service_client_t)service->client, plist); + default: + break; + } + return -1; +} + +static int _restore_service_recv(restore_service_client_t service, plist_t *plist) +{ + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return restored_receive((restored_client_t)service->client, plist); + case SERVICE_TYPE_PLIST: + return property_list_service_receive_plist((property_list_service_client_t)service->client, plist); + default: + break; + } + return -1; +} + +static void _restore_service_free(restore_service_client_t service) +{ + if (!service) { + return; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + break; + case SERVICE_TYPE_PLIST: + property_list_service_client_free((property_list_service_client_t)service->client); + break; + default: + break; + } + free(service); +} + static int lastop = 0; static int restore_handle_previous_restore_log_msg(restored_client_t client, plist_t msg) @@ -686,6 +784,9 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } switch (adapted_operation) { + case RESTORE_IMAGE: + idevicerestore_progress(client, RESTORE_STEP_UPLOAD_FS, progress / 100.0); + break; case VERIFY_RESTORE: idevicerestore_progress(client, RESTORE_STEP_VERIFY_FS, progress / 100.0); break; @@ -715,7 +816,7 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t return 0; } -int restore_handle_status_msg(restored_client_t client, plist_t msg) +int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t msg) { int result = 0; uint64_t value = 0; @@ -781,10 +882,10 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) return result; } -static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +static int restore_handle_baseband_updater_output_data(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "DataPort"); + plist_t node = plist_dict_get_item(message, "DataPort"); uint64_t u64val = 0; plist_get_uint_val(node, &u64val); uint16_t data_port = (uint16_t)u64val; @@ -855,10 +956,10 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore return result; } -static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t msg) +static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "Accepted"); + plist_t node = plist_dict_get_item(message, "Accepted"); uint8_t accepted = 0; plist_get_bool_val(node, &accepted); @@ -868,14 +969,14 @@ static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t } uint8_t done = 0; - node = plist_access_path(msg, 2, "Output", "done"); + node = plist_access_path(message, 2, "Output", "done"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { plist_get_bool_val(node, &done); } if (done) { info("Updating Baseband completed.\n"); - plist_t provisioning = plist_access_path(msg, 2, "Output", "provisioning"); + plist_t provisioning = plist_access_path(message, 2, "Output", "provisioning"); if (provisioning && plist_get_node_type(provisioning) == PLIST_DICT) { char* sval = NULL; node = plist_dict_get_item(provisioning, "IMEI"); @@ -903,7 +1004,7 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client) +int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message) { asr_client_t asr = NULL; ipsw_archive_t ipsw_dummy = NULL; @@ -936,7 +1037,11 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) free(fsname); } - if (asr_open_with_timeout(client->restore->device, &asr) < 0) { + uint16_t asr_port = (uint16_t)plist_dict_get_uint(message, "DataPort"); + if (asr_port == 0) { + asr_port = ASR_DEFAULT_PORT; + } + if (asr_open_with_timeout(client->restore->device, &asr, asr_port) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); @@ -944,7 +1049,9 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) } info("Connected to ASR\n"); - asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); + if (asr_port == ASR_DEFAULT_PORT) { + asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); + } // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it @@ -977,7 +1084,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) return 0; } -int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -1017,9 +1124,16 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi free(data); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending RecoveryOSRootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send RootTicket (%d)\n", restore_error); return -1; @@ -1030,7 +1144,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi } -int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -1070,9 +1184,16 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl free(data); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending RootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send RootTicket (%d)\n", restore_error); return -1; @@ -1082,7 +1203,246 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl return 0; } -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name) +typedef struct { + int length; + char* content; +} query_response; + +static size_t _curl_write_callback(char* data, size_t size, size_t nmemb, query_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; +} + +static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, void* userdata) +{ + plist_t header_dict = (plist_t)userdata; + size_t len = nitems*size; + char* key = NULL; + char* val = NULL; + size_t i = 0; + while (i < len) { + if (buffer[i] == ':') { + key = malloc(i+1); + strncpy(key, buffer, i); + key[i] = '\0'; + i++; + while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++; + val = malloc(len-i); + strncpy(val, buffer+i, len-i); + val[len-i] = '\0'; + break; + } + i++; + } + if (key && val) { + plist_dict_set_item(header_dict, key, plist_new_string(val)); + } + free(key); + free(val); + return len; +} + +int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message) +{ + debug("DEBUG: %s\n", __func__); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + error("ERROR: %s: Unexpected arguments\n", __func__); + debug_plist(arguments); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "GET")) { + error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + info("Requesting URLAsset from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + if (idevicerestore_debug) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + + return 0; +} + +int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* client, plist_t message) +{ + debug("DEBUG: %s\n", __func__); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + error("ERROR: %s: Unexpected arguments\n", __func__); + debug_plist(arguments); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "POST")) { + error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + + struct curl_slist* header = NULL; + + plist_t headers = plist_dict_get_item(arguments, "RequestAdditionalHeaders"); + if (!headers) { + error("ERROR: %s: Missing 'RequestAdditionalHeaders'\n", __func__); + return -1; + } + + uint64_t request_body_size = 0; + const char* request_body = plist_get_data_ptr(plist_dict_get_item(arguments, "RequestBody"), &request_body_size); + if (!request_body) { + error("ERROR: %s: Missing 'RequestBody'\n", __func__); + return -1; + } + + info("Requesting image decryption key from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + char header_tmp[1024]; + plist_dict_iter iter = NULL; + plist_dict_new_iter(headers, &iter); + plist_t node = NULL; + do { + char *key = NULL; + plist_dict_next_item(headers, iter, &key, &node); + if (!node) break; + snprintf(header_tmp, sizeof(header_tmp), "%s: %s", key, plist_get_string_ptr(node, NULL)); + curl_slist_append(header, header_tmp); + } while (node); + plist_mem_free(iter); + + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body); + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, request_body_size); + if (idevicerestore_debug) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + curl_slist_free_all(header); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + + return 0; +} + +int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name) { unsigned int size = 0; unsigned char* data = NULL; @@ -1139,9 +1499,16 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie plist_dict_set_item(dict, compkeyname, blob); free(data); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now...\n", component_name); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send component %s data\n", component_name); return -1; @@ -1151,7 +1518,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1460,15 +1827,22 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* if (idevicerestore_debug) debug_plist(dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending NORData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { + restored_error_t restore_error = _restore_service_send(service, dict, 0); + plist_free(dict); + _restore_service_free(service); + if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send NORData\n"); - plist_free(dict); return -1; } info("Done sending NORData\n"); - plist_free(dict); return 0; } @@ -1840,7 +2214,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned return res; } -static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_baseband_data(struct idevicerestore_client_t* client, plist_t message) { int res = -1; uint64_t bb_cert_id = 0; @@ -1990,12 +2364,20 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer free(buffer); buffer = NULL; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending BasebandData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { + if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) { error("ERROR: Unable to send BasebandData data\n"); goto leave; } + _restore_service_free(service); + info("Done sending BasebandData\n"); res = 0; @@ -2011,7 +2393,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer return res; } -int restore_send_fdr_trust_data(restored_client_t restore) +int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -2023,9 +2405,16 @@ int restore_send_fdr_trust_data(restored_client_t restore) * and this is what iTunes seems to be doing too */ dict = plist_new_dict(); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending FDR Trust data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: During sending FDR Trust data (%d)\n", restore_error); return -1; @@ -2036,7 +2425,7 @@ int restore_send_fdr_trust_data(restored_client_t restore) return 0; } -static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) +static int restore_send_image_data(struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) { restored_error_t restore_error; plist_t arguments; @@ -2140,6 +2529,12 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest free(iter); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); if (want_image_list) { plist_dict_set_item(dict, image_list_k, matched_images); @@ -2158,8 +2553,9 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest } } - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { if (want_image_list) { error("ERROR: Failed to send %s image list (%d)\n", image_type_k, restore_error); @@ -2185,7 +2581,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2291,7 +2687,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return response; } -static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2387,7 +2783,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc return response; } -static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2476,7 +2872,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2628,7 +3024,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -2729,7 +3125,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } -static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t request = NULL; plist_t response = NULL; @@ -2784,7 +3180,7 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -2858,7 +3254,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char comp_name[64]; char *comp_path = NULL; @@ -3048,7 +3444,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t parameters = NULL; plist_t request = NULL; @@ -3143,7 +3539,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str return response; } -static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message) { plist_t dict = NULL; int restore_error; @@ -3153,11 +3549,18 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st debug_plist(message); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); info("Sending FirmwareResponsePreflight now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); return -1; @@ -3167,7 +3570,7 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st return 0; } -static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_firmware_updater_data(struct idevicerestore_client_t* client, plist_t message) { plist_t arguments; plist_t p_type, p_updater_name, p_loop_count, p_info; @@ -3229,7 +3632,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_se_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; @@ -3239,59 +3642,59 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(restore, client, p_info2); + fwdict = restore_get_yonkers_firmware_data(client, p_info2); } else { - fwdict = restore_get_savage_firmware_data(restore, client, p_info); + fwdict = restore_get_savage_firmware_data(client, p_info); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_rose_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(restore, client, p_info); + fwdict = restore_get_veridian_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(restore, client, p_info); + fwdict = restore_get_tcon_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(restore, client, p_info); + fwdict = restore_get_timer_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { - fwdict = restore_get_cryptex1_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; @@ -3300,12 +3703,19 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct free(s_updater_name); s_updater_name = NULL; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "FirmwareResponseData", fwdict); info("Sending FirmwareResponse data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send FirmwareResponse data (%d)\n", restore_error); goto error_out; @@ -3322,7 +3732,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct return -1; } -static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client) +static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message) { plist_t dict; int restore_error; @@ -3338,12 +3748,19 @@ static int restore_send_receipt_manifest(restored_client_t restore, struct idevi goto error_out; } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "ReceiptManifest", plist_copy(manifest)); info("Sending ReceiptManifest data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error); goto error_out; @@ -3460,7 +3877,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3528,16 +3945,16 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); if (unique_id_node) { - printf("UniqueBuildID: "); + info("UniqueBuildID: "); plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); } return build_identity; } -plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) +plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t message) { - plist_t args = plist_dict_get_item(msg, "Arguments"); + plist_t args = plist_dict_get_item(message, "Arguments"); return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS")); } @@ -3617,7 +4034,7 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil struct _restore_send_file_data_ctx { struct idevicerestore_client_t* client; - restored_client_t restore; + restore_service_client_t service; int last_progress; }; @@ -3631,13 +4048,22 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); } - restored_error_t restore_error = restored_send(rctx->restore, dict); + restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); + + /* special handling for AEA image format */ + if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { + info("Encountered First Chunk in AEA image\n"); + plist_t message = NULL; + _restore_service_recv(rctx->service, &message); + restore_send_url_asset(rctx->client, message); + } + if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; int progress_int = (int)(progress*100.0); @@ -3649,15 +4075,15 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return 0; } -int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(msg); + debug_plist(message); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); return -1; @@ -3703,7 +4129,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (!build_identity) { error("ERROR: Unable to find a matching build identity\n"); return -1; @@ -3735,11 +4161,17 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; int64_t i = size; @@ -3747,6 +4179,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i int blob_size = i > 8192 ? 8192 : i; if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { free(data); + _restore_service_free(service); error("ERROR: Unable to send component %s data\n", component); return -1; } @@ -3756,19 +4189,21 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i _restore_send_file_data(&rctx, NULL, 0, size-i, size); + _restore_service_free(service); + info("Done sending %s\n", component); return 0; } -int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(msg); + debug_plist(message); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; @@ -3793,7 +4228,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; @@ -3817,7 +4252,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (build_identity_get_component_path(build_identity, component, &path) < 0) { error("ERROR: Unable to find %s path from build identity\n", component); return -1; @@ -3833,25 +4268,34 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice uint64_t fsize = 0; ipsw_get_file_size(client->ipsw, path, &fsize); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); + _restore_service_free(service); error("ERROR: Failed to send component %s\n", component); return -1; } free(path); + _restore_service_free(service); + info("Done sending %s\n", component); return 0; } -int restore_send_restore_local_policy(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_restore_local_policy(struct idevicerestore_client_t* client, plist_t message) { unsigned int size = 0; unsigned char* data = NULL; @@ -3868,7 +4312,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer // The Update mode does not have a specific build identity for the recovery os. plist_t build_identity = restore_get_build_identity(client, client->flags & FLAG_ERASE ? 1 : 0); - int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(msg, "Arguments")); + int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(message, "Arguments")); if (ret < 0) { error("ERROR: Unable to get recovery os local policy tss response\n"); return -1; @@ -3885,7 +4329,15 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); - int restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + int restore_error = 0; + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send component %s data\n", component); return -1; @@ -3897,19 +4349,25 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer return 0; } -int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("About to send BuildIdentity Dict...\n"); - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); dict = plist_new_dict(); plist_dict_set_item(dict, "BuildIdentityDict", plist_copy(build_identity)); - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if(node) { plist_dict_set_item(dict, "Variant", plist_copy(node)); } else { @@ -3917,7 +4375,8 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ } info("Sending BuildIdentityDict now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); plist_free(dict); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send BuildIdentityDict (%d)\n", restore_error); @@ -3928,7 +4387,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message) { plist_t node = NULL; @@ -3937,38 +4396,38 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest node = plist_dict_get_item(message, "DataType"); if (node && PLIST_STRING == plist_get_node_type(node)) { const char *type = plist_get_string_ptr(node, NULL); - +debug("%s: type = %s\n", __func__, type); // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client) < 0) { + if (restore_send_filesystem(client, message) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } } else if (!strcmp(type, "BuildIdentityDict")) { - if (restore_send_buildidentity(restore, client, message) < 0) { + if (restore_send_buildidentity(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } } else if (!strcmp(type, "PersonalizedBootObjectV3")) { - if (restore_send_personalized_boot_object_v3(restore, client, message) < 0) { + if (restore_send_personalized_boot_object_v3(client, message) < 0) { error("ERROR: Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { - if (restore_send_source_boot_object_v4(restore, client, message) < 0) { + if (restore_send_source_boot_object_v4(client, message) < 0) { error("ERROR: Unable to send SourceBootObjectV4\n"); return -1; } } else if (!strcmp(type, "RecoveryOSLocalPolicy")) { - if (restore_send_restore_local_policy(restore, client, message) < 0) { + if (restore_send_restore_local_policy(client, message) < 0) { error("ERROR: Unable to send RecoveryOSLocalPolicy\n"); return -1; } @@ -3976,7 +4435,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client) < 0) { + if (restore_send_filesystem(client, message) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3984,7 +4443,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // Send RecoveryOS RTD else if(!strcmp(type, "RecoveryOSRootTicketData")) { - if (restore_send_recovery_os_root_ticket(restore, client) < 0) { + if (restore_send_recovery_os_root_ticket(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } @@ -3992,35 +4451,35 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // send RootTicket (== APTicket from the TSS request) else if (!strcmp(type, "RootTicket")) { - if (restore_send_root_ticket(restore, client) < 0) { + if (restore_send_root_ticket(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } } // send KernelCache else if (!strcmp(type, "KernelCache")) { - if (restore_send_component(restore, client, "KernelCache", NULL) < 0) { + if (restore_send_component(client, message, "KernelCache", NULL) < 0) { error("ERROR: Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { - if (restore_send_component(restore, client, "DeviceTree", NULL) < 0) { + if (restore_send_component(client, message, "DeviceTree", NULL) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { - if (restore_send_component(restore, client, "SystemVolume", type) < 0) { + if (restore_send_component(client, message, "SystemVolume", type) < 0) { error("ERROR: Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { - if (restore_send_component(restore, client, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { + if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); return -1; } @@ -4028,7 +4487,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, message) < 0) { + if(restore_send_nor(client, message) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -4039,75 +4498,89 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest } else if (!strcmp(type, "BasebandData")) { - if(restore_send_baseband_data(restore, client, message) < 0) { + if(restore_send_baseband_data(client, message) < 0) { error("ERROR: Unable to send baseband data\n"); return -1; } } else if (!strcmp(type, "FDRTrustData")) { - if(restore_send_fdr_trust_data(restore) < 0) { + if(restore_send_fdr_trust_data(client, message) < 0) { error("ERROR: Unable to send FDR Trust data\n"); return -1; } } else if (!strcmp(type, "FUDData")) { - if(restore_send_image_data(restore, client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { + if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { error("ERROR: Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { - if(restore_send_firmware_updater_preflight(restore, client, message) < 0) { + if(restore_send_firmware_updater_preflight(client, message) < 0) { error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { - if(restore_send_firmware_updater_data(restore, client, message) < 0) { + if(restore_send_firmware_updater_data(client, message) < 0) { error("ERROR: Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { - if(restore_send_image_data(restore, client, message, "ImageList", NULL, "ImageData") < 0) { + if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { - if(restore_send_image_data(restore, client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { + if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, message) < 0) { + if (restore_send_bootability_bundle_data(client, message) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { - if (restore_send_receipt_manifest(restore, client) < 0) { + if (restore_send_receipt_manifest(client, message) < 0) { error("ERROR: Unable to send ReceiptManifest data\n"); return -1; } } else if (!strcmp(type, "BasebandUpdaterOutputData")) { - if (restore_handle_baseband_updater_output_data(restore, client, message) < 0) { + if (restore_handle_baseband_updater_output_data(client, message) < 0) { error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); return -1; } } + else if (!strcmp(type, "URLAsset")) { + if (restore_send_url_asset(client, message) < 0) { + error("ERROR: Unable to send URLAsset data\n"); + return -1; + } + } + + else if (!strcmp(type, "StreamedImageDecryptionKey")) { + if (restore_send_streamed_image_decryption_key(client, message) < 0) { + error("ERROR: Unable to send StreamedImageDecryptionKey data\n"); + return -1; + } + } + else { // Unknown DataType!! error("Unknown data request '%s' received\n", type); @@ -4118,6 +4591,70 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest return 0; } +struct _restore_async_args { + struct idevicerestore_client_t* client; + plist_t message; +}; + +static void* _restore_handle_async_data_request(void* args) +{ + struct _restore_async_args* async_args = (struct _restore_async_args*)args; + struct idevicerestore_client_t* client = async_args->client; + plist_t message = async_args->message; + free(async_args); + + int err = restore_handle_data_request_msg(client, message); + if (err < 0) { + client->async_err = err; + client->flags |= FLAG_QUIT; + } + + plist_free(message); + return NULL; +} + +static int restore_handle_restored_crash(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t backtrace = plist_dict_get_item(message, "RestoredBacktrace"); + info("*** restored crashed, backtrace following ***"); + if (PLIST_IS_STRING(backtrace)) { + info("%s\n", plist_get_string_ptr(backtrace, NULL)); + } else if (PLIST_IS_ARRAY(backtrace)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(backtrace); i++) { + plist_t line = plist_array_get_item(backtrace, i); + info("\t%s\n", plist_get_string_ptr(line, NULL)); + } + } else { + debug_plist(message); + } + return 0; +} + +static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message) +{ + debug("AsyncWait\n"); + if (idevicerestore_debug) + debug_plist(message); + return 0; +} + +static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message) +{ + if (idevicerestore_debug) + debug_plist(message); + debug("Sending RestoreShouldAttest: false\n"); + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RestoreShouldAttest", plist_new_bool(0)); + restored_error_t restore_error = restored_send(client->restore->client, dict); + plist_free(dict); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to send RestoreShouldAttest (%d)\n", restore_error); + return -1; + } + return 0; +} + // Extracted from ac2 plist_t restore_supported_data_types() { @@ -4184,6 +4721,10 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); + plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); + plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1)); + plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); return dict; } @@ -4204,6 +4745,9 @@ plist_t restore_supported_message_types() plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1)); plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0)); + plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); + plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); return dict; } @@ -4441,6 +4985,18 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // FIXME: does this have any effect actually? plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0)); + // Added for iOS 18.0 beta 1 + plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); + plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage")); + plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0)); + plist_t async_data_types = plist_new_dict(); + plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); + plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); + plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info"); if (sep) { node = plist_dict_get_item(sep, "RequiredCapacity"); @@ -4543,7 +5099,22 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, restore, message); + err = restore_handle_data_request_msg(client, message); + } + + // async data request message + else if (!strcmp(type, "AsyncDataRequestMsg")) { + THREAD_T t = THREAD_T_NULL; + struct _restore_async_args* args = (struct _restore_async_args*)malloc(sizeof(struct _restore_async_args)); + args->client = client; + args->message = plist_copy(message); + if (thread_new(&t, _restore_handle_async_data_request, args) < 0) { + free(args); + error("ERROR: Failed to start async data request handler thread!\n"); + err = -1; + } else { + thread_detach(t); + } } // restore logs are available if a previous restore failed @@ -4560,7 +5131,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // 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")) { - err = restore_handle_status_msg(restore, message); + err = restore_handle_status_msg(client, message); if (restore_finished) { plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "MsgType", plist_new_string("ReceivedFinalStatusMsg")); @@ -4579,7 +5150,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(message, "CHECKPOINT_ID"); if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint id from checkpoint plist\n"); - return -1; + err = -1; + break; } plist_get_uint_val(node, &ckpt_id); // Get checkpoint_name @@ -4589,7 +5161,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint result from checkpoint plist\n"); - return -1; + err = -1; + break; } plist_get_int_val(node, &ckpt_res); // Get checkpoint complete @@ -4615,12 +5188,26 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // baseband update message else if (!strcmp(type, "BBUpdateStatusMsg")) { - err = restore_handle_bb_update_status_msg(restore, message); + err = restore_handle_bb_update_status_msg(client, message); } // baseband updater output data request else if (!strcmp(type, "BasebandUpdaterOutputData")) { - err = restore_handle_baseband_updater_output_data(restore, client, message); + err = restore_handle_baseband_updater_output_data(client, message); + } + + // handle restored crash, print backtrace + else if (!strcmp(type, "RestoredCrash")) { + err = restore_handle_restored_crash(client, message); + } + + // handle async wait + else if (!strcmp(type, "AsyncWait")) { + err = restore_handle_async_wait(client, message); + } + + else if (!strcmp(type, "RestoreAttestation")) { + err = restore_handle_restore_attestation(client, message); } // there might be some other message types i'm not aware of, but I think @@ -4635,6 +5222,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_free(message); message = NULL; } + if (client->async_err != 0) { + err = client->async_err; + } #ifdef HAVE_REVERSE_PROXY reverse_proxy_client_free(rproxy); diff --git a/src/restore.h b/src/restore.h index 851b1813..763331dd 100644 --- a/src/restore.h +++ b/src/restore.h @@ -50,16 +50,16 @@ void restore_client_free(struct idevicerestore_client_t* client); int restore_is_image4_supported(struct idevicerestore_client_t* client); int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); -int restore_handle_status_msg(restored_client_t client, plist_t msg); -int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message); -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); -int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); +int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_send_nor(struct idevicerestore_client_t* client, plist_t message); +int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message); +int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client); -int restore_send_fdr_trust_data(restored_client_t restore); +int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message); +int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message); #ifdef __cplusplus } From 63094e703b807441d4b84b59d2124edda04cb64f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 26 Jun 2024 16:21:42 +0200 Subject: [PATCH 091/159] restore: Always try to use DeviceGeneratedRequest data for TSS requests if present --- src/restore.c | 60 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/restore.c b/src/restore.c index a62886df..5c6011f5 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2687,7 +2687,7 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie return response; } -static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2704,6 +2704,12 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2720,7 +2726,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* plist_dict_merge(¶meters, p_info); /* add required tags for Savage TSS request */ - tss_request_add_savage_tags(request, parameters, NULL, &comp_name); + tss_request_add_savage_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); @@ -2783,7 +2789,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* return response; } -static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2799,6 +2805,12 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2817,7 +2829,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* plist_dict_merge(¶meters, p_info); /* add required tags for Yonkers TSS request */ - tss_request_add_yonkers_tags(request, parameters, NULL, &comp_name); + tss_request_add_yonkers_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); @@ -3024,7 +3036,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl return response; } -static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -3040,6 +3052,12 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3057,7 +3075,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t plist_dict_merge(¶meters, p_info); /* add required tags for Veridian TSS request */ - tss_request_add_veridian_tags(request, parameters, NULL); + tss_request_add_veridian_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3180,7 +3198,7 @@ static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* return response; } -static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -3196,6 +3214,12 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3213,7 +3237,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl plist_dict_merge(¶meters, p_info); /* add required tags for Baobab TSS request */ - tss_request_add_tcon_tags(request, parameters, NULL); + tss_request_add_tcon_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3254,7 +3278,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl return response; } -static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char comp_name[64]; char *comp_path = NULL; @@ -3275,6 +3299,12 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3345,7 +3375,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c } /* add required tags for Timer TSS request */ - tss_request_add_timer_tags(request, parameters, NULL); + tss_request_add_timer_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3642,9 +3672,9 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(client, p_info2); + fwdict = restore_get_yonkers_firmware_data(client, p_info2, arguments); } else { - fwdict = restore_get_savage_firmware_data(client, p_info); + fwdict = restore_get_savage_firmware_data(client, p_info, arguments); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); @@ -3657,13 +3687,13 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(client, p_info); + fwdict = restore_get_veridian_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(client, p_info); + fwdict = restore_get_tcon_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; @@ -3675,7 +3705,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(client, p_info); + fwdict = restore_get_timer_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; From 1d0821a79011fb5414ede7fdcb5ce4bfcee6958c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 29 Jun 2024 13:29:16 +0200 Subject: [PATCH 092/159] Remove debug printf --- src/common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common.c b/src/common.c index 80d82560..d31c5583 100644 --- a/src/common.c +++ b/src/common.c @@ -85,7 +85,6 @@ static thread_once_t init_once = THREAD_ONCE_INIT; static void _log_init(void) { - printf("******** _log_init ********\n"); mutex_init(&log_mutex); } From 26613f928cb32fa29e31310d0e330c9c3c32085c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 1 Jul 2024 18:44:08 +0200 Subject: [PATCH 093/159] Fix heap buffer overflow in URLAsset handling --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 5c6011f5..d3828f96 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1235,7 +1235,7 @@ static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, vo key[i] = '\0'; i++; while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++; - val = malloc(len-i); + val = malloc(len-i+1); strncpy(val, buffer+i, len-i); val[len-i] = '\0'; break; From f7e24ce6e56d67c9889744bb270ad6a98fe653f5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 9 Jul 2024 11:45:10 +0200 Subject: [PATCH 094/159] ipsw: Fix concurrent access to ZIP file With the new AsyncDataRequestMsg we have the problem that multiple threads would access the .ipsw, however we were only using one struct zip* handle for the entire procedure, resulting in read errors when concurrent access occurs. This commit fixes it by opening the zip file for every access separately. --- src/ipsw.c | 169 ++++++++++++++++++++++++++++++++++++++++++----------- src/ipsw.h | 3 +- 2 files changed, 137 insertions(+), 35 deletions(-) diff --git a/src/ipsw.c b/src/ipsw.c index 6a747f40..3ae10661 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -300,7 +300,7 @@ int ipsw_print_info(const char* path) ipsw_archive_t ipsw_open(const char* ipsw) { int err = 0; - ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct ipsw_archive)); + ipsw_archive_t archive = (ipsw_archive_t)calloc(1, sizeof(struct ipsw_archive)); if (archive == NULL) { error("ERROR: Out of memory\n"); return NULL; @@ -312,14 +312,15 @@ ipsw_archive_t ipsw_open(const char* ipsw) return NULL; } if (S_ISDIR(fst.st_mode)) { - archive->zip = NULL; + archive->zip = 0; } else { - archive->zip = zip_open(ipsw, 0, &err); - if (archive->zip == NULL) { + struct zip *zip = zip_open(ipsw, 0, &err); + if (zip == NULL) { error("ERROR: zip_open: %s: %d\n", ipsw, err); free(archive); return NULL; } + archive->zip = 1; } archive->path = strdup(ipsw); return (ipsw_archive_t)archive; @@ -329,10 +330,6 @@ void ipsw_close(ipsw_archive_t ipsw) { if (ipsw != NULL) { free(ipsw->path); - if (ipsw->zip) { - zip_unchange_all(ipsw->zip); - zip_close(ipsw->zip); - } free(ipsw); } } @@ -355,18 +352,30 @@ int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); + zip_unchange_all(zip); + zip_close(zip); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); + zip_unchange_all(zip); + zip_close(zip); return -1; } + zip_unchange_all(zip); + zip_close(zip); *size = zstat.size; } else { @@ -396,35 +405,52 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, cancel_flag = 0; if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_name_locate: %s\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } char* buffer = (char*) malloc(BUFSIZE); if (buffer == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: Unable to allocate memory\n"); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } FILE* fd = fopen(outfile, "wb"); if (fd == NULL) { - error("ERROR: Unable to open output file: %s\n", outfile); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + error("ERROR: Unable to open output file: %s\n", outfile); return -1; } @@ -439,7 +465,10 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, size = i; count = zip_fread(zfile, buffer, size); if (count < 0) { - error("ERROR: zip_fread: %s\n", infile); + int zep = 0; + int sep = 0; + zip_file_error_get(zfile, &zep, &sep); + error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); ret = -1; break; } @@ -458,6 +487,8 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, free(buffer); fclose(fd); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); } else { char *filepath = build_path(ipsw->path, infile); char actual_filepath[PATH_MAX+1]; @@ -558,7 +589,15 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return 0; + } + int zindex = zip_name_locate(zip, infile, 0); + zip_unchange_all(zip); + zip_close(zip); if (zindex < 0) { return 0; } @@ -584,21 +623,34 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } @@ -608,19 +660,29 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); return -1; } - if (zip_fread(zfile, buffer, size) != size) { - error("ERROR: zip_fread: %s\n", infile); - zip_fclose(zfile); + zip_int64_t zr = zip_fread(zfile, buffer, size); + zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + if (zr < 0) { + int zep = 0; + int sep = 0; + zip_file_error_get(zfile, &zep, &sep); + error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); + free(buffer); + return -1; + } else if (zr != size) { + error("ERROR: zip_fread: %s got only %lld of %zu\n", infile, zr, size); free(buffer); return -1; } buffer[size] = '\0'; - - zip_fclose(zfile); } else { char *filepath = build_path(ipsw->path, infile); struct stat fst; @@ -691,21 +753,34 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } @@ -713,8 +788,10 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip total_size = zstat.size; buffer = (unsigned char*) malloc(blocksize); if (buffer == NULL) { - error("ERROR: Out of memory\n"); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + error("ERROR: Out of memory\n"); return -1; } @@ -736,6 +813,9 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip done += zr; } free(buffer); + zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); } else { char *filepath = build_path(ipsw->path, infile); struct stat fst; @@ -918,7 +998,14 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) } if (ipsw->zip) { - int64_t entries = zip_get_num_entries(ipsw->zip, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int64_t entries = zip_get_num_entries(zip, 0); if (entries < 0) { error("ERROR: zip_get_num_entries failed\n"); return -1; @@ -928,7 +1015,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) zip_stat_t stat; zip_stat_init(&stat); - if (zip_stat_index(ipsw->zip, index, 0, &stat) < 0) { + if (zip_stat_index(zip, index, 0, &stat) < 0) { error("ERROR: zip_stat_index failed for %s\n", stat.name); ret = -1; continue; @@ -936,7 +1023,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) uint8_t opsys; uint32_t attributes; - if (zip_file_get_external_attributes(ipsw->zip, index, 0, &opsys, &attributes) < 0) { + if (zip_file_get_external_attributes(zip, index, 0, &opsys, &attributes) < 0) { error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name); ret = -1; continue; @@ -1300,23 +1387,35 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) { ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); if (ipsw->zip) { + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return NULL; + } + zip_stat_t zst; - zip_int64_t zindex = zip_name_locate(ipsw->zip, path, 0); + zip_int64_t zindex = zip_name_locate(zip, path, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s not found\n", path); + zip_unchange_all(zip); + zip_close(zip); free(handle); return NULL; } - handle->zfile = zip_fopen_index(ipsw->zip, zindex, 0); + handle->zfile = zip_fopen_index(zip, zindex, 0); if (handle->zfile == NULL) { error("ERROR: zip_fopen_index: %s could not be opened\n", path); + zip_unchange_all(zip); + zip_close(zip); free(handle); return NULL; } zip_stat_init(&zst); - zip_stat(ipsw->zip, path, 0, &zst); + zip_stat(zip, path, 0, &zst); handle->size = zst.size; handle->seekable = (zst.comp_method == ZIP_CM_STORE); + handle->zip = zip; } else { struct stat st; char *filepath = build_path(ipsw->path, path); @@ -1338,6 +1437,8 @@ void ipsw_file_close(ipsw_file_handle_t handle) { if (handle && handle->zfile) { zip_fclose(handle->zfile); + zip_unchange_all(handle->zip); + zip_close(handle->zip); } else if (handle && handle->file) { fclose(handle->file); } diff --git a/src/ipsw.h b/src/ipsw.h index f0e11a12..8cb25612 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -33,7 +33,7 @@ extern "C" { #include struct ipsw_archive { - struct zip* zip; + int zip; char *path; }; typedef struct ipsw_archive* ipsw_archive_t; @@ -48,6 +48,7 @@ typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, siz struct ipsw_file_handle { FILE* file; + struct zip* zip; struct zip_file* zfile; uint64_t size; int seekable; From 7df9e9e43bb116ad963024f9fb1735a6b24b6806 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 18:32:44 +0200 Subject: [PATCH 095/159] restore: Make wait for URLAsset on first chunk optional --- src/restore.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/restore.c b/src/restore.c index d3828f96..2b1ad3ea 100644 --- a/src/restore.c +++ b/src/restore.c @@ -698,16 +698,22 @@ static int _restore_service_send(restore_service_client_t service, plist_t plist return -1; } -static int _restore_service_recv(restore_service_client_t service, plist_t *plist) +static int _restore_service_recv_timeout(restore_service_client_t service, plist_t *plist, unsigned int timeout) { + struct restored_client_private { + property_list_service_client_t parent; + char *udid; + char *label; + plist_t info; + }; if (!service) { return -1; } switch (service->type) { case SERVICE_TYPE_RESTORED: - return restored_receive((restored_client_t)service->client, plist); + return property_list_service_receive_plist_with_timeout(((struct restored_client_private*)service->client)->parent, plist, timeout); case SERVICE_TYPE_PLIST: - return property_list_service_receive_plist((property_list_service_client_t)service->client, plist); + return property_list_service_receive_plist_with_timeout((property_list_service_client_t)service->client, plist, timeout); default: break; } @@ -4090,8 +4096,12 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { info("Encountered First Chunk in AEA image\n"); plist_t message = NULL; - _restore_service_recv(rctx->service, &message); - restore_send_url_asset(rctx->client, message); + property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000); + if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { + info("NOTE: No URLAsset requested, assuming it is not necessary."); + } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) { + restore_send_url_asset(rctx->client, message); + } } if (total_size > 0x1000000) { From f5d73075e00510394173299c6c328bafe8958cef Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 18:34:03 +0200 Subject: [PATCH 096/159] restore: Make sure to error out when async data request handler can't be started When passing --ignore-errors, it would not fail when the async data request handler thread cannot be started, and might end up waiting forever for something to happen. --- src/restore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/restore.c b/src/restore.c index 2b1ad3ea..d836470e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -5152,6 +5152,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit free(args); error("ERROR: Failed to start async data request handler thread!\n"); err = -1; + if (client->flags & FLAG_IGNORE_ERRORS) { + client->flags &= ~FLAG_IGNORE_ERRORS; + } } else { thread_detach(t); } From 3faf2926aa03f5d9fd9e394fda9f88e22ae43a5b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 20:56:01 +0200 Subject: [PATCH 097/159] restore: Only send FirmwareData when it has been requested --- src/restore.c | 122 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/src/restore.c b/src/restore.c index d836470e..fc583c60 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2587,6 +2587,28 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist return 0; } +static int _wants_firmware_data(plist_t arguments) +{ + int result = 0; + plist_t tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + if (tags) { + plist_array_iter iter = NULL; + plist_array_new_iter(tags, &iter); + plist_t node = NULL; + do { + plist_array_next_item(tags, iter, &node); + if (node) { + const char* tag = plist_get_string_ptr(node, NULL); + if (tag && (strcmp(tag, "FirmwareData") == 0)) { + result = 1; + } + } + } while (node); + plist_mem_free(iter); + } + return result; +} + static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; @@ -2634,19 +2656,6 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie return NULL; } - if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); - return NULL; - } - - ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); - free(comp_path); - comp_path = NULL; - if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); - return NULL; - } - /* create SE request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2685,6 +2694,27 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + error("ERROR: Unable to get path for '%s' component\n", comp_name); + return NULL; + } + + ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); + free(comp_path); + comp_path = NULL; + if (ret < 0) { + plist_free(response); + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; @@ -2758,8 +2788,15 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + /* now get actual component data */ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2769,6 +2806,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2779,6 +2817,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* component_data_tmp = realloc(component_data, (size_t)component_size+16); if (!component_data_tmp) { free(component_data); + plist_free(response); return NULL; } component_data = component_data_tmp; @@ -2821,8 +2860,6 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create Yonkers TSS request\n"); - free(component_data); - free(comp_name); return NULL; } @@ -2851,7 +2888,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* plist_free(request); if (response == NULL) { error("ERROR: Unable to fetch Yonkers ticket\n"); - free(component_data); + free(comp_name); return NULL; } @@ -2861,7 +2898,15 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + free(comp_name); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2872,6 +2917,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2913,7 +2959,6 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create Rose TSS request\n"); - free(component_data); return NULL; } @@ -2949,7 +2994,6 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl plist_free(request); if (response == NULL) { error("ERROR: Unable to fetch Rose ticket\n"); - free(component_data); return NULL; } @@ -2959,14 +3003,15 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); } - /* skip FirmwareData for newer versions */ - if (client->build_major >= 20) { - debug("DEBUG: Not adding FirmwareData.\n"); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); return response; } comp_name = "Rap,RTKitOS"; if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2974,10 +3019,12 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { + plist_free(response); free(component_data); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; @@ -2993,6 +3040,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3001,6 +3049,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl comp_path = NULL; if (ret < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3009,6 +3058,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } @@ -3100,7 +3150,14 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3110,6 +3167,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3125,6 +3183,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t component_size = 0; if (!fw_map) { + plist_free(response); error("ERROR: Unable to parse '%s' component data as plist\n", comp_name); return NULL; } @@ -3132,6 +3191,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest"); if (!fw_map_digest) { plist_free(fw_map); + plist_free(response); error("ERROR: Unable to get Digest for '%s' component\n", comp_name); return NULL; } @@ -3262,8 +3322,15 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); + plist_free(response); return NULL; } @@ -3273,6 +3340,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl comp_path = NULL; if (ret < 0) { error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } @@ -3399,9 +3467,16 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + sprintf(comp_name, "Timer,RTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3410,10 +3485,12 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c comp_path = NULL; if (ret < 0) { error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { free(component_data); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } @@ -3431,6 +3508,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3439,6 +3517,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c comp_path = NULL; if (ret < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3447,6 +3526,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } From 1c4e53e673a8f25033e4ad55e7c59af9308a7d7d Mon Sep 17 00:00:00 2001 From: tihmstar Date: Tue, 17 Sep 2024 11:01:25 +0200 Subject: [PATCH 098/159] restore: Fix incorrect fallback case When the updated behavior is not triggered, the legacy behavior must be correctly executed. Thus, always correctly fall back to old behavior instead of aborting here. For example message can be NULL when restoring iOS 1.0 (in my fork). --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index fc583c60..92e87ebd 100644 --- a/src/restore.c +++ b/src/restore.c @@ -650,9 +650,9 @@ typedef struct restore_service_client { static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message) { - if (!client || !client->restore || !client->restore->client || !PLIST_IS_DICT(message)) return NULL; + if (!client || !client->restore || !client->restore->client) return NULL; restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client)); - if (!plist_dict_get_item(message, "DataPort")) { + if (!PLIST_IS_DICT(message) || !plist_dict_get_item(message, "DataPort")) { service->client = client->restore->client; service->type = SERVICE_TYPE_RESTORED; return service; From 90c2cf1e646fcb2c0d4325ed4ce7ce252dd28a2c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:22:23 +0200 Subject: [PATCH 099/159] common: Try to improve terminal output with fflush() --- src/common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common.c b/src/common.c index d31c5583..c7be4f66 100644 --- a/src/common.c +++ b/src/common.c @@ -97,6 +97,7 @@ void info(const char* format, ...) va_start(vargs, format); vfprintf((info_stream) ? info_stream : stdout, format, vargs); va_end(vargs); + fflush(info_stream?info_stream:stdout); mutex_unlock(&log_mutex); } @@ -113,6 +114,7 @@ void error(const char* format, ...) vfprintf((error_stream) ? error_stream : stderr, format, vargs2); } va_end(vargs2); + fflush(error_stream?error_stream:stderr); mutex_unlock(&log_mutex); } @@ -128,6 +130,7 @@ void debug(const char* format, ...) va_start(vargs, format); vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); va_end(vargs); + fflush(debug_stream?debug_stream:stderr); mutex_unlock(&log_mutex); } From 9764c08e4f0ca6ca0d7ebdbd9df3841c3bb691e6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:30:02 +0200 Subject: [PATCH 100/159] Only print libimobiledevice debug info for debug level > 2 --- src/idevicerestore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 8de9186d..ae48deae 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -350,9 +350,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->debug_level > 0) { idevicerestore_debug = 1; if (client->debug_level > 1) { - idevice_set_debug_level(1); irecv_set_debug_level(1); } + if (client->debug_level > 2) { + idevice_set_debug_level(1); + } tss_set_debug_level(client->debug_level); } From dab6a34ef1e38a781952f53aa9746a50202f31b3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:44:48 +0200 Subject: [PATCH 101/159] Print libtatsu version alongside idevicerestore version --- src/idevicerestore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ae48deae..3042ce34 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1837,7 +1837,7 @@ int main(int argc, char* argv[]) { break; case 'v': - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); return EXIT_SUCCESS; case 'T': { @@ -1895,7 +1895,7 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); if (ipsw) { // verify if ipsw file exists From 17c65b2dfd11b144cf3335b47c203b711fa61911 Mon Sep 17 00:00:00 2001 From: Florian Brandstetter Date: Thu, 19 Sep 2024 00:05:04 +0200 Subject: [PATCH 102/159] restore: Add SupportedAsyncDataTypes for both iOS and macOS --- src/restore.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/restore.c b/src/restore.c index 92e87ebd..47f11d11 100644 --- a/src/restore.c +++ b/src/restore.c @@ -5109,13 +5109,6 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage")); plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0)); - plist_t async_data_types = plist_new_dict(); - plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); - plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info"); if (sep) { @@ -5135,6 +5128,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "PersonalizedDuringPreflight", plist_new_bool(1)); } + // Added for iOS 18.0 and macOS 15.0 + plist_t async_data_types = plist_new_dict(); + plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); + plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); + plist_dict_set_item(opts, "RootToInstall", plist_new_bool(0)); char* guid = generate_guid(); if (guid) { From ad46e149702ece0af81932cc48f8603362102b96 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2024 00:33:56 +0200 Subject: [PATCH 103/159] Replace sprintf with snprintf --- src/idevicerestore.c | 19 ++++++++++--------- src/img4.c | 2 +- src/ipsw.c | 12 ++++++------ src/restore.c | 25 +++++++++++++------------ 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3042ce34..461e057b 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -393,7 +393,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } char wtfname[256]; - sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); + snprintf(wtfname, sizeof(wtfname), "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); unsigned char* wtftmp = NULL; unsigned int wtfsize = 0; @@ -876,7 +876,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) x++; } - sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); + snprintf(p_all_flash, sizeof(p_all_flash), "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); strcpy(tmpstr, p_all_flash); strcat(tmpstr, "/manifest"); @@ -926,7 +926,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } // add iBSS - sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); + snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); inf = plist_new_dict(); plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); comp = plist_new_dict(); @@ -934,7 +934,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_dict_set_item(manifest, "iBSS", comp); // add iBEC - sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); + snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); inf = plist_new_dict(); plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); comp = plist_new_dict(); @@ -1300,7 +1300,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) strcpy(zfn, "shsh"); } mkdir_with_parents(zfn, 0755); - sprintf(zfn+strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); + snprintf(&zfn[0]+strlen(zfn), sizeof(zfn)-strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); struct stat fst; if (stat(zfn, &fst) != 0) { gzFile zf = gzopen(zfn, "wb"); @@ -1755,8 +1755,9 @@ int main(int argc, char* argv[]) { if (!p || *(p+1) == '\0') { // no path component, add default path const char default_path[] = "/TSS/controller?action=2"; - char* newurl = malloc(strlen(optarg)+sizeof(default_path)); - sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path); + size_t usize = strlen(optarg)+sizeof(default_path); + char* newurl = malloc(usize); + snprintf(newurl, usize, "%s%s", optarg, (p) ? default_path+1 : default_path); client->tss_url = newurl; } else { client->tss_url = strdup(optarg); @@ -2202,9 +2203,9 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident char zfn[1024]; if (client->version) { if (client->cache_dir) { - sprintf(zfn, "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version); + snprintf(zfn, sizeof(zfn), "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version); } else { - sprintf(zfn, "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); + snprintf(zfn, sizeof(zfn), "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); } struct stat fst; if (stat(zfn, &fst) == 0) { diff --git a/src/img4.c b/src/img4.c index cfd3c934..dc21e567 100644 --- a/src/img4.c +++ b/src/img4.c @@ -448,7 +448,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo unsigned char *additional_data = NULL; unsigned int additional_size = 0; char *tbm_key = malloc(strlen(component_name) + 5); - sprintf(tbm_key, "%s-TBM", component_name); + snprintf(tbm_key, strlen(component_name)+5, "%s-TBM", component_name); plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); free(tbm_key); if (tbm_dict) { diff --git a/src/ipsw.c b/src/ipsw.c index 3ae10661..da7528d0 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -76,13 +76,13 @@ int ipsw_print_info(const char* path) char thepath[PATH_MAX]; if (S_ISDIR(fst.st_mode)) { - sprintf(thepath, "%s/BuildManifest.plist", path); + snprintf(thepath, sizeof(thepath), "%s/BuildManifest.plist", path); if (stat(thepath, &fst) != 0) { error("ERROR: '%s': %s\n", thepath, strerror(errno)); return -1; } } else { - sprintf(thepath, "%s", path); + snprintf(thepath, sizeof(thepath), "%s", path); } FILE* f = fopen(thepath, "r"); @@ -1169,7 +1169,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, } char majstr[32]; // should be enough for a uint64_t value - sprintf(majstr, "%"PRIu64, (uint64_t)major); + snprintf(majstr, sizeof(majstr), "%"PRIu64, (uint64_t)major); n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore"); if (!n1) { error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); @@ -1277,13 +1277,13 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char fwlfn[PATH_MAX - 5]; if (todir) { - sprintf(fwlfn, "%s/%s", todir, fwfn); + snprintf(fwlfn, sizeof(fwlfn), "%s/%s", todir, fwfn); } else { - sprintf(fwlfn, "%s", fwfn); + snprintf(fwlfn, sizeof(fwlfn), "%s", fwfn); } char fwlock[PATH_MAX]; - sprintf(fwlock, "%s.lock", fwlfn); + snprintf(fwlock, sizeof(fwlock), "%s.lock", fwlfn); lock_info_t lockinfo; diff --git a/src/restore.c b/src/restore.c index 47f11d11..6fdf755e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1501,7 +1501,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa dict = plist_new_dict(); blob = plist_new_data((char*)data, size); char compkeyname[256]; - sprintf(compkeyname, "%sFile", component_name); + snprintf(compkeyname, sizeof(compkeyname), "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); free(data); @@ -3418,25 +3418,25 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c plist_dict_set_item(parameters, "TicketName", plist_copy(node)); } - sprintf(key, "Timer,ChipID,%u", tag); + snprintf(key, sizeof(key), "Timer,ChipID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ChipID"); - sprintf(key, "Timer,BoardID,%u", tag); + snprintf(key, sizeof(key), "Timer,BoardID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "BoardID"); - sprintf(key, "Timer,ECID,%u", tag); + snprintf(key, sizeof(key), "Timer,ECID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ECID"); - sprintf(key, "Timer,Nonce,%u", tag); + snprintf(key, sizeof(key), "Timer,Nonce,%u", tag); plist_dict_copy_data(parameters, hwid, key, "Nonce"); - sprintf(key, "Timer,SecurityMode,%u", tag); + snprintf(key, sizeof(key), "Timer,SecurityMode,%u", tag); plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); - sprintf(key, "Timer,SecurityDomain,%u", tag); + snprintf(key, sizeof(key), "Timer,SecurityDomain,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); - sprintf(key, "Timer,ProductionMode,%u", tag); + snprintf(key, sizeof(key), "Timer,ProductionMode,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); @@ -3473,7 +3473,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c return response; } - sprintf(comp_name, "Timer,RTKitOS,%u", tag); + snprintf(comp_name, sizeof(comp_name), "Timer,RTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); @@ -3504,7 +3504,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c info("NOTE: Build identity does not have a '%s' component.\n", comp_name); } - sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); + snprintf(comp_name, sizeof(comp_name), "Timer,RestoreRTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); @@ -4121,8 +4121,9 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. - char *ticket_path = malloc((42+strlen(macos_variant)+strlen(device_class)+1)*sizeof(char)); - sprintf(ticket_path, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); + size_t psize = 42+strlen(macos_variant)+strlen(device_class)+1; + char *ticket_path = malloc(psize); + snprintf(ticket_path, psize, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); free(device_class); free(macos_variant); From a31eb2bf5fb2b5df1468e2ec4d31bcdc584af7d1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2024 16:13:36 +0200 Subject: [PATCH 104/159] Also print libirecovery version --- src/idevicerestore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 461e057b..36099d1b 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1838,7 +1838,7 @@ int main(int argc, char* argv[]) { break; case 'v': - info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); + info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); return EXIT_SUCCESS; case 'T': { @@ -1896,7 +1896,7 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); + info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); if (ipsw) { // verify if ipsw file exists From 4145e9584980f2c2d994a1b543478b38156be5e7 Mon Sep 17 00:00:00 2001 From: Florian Brandstetter Date: Sat, 21 Sep 2024 00:13:37 +0200 Subject: [PATCH 105/159] asr: Add support for second Initiate request First observed in iBridgeOS 9.0. The first Initiate ASR packet (checksum_chunks = false) requests 64 bytes of the IPSW at offset 0, after which another Initiate follows requesting a switch to (checksum_chunks = true) and additional OOBData. --- src/asr.c | 59 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/asr.c b/src/asr.c index b150e852..8463f0d6 100644 --- a/src/asr.c +++ b/src/asr.c @@ -202,23 +202,12 @@ void asr_free(asr_client_t asr) } } -int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) -{ - 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; - int attempts = 0; - - length = ipsw_file_size(file); - - payload_info = plist_new_dict(); +int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { + plist_t payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); - plist_dict_set_item(payload_info, "Size", plist_new_uint(length)); + plist_dict_set_item(payload_info, "Size", plist_new_uint(ipsw_size)); - packet_info = plist_new_dict(); + plist_t packet_info = plist_new_dict(); if (asr->checksum_chunks) { plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE)); } @@ -230,11 +219,30 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION)); 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); + plist_free(payload_info); + + return 0; +} + +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) +{ + uint64_t length = 0; + char* command = NULL; + plist_t node = NULL; + plist_t packet = NULL; + int attempts = 0; + + length = ipsw_file_size(file); + + // Expected by device after every initiate + if (asr_send_validation_packet_info(asr, length) < 0) { + error("ERROR: Unable to send validation packet info to ASR\n"); + return -1; + } while (1) { if (asr_receive(asr, &packet) < 0) { @@ -260,6 +268,25 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) } plist_get_string_val(node, &command); + // Added for iBridgeOS 9.0 - second initiate request to change to checksum chunks + if (!strcmp(command, "Initiate")) { + // This might switch on the second Initiate + node = plist_dict_get_item(packet, "Checksum Chunks"); + if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) { + plist_get_bool_val(node, &(asr->checksum_chunks)); + } + plist_free(packet); + + // Expected by device after every Initiate + if (asr_send_validation_packet_info(asr, length) < 0) { + error("ERROR: Unable to send validation packet info to ASR\n"); + return -1; + } + + // A OOBData request should follow + continue; + } + if (!strcmp(command, "OOBData")) { int ret = asr_handle_oob_data_request(asr, packet, file); plist_free(packet); From d2e1c4f2ab81c419d2cbb8d921fa385a0bf0433b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 21 Sep 2024 03:14:15 +0200 Subject: [PATCH 106/159] asr: Fix memory corruption due to double free --- src/asr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/asr.c b/src/asr.c index 8463f0d6..15396c4a 100644 --- a/src/asr.c +++ b/src/asr.c @@ -202,7 +202,8 @@ void asr_free(asr_client_t asr) } } -int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { +int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) +{ plist_t payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); plist_dict_set_item(payload_info, "Size", plist_new_uint(ipsw_size)); @@ -223,7 +224,6 @@ int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { return -1; } plist_free(packet_info); - plist_free(payload_info); return 0; } From 48350d676e9d817c8c8f1af2cd1e0006e1ad9c3b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 21 Sep 2024 03:15:23 +0200 Subject: [PATCH 107/159] Initial support for iPhone 16 restore --- src/idevicerestore.c | 10 ++++++++++ src/img4.c | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 36099d1b..2dd7eb88 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1258,6 +1258,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); return -1; } + } else { + plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant"); + if (recovery_variant) { + const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL); + plist_t recovery_build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); + if (get_tss_response(client, recovery_build_identity, &client->tss_recoveryos_root_ticket) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); + return -1; + } + } } } diff --git a/src/img4.c b/src/img4.c index dc21e567..c010ce4f 100644 --- a/src/img4.c +++ b/src/img4.c @@ -441,6 +441,14 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo memcpy((void*)tag, "rcio", 4); } else if (strcmp(component_name, "Ap,DCP2") == 0) { memcpy((void*)tag, "dcp2", 4); + } else if (strcmp(component_name, "Ap,RestoreSecureM3Firmware") == 0) { + memcpy((void*)tag, "rsm3", 4); + } else if (strcmp(component_name, "Ap,RestoreSecurePageTableMonitor") == 0) { + memcpy((void*)tag, "rspt", 4); + } else if (strcmp(component_name, "Ap,RestoreTrustedExecutionMonitor") == 0) { + memcpy((void*)tag, "rtrx", 4); + } else if (strcmp(component_name, "Ap,RestorecL4") == 0) { + memcpy((void*)tag, "rxcl", 4); } } From be6751c2cb7d63cee43a11cf93ee4a23cca699cb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Sep 2024 02:18:07 +0200 Subject: [PATCH 108/159] ace3: Fix Ace3Binary generation for newer devices --- src/ace3.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/ace3.c b/src/ace3.c index b96e6b4f..a482f6f3 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -50,11 +50,39 @@ static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, un return result; } +static int uarp_version_convert(uint32_t* version_data, uint32_t* version_out) +{ + if (version_out) *version_out = 0; + if (!version_data) { + return -1; + } + uint32_t part1 = (version_data[0] < 0xE00) ? version_data[0] : version_data[0] - 0xE00; + if (part1 > 0x63) { + return 0; + } + uint32_t part2 = (version_data[0] < 0xE00) ? 0 : 0xE00; + uint32_t part3 = version_data[1]; + if (part3 > 0x3E7) { + return 0; + } + uint32_t part4 = version_data[2]; + if (part4 > 0x63) { + return 0; + } + if (version_out) { + *version_out = ((((0x147B * (unsigned int)((uint16_t)part3 >> 2)) >> 9) & 0x3FF00 | (0x10 * (((uint8_t)((uint16_t)part3 / 0xA) % 0xA) & 0xF)) | ((uint16_t)part3 % 0xA)) << 8) + | ((((uint8_t)part1 % 0xA) | (0x10 * ((uint8_t)part1 / 0xA)) | part2) << 20) + | ((uint8_t)part4 % 0xA) + | ((0xCD * (unsigned int)(uint8_t)part4) >> 7) & 0xF0; + } + return 0; +} + int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size) { struct ace3bin_header { uint32_t magic; // 0xACE00003 - uint32_t unk4; // 0x00203400 + uint32_t version; // ace3 version, e.g. 0x00203400 uint32_t unk8; // 0x00002800 uint32_t header_size; // 0x00000040 uint32_t data1_size; @@ -84,10 +112,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t struct uarp_toc_entry { uint32_t this_size; // BE usually 0x28 uint32_t fourcc; // 'PT01' or similar - uint32_t index; // BE starting with 0, increment+1 for each entry - uint32_t unk_0c; // BE usually not zero - uint32_t unk_10; // BE usually 0 - uint32_t unk_14; // BE usually 0 + uint32_t version[4]; // BE values uint32_t unk_18; // BE other offset, not sure uint32_t unk_1c; // BE usually 0 uint32_t offset; // BE @@ -142,6 +167,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint64_t boardid = 0; plist_get_uint_val(p_boardid, &boardid); if (boardid == bdid) { + debug("DEBUG: %s: Found Board ID 0x%" PRIx64 "\n", __func__, bdid); plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC"); plist_get_string_val(p4cc, &payload_4cc); plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data"); @@ -163,6 +189,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t if (prev >= minrev && prev <= maxrev) { plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags"); plist_get_string_val(tags, &data_payload_4ccs); + debug("DEBUG: %s: Found matching tags %s\n", __func__, data_payload_4ccs); break; } } while (match); @@ -187,11 +214,12 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint32_t dl_size = 0; uint32_t data1_offset = 0; uint32_t data1_size = 0; + uint32_t data1_version = 0; uint32_t data2_offset = 0; uint32_t data2_size = 0; uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); uint32_t toc_size = be32toh(uarp_hdr->toc_size); - const unsigned char* p = uarp_fw + uarp_hdr_size; + const unsigned char* p = uarp_fw + uarp_hdr_size; while (p < uarp_fw + toc_size) { struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p; uint32_t te_size = be32toh(entry->this_size); @@ -199,8 +227,14 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t dl_offset = be32toh(entry->offset); dl_size = be32toh(entry->size); } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs, 4) == 0) { + uint32_t version_data[4]; + version_data[0] = be32toh(entry->version[0]); + version_data[1] = be32toh(entry->version[1]); + version_data[2] = be32toh(entry->version[2]); + version_data[3] = be32toh(entry->version[3]); data1_offset = be32toh(entry->offset); data1_size = be32toh(entry->size); + uarp_version_convert(version_data, &data1_version); } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs+5, 4) == 0) { data2_offset = be32toh(entry->offset); data2_size = be32toh(entry->size); @@ -213,7 +247,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t *bin_out = (unsigned char*)malloc(0x40 + content_size); struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out); hdr->magic = htole32(0xACE00003); - hdr->unk4 = htole32(0x00203400); + hdr->version = htole32(data1_version); hdr->unk8 = htole32(0x00002800); hdr->header_size = htole32(0x40); hdr->data1_size = htole32(data1_size); From 27402caabadfe0d5114a8999bdae413202f3d19c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Sep 2024 02:46:07 +0200 Subject: [PATCH 109/159] Release DFU/Recovery client on disconnect and Increase timeout for port DFU -> KIS --- src/idevicerestore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 2dd7eb88..bf58a3e9 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -817,8 +817,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } return -2; } + dfu_client_free(client); debug("Waiting for device to reconnect in DFU mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 20000); if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { @@ -1416,6 +1417,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } return -2; } + recovery_client_free(client); debug("Waiting for device to reconnect in recovery mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { From 511261e12d23d80cc3c08290022380b8d3411f9c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 28 Sep 2024 03:08:15 +0200 Subject: [PATCH 110/159] Be more precise about what is wrong when entering restore mode fails --- src/idevicerestore.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index bf58a3e9..fb0b3290 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1494,7 +1494,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); error("ERROR: Device failed to enter restore mode.\n"); - error("Please make sure that usbmuxd is running.\n"); + if (client->mode == MODE_UNKNOWN) { + error("Make sure that usbmuxd is running.\n"); + } else if (client->mode == MODE_RECOVERY) { + error("Device reconnected in recovery mode, most likely image personalization failed.\n"); + } return -1; } mutex_unlock(&client->device_event_mutex); From f4a18ee13dd84d76dd6ebb9b21cd6bce6f37e4ec Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 11 Oct 2024 11:59:40 +0200 Subject: [PATCH 111/159] configure: Require newer libtatsu and libirecovery --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d0a052f8..9d71e956 100644 --- a/configure.ac +++ b/configure.ac @@ -15,12 +15,12 @@ if test -z $PACKAGE_VERSION; then fi # Minimum package versions -LIBIRECOVERY_VERSION=1.2.0 +LIBIRECOVERY_VERSION=1.2.1 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.3.0 -LIBTATSU_VERSION=1.0.3 +LIBTATSU_VERSION=1.0.4 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 From 151c680feb6a0775d1b979dbdfca2ac6fdfc8cad Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 15 Oct 2024 22:09:43 +0200 Subject: [PATCH 112/159] Fix iPhone 16 restore from normal mode and add support for RecoveryOS --- src/common.h | 3 + src/dfu.c | 2 +- src/idevicerestore.c | 60 +++++-- src/idevicerestore.h | 2 +- src/img4.c | 193 ++++++++++++++------- src/img4.h | 2 +- src/normal.c | 26 ++- src/normal.h | 1 + src/recovery.c | 2 +- src/restore.c | 391 ++++++++++++++++++++++++++++++++++++++++--- 10 files changed, 578 insertions(+), 104 deletions(-) diff --git a/src/common.h b/src/common.h index 8085a1a1..872d2f92 100644 --- a/src/common.h +++ b/src/common.h @@ -104,7 +104,9 @@ struct idevicerestore_client_t { int nonce_size; int image4supported; plist_t build_manifest; + plist_t firmware_preflight_info; plist_t preflight_info; + plist_t parameters; char* udid; char* srnm; ipsw_archive_t ipsw; @@ -131,6 +133,7 @@ struct idevicerestore_client_t { cond_t device_event_cond; int ignore_device_add_events; plist_t macos_variant; + plist_t recovery_variant; char* restore_variant; char* filesystem; int delete_fs; diff --git a/src/dfu.c b/src/dfu.c index 8557c292..e6b45afa 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -168,7 +168,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide unsigned char* data = NULL; uint32_t size = 0; - if (personalize_component(component, component_data, component_size, tss, &data, &size) < 0) { + if (personalize_component(client, component, component_data, component_size, tss, &data, &size) < 0) { error("ERROR: Unable to get personalized component: %s\n", component); free(component_data); return -1; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fb0b3290..b8bb1d06 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1227,6 +1227,29 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } else { free(nonce); } + if (client->mode == MODE_NORMAL) { + plist_t ap_params = normal_get_lockdown_value(client, NULL, "ApParameters"); + if (ap_params) { + if (!client->parameters) { + client->parameters = plist_new_dict(); + } + plist_dict_merge(&client->parameters, ap_params); + plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce"); + uint64_t sep_nonce_size = 0; + const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size); + info("Getting SepNonce in normal mode... "); + int i = 0; + for (i = 0; i < sep_nonce_size; i++) { + info("%02x ", (unsigned char)sep_nonce[i]); + } + info("\n"); + plist_free(ap_params); + } + plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot"); + if (req_nonce_slot) { + plist_dict_set_item(client->parameters, "RequiresNonceSlot", plist_copy(req_nonce_slot)); + } + } } if (client->flags & FLAG_QUIT) { @@ -1263,8 +1286,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant"); if (recovery_variant) { const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL); - plist_t recovery_build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); - if (get_tss_response(client, recovery_build_identity, &client->tss_recoveryos_root_ticket) < 0) { + client->recovery_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); + if (!client->recovery_variant) { + error("ERROR: Variant '%s' not found in BuildManifest\n", recovery_variant_str); + return -1; + } + if (get_tss_response(client, client->recovery_variant, &client->tss_recoveryos_root_ticket) < 0) { error("ERROR: Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); return -1; } @@ -1614,6 +1641,9 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) if (client->build_manifest) { plist_free(client->build_manifest); } + if (client->firmware_preflight_info) { + plist_free(client->firmware_preflight_info); + } if (client->preflight_info) { plist_free(client->preflight_info); } @@ -2276,17 +2306,21 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident /* populate parameters */ plist_t parameters = plist_new_dict(); + plist_dict_merge(¶meters, client->parameters); + plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } - unsigned char* sep_nonce = NULL; - unsigned int sep_nonce_size = 0; - get_sep_nonce(client, &sep_nonce, &sep_nonce_size); - if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); - free(sep_nonce); + if (!plist_dict_get_item(parameters, "SepNonce")) { + unsigned char* sep_nonce = NULL; + unsigned int sep_nonce_size = 0; + get_sep_nonce(client, &sep_nonce, &sep_nonce_size); + if (sep_nonce) { + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + free(sep_nonce); + } } plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); @@ -2344,7 +2378,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident if (client->mode == MODE_NORMAL) { /* normal mode; request baseband ticket aswell */ plist_t pinfo = NULL; - normal_get_preflight_info(client, &pinfo); + normal_get_firmware_preflight_info(client, &pinfo); if (pinfo) { plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); @@ -2365,6 +2399,10 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident tss_request_add_vinyl_tags(request, parameters, NULL); } } + client->firmware_preflight_info = pinfo; + pinfo = NULL; + + normal_get_preflight_info(client, &pinfo); client->preflight_info = pinfo; } @@ -2718,7 +2756,7 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com return 0; } -int personalize_component(const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) +int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) { unsigned char* component_blob = NULL; unsigned int component_blob_size = 0; @@ -2727,7 +2765,7 @@ int personalize_component(const char *component_name, const unsigned char* compo if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ - img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size); + img4_stitch_component(component_name, component_data, component_size, client->parameters, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 5afcf1af..fe9d11f2 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -115,7 +115,7 @@ int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem); int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); -int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); +int personalize_component(struct idevicerestore_client_t* client, const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest); const char* get_component_name(const char* filename); diff --git a/src/img4.c b/src/img4.c index c010ce4f..e9d4ccac 100644 --- a/src/img4.c +++ b/src/img4.c @@ -26,6 +26,7 @@ #include "common.h" #include "img4.h" +#include "endianness.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f @@ -395,7 +396,7 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; @@ -459,14 +460,17 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo snprintf(tbm_key, strlen(component_name)+5, "%s-TBM", component_name); plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); free(tbm_key); + uint64_t ucon_size = 0; + const char* ucon_data = NULL; + uint64_t ucer_size = 0; + const char* ucer_data = NULL; if (tbm_dict) { plist_t dt = plist_dict_get_item(tbm_dict, "ucon"); if (!dt) { error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); return -1; } - uint64_t ucon_size = 0; - const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -476,76 +480,141 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); return -1; } - uint64_t ucer_size = 0; - const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; } + } + + int nonce_slot_required = plist_dict_get_bool(parameters, "RequiresNonceSlot") && (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1") || !strcmp(component_name, "LLB")); - unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16); + if (ucon_data || ucer_data || nonce_slot_required) { + size_t im4r_size = 16; + if (ucon_data) { + im4r_size += 8 + 8 + ucon_size + 16; + } + if (ucer_data) { + im4r_size += 8 + 8 + ucer_size + 16; + } + if (nonce_slot_required) { + im4r_size += 16; + } + unsigned char *im4rset = (unsigned char*)malloc(im4r_size); unsigned char *p_im4rset = im4rset; unsigned int im4rlen = 0; + // ----------- anid/snid ------- + if (nonce_slot_required) { + const char* tag_name = NULL; + uint64_t tag_value = 0; + if (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1")) { + tag_name = "snid"; + tag_value = 2; + if (plist_dict_get_item(parameters, "SepNonceSlotID")) { + tag_value = plist_dict_get_uint(parameters, "SepNonceSlotID"); + } + } else { + tag_name = "anid"; + tag_value = 0; + if (plist_dict_get_item(parameters, "ApNonceSlotID")) { + tag_value = plist_dict_get_uint(parameters, "ApNonceSlotID"); + } + } + // write priv anid/snid element + asn1_write_priv_element(&p_im4rset, &im4rlen, __bswap_32(*(uint32_t*)tag_name)); + // write anid/snid IA5STRING and anid/snid value + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)tag_name, -1); + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_INTEGER, (void*)&tag_value, -1); + + // write anid/snid sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len, &p, &seq_hdr_len); + + // add size to priv anid/snid element + asn1_write_size(inner_seq_hdr_len + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + } + // ----------- ucon ------------ - // write priv ucon element - asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); - - // write ucon IA5STRING and ucon data - unsigned char ucon_seq[16]; - unsigned char *p_ucon_seq = &ucon_seq[0]; - unsigned int ucon_seq_hdr_len = 0; - asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); - asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_seq_hdr_len); - - // write ucon sequence - unsigned char elem_seq[8]; - unsigned char *p = &elem_seq[0]; - unsigned int seq_hdr_len = 0; - asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len); - - // add size to priv ucon element - asn1_write_size(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); - - // put it together - memcpy(p_im4rset, elem_seq, seq_hdr_len); - p_im4rset += seq_hdr_len; - im4rlen += seq_hdr_len; - memcpy(p_im4rset, ucon_seq, ucon_seq_hdr_len); - p_im4rset += ucon_seq_hdr_len; - im4rlen += ucon_seq_hdr_len; - memcpy(p_im4rset, ucon_data, ucon_size); - p_im4rset += ucon_size; - im4rlen += ucon_size; + if (ucon_data) { + // write priv ucon element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); + + // write ucon IA5STRING and ucon data header + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_inner_seq, &inner_seq_hdr_len); + + // write ucon sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucon_size, &p, &seq_hdr_len); + + // add size to priv ucon element + asn1_write_size(inner_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + // write ucon data + memcpy(p_im4rset, ucon_data, ucon_size); + p_im4rset += ucon_size; + im4rlen += ucon_size; + } // ----------- ucer ------------ - // write priv ucer element - asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); - - // write ucon IA5STRING and ucer data - unsigned char ucer_seq[16]; - unsigned char *p_ucer_seq = &ucer_seq[0]; - unsigned int ucer_seq_hdr_len = 0; - asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); - asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len); - - p = &elem_seq[0]; - seq_hdr_len = 0; - asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len); - - // add size to priv ucer element - asn1_write_size(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); - - // put it together - memcpy(p_im4rset, elem_seq, seq_hdr_len); - p_im4rset += seq_hdr_len; - im4rlen += seq_hdr_len; - memcpy(p_im4rset, ucer_seq, ucer_seq_hdr_len); - p_im4rset += ucer_seq_hdr_len; - im4rlen += ucer_seq_hdr_len; - memcpy(p_im4rset, ucer_data, ucer_size); - p_im4rset += ucer_size; - im4rlen += ucer_size; + if (ucer_data) { + // write priv ucer element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); + + // write ucer IA5STRING and ucer data header + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_inner_seq, &inner_seq_hdr_len); + + // write ucer sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucer_size, &p, &seq_hdr_len); + + // add size to priv ucer element + asn1_write_size(inner_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + // write ucer data + memcpy(p_im4rset, ucer_data, ucer_size); + p_im4rset += ucer_size; + im4rlen += ucer_size; + } // now construct IM4R diff --git a/src/img4.h b/src/img4.h index 1056fa68..19c1c84e 100644 --- a/src/img4.h +++ b/src/img4.h @@ -26,7 +26,7 @@ extern "C" { #endif -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest); #ifdef __cplusplus diff --git a/src/normal.c b/src/normal.c index e699bbe6..9e460803 100644 --- a/src/normal.c +++ b/src/normal.c @@ -342,6 +342,18 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { + plist_t node = normal_get_lockdown_value(client, NULL, "ApParameters"); + if (PLIST_IS_DICT(node)) { + plist_t nonce_node = plist_dict_get_item(node, "SepNonce"); + if (nonce_node) { + uint64_t n_size = 0; + plist_get_data_val(nonce_node, (char**)nonce, &n_size); + *nonce_size = (unsigned int)n_size; + plist_free(node); + return 0; + } + } + plist_free(node); return normal_get_nonce_by_key(client, "SEPNonce", nonce, nonce_size); } @@ -365,7 +377,7 @@ int normal_is_image4_supported(struct idevicerestore_client_t* client) return bval; } -int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) +int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) { uint8_t has_telephony_capability = 0; plist_t node; @@ -389,6 +401,18 @@ int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *p return 0; } +int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) +{ + plist_t node = normal_get_lockdown_value(client, NULL, "PreflightInfo"); + if (PLIST_IS_DICT(node)) { + *preflight_info = node; + } else { + debug("DEBUG: No PreflightInfo available.\n"); + *preflight_info = NULL; + } + return 0; +} + int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest) { int result = -1; diff --git a/src/normal.h b/src/normal.h index 7741ac5f..d3d7b0cd 100644 --- a/src/normal.h +++ b/src/normal.h @@ -38,6 +38,7 @@ int normal_enter_recovery(struct idevicerestore_client_t* client); int normal_is_image4_supported(struct idevicerestore_client_t* client); int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const char* domain, const char* key); int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest); diff --git a/src/recovery.c b/src/recovery.c index afda4a97..c4513502 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -305,7 +305,7 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); if (ret < 0) { error("ERROR: Unable to get personalized component: %s\n", component); diff --git a/src/restore.c b/src/restore.c index 6fdf755e..2daeea2b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1490,7 +1491,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -1662,7 +1663,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &llb_data, &llb_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &llb_data, &llb_size); free(component_data); component_data = NULL; component_size = 0; @@ -1718,7 +1719,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - if (personalize_component(component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { + if (personalize_component(client, component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { free(iter); free(comp); free(comppath); @@ -1765,7 +1766,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -1790,7 +1791,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -1815,7 +1816,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -2518,7 +2519,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist error("ERROR: Unable to extract component: %s\n", component); } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4273,7 +4274,7 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli } // Personalize IMG4 - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4439,7 +4440,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl return -1; } - ret = personalize_component(component, component_data, component_size, client->tss_localpolicy, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss_localpolicy, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4508,6 +4509,232 @@ int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t m return 0; } +int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* client, plist_t message) +{ + char *fw_override_key = NULL; + plist_t node = plist_access_path(message, 2, "Arguments", "FWOverrideKey"); + if (PLIST_IS_STRING(node)) { + plist_get_string_val(node, &fw_override_key); + } + if (!fw_override_key) { + error("ERROR: Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n"); + return -1; + } + + plist_t dict = plist_new_dict(); + if (!client->recovery_variant) { + error("ERROR: no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + if (strncmp(fw_override_key, "RecoveryOS", 10) != 0) { + error("ERROR: FWOVerrideKey has unexpected prefix\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + const char* component = fw_override_key+10; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + error("ERROR: Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + unsigned char* component_data = NULL; + unsigned int component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + free(path); + path = NULL; + if (ret < 0) { + error("ERROR: Unable to extract component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + unsigned char* data = NULL; + unsigned int size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret < 0) { + error("ERROR: Unable to get personalized component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + info("Sending %s\n", fw_override_key); + + plist_dict_set_item(dict, "AdditionalBootImages", plist_new_data((char*)data, size)); + free(data); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + if (!build_id_manifest) { + error("ERROR: Missing Manifest dictionary in build identity?!\n"); + return -1; + } + + plist_t firmware_files = plist_new_dict(); + + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry)) { + uint8_t loaded_by_iboot = 0; + uint8_t loaded_by_iboot_stage1 = 0; + plist_t fw_node; + + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot); + } + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBootStage1"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot_stage1); + } + if (loaded_by_iboot || loaded_by_iboot_stage1) { + plist_t comp_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (comp_path) { + const char* path = plist_get_string_ptr(comp_path, NULL); + unsigned char* component_data = NULL; + unsigned int component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + if (ret == 0) { + unsigned char* data = NULL; + unsigned int size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret == 0) { + plist_dict_set_item(firmware_files, component, plist_new_data((char*)data, size)); + free(data); + } + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + + plist_t dict = plist_new_dict(); + + if (plist_dict_get_size(firmware_files) == 0) { + plist_free(firmware_files); + info("NOTE: No iBoot firmware files. Continuing.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + + } + + info("Sending iBoot additional firmware files\n"); + + plist_dict_set_item(dict, "AdditionalBootImages", firmware_files); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist_t message) +{ + const char* component = "OS"; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + error("ERROR: Unable to find %s path from build identity\n", component); + return -1; + } + if (!path) { + error("ERROR: Failed to get path for component %s\n", component); + return -1; + } + + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.service = service; + rctx.last_progress = 0; + + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { + free(path); + _restore_service_free(service); + error("ERROR: Failed to send component %s\n", component); + return -1; + } + free(path); + + _restore_service_free(service); + + info("Done sending %s\n", component); + + return 0; +} + +int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_info = plist_dict_get_item(client->recovery_variant, "Info"); + if (!build_id_info) { + error("ERROR: Missing Info dictionary in build identity?!\n"); + return -1; + } + plist_t version_data = plist_new_dict(); + plist_dict_copy_item(version_data, build_id_info, "BuildNumber", NULL); + plist_dict_copy_item(version_data, build_id_info, "Variant", NULL); + plist_dict_copy_item(version_data, build_id_info, "BuildTrain", NULL); + plist_dict_copy_item(version_data, build_id_info, "ProductVersion", "ProductMarketingVersion"); + char *xml = NULL; + uint32_t xml_len = 0; + plist_to_xml(version_data, &xml, &xml_len); + plist_free(version_data); + + info("Sending RecoveryOS version data\n"); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_data(xml, xml_len)); + plist_mem_free(xml); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message) { plist_t node = NULL; @@ -4702,6 +4929,34 @@ debug("%s: type = %s\n", __func__, type); } } + else if (!strcmp(type, "RecoveryOSFileAssetImage")) { + if (restore_send_recovery_os_file_asset_image(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSFileImageAssetImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSIBootFWFilesImages")) { + if (restore_send_recovery_os_iboot_fw_files_images(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSIBootFWFilesImages data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSImage")) { + if (restore_send_recovery_os_image(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSVersionData")) { + if (restore_send_recovery_os_version_data(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSVersionData data\n"); + return -1; + } + } + else { // Unknown DataType!! error("Unknown data request '%s' received\n", type); @@ -4776,10 +5031,70 @@ static int restore_handle_restore_attestation(struct idevicerestore_client_t* cl return 0; } +static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_client_t* client, uint64_t* min_size, uint64_t* max_size) +{ + const char* asset_list[] = { "OS", "KernelCache", "DeviceTree", "iBEC", "AppleLogo", "StaticTrustCache", "iBootData", "Diags", "Ap,SystemVolumeCanonicalMetadata", "SystemVolume", "BaseSystemVolume", "Ap,BaseSystemTrustCache", "AVISP1,RTKitOS", NULL }; + + if (min_size) *min_size = 356; + if (max_size) *max_size = 420; + + double total_size = 0; + plist_t firmware_items = plist_new_dict(); + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry) && plist_dict_get_item(firmware_items, component) == NULL) { + int add_image = 0; + int i = 0; + while (asset_list[i]) { + if (!strcmp(asset_list[i], component)) { + add_image = 1; + break; + } + i++; + } + plist_t fw_node; + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + uint8_t loaded_by_iboot = 0; + plist_get_bool_val(fw_node, &loaded_by_iboot); + if (loaded_by_iboot) { + add_image = 1; + } + } + if (add_image) { + plist_t p_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (p_path) { + const char* path = plist_get_string_ptr(p_path, NULL); + uint64_t fsize = 0; + if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) { + debug("%s: Adding %s (%s, %llu bytes)\n", __func__, component, path, fsize); + total_size += (double)fsize / 0x100000; + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + total_size = ceil(total_size); + if (min_size) *min_size = total_size * 1.05 + 25; + if (max_size) *max_size = total_size * 1.25 + 25; +} + // Extracted from ac2 plist_t restore_supported_data_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); plist_dict_set_item(dict, "BasebandBootData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandStackData", plist_new_bool(0)); @@ -4797,20 +5112,26 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "FileData", plist_new_bool(0)); plist_dict_set_item(dict, "FileDataDone", plist_new_bool(0)); plist_dict_set_item(dict, "FirmwareUpdaterData", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); plist_dict_set_item(dict, "GrapeFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HPMFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HostSystemTime", plist_new_bool(1)); plist_dict_set_item(dict, "KernelCache", plist_new_bool(0)); + plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); plist_dict_set_item(dict, "NORData", plist_new_bool(0)); plist_dict_set_item(dict, "NitrogenFWData", plist_new_bool(1)); plist_dict_set_item(dict, "OpalFWData", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataCount", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataForKey", plist_new_bool(1)); + plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); plist_dict_set_item(dict, "PeppyFWData", plist_new_bool(1)); plist_dict_set_item(dict, "PersonalizedBootObjectV3", plist_new_bool(0)); plist_dict_set_item(dict, "PersonalizedData", plist_new_bool(1)); plist_dict_set_item(dict, "ProvisioningData", plist_new_bool(0)); plist_dict_set_item(dict, "RamdiskFWData", plist_new_bool(1)); + plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSASRImage", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSAppleLogo", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSDeviceTree", plist_new_bool(1)); @@ -4824,6 +5145,7 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSStaticTrustCache", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_bool(1)); + plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "RootData", plist_new_bool(0)); plist_dict_set_item(dict, "RootTicket", plist_new_bool(0)); plist_dict_set_item(dict, "S3EOverride", plist_new_bool(0)); @@ -4834,18 +5156,10 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "SystemImageCanonicalMetadata", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageData", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0)); + plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); plist_dict_set_item(dict, "USBCFWData", plist_new_bool(0)); plist_dict_set_item(dict, "USBCOverride", plist_new_bool(0)); - plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); - plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); - plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); - plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); - plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); - plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); - plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); - plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1)); - plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); return dict; } @@ -4853,8 +5167,11 @@ plist_t restore_supported_data_types() plist_t restore_supported_message_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); plist_dict_set_item(dict, "BBUpdateStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "CheckpointMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "CrashLog", plist_new_bool(1)); plist_dict_set_item(dict, "DataRequestMsg", plist_new_bool(0)); plist_dict_set_item(dict, "FDRSubmit", plist_new_bool(1)); plist_dict_set_item(dict, "MsgType", plist_new_bool(0)); @@ -4864,11 +5181,9 @@ plist_t restore_supported_message_types() plist_dict_set_item(dict, "ProvisioningInfo", plist_new_bool(0)); plist_dict_set_item(dict, "ProvisioningStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0)); + plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1)); plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0)); - plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); - plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); - plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); return dict; } @@ -5024,15 +5339,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit //plist_dict_set_item(opts, "AuthInstallRestoreBehavior", plist_new_string("Erase")); plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0)); - if (client->preflight_info) { - plist_t bbus = plist_copy(client->preflight_info); + if (client->firmware_preflight_info) { + plist_t bbus = plist_copy(client->firmware_preflight_info); plist_dict_remove_item(bbus, "FusingStatus"); plist_dict_remove_item(bbus, "PkHash"); plist_dict_set_item(opts, "BBUpdaterState", bbus); - plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); + plist_dict_copy_data(opts, client->firmware_preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); @@ -5078,7 +5393,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } } else { // FIXME: new on iOS 5 ? - plist_dict_set_item(opts, "BootImageType", plist_new_string("UserOrInternal")); + plist_dict_set_item(opts, "BootImageType", plist_new_string("User")); // FIXME: required? //plist_dict_set_item(opts, "BootImageFile", plist_new_string("018-7923-347.dmg")); plist_dict_set_item(opts, "DFUFileType", plist_new_string("RELEASE")); @@ -5104,7 +5419,27 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // FIXME: new on iOS 5 ? plist_dict_set_item(opts, "SystemImageType", plist_new_string("User")); // FIXME: does this have any effect actually? - plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0)); + plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(1)); + plist_dict_set_item(opts, "InstallDiags", plist_new_bool(0)); + if (client->recovery_variant) { + plist_dict_set_item(opts, "InstallRecoveryOS", plist_new_bool(1)); + plist_dict_set_item(opts, "RecoveryOSBundlePath", plist_new_string("/tmp/Per2.tmp")); + plist_t recovery_variant = plist_access_path(client->recovery_variant, 2, "Info", "Variant"); + plist_dict_set_item(opts, "AuthInstallRecoveryOSVariant", plist_copy(recovery_variant)); + uint64_t max_size = 0; + uint64_t min_size = 0; + _restore_calculate_recovery_os_partition_size(client, &min_size, &max_size); + info("Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size); + info("Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size); + plist_dict_set_item(opts, "recoveryOSMaxPartitionSize", plist_new_uint(max_size)); + plist_dict_set_item(opts, "recoveryOSPartitionSize", plist_new_uint(min_size)); + } + + if (plist_dict_get_bool(client->parameters, "RequiresNonceSlot")) { + info("Device will use nonce slots.\n"); + } else { + info("Device will not use nonce slots.\n"); + } // Added for iOS 18.0 beta 1 plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); @@ -5154,10 +5489,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit spp = plist_copy(spp); } else { spp = plist_new_dict(); + plist_dict_set_item(spp, "1024", plist_new_uint(1280)); plist_dict_set_item(spp, "128", plist_new_uint(1280)); plist_dict_set_item(spp, "16", plist_new_uint(160)); + plist_dict_set_item(spp, "256", plist_new_uint(1280)); plist_dict_set_item(spp, "32", plist_new_uint(320)); + plist_dict_set_item(spp, "512", plist_new_uint(1280)); plist_dict_set_item(spp, "64", plist_new_uint(640)); + plist_dict_set_item(spp, "768", plist_new_uint(1280)); plist_dict_set_item(spp, "8", plist_new_uint(80)); } plist_dict_set_item(opts, "SystemPartitionPadding", spp); From 559adb735debcd9743569763a3d51270008310e1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 22 Oct 2024 19:33:22 +0200 Subject: [PATCH 113/159] Updated README --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1af2d935..c7d22d6c 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,10 @@ Only the prerequisites differ and they are described in this section. make \ libtool \ autoconf \ - automake-wrapper + automake-wrapper \ + pkg-config \ + libcurl-devel \ + mingw-w64-x86_64-libzip ``` NOTE: You can use a different shell and different compiler according to your needs. Adapt the above command accordingly. @@ -280,8 +283,8 @@ Please make sure your contribution adheres to: ## Links * Homepage: https://libimobiledevice.org/ -* Repository: https://git.libimobiledevice.org/idevicerestore.git -* Repository (Mirror): https://github.com/libimobiledevice/idevicerestore.git +* Repository: https://github.com/libimobiledevice/idevicerestore.git +* Repository (Mirror): https://git.libimobiledevice.org/idevicerestore.git * Issue Tracker: https://github.com/libimobiledevice/idevicerestore/issues * Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel * Twitter: https://twitter.com/libimobiledev @@ -299,4 +302,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2024-06-19 +README Updated on: 2024-10-22 From 61a76ce6fc68e9bc14e3bb4ba7a20344afb1e300 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 3 Nov 2024 22:09:51 +0100 Subject: [PATCH 114/159] [github-actions] Update curl workflow to build 8.10.1 for UCRT64 --- .github/workflows/curl.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml index 87e4459b..a1a80167 100644 --- a/.github/workflows/curl.yml +++ b/.github/workflows/curl.yml @@ -12,8 +12,9 @@ jobs: fail-fast: false matrix: include: [ - { msystem: MINGW64, arch: x86_64 }, - { msystem: MINGW32, arch: i686 } + { msystem: UCRT64, arch: x86_64, flavor: w64-ucrt }, + { msystem: MINGW64, arch: x86_64, flavor: w64 }, + { msystem: MINGW32, arch: i686, flavor: w64 } ] steps: - uses: msys2/setup-msys2@v2 @@ -24,12 +25,13 @@ jobs: install: >- base-devel git - mingw-w64-${{ matrix.arch }}-gcc + mingw-${{ matrix.flavor }}-${{ matrix.arch }}-gcc make libtool autoconf automake-wrapper liblzma + mingw-${{ matrix.flavor }}-${{ matrix.arch }}-openssl - name: prepare environment run: | dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]` @@ -37,22 +39,22 @@ jobs: echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch curl source run: | - curl -Ls -o curl-8.1.0.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_1_0/curl-8.1.0.tar.bz2 - tar xjf curl-8.1.0.tar.bz2 + curl -Ls -o curl-8.10.1.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.bz2 + tar xjf curl-8.10.1.tar.bz2 - name: configure curl run: | - cd curl-8.1.0 - ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-bindlocal --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl + cd curl-8.10.1 + ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl - name: build libcurl run: | CURDIR=`pwd` - cd curl-8.1.0/lib + cd curl-8.10.1/lib make cp .libs/libcurl.a . cd .. tar cf $CURDIR/libcurl-static.tar lib/libcurl.a include/curl/*.h - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: libcurl_${{ matrix.arch }}-${{ env.dest }} path: libcurl-static.tar From 5d92c7a5875383b81a4d20c479f05b611e54097f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:52:12 +0100 Subject: [PATCH 115/159] [github-actions] Bump dawidd6/action-download-artifact from 3 to 6 --- .github/workflows/build.yml | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd2bdd58..3b7d0dc3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: build -on: [push] +on: + push: + pull_request: + schedule: + - cron: '0 0 1 * *' jobs: build-linux-ubuntu: @@ -14,42 +18,42 @@ jobs: run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{env.target_triplet}} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -95,42 +99,42 @@ jobs: fi shell: bash - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_macOS repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_macOS repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_macOS repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_macOS repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_macOS repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -221,42 +225,42 @@ jobs: echo "dest=$dest" >> $GITHUB_ENV echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml From 914fbb35f97b37738a93f3f80fb9548bac7afcee Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:57:58 +0100 Subject: [PATCH 116/159] Fix build --- src/dfu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index e6b45afa..508b4f61 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -84,7 +84,6 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) irecv_error_t dfu_error = IRECV_E_SUCCESS; irecv_device_t device = NULL; - irecv_init(); if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) { return NULL; } From bb5591d690a057fbc6533df2617189005ea95f40 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 3 Dec 2024 01:34:41 +0100 Subject: [PATCH 117/159] configure: Fix Linux build with LTO --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 9d71e956..9c27a7be 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,7 @@ if test x$ac_cv_func_strsep != xyes; then fi fi +AC_SEARCH_LIBS([ceil], [m]) AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"]) if test "x$ac_cv_have_endian_h" = "xno"; then From 866b6b773c1326d2b407f04c80aab3b43db02468 Mon Sep 17 00:00:00 2001 From: Cameron Cross Date: Thu, 2 Feb 2023 06:24:47 +1100 Subject: [PATCH 118/159] Add docker scripts to simplify setting up idevicerestore --- README.md | 9 ++++ docker/Dockerfile | 89 ++++++++++++++++++++++++++++++++++++++++ docker/build.sh | 8 ++++ docker/idevicerestore.sh | 7 ++++ docker/run.sh | 13 ++++++ 5 files changed, 126 insertions(+) create mode 100644 docker/Dockerfile create mode 100755 docker/build.sh create mode 100755 docker/idevicerestore.sh create mode 100755 docker/run.sh diff --git a/README.md b/README.md index c7d22d6c..38d227c2 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,15 @@ idevicerestore --help man idevicerestore ``` +### Docker + +Build the container with `build.sh` in the docker folder, which will build a +docker container with the latest source versions of all the required libraries. + +Run the container with `run.sh --latest` in the docker folder, +which will execute `usbmuxd` in the background, and then start `idevicerestore --latest`. +Any arguments passed to `run.sh` will be passed in to `idevicerestore`. + ## Contributing We welcome contributions from anyone and are grateful for every pull request! diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..37f23066 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,89 @@ +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND="noninteractive" +RUN apt-get update && apt-get install -y \ + build-essential \ + pkg-config \ + checkinstall \ + git \ + autoconf \ + automake \ + libtool-bin \ + libreadline-dev \ + libusb-1.0-0-dev \ + libcurl4-openssl-dev \ + libssl-dev \ + libzip-dev \ + zlib1g-dev \ + python3 \ + udev + +RUN git clone https://github.com/libimobiledevice/libplist.git && \ + cd libplist && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libplist -rf + +RUN git clone https://github.com/libimobiledevice/libtatsu.git && \ + cd libtatsu && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libtatsu -rf + +RUN git clone https://github.com/libimobiledevice/libimobiledevice-glue.git && \ + cd libimobiledevice-glue && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libimobiledevice-glue -rf + +RUN git clone https://github.com/libimobiledevice/libusbmuxd.git && \ + cd libusbmuxd && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libusbmuxd -rf + +RUN git clone https://github.com/libimobiledevice/libimobiledevice.git && \ + cd libimobiledevice && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libimobiledevice -rf + +RUN git clone https://github.com/libimobiledevice/libirecovery.git && \ + cd libirecovery && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm libirecovery -rf + +RUN git clone https://github.com/libimobiledevice/usbmuxd.git && \ + cd usbmuxd && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm usbmuxd -rf + +RUN git clone https://github.com/libimobiledevice/idevicerestore.git && \ + cd idevicerestore && \ + ./autogen.sh && \ + make && \ + make install && \ + cd .. && \ + rm idevicerestore -rf + +RUN ldconfig +WORKDIR /tmp +COPY idevicerestore.sh /usr/sbin/idevicerestore.sh +CMD idevicerestore.sh + diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 00000000..dc415661 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +cd "$(dirname "$0")" + +docker build . -t idevicerestore-docker --no-cache + +echo "You can now use 'run.sh --latest' to run the restore." + diff --git a/docker/idevicerestore.sh b/docker/idevicerestore.sh new file mode 100755 index 00000000..cc80fbf5 --- /dev/null +++ b/docker/idevicerestore.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e + +usbmuxd & + +idevicerestore "$@" + diff --git a/docker/run.sh b/docker/run.sh new file mode 100755 index 00000000..0078309d --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e +cd "$(dirname "$0")" + +if [[ -z $(docker images | grep idevicerestore-docker) ]]; then + echo "Container not built, you will need to build it with 'build.sh'" + exit -1 +fi + +docker rm --force idevicerestore || true + +docker run --name idevicerestore -it --privileged --net=host -v /dev:/dev -v /run/udev/control:/run/udev/control -v "$(pwd):/tmp" idevicerestore-docker idevicerestore.sh "$@" + From 437e5134850c5090720ddb8c0c78eb9e75b7a761 Mon Sep 17 00:00:00 2001 From: Cameron Cross Date: Wed, 23 Oct 2024 10:43:51 +1100 Subject: [PATCH 119/159] [docker] Add CI to build and archive docker image --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b7d0dc3..70287669 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -308,3 +308,16 @@ jobs: with: name: idevicerestore-latest_${{ matrix.arch }}-${{ env.dest }} path: idevicerestore.tar + build-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + pushd docker && ./build.sh; popd + docker image save -o idevicerestore-docker.tar idevicerestore-docker + - name: publish artifact + uses: actions/upload-artifact@v4 + with: + name: idevicerestore-latest_docker + path: idevicerestore-docker.tar From b05d50cf41900ea3cf8606d018450a67bdbb4a47 Mon Sep 17 00:00:00 2001 From: Cameron Cross Date: Wed, 23 Oct 2024 10:54:00 +1100 Subject: [PATCH 120/159] [docker] Update docker image base to ubuntu 24.04 --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 37f23066..8da9bd40 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ENV DEBIAN_FRONTEND="noninteractive" RUN apt-get update && apt-get install -y \ From 2ee5021f36a26f7344b63d3321cda78899edc319 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 20 Mar 2025 15:10:16 +0100 Subject: [PATCH 121/159] Allow building without support for limera1n Use --without-limera1n at configure time to disable this feature. --- configure.ac | 10 ++++++++++ src/Makefile.am | 5 +++-- src/idevicerestore.c | 27 ++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 9c27a7be..98516b7c 100644 --- a/configure.ac +++ b/configure.ac @@ -150,6 +150,16 @@ if test "$ac_cv_reverse_proxy" = "yes"; then AC_DEFINE(HAVE_REVERSE_PROXY, 1, [Define if libimobiledevice has a reverse proxy implementation]) fi +AC_ARG_WITH([limera1n], + [AS_HELP_STRING([--with-limera1n], + [build with support for limera1n exploit (default is yes)])], + [have_limera1n=$withval], + [have_limera1n=yes]) +if test "x$have_limera1n" = "xyes"; then + AC_DEFINE(HAVE_LIMERA1N, 1, [Define if limera1n support is available]) +fi +AM_CONDITIONAL([HAVE_LIMERA1N],[test "x$have_limera1n" = "xyes"]) + CFLAGS="$CACHED_CFLAGS" AC_SUBST(GLOBAL_CFLAGS) diff --git a/src/Makefile.am b/src/Makefile.am index 80f02f20..a717b45f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,10 +44,11 @@ idevicerestore_SOURCES = \ asr.c asr.h \ fdr.c fdr.h \ ace3.c ace3.h \ - limera1n_payload.h \ - limera1n.c limera1n.h \ download.c download.h \ locking.c locking.h +if HAVE_LIMERA1N +idevicerestore_SOURCES += limera1n_payload.h limera1n.c limera1n.h +endif idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) idevicerestore_LDADD = $(AM_LDADD) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index b8bb1d06..a61409ac 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -54,13 +54,15 @@ #include "recovery.h" #include "idevicerestore.h" +#ifdef HAVE_LIMERA1N #include "limera1n.h" +#endif #include "locking.h" #define VERSION_XML "version.xml" -#ifndef IDEVICERESTORE_NOMAIN +#ifndef IDEVICERESTORE_NOMAIN static struct option longopts[] = { { "ecid", required_argument, NULL, 'i' }, { "udid", required_argument, NULL, 'u' }, @@ -73,7 +75,9 @@ static struct option longopts[] = { { "exclude", no_argument, NULL, 'x' }, { "shsh", no_argument, NULL, 't' }, { "keep-pers", no_argument, NULL, 'k' }, +#ifdef HAVE_LIMERA1N { "pwn", no_argument, NULL, 'p' }, +#endif { "no-action", no_argument, NULL, 'n' }, { "cache-path", required_argument, NULL, 'C' }, { "no-input", no_argument, NULL, 'y' }, @@ -90,6 +94,11 @@ static struct option longopts[] = { static void usage(int argc, char* argv[], int err) { +#ifdef HAVE_LIMERA1N +#define PWN_FLAG_LINE " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n" +#else +#define PWN_FLAG_LINE "" +#endif char* name = strrchr(argv[0], '/'); fprintf((err) ? stderr : stdout, "Usage: %s [OPTIONS] PATH\n" \ @@ -134,7 +143,7 @@ static void usage(int argc, char* argv[], int err) " -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \ " -z, --no-restore Do not restore and end after booting to the ramdisk\n" \ " -k, --keep-pers Write personalized components to files for debugging\n" \ - " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n" \ + PWN_FLAG_LINE \ " -P, --plain-progress Print progress as plain step and progress\n" \ " -R, --restore-mode Allow restoring from Restore mode\n" \ " -T, --ticket PATH Use file at PATH to send as AP ticket\n" \ @@ -501,6 +510,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); if (client->flags & FLAG_PWN) { +#ifdef HAVE_LIMERA1N recovery_client_free(client); if (client->mode != MODE_DFU) { @@ -530,6 +540,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: This device is not supported by the limera1n exploit"); return -1; } +#endif } if (client->flags & FLAG_LATEST) { @@ -1392,6 +1403,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // if the device is in DFU mode, place it into recovery mode dfu_client_free(client); recovery_client_free(client); +#ifdef HAVE_LIMERA1N if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) { info("connecting to DFU\n"); if (dfu_client_new(client) < 0) { @@ -1406,6 +1418,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) dfu_client_free(client); info("exploited\n"); } +#endif if (dfu_enter_recovery(client, build_identity) < 0) { error("ERROR: Unable to place device into recovery mode from DFU mode\n"); if (client->tss) @@ -1765,7 +1778,13 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_INTERACTIVE; } - while ((opt = getopt_long(argc, argv, "dhces:xtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { +#ifdef HAVE_LIMERA1N +#define P_FLAG "p" +#else +#define P_FLAG "" +#endif + + while ((opt = getopt_long(argc, argv, "dhces:xtli:u:nC:kyPRT:zv" P_FLAG, longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv, 0); @@ -1855,9 +1874,11 @@ int main(int argc, char* argv[]) { idevicerestore_keep_pers = 1; break; +#ifdef HAVE_LIMERA1N case 'p': client->flags |= FLAG_PWN; break; +#endif case 'n': client->flags |= FLAG_NOACTION; From a5905b7f905fc3cc83033ebd963f0dcba071e512 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 25 Mar 2025 00:03:42 +0100 Subject: [PATCH 122/159] Fix iPhone 16e restore from normal mode Because of the new Apple baseband the initial TSS request won't succeed when restoring from normal mode due to missing data for a @BBTicket. So now if the baseband information is missing, we don't try to add BBTicket data at all, which will make it work for iPhone 16e devices. --- src/idevicerestore.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index a61409ac..9911e9d3 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2406,18 +2406,20 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); - /* add baseband parameters */ - tss_request_add_baseband_tags(request, parameters, NULL); - - plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); - if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { - plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); - plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); - plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); - plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); - - /* add vinyl parameters */ - tss_request_add_vinyl_tags(request, parameters, NULL); + if (plist_dict_get_item(parameters, "BbSNUM")) { + /* add baseband parameters */ + tss_request_add_baseband_tags(request, parameters, NULL); + + plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); + if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { + plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); + plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); + plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); + plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); + + /* add vinyl parameters */ + tss_request_add_vinyl_tags(request, parameters, NULL); + } } } client->firmware_preflight_info = pinfo; From 8061f08b4e0a8f0ab5d1548b7e9978f3cc8647a2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 23 Jun 2025 14:00:10 +0200 Subject: [PATCH 123/159] Refactor logging and add logfile support idevicerestore will now also create a logfile automatically, unless disabled with --logfile=NONE. --- docs/idevicerestore.1 | 4 + src/Makefile.am | 1 + src/ace3.c | 8 +- src/asr.c | 53 +- src/common.c | 461 +++++++++++------ src/common.h | 40 +- src/dfu.c | 110 ++-- src/download.c | 37 +- src/fdr.c | 130 +++-- src/fls.c | 18 +- src/ftab.c | 10 +- src/idevicerestore.c | 636 +++++++++++++----------- src/idevicerestore.h | 4 +- src/img3.c | 78 +-- src/img4.c | 24 +- src/ipsw.c | 242 +++++---- src/limera1n.c | 22 +- src/locking.c | 12 +- src/log.c | 210 ++++++++ src/log.h | 41 ++ src/mbn.c | 8 +- src/normal.c | 116 ++--- src/recovery.c | 106 ++-- src/restore.c | 1102 +++++++++++++++++++++-------------------- 24 files changed, 2014 insertions(+), 1459 deletions(-) create mode 100644 src/log.c create mode 100644 src/log.h diff --git a/docs/idevicerestore.1 b/docs/idevicerestore.1 index d1415482..633469a6 100644 --- a/docs/idevicerestore.1 +++ b/docs/idevicerestore.1 @@ -58,6 +58,10 @@ Prints usage information. .B \-C, \-\-cache\-path DIR Use specified directory for caching extracted or other reused files. .TP +.B \-\-logfile PATH +Write logging output to file at PATH. If PATH equals \f[B]NULL\f[] or \f[B]NONE\f[], +no log file will be written. This disables automatic log file creation. +.TP .B \-d, \-\-debug Enable communication debugging. .TP diff --git a/src/Makefile.am b/src/Makefile.am index a717b45f..2b7084ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,6 +29,7 @@ bin_PROGRAMS = idevicerestore idevicerestore_SOURCES = \ idevicerestore.c idevicerestore.h \ + log.c log.h \ endianness.h \ common.c common.h \ fls.c fls.h \ diff --git a/src/ace3.c b/src/ace3.c index a482f6f3..9bbc8b63 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -167,7 +167,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint64_t boardid = 0; plist_get_uint_val(p_boardid, &boardid); if (boardid == bdid) { - debug("DEBUG: %s: Found Board ID 0x%" PRIx64 "\n", __func__, bdid); + logger(LL_DEBUG, "%s: Found Board ID 0x%" PRIx64 "\n", __func__, bdid); plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC"); plist_get_string_val(p4cc, &payload_4cc); plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data"); @@ -189,7 +189,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t if (prev >= minrev && prev <= maxrev) { plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags"); plist_get_string_val(tags, &data_payload_4ccs); - debug("DEBUG: %s: Found matching tags %s\n", __func__, data_payload_4ccs); + logger(LL_DEBUG, "%s: Found matching tags %s\n", __func__, data_payload_4ccs); break; } } while (match); @@ -201,11 +201,11 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t plist_mem_free(iter); } if (!payload_4cc) { - printf("Failed to get payload 4cc\n"); + logger(LL_ERROR, "Failed to get payload 4cc\n"); return -1; } if (!data_payload_4ccs) { - printf("Failed to get data payload 4ccs\n"); + logger(LL_ERROR, "Failed to get data payload 4ccs\n"); return -1; } diff --git a/src/asr.c b/src/asr.c index 15396c4a..fba59d9d 100644 --- a/src/asr.c +++ b/src/asr.c @@ -63,7 +63,7 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) if (port == 0) { port = ASR_DEFAULT_PORT; } - debug("Connecting to ASR on port %u\n", port); + logger(LL_VERBOSE, "Connecting to ASR on port %u\n", port); for (i = 1; i <= attempts; i++) { device_error = idevice_connect(device, port, &connection); @@ -72,12 +72,12 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) } if (i >= attempts) { - error("ERROR: Unable to connect to ASR client\n"); + logger(LL_ERROR, "Unable to connect to ASR client\n"); return -1; } sleep(2); - debug("Retrying connection...\n"); + logger(LL_VERBOSE, "Retrying connection...\n"); } asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client)); @@ -88,7 +88,7 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) plist_t data = NULL; asr_loc->checksum_chunks = 0; if (asr_receive(asr_loc, &data) < 0) { - error("ERROR: Unable to receive data from ASR\n"); + logger(LL_ERROR, "Unable to receive data from ASR\n"); asr_free(asr_loc); plist_free(data); return -1; @@ -99,8 +99,8 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) char* strval = NULL; plist_get_string_val(node, &strval); if (strval && (strcmp(strval, "Initiate") != 0)) { - error("ERROR: unexpected ASR plist received:\n"); - debug_plist(data); + logger(LL_ERROR, "Unexpected ASR plist received\n"); + logger_dump_plist(LL_VERBOSE, data, 1); plist_free(data); asr_free(asr_loc); return -1; @@ -138,13 +138,13 @@ int asr_receive(asr_client_t asr, plist_t* data) buffer = (char*)malloc(ASR_BUFFER_SIZE); if (buffer == NULL) { - error("ERROR: Unable to allocate memory for ASR receive buffer\n"); + logger(LL_ERROR, "Unable to allocate memory for ASR receive buffer\n"); return -1; } device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to receive data from ASR\n"); + logger(LL_ERROR, "Unable to receive data from ASR\n"); free(buffer); return -1; } @@ -152,9 +152,8 @@ int asr_receive(asr_client_t asr, plist_t* data) *data = request; - debug("Received %d bytes:\n", size); - if (idevicerestore_debug) - debug_plist(request); + logger(LL_DEBUG, "Received %d bytes:\n", size); + logger_dump_plist(LL_DEBUG, request, 1); free(buffer); return 0; } @@ -166,7 +165,7 @@ int asr_send(asr_client_t asr, plist_t data) plist_to_xml(data, &buffer, &size); if (asr_send_buffer(asr, buffer, size) < 0) { - error("ERROR: Unable to send plist to ASR\n"); + logger(LL_ERROR, "Unable to send plist to ASR\n"); free(buffer); return -1; } @@ -183,7 +182,7 @@ int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size) device_error = idevice_connection_send(asr->connection, data, size, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != size) { - error("ERROR: Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size); + logger(LL_ERROR, "Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size); return -1; } @@ -240,19 +239,19 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) // Expected by device after every initiate if (asr_send_validation_packet_info(asr, length) < 0) { - error("ERROR: Unable to send validation packet info to ASR\n"); + logger(LL_ERROR, "Unable to send validation packet info to ASR\n"); return -1; } while (1) { if (asr_receive(asr, &packet) < 0) { - error("ERROR: Unable to receive validation packet\n"); + logger(LL_ERROR, "Unable to receive validation packet\n"); return -1; } if (packet == NULL) { if (attempts < 5) { - info("Retrying to receive validation packet... %d\n", attempts); + logger(LL_INFO, "Retrying to receive validation packet... %d\n", attempts); attempts++; sleep(1); continue; @@ -263,7 +262,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) 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"); + logger(LL_ERROR, "Unable to find command node in validation request\n"); return -1; } plist_get_string_val(node, &command); @@ -279,7 +278,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) // Expected by device after every Initiate if (asr_send_validation_packet_info(asr, length) < 0) { - error("ERROR: Unable to send validation packet info to ASR\n"); + logger(LL_ERROR, "Unable to send validation packet info to ASR\n"); return -1; } @@ -297,7 +296,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) break; } else { - error("ERROR: Unknown command received from ASR\n"); + logger(LL_ERROR, "Unknown command received from ASR\n"); plist_free(packet); return -1; } @@ -316,38 +315,38 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_hand 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"); + logger(LL_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"); + logger(LL_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"); + logger(LL_ERROR, "Out of memory\n"); return -1; } if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) { - error("ERROR: Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset); + logger(LL_ERROR, "Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset); free(oob_data); return -1; } int64_t ir = ipsw_file_read(file, oob_data, oob_length); if (ir != oob_length) { - error("ERROR: Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir); + logger(LL_ERROR, "Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir); 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"); + logger(LL_ERROR, "Unable to send OOB data to ASR\n"); free(oob_data); return -1; } @@ -377,7 +376,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) } if (ipsw_file_read(file, data, size) != (int64_t)size) { - error("Error reading filesystem\n"); + logger(LL_ERROR, "Error reading filesystem\n"); retry--; continue; } @@ -388,7 +387,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) sendsize += 20; } if (asr_send_buffer(asr, data, sendsize) < 0) { - error("Unable to send filesystem payload chunk, retrying...\n"); + logger(LL_ERROR, "Unable to send filesystem payload chunk, retrying...\n"); retry--; continue; } diff --git a/src/common.c b/src/common.c index c7be4f66..4c99a3a9 100644 --- a/src/common.c +++ b/src/common.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -57,6 +58,13 @@ #define MAX_PRINT_LEN 64*1024 +int global_quit_flag = 0; +static const char* STARS = "******************************************************************************"; +static const char* SPACES = " "; +static const char* POUNDS = "##############################################################################"; + +static uint32_t progress_unique_tag = 1; + struct idevicerestore_mode_t idevicerestore_modes[] = { { 0, "Unknown" }, { 1, "WTF" }, @@ -69,122 +77,17 @@ struct idevicerestore_mode_t idevicerestore_modes[] = { int idevicerestore_debug = 0; -#define idevicerestore_err_buff_size 256 -static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, }; - -static FILE* info_stream = NULL; -static FILE* error_stream = NULL; -static FILE* debug_stream = NULL; - -static int info_disabled = 0; -static int error_disabled = 0; -static int debug_disabled = 0; - -static mutex_t log_mutex; -static thread_once_t init_once = THREAD_ONCE_INIT; - -static void _log_init(void) -{ - mutex_init(&log_mutex); -} - -void info(const char* format, ...) -{ - if (info_disabled) return; - thread_once(&init_once, _log_init); - mutex_lock(&log_mutex); - va_list vargs; - va_start(vargs, format); - vfprintf((info_stream) ? info_stream : stdout, format, vargs); - va_end(vargs); - fflush(info_stream?info_stream:stdout); - mutex_unlock(&log_mutex); -} - -void error(const char* format, ...) -{ - thread_once(&init_once, _log_init); - mutex_lock(&log_mutex); - va_list vargs, vargs2; - va_start(vargs, format); - va_copy(vargs2, vargs); - vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs); - va_end(vargs); - if (!error_disabled) { - vfprintf((error_stream) ? error_stream : stderr, format, vargs2); - } - va_end(vargs2); - fflush(error_stream?error_stream:stderr); - mutex_unlock(&log_mutex); -} - -void debug(const char* format, ...) -{ - if (debug_disabled) return; - if (!idevicerestore_debug) { - return; - } - thread_once(&init_once, _log_init); - mutex_lock(&log_mutex); - va_list vargs; - va_start(vargs, format); - vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); - va_end(vargs); - fflush(debug_stream?debug_stream:stderr); - mutex_unlock(&log_mutex); -} - -void idevicerestore_set_info_stream(FILE* strm) -{ - if (strm) { - info_disabled = 0; - info_stream = strm; - } else { - info_disabled = 1; - } -} - -void idevicerestore_set_error_stream(FILE* strm) -{ - if (strm) { - error_disabled = 0; - error_stream = strm; - } else { - error_disabled = 1; - } -} - -void idevicerestore_set_debug_stream(FILE* strm) -{ - if (strm) { - debug_disabled = 0; - debug_stream = strm; - } else { - debug_disabled = 1; - } -} - -const char* idevicerestore_get_error(void) -{ - if (idevicerestore_err_buff[0] == 0) { - return NULL; - } else { - char* p = NULL; - while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) { - p[0] = '\0'; - } - return (const char*)idevicerestore_err_buff; - } -} +static void (*banner_func)(const char*) = NULL; +static void (*banner_hide_func)(void) = NULL; int write_file(const char* filename, const void* data, size_t size) { size_t bytes = 0; FILE* file = NULL; - debug("Writing data to %s\n", filename); + logger(LL_DEBUG, "Writing data to %s\n", filename); file = fopen(filename, "wb"); if (file == NULL) { - error("write_file: Unable to open file %s\n", filename); + logger(LL_ERROR, "write_file: Unable to open file %s\n", filename); return -1; } @@ -192,7 +95,7 @@ int write_file(const char* filename, const void* data, size_t size) { fclose(file); if (bytes != size) { - error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size); + logger(LL_ERROR, "Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size); return -1; } @@ -206,26 +109,26 @@ int read_file(const char* filename, void** data, size_t* size) { char* buffer = NULL; struct stat fst; - debug("Reading data from %s\n", filename); + logger(LL_DEBUG, "Reading data from %s\n", filename); *size = 0; *data = NULL; file = fopen(filename, "rb"); if (file == NULL) { - error("read_file: cannot open %s: %s\n", filename, strerror(errno)); + logger(LL_ERROR, "read_file: cannot open %s: %s\n", filename, strerror(errno)); return -1; } if (fstat(fileno(file), &fst) < 0) { - error("read_file: fstat: %s\n", strerror(errno)); + logger(LL_ERROR, "read_file: fstat: %s\n", strerror(errno)); return -1; } length = fst.st_size; buffer = (char*) malloc(length); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); fclose(file); return -1; } @@ -233,7 +136,7 @@ int read_file(const char* filename, void** data, size_t* size) { fclose(file); if (bytes != length) { - error("ERROR: Unable to read entire file\n"); + logger(LL_ERROR, "Unable to read entire file\n"); free(buffer); return -1; } @@ -243,32 +146,309 @@ int read_file(const char* filename, void** data, size_t* size) { return 0; } -void debug_plist(plist_t plist) { - uint32_t size = 0; - char* data = NULL; - plist_to_xml(plist, &data, &size); - if (size <= MAX_PRINT_LEN) - info("printing %i bytes plist:\n%s", size, data); - else - info("supressed printing %i bytes plist...\n", size); - free(data); +int process_text_lines(const char* text, int maxwidth, struct tuple** lines_out, int* maxlen_out) +{ + if (!text) return 0; + int len = strlen(text); + int numlines = 0; + int maxlen = 0; + int linestart = 0; + int linelen = 0; + int lastspace = 0; + int maxlines = 8; + int count = 0; + struct tuple* lines = (struct tuple*)malloc(sizeof(struct tuple) * maxlines); + int i = 0; + while (i <= len) { + int split_line = 0; + if ((text[i] & 0xE0) == 0xC0) i += 1; + else if ((text[i] & 0xF0) == 0xE0) i += 2; + else if ((text[i] & 0xF8) == 0xF0) i += 3; + if (i > len) i = len; + linelen = i - linestart; + if (text[i] == '\0') { + split_line = 1; + } + if (linelen > maxwidth) { + if (lastspace > linestart+maxwidth/2+6) { + count -= i-lastspace; + i = lastspace; + linelen = i - linestart; + split_line = 1; + } else { + split_line = 1; + } + } + if ((linelen > 0 && split_line) || text[i] == '\n') { + split_line = 0; + if (numlines == maxlines) { + maxlines += 8; + struct tuple* newlines = (struct tuple*)realloc(lines, sizeof(struct tuple) * maxlines); + if (!newlines) { + printf("FATAL: Out of memory\n"); + return -1; + } + lines = newlines; + } + lines[numlines].idx = linestart; + lines[numlines].len = linelen; + lines[numlines].plen = count; + if (count > maxlen) maxlen = count; + numlines++; + linestart = i+1; + count = 0; + } + else if (text[i] == ' ') { + lastspace = i; + count++; + } else { + count++; + } + i++; + } + *lines_out = lines; + *maxlen_out = maxlen; + return numlines; +} + +void set_banner_funcs(void (*showfunc)(const char*), void (*hidefunc)(void)) +{ + banner_func = showfunc; + banner_hide_func = hidefunc; +} + +void show_banner(const char* text) +{ + if (banner_func) { + banner_func(text); + } else { + int i; + int maxlen = 0; + struct tuple* lines = NULL; + int numlines = process_text_lines(text, 74, &lines, &maxlen); + printf("%.*s\n", maxlen + 4, STARS); + for (i = 0; i < numlines; i++) { + printf("* %.*s%.*s *\n", lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES); + } + printf("%.*s\n", maxlen + 4, STARS); + free(lines); + } +} + +void hide_banner() +{ + if (banner_hide_func) { + banner_hide_func(); + } +} + +static int (*prompt_func)(const char* title, const char* text) = NULL; + +void set_prompt_func(int (*func)(const char* title, const char* text)) +{ + prompt_func = func; +} + +int prompt_user(const char* title, const char* text) +{ + if (!text) return -1; + if (prompt_func) { + return prompt_func(title, text); + } + int i; + int result = 0; + int maxlen = 0; + struct tuple* lines = NULL; + int numlines = process_text_lines(text, 74, &lines, &maxlen); + int outerlen = maxlen+4; + int titlelen = (title) ? strlen(title) : 0; + if (titlelen > 0) { + int lefttitlelen = (titlelen+4)/2; + int righttitlelen = titlelen+4 - lefttitlelen; + int leftpounds = outerlen/2 - lefttitlelen; + int rightpounds = outerlen-(titlelen+4) - leftpounds; + printf("%.*s[ %.*s ]%.*s\n", leftpounds, POUNDS, titlelen, title, rightpounds, POUNDS); + } else { + printf("%.*s\n", outerlen, POUNDS); + } + for (i = 0; i < numlines; i++) { + printf("%c %.*s%.*s %c\n", *POUNDS, lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES, *POUNDS); + } + free(lines); + const char* yesmsg = "Type YES and press ENTER to continue, or hit CTRL+C to cancel."; + int ylen = strlen(yesmsg); + printf("%c %.*s%.*s %c\n", *POUNDS, ylen, yesmsg, maxlen-ylen, SPACES, *POUNDS); + printf("%.*s\n", outerlen, POUNDS); + + char input[64]; + while (1) { + printf("> "); + fflush(stdout); + fflush(stdin); + input[0] = '\0'; + get_user_input(input, 63, 0); + if (global_quit_flag) { + result = -1; + break; + } + if (*input != '\0' && !strcmp(input, "YES")) { + result = 1; + break; + } else { + printf("Invalid input. Please type YES or hit CTRL+C to abort.\n"); + continue; + } + } + return result; +} + +static void (*update_progress_func)(struct progress_info_entry** list, int count) = NULL; +static double progress_granularity = 0.001; + +void set_update_progress_func(void (*func)(struct progress_info_entry** list, int count)) +{ + update_progress_func = func; +} + +void set_progress_granularity(double granularity) +{ + progress_granularity = granularity; +} + +mutex_t prog_mutex; +struct collection progress_info; +thread_once_t progress_info_once = THREAD_ONCE_INIT; +static void _init_progress_info(void) +{ + mutex_init(&prog_mutex); + collection_init(&progress_info); +} + +uint32_t progress_get_next_tag(void) +{ + mutex_lock(&prog_mutex); + uint32_t newtag = ++progress_unique_tag; + mutex_unlock(&prog_mutex); + return newtag; +} + +void progress_reset_tag(void) +{ + progress_unique_tag = 1; +} + +void register_progress(uint32_t tag, const char* label) +{ + thread_once(&progress_info_once, _init_progress_info); + if (!label) { + return; + } + mutex_lock(&prog_mutex); + struct progress_info_entry* found = NULL; + FOREACH(struct progress_info_entry* e, &progress_info) { + if (e->tag == tag) { + found = e; + break; + } + } ENDFOREACH + if (found) { + if (strcmp(found->label, label) != 0) { + free(found->label); + found->label = strdup(label); + if (update_progress_func) { + update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); + } else { + print_progress_bar(found->label, found->progress); + } + } + mutex_unlock(&prog_mutex); + return; + } + struct progress_info_entry* newinfo = (struct progress_info_entry*)calloc(1, sizeof(struct progress_info_entry)); + if (!newinfo) { + logger(LL_ERROR, "Out of memory?!\n"); + exit(1); + } + newinfo->tag = tag; + newinfo->label = strdup(label); + newinfo->progress = 0; + collection_add(&progress_info, newinfo); + if (update_progress_func) { + update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); + } else { + print_progress_bar(newinfo->label, newinfo->progress); + } + mutex_unlock(&prog_mutex); } -void print_progress_bar(double progress) { -#ifndef WIN32 - if (info_disabled) return; +void finalize_progress(uint32_t tag) +{ + mutex_lock(&prog_mutex); + struct progress_info_entry* found = NULL; + FOREACH(struct progress_info_entry* e, &progress_info) { + if (e->tag == tag) { + found = e; + break; + } + } ENDFOREACH + if (!found) { + mutex_unlock(&prog_mutex); + return; + } + collection_remove(&progress_info, found); + free(found->label); + free(found); + if (update_progress_func) { + update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); + } + mutex_unlock(&prog_mutex); +} + +void print_progress_bar(const char* prefix, double progress) +{ int i = 0; - if(progress < 0) return; - if(progress > 100) progress = 100; - fprintf((info_stream) ? info_stream : stdout, "\r["); - for(i = 0; i < 50; i++) { - if(i < progress / 2) fprintf((info_stream) ? info_stream : stdout, "="); - else fprintf((info_stream) ? info_stream : stdout, " "); - } - fprintf((info_stream) ? info_stream : stdout, "] %5.1f%%", progress); - if(progress >= 100) fprintf((info_stream) ? info_stream : stdout, "\n"); - fflush((info_stream) ? info_stream : stdout); -#endif + if (progress < 0) return; + if (progress > 1) progress = 1; + if (prefix) { + printf("\r%s [", prefix); + } else { + printf("\r["); + } + for (i = 0; i < 50; i++) { + if (i < (int)(progress*50.0)) printf("="); + else printf(" "); + } + printf("] %5.1f%% ", progress*100.0); + if (progress >= 1) printf("\n"); + fflush(stdout); +} + +void set_progress(uint32_t tag, double progress) +{ + mutex_lock(&prog_mutex); + struct progress_info_entry* found = NULL; + FOREACH(struct progress_info_entry* e, &progress_info) { + if (e->tag == tag) { + found = e; + break; + } + } ENDFOREACH + if (!found) { + mutex_unlock(&prog_mutex); + return; + } + if (progress < 0) progress = 0; + if (progress > 1.0) progress = 1.0; + found->progress = progress; + if ((progress == 0) || (found->progress - found->lastprog >= progress_granularity)) { + if (update_progress_func) { + update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); + } else { + print_progress_bar(found->label, found->progress); + } + found->lastprog = found->progress; + } + mutex_unlock(&prog_mutex); } #define GET_RAND(min, max) ((rand() % (max - min)) + min) @@ -485,17 +665,14 @@ char *get_temp_filename(const char *prefix) void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress) { - thread_once(&init_once, _log_init); - mutex_lock(&log_mutex); if(client && client->progress_cb) { client->progress_cb(step, progress, client->progress_cb_data); } else { // we don't want to be too verbose in regular idevicerestore. if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW) || (step == RESTORE_STEP_UPLOAD_IMG)) { - print_progress_bar(100.0 * progress); + print_progress_bar(NULL, progress); } } - mutex_unlock(&log_mutex); } #ifndef HAVE_STRSEP diff --git a/src/common.h b/src/common.h index 872d2f92..08675a2c 100644 --- a/src/common.h +++ b/src/common.h @@ -40,6 +40,7 @@ extern "C" { #include #include "idevicerestore.h" +#include "log.h" #define _MODE_UNKNOWN 0 #define _MODE_WTF 1 @@ -140,19 +141,42 @@ struct idevicerestore_client_t { int async_err; }; +extern int global_quit_flag; + extern struct idevicerestore_mode_t idevicerestore_modes[]; extern int idevicerestore_debug; -__attribute__((format(printf, 1, 2))) -void info(const char* format, ...); -__attribute__((format(printf, 1, 2))) -void error(const char* format, ...); -__attribute__((format(printf, 1, 2))) -void debug(const char* format, ...); +void set_banner_funcs(void (*showfunc)(const char*), void (*hidefunc)(void)); +void show_banner(const char* text); +void hide_banner(); + +struct progress_info_entry { + uint32_t tag; + char* label; + double progress; + int lastprog; +}; +void set_update_progress_func(void (*func)(struct progress_info_entry** list, int count)); +void set_progress_granularity(double granularity); +uint32_t progress_get_next_tag(void); +void progress_reset_tag(void); +void register_progress(uint32_t tag, const char* label); +void set_progress(uint32_t tag, double progress); +void finalize_progress(uint32_t tag); +void print_progress_bar(const char* prefix, double progress); + +struct tuple { + int idx; + int len; + int plen; +}; + +int process_text_lines(const char* text, int maxwidth, struct tuple** lines_out, int* maxlen_out); + +void set_prompt_func(int (*func)(const char* title, const char* text)); +int prompt_user(const char* title, const char* message); -void debug_plist(plist_t plist); -void print_progress_bar(double progress); int read_file(const char* filename, void** data, size_t* size); int write_file(const char* filename, const void* data, size_t size); diff --git a/src/dfu.c b/src/dfu.c index 508b4f61..83046b96 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -36,7 +36,7 @@ static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) { if (event->type == IRECV_PROGRESS) { - print_progress_bar(event->progress); + set_progress('DFUP', (double)event->progress/100.0); } return 0; } @@ -49,24 +49,26 @@ int dfu_client_new(struct idevicerestore_client_t* client) client->dfu = (struct dfu_client_t*)malloc(sizeof(struct dfu_client_t)); memset(client->dfu, 0, sizeof(struct dfu_client_t)); if (client->dfu == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } } if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) { - error("ERROR: Unable to connect to device in DFU mode\n"); + logger(LL_ERROR, "Unable to connect to device in DFU mode\n"); return -1; } irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL); client->dfu->client = dfu; + register_progress('DFUP', "Uploading"); return 0; } void dfu_client_free(struct idevicerestore_client_t* client) { if(client != NULL) { + finalize_progress('DFUP'); if (client->dfu != NULL) { if(client->dfu->client != NULL) { irecv_close(client->dfu->client); @@ -107,11 +109,11 @@ int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigne { irecv_error_t err = 0; - info("Sending data (%d bytes)...\n", size); + logger(LL_INFO, "Sending data (%d bytes)...\n", size); err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); + logger(LL_ERROR, "Unable to send data: %s\n", irecv_strerror(err)); return -1; } @@ -144,19 +146,19 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide } else { if (tss) { if (tss_response_get_path_by_entry(tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build_identity\n", component); } } if (!path) { if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to get path for component '%s'\n", component); + logger(LL_ERROR, "Unable to get path for component '%s'\n", component); free(path); return -1; } } if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); free(path); return -1; } @@ -168,7 +170,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide uint32_t size = 0; if (personalize_component(client, component, component_data, component_size, tss, &data, &size) < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); free(component_data); return -1; } @@ -179,14 +181,14 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide unsigned char* ticket = NULL; unsigned int tsize = 0; if (tss_response_get_ap_ticket(client->tss, &ticket, &tsize) < 0) { - error("ERROR: Unable to get ApTicket from TSS request\n"); + logger(LL_ERROR, "Unable to get ApTicket from TSS request\n"); return -1; } uint32_t fillsize = 0; if (tsize % 64 != 0) { fillsize = ((tsize / 64) + 1) * 64; } - debug("ticket size = %d\nfillsize = %d\n", tsize, fillsize); + logger(LL_DEBUG, "ticket size = %d\nfillsize = %d\n", tsize, fillsize); unsigned char* newdata = (unsigned char*)malloc(size + fillsize); memcpy(newdata, ticket, tsize); memset(newdata + tsize, '\xFF', fillsize - tsize); @@ -196,11 +198,11 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide size += fillsize; } - info("Sending %s (%d bytes)...\n", component, size); + logger(LL_INFO, "Sending %s (%d bytes)...\n", component, size); irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); + logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err)); free(data); return -1; } @@ -366,14 +368,14 @@ int dfu_send_component_and_command(struct idevicerestore_client_t* client, plist irecv_error_t dfu_error = IRECV_E_SUCCESS; if (dfu_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } - info("INFO: executing command: %s\n", command); + logger(LL_INFO, "INFO: executing command: %s\n", command); dfu_error = irecv_send_command(client->dfu->client, command); if (dfu_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", command); + logger(LL_ERROR, "Unable to execute %s\n", command); return -1; } @@ -384,10 +386,10 @@ int dfu_send_command(struct idevicerestore_client_t* client, const char* command { irecv_error_t dfu_error = IRECV_E_SUCCESS; - info("INFO: executing command: %s\n", command); + logger(LL_INFO, "INFO: executing command: %s\n", command); dfu_error = irecv_send_command(client->dfu->client, command); if (dfu_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", command); + logger(LL_ERROR, "Unable to execute %s\n", command); return -1; } @@ -398,7 +400,7 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli { 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"); + logger(LL_ERROR, "Unable to find manifest node\n"); return -1; } @@ -422,12 +424,12 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli uint8_t b = 0; plist_get_bool_val(iboot_node, &b); if (b) { - debug("DEBUG: %s is loaded by iBoot Stage 1 and iBoot.\n", key); + logger(LL_DEBUG, "%s is loaded by iBoot Stage 1 and iBoot.\n", key); } else { - debug("DEBUG: %s is loaded by iBoot Stage 1 but not iBoot...\n", key); + logger(LL_DEBUG, "%s is loaded by iBoot Stage 1 but not iBoot...\n", key); } if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { - error("ERROR: Unable to send component '%s' to device.\n", key); + logger(LL_ERROR, "Unable to send component '%s' to device.\n", key); err++; } } @@ -443,14 +445,14 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide int mode = 0; if (dfu_client_new(client) < 0) { - error("ERROR: Unable to connect to DFU device\n"); + logger(LL_ERROR, "Unable to connect to DFU device\n"); return -1; } irecv_get_mode(client->dfu->client, &mode); if (mode != IRECV_K_DFU_MODE) { - info("NOTE: device is not in DFU mode, assuming recovery mode.\n"); + logger(LL_NOTICE, "device is not in DFU mode, assuming recovery mode.\n"); client->mode = MODE_RECOVERY; return 0; } @@ -458,7 +460,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide mutex_lock(&client->device_event_mutex); if (dfu_send_component(client, build_identity, "iBSS") < 0) { - error("ERROR: Unable to send iBSS to device\n"); + logger(LL_ERROR, "Unable to send iBSS to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -467,21 +469,21 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (client->build_major > 8) { /* reconnect */ - debug("Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n"); + logger(LL_ERROR, "Device did not disconnect. Possibly invalid iBSS. Reset device and try again.\n"); } return -1; } - debug("Waiting for device to reconnect...\n"); + logger(LL_DEBUG, "Waiting for device to reconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); if ((client->mode != MODE_DFU && client->mode != MODE_RECOVERY) || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n"); + logger(LL_ERROR, "Device did not reconnect in DFU or recovery mode. Possibly invalid iBSS. Reset device and try again.\n"); } return -1; } @@ -493,7 +495,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide unsigned int nonce_size = 0; int nonce_changed = 0; if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) { - error("ERROR: Unable to get ApNonce from device!\n"); + logger(LL_ERROR, "Unable to get ApNonce from device!\n"); return -1; } @@ -508,29 +510,25 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide free(nonce); } - info("Nonce: "); - int i; - for (i = 0; i < client->nonce_size; i++) { - info("%02x ", client->nonce[i]); - } - info("\n"); + logger(LL_INFO, "Nonce: "); + logger_dump_hex(LL_INFO, client->nonce, client->nonce_size); if (nonce_changed && !(client->flags & FLAG_CUSTOM)) { // Welcome iOS5. We have to re-request the TSS with our nonce. plist_free(client->tss); if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); + logger(LL_ERROR, "Unable to get SHSH blobs for this device\n"); return -1; } if (!client->tss) { - error("ERROR: can't continue without TSS\n"); + logger(LL_ERROR, "can't continue without TSS\n"); return -1; } fixup_tss(client->tss); } if (irecv_usb_set_configuration(client->dfu->client, 1) < 0) { - error("ERROR: set configuration failed\n"); + logger(LL_ERROR, "set configuration failed\n"); } mutex_lock(&client->device_event_mutex); @@ -540,7 +538,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide // Without this empty policy file & its special signature, iBEC won't start. if (dfu_send_component_and_command(client, build_identity, "Ap,LocalPolicy", "lpolrestore") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send Ap,LocalPolicy to device\n"); + logger(LL_ERROR, "Unable to send Ap,LocalPolicy to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -553,17 +551,17 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide boot_stage = strtoul(value, NULL, 0); } if (boot_stage > 0) { - info("iBoot boot-stage=%s\n", value); + logger(LL_INFO, "iBoot boot-stage=%s\n", value); free(value); value = NULL; if (boot_stage != 1) { - error("ERROR: iBoot should be at boot stage 1, continuing anyway...\n"); + logger(LL_ERROR, "iBoot should be at boot stage 1, continuing anyway...\n"); } } if (dfu_send_iboot_stage1_components(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send iBoot stage 1 components to device\n"); + logger(LL_ERROR, "Unable to send iBoot stage 1 components to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -571,7 +569,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_command(client, "setenv auto-boot false") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send command to device\n"); + logger(LL_ERROR, "Unable to send command to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -579,7 +577,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_command(client, "saveenv") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send command to device\n"); + logger(LL_ERROR, "Unable to send command to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -587,7 +585,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_command(client, "setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send command to device\n"); + logger(LL_ERROR, "Unable to send command to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -595,7 +593,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_component(client, build_identity, "RestoreLogo") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send RestoreDCP to device\n"); + logger(LL_ERROR, "Unable to send RestoreDCP to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -603,7 +601,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_command(client, "setpicture 4") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send command to device\n"); + logger(LL_ERROR, "Unable to send command to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -611,7 +609,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide if (dfu_send_command(client, "bgcolor 0 0 0") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send command to device\n"); + logger(LL_ERROR, "Unable to send command to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -621,7 +619,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide /* send iBEC */ if (dfu_send_component(client, build_identity, "iBEC") < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send iBEC to device\n"); + logger(LL_ERROR, "Unable to send iBEC to device\n"); irecv_close(client->dfu->client); client->dfu->client = NULL; return -1; @@ -631,7 +629,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide sleep(1); if (irecv_send_command_breq(client->dfu->client, "go", 1) != IRECV_E_SUCCESS) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to execute iBEC\n"); + logger(LL_ERROR, "Unable to execute iBEC\n"); return -1; } @@ -642,28 +640,28 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide dfu_client_free(client); } - debug("Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS"); + logger(LL_ERROR, "Device did not disconnect. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS"); } return -1; } - debug("Waiting for device to reconnect in recovery mode...\n"); + logger(LL_DEBUG, "Waiting for device to reconnect in recovery mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS"); + logger(LL_ERROR, "Device did not reconnect in recovery mode. Possibly invalid %s. Reset device and try again.\n", (client->build_major > 8) ? "iBEC" : "iBSS"); } return -1; } mutex_unlock(&client->device_event_mutex); if (recovery_client_new(client) < 0) { - error("ERROR: Unable to connect to recovery device\n"); + logger(LL_ERROR, "Unable to connect to recovery device\n"); if (client->recovery->client) { irecv_close(client->recovery->client); client->recovery->client = NULL; diff --git a/src/download.c b/src/download.c index a258da2e..d9fac45e 100644 --- a/src/download.c +++ b/src/download.c @@ -48,7 +48,7 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length) int res = 0; CURL* handle = curl_easy_init(); if (handle == NULL) { - error("ERROR: could not initialize CURL\n"); + logger(LL_ERROR, "could not initialize CURL\n"); return -1; } @@ -57,7 +57,7 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length) response.content = malloc(1); response.content[0] = '\0'; - if (idevicerestore_debug) + if (log_level >= LL_DEBUG) curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); /* disable SSL verification to allow download from untrusted https locations */ @@ -86,17 +86,14 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length) return res; } -static int lastprogress = 0; - static int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - double p = (dlnow / dltotal) * 100; + double p = (dlnow / dltotal); + + set_progress('DNLD', p); - if (p < 100.0) { - if ((int)p > lastprogress) { - info("downloading: %d%%\n", (int)p); - lastprogress = (int)p; - } + if (global_quit_flag > 0) { + return 1; } return 0; @@ -107,19 +104,17 @@ int download_to_file(const char* url, const char* filename, int enable_progress) int res = 0; CURL* handle = curl_easy_init(); if (handle == NULL) { - error("ERROR: could not initialize CURL\n"); + logger(LL_ERROR, "Could not initialize CURL\n"); return -1; } FILE* f = fopen(filename, "wb"); if (!f) { - error("ERROR: cannot open '%s' for writing\n", filename); + logger(LL_ERROR, "Cannot open '%s' for writing\n", filename); return -1; } - lastprogress = 0; - - if (idevicerestore_debug) + if (log_level >= LL_DEBUG) curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); /* disable SSL verification to allow download from untrusted https locations */ @@ -128,8 +123,10 @@ int download_to_file(const char* url, const char* filename, int enable_progress) curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(handle, CURLOPT_WRITEDATA, f); - if (enable_progress > 0) + if (enable_progress > 0) { + register_progress('DNLD', "Downloading"); curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress); + } curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1); curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING); @@ -137,6 +134,11 @@ int download_to_file(const char* url, const char* filename, int enable_progress) curl_easy_setopt(handle, CURLOPT_URL, url); curl_easy_perform(handle); + + if (enable_progress) { + finalize_progress('DNLD'); + } + curl_easy_cleanup(handle); #ifdef WIN32 @@ -151,6 +153,9 @@ int download_to_file(const char* url, const char* filename, int enable_progress) res = -1; remove(filename); } + if (global_quit_flag > 0) { + res = -2; + } return res; } diff --git a/src/fdr.c b/src/fdr.c index ca9b7c75..378d4f95 100644 --- a/src/fdr.c +++ b/src/fdr.c @@ -66,7 +66,7 @@ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr) *fdr = NULL; - debug("Connecting to FDR client at port %u\n", port); + logger(LL_DEBUG, "Connecting to FDR client at port %u\n", port); for (i = 1; i <= attempts; i++) { device_error = idevice_connect(device, port, &connection); @@ -75,17 +75,17 @@ int fdr_connect(idevice_t device, fdr_type_t type, fdr_client_t* fdr) } if (i >= attempts) { - error("ERROR: Unable to connect to FDR client (%d)\n", device_error); + logger(LL_ERROR, "Unable to connect to FDR client (%d)\n", device_error); return -1; } sleep(2); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } fdr_client_t fdr_loc = calloc(1, sizeof(struct fdr_client)); if (!fdr_loc) { - error("ERROR: Unable to allocate memory\n"); + logger(LL_ERROR, "Unable to allocate memory\n"); return -1; } fdr_loc->connection = connection; @@ -138,7 +138,7 @@ int fdr_poll_and_handle_message(fdr_client_t fdr) uint16_t cmd; if (!fdr) { - error("ERROR: Invalid FDR client\n"); + logger(LL_ERROR, "Invalid FDR client\n"); return -1; } @@ -149,32 +149,32 @@ int fdr_poll_and_handle_message(fdr_client_t fdr) if (device_error == IDEVICE_E_SUCCESS && bytes != sizeof(cmd)) #endif { - debug("FDR %p timeout waiting for command\n", fdr); + logger(LL_DEBUG, "FDR %p timeout waiting for command\n", fdr); return 0; } else if (device_error != IDEVICE_E_SUCCESS) { if (fdr->connection) { - error("ERROR: Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd)); + logger(LL_ERROR, "Unable to receive message from FDR %p (%d). %u/%u bytes\n", fdr, device_error, bytes, (uint32_t)sizeof(cmd)); } return -1; } if (cmd == FDR_SYNC_MSG) { - debug("FDR %p got sync message\n", fdr); + logger(LL_DEBUG, "FDR %p got sync message\n", fdr); return fdr_handle_sync_cmd(fdr); } if (cmd == FDR_PROXY_MSG) { - debug("FDR %p got proxy message\n", fdr); + logger(LL_DEBUG, "FDR %p got proxy message\n", fdr); return fdr_handle_proxy_cmd(fdr); } if (cmd == FDR_PLIST_MSG) { - debug("FDR %p got plist message\n", fdr); + logger(LL_DEBUG, "FDR %p got plist message\n", fdr); return fdr_handle_plist_cmd(fdr); } - error("WARNING: FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes); + logger(LL_WARNING, "FDR %p received unknown packet %#x of size %u\n", fdr, cmd, bytes); return 0; } @@ -184,14 +184,14 @@ void *fdr_listener_thread(void *cdata) int res; while (fdr && fdr->connection) { - debug("FDR %p waiting for message...\n", fdr); + logger(LL_DEBUG, "FDR %p waiting for message...\n", fdr); res = fdr_poll_and_handle_message(fdr); if (fdr->type == FDR_CTRL && res >= 0) continue; // main thread should always retry if (res != 0) break; } - debug("FDR %p terminating...\n", fdr); + logger(LL_DEBUG, "FDR %p terminating...\n", fdr); fdr_free(fdr); return (void *)(intptr_t)res; } @@ -204,26 +204,26 @@ static int fdr_receive_plist(fdr_client_t fdr, plist_t* data) device_error = idevice_connection_receive(fdr->connection, (char*)&len, sizeof(len), &bytes); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to receive packet length from FDR (%d)\n", device_error); + logger(LL_ERROR, "Unable to receive packet length from FDR (%d)\n", device_error); return -1; } buf = calloc(1, len); if (!buf) { - error("ERROR: Unable to allocate memory for FDR receive buffer\n"); + logger(LL_ERROR, "Unable to allocate memory for FDR receive buffer\n"); return -1; } device_error = idevice_connection_receive(fdr->connection, buf, len, &bytes); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to receive data from FDR\n"); + logger(LL_ERROR, "Unable to receive data from FDR\n"); free(buf); return -1; } plist_from_bin(buf, bytes, data); free(buf); - debug("FDR Received %d bytes\n", bytes); + logger(LL_DEBUG, "FDR Received %d bytes\n", bytes); return 0; } @@ -241,12 +241,11 @@ static int fdr_send_plist(fdr_client_t fdr, plist_t data) if (!buf) return -1; - debug("FDR sending %d bytes:\n", len); - if (idevicerestore_debug) - debug_plist(data); + logger(LL_DEBUG, "FDR sending %d bytes:\n", len); + logger_dump_plist(LL_DEBUG, data, 1); device_error = idevice_connection_send(fdr->connection, (char *)&len, sizeof(len), &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(len)) { - error("ERROR: FDR unable to send data length. (%d) Sent %u of %u bytes.\n", + logger(LL_ERROR, "FDR unable to send data length. (%d) Sent %u of %u bytes.\n", device_error, bytes, (uint32_t)sizeof(len)); free(buf); return -1; @@ -254,12 +253,12 @@ static int fdr_send_plist(fdr_client_t fdr, plist_t data) device_error = idevice_connection_send(fdr->connection, buf, len, &bytes); free(buf); if (device_error != IDEVICE_E_SUCCESS || bytes != len) { - error("ERROR: FDR unable to send data (%d). Sent %u of %u bytes.\n", + logger(LL_ERROR, "FDR unable to send data (%d). Sent %u of %u bytes.\n", device_error, bytes, len); return -1; } - debug("FDR Sent %d bytes\n", bytes); + logger(LL_DEBUG, "FDR Sent %d bytes\n", bytes); return 0; } @@ -270,18 +269,18 @@ static int fdr_ctrl_handshake(fdr_client_t fdr) plist_t dict, node; int res; - debug("About to do ctrl handshake\n"); + logger(LL_DEBUG, "About to do ctrl handshake\n"); ctrlprotoversion = 2; device_error = idevice_connection_send(fdr->connection, CTRLCMD, len, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != len) { - debug("Hmm... looks like the device doesn't like the newer protocol, using the old one\n"); + logger(LL_DEBUG, "Hmm... looks like the device doesn't like the newer protocol, using the old one\n"); ctrlprotoversion = 1; len = sizeof(HELLOCTRLCMD); device_error = idevice_connection_send(fdr->connection, HELLOCTRLCMD, len, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != len) { - error("ERROR: FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len); + logger(LL_ERROR, "FDR unable to send BeginCtrl. Sent %u of %u bytes.\n", bytes, len); return -1; } } @@ -293,21 +292,20 @@ static int fdr_ctrl_handshake(fdr_client_t fdr) res = fdr_send_plist(fdr, dict); plist_free(dict); if (res) { - error("ERROR: FDR could not send Begin command.\n"); + logger(LL_ERROR, "FDR could not send Begin command.\n"); return -1; } if (fdr_receive_plist(fdr, &dict)) { - error("ERROR: FDR did not get Begin command reply.\n"); + logger(LL_ERROR, "FDR did not get Begin command reply.\n"); return -1; } - if (idevicerestore_debug) - debug_plist(dict); + logger_dump_plist(LL_DEBUG, dict, 1); node = plist_dict_get_item(dict, "ConnPort"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &conn_port); } else { - error("ERROR: Could not get FDR ConnPort value\n"); + logger(LL_ERROR, "Could not get FDR ConnPort value\n"); return -1; } @@ -321,26 +319,26 @@ static int fdr_ctrl_handshake(fdr_client_t fdr) bytes = 0; device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Could not receive reply to HelloCtrl command\n"); + logger(LL_ERROR, "Could not receive reply to HelloCtrl command\n"); return -1; } if (memcmp(buf, "HelloCtrl", 10) != 0) { buf[9] = '\0'; - error("ERROR: Did not receive HelloCtrl as reply, but %s\n", buf); + logger(LL_ERROR, "Did not receive HelloCtrl as reply, but %s\n", buf); return -1; } bytes = 0; device_error = idevice_connection_receive(fdr->connection, (char*)&cport, 2, &bytes); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Failed to receive conn port\n"); + logger(LL_ERROR, "Failed to receive conn port\n"); return -1; } conn_port = le16toh(cport); } - debug("Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port); + logger(LL_DEBUG, "Ctrl handshake done (ConnPort = %" PRIu64 ")\n", (uint64_t)conn_port); return 0; } @@ -353,13 +351,13 @@ static int fdr_sync_handshake(fdr_client_t fdr) device_error = idevice_connection_send(fdr->connection, HELLOCMD, len, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != len) { - error("ERROR: FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len); + logger(LL_ERROR, "FDR unable to send Hello. Sent %u of %u bytes.\n", bytes, len); return -1; } if (ctrlprotoversion == 2) { if (fdr_receive_plist(fdr, &reply)) { - error("ERROR: FDR did not get HelloConn reply.\n"); + logger(LL_ERROR, "FDR did not get HelloConn reply.\n"); return -1; } char* identifier = NULL; @@ -382,13 +380,13 @@ static int fdr_sync_handshake(fdr_client_t fdr) if (identifier) { free(identifier); } - error("ERROR: Did not receive HelloConn reply...\n"); + logger(LL_ERROR, "Did not receive HelloConn reply...\n"); return -1; } free(cmd); if (identifier) { - debug("Got device identifier %s\n", identifier); + logger(LL_DEBUG, "Got device identifier %s\n", identifier); free(identifier); } @@ -398,12 +396,12 @@ static int fdr_sync_handshake(fdr_client_t fdr) bytes = 0; device_error = idevice_connection_receive(fdr->connection, buf, 10, &bytes); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Could not receive reply to HelloConn command\n"); + logger(LL_ERROR, "Could not receive reply to HelloConn command\n"); return -1; } if (memcmp(buf, "HelloConn", 10) != 0) { buf[9] = '\0'; - error("ERROR: Did not receive HelloConn as reply, but %s\n", buf); + logger(LL_ERROR, "Did not receive HelloConn as reply, but %s\n", buf); return -1; } } @@ -422,18 +420,18 @@ static int fdr_handle_sync_cmd(fdr_client_t fdr_ctrl) device_error = idevice_connection_receive(fdr_ctrl->connection, buf, sizeof(buf), &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != 2) { - error("ERROR: Unexpected data from FDR\n"); + logger(LL_ERROR, "Unexpected data from FDR\n"); return -1; } /* Open a new connection and wait for messages on it */ if (fdr_connect(fdr_ctrl->device, FDR_CONN, &fdr)) { - error("ERROR: Failed to connect to FDR port\n"); + logger(LL_ERROR, "Failed to connect to FDR port\n"); return -1; } - debug("FDR connected in reply to sync message, starting command thread\n"); + logger(LL_DEBUG, "FDR connected in reply to sync message, starting command thread\n"); res = thread_new(&fdr_thread, fdr_listener_thread, fdr); if(res) { - error("ERROR: Failed to start FDR command thread\n"); + logger(LL_ERROR, "Failed to start FDR command thread\n"); fdr_free(fdr); } return res; @@ -445,12 +443,12 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr) plist_t dict; if (fdr_receive_plist(fdr, &dict)) { - error("ERROR: FDR %p could not receive plist command.\n", fdr); + logger(LL_ERROR, "FDR %p could not receive plist command.\n", fdr); return -1; } plist_t node = plist_dict_get_item(dict, "Command"); if (!node || (plist_get_node_type(node) != PLIST_STRING)) { - error("ERROR: FDR %p Could not find Command in plist command\n", fdr); + logger(LL_ERROR, "FDR %p Could not find Command in plist command\n", fdr); plist_free(dict); return -1; } @@ -459,7 +457,7 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr) plist_free(dict); if (!command) { - info("FDR %p received empty plist command\n", fdr); + logger(LL_INFO, "FDR %p received empty plist command\n", fdr); return -1; } @@ -469,12 +467,12 @@ static int fdr_handle_plist_cmd(fdr_client_t fdr) res = fdr_send_plist(fdr, dict); plist_free(dict); if (res) { - error("ERROR: FDR %p could not send Ping command reply.\n", fdr); + logger(LL_ERROR, "FDR %p could not send Ping command reply.\n", fdr); free(command); return -1; } } else { - error("WARNING: FDR %p received unknown plist command: %s\n", fdr, command); + logger(LL_WARNING, "FDR %p received unknown plist command: %s\n", fdr, command); free(command); return -1; } @@ -495,17 +493,17 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) buf = malloc(bufsize); if (!buf) { - error("ERROR: %s: malloc failed\n", __func__); + logger(LL_ERROR, "%s: malloc failed\n", __func__); return -1; } device_error = idevice_connection_receive(fdr->connection, buf, bufsize, &bytes); if (device_error != IDEVICE_E_SUCCESS) { free(buf); - error("ERROR: FDR %p failed to read data for proxy command\n", fdr); + logger(LL_ERROR, "FDR %p failed to read data for proxy command\n", fdr); return -1; } - debug("Got proxy command with %u bytes\n", bytes); + logger(LL_DEBUG, "Got proxy command with %u bytes\n", bytes); /* Just return success here unconditionally because we don't know * anything else and we will eventually abort on failure anyway */ @@ -513,13 +511,13 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) device_error = idevice_connection_send(fdr->connection, (char *)&ack, sizeof(ack), &sent); if (device_error != IDEVICE_E_SUCCESS || sent != sizeof(ack)) { free(buf); - error("ERROR: FDR %p unable to send ack. Sent %u of %u bytes.\n", + logger(LL_ERROR, "FDR %p unable to send ack. Sent %u of %u bytes.\n", fdr, sent, (uint32_t)sizeof(ack)); return -1; } if (bytes < 3) { - debug("FDR %p proxy command data too short, retrying\n", fdr); + logger(LL_DEBUG, "FDR %p proxy command data too short, retrying\n", fdr); return fdr_poll_and_handle_message(fdr); } @@ -527,7 +525,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) device_error = idevice_connection_send(fdr->connection, buf, bytes, &sent); if (device_error != IDEVICE_E_SUCCESS || sent != bytes) { free(buf); - error("ERROR: FDR %p unable to send data. Sent %u of %u bytes.\n", + logger(LL_ERROR, "FDR %p unable to send data. Sent %u of %u bytes.\n", fdr, sent, bytes); return -1; } @@ -539,7 +537,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) port = be16toh(*p); buf[bytes - 2] = '\0'; host = strdup(&buf[3]); - debug("FDR %p Proxy connect request to %s:%u\n", fdr, host, port); + logger(LL_DEBUG, "FDR %p Proxy connect request to %s:%u\n", fdr, host, port); } if (!host || !buf[2]) { @@ -553,7 +551,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) free(host); if (sockfd < 0) { free(buf); - error("ERROR: Failed to connect socket: %s\n", strerror(errno)); + logger(LL_ERROR, "Failed to connect socket: %s\n", strerror(errno)); return -1; } @@ -567,16 +565,16 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) if (device_error == IDEVICE_E_SUCCESS && !bytes) #endif { - //debug("WARNING: Timeout waiting for proxy payload. %p\n", fdr); + //logger(LL_DEBUG, "Timeout waiting for proxy payload. %p\n", fdr); } else if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error); + logger(LL_ERROR, "FDR %p Unable to receive proxy payload (%d)\n", fdr, device_error); res = -1; break; } if (bytes) { - debug("FDR %p got payload of %u bytes, now trying to proxy it\n", fdr, bytes); - debug("Sending %u bytes of data\n", bytes); + logger(LL_DEBUG, "FDR %p got payload of %u bytes, now trying to proxy it\n", fdr, bytes); + logger(LL_DEBUG, "Sending %u bytes of data\n", bytes); sent = 0; while (sent < bytes) { int s = socket_send(sockfd, buf + sent, bytes - sent); @@ -586,7 +584,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) sent += s; } if (sent != bytes) { - error("ERROR: Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes); + logger(LL_ERROR, "Sending proxy payload failed: %s. Sent %u of %u bytes. \n", strerror(errno), sent, bytes); socket_close(sockfd); res = -1; break; @@ -599,14 +597,14 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) res = 1; break; } else if (bytes_ret < 0) { - error("ERROR: FDR %p receiving proxy payload failed: %d (%s)\n", + logger(LL_ERROR, "FDR %p receiving proxy payload failed: %d (%s)\n", fdr, bytes_ret, strerror(-bytes_ret)); break; } bytes = bytes_ret; if (bytes) { - debug("FDR %p Received %u bytes reply data,%s sending to device\n", + logger(LL_DEBUG, "FDR %p Received %u bytes reply data,%s sending to device\n", fdr, bytes, (bytes ? "" : " not")); sent = 0; @@ -619,7 +617,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) sent += s; } if (device_error != IDEVICE_E_SUCCESS || bytes != sent) { - error("ERROR: FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes); + logger(LL_ERROR, "FDR %p unable to send data (%d). Sent %u of %u bytes.\n", fdr, device_error, sent, bytes); res = -1; break; } diff --git a/src/fls.c b/src/fls.c index f4224478..cc75c54d 100644 --- a/src/fls.c +++ b/src/fls.c @@ -96,7 +96,7 @@ static void fls_parse_elements(fls_file* fls) offset += cur->size; } while (offset < fls->size); if (offset != fls->size) { - error("ERROR: %s: error parsing elements\n", __func__); + logger(LL_ERROR, "%s: error parsing elements\n", __func__); return; } } @@ -136,22 +136,22 @@ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned in { /* FIXME: the code in this function is not big endian safe */ if (!fls || !fls->num_elements) { - error("ERROR: %s: no data\n", __func__); + logger(LL_ERROR, "%s: no data\n", __func__); return -1; } if (!fls->c_element) { - error("ERROR: %s: no fls_0c_element in fls data\n", __func__); + logger(LL_ERROR, "%s: no fls_0c_element in fls data\n", __func__); return -1; } uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10); if (datasize != fls->c_element->data_size) { - error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size); + logger(LL_ERROR, "%s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size); return -1; } uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14); if (sigoffset > datasize) { - error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize); + logger(LL_ERROR, "%s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize); return -1; } @@ -162,7 +162,7 @@ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned in uint32_t offset = 0; void* newdata = malloc(newsize); if (!newdata) { - error("ERROR: %s: out of memory\n", __func__); + logger(LL_ERROR, "%s: out of memory\n", __func__); return -1; } uint32_t hdrsize = 0; @@ -243,11 +243,11 @@ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int siz { /* FIXME: the code in this function is not big endian safe */ if (!fls || !fls->num_elements) { - error("ERROR: %s: no data\n", __func__); + logger(LL_ERROR, "%s: no data\n", __func__); return -1; } if (!fls->c_element) { - error("ERROR: %s: no fls_0c_element in fls data\n", __func__); + logger(LL_ERROR, "%s: no fls_0c_element in fls data\n", __func__); return -1; } @@ -260,7 +260,7 @@ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int siz uint32_t offset = 0; void* newdata = malloc(newsize); if (!newdata) { - error("ERROR: %s: out of memory\n", __func__); + logger(LL_ERROR, "%s: out of memory\n", __func__); return -1; } uint32_t hdrsize = 0; diff --git a/src/ftab.c b/src/ftab.c index 8515d1f5..cc742516 100644 --- a/src/ftab.c +++ b/src/ftab.c @@ -35,13 +35,13 @@ int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32 } if (data_size < sizeof(struct ftab_header)) { - error("ERROR: %s: Buffer too small for ftab data\n", __func__); + logger(LL_ERROR, "%s: Buffer too small for ftab data\n", __func__); return -1; } struct ftab_header *hdr_ptr = (struct ftab_header*)data; if (be32toh(hdr_ptr->magic) != 'ftab') { - error("ERROR: %s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic)); + logger(LL_ERROR, "%s: Unexpected magic value 0x%08x\n", __func__, le32toh(hdr_ptr->magic)); return -1; } @@ -108,13 +108,13 @@ int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int uint32_t new_index = ftab->header.num_entries; struct ftab_entry *new_entries = realloc(ftab->entries, sizeof(struct ftab_entry) * (ftab->header.num_entries + 1)); if (!new_entries) { - error("ERROR: %s: realloc failed!\n", __func__); + logger(LL_ERROR, "%s: realloc failed!\n", __func__); return -1; } ftab->entries = new_entries; unsigned char **new_storage = realloc(ftab->storage, sizeof(unsigned char*) * (ftab->header.num_entries + 1)); if (!new_storage) { - error("ERROR: %s: realloc failed!\n", __func__); + logger(LL_ERROR, "%s: realloc failed!\n", __func__); return -1; } ftab->storage = new_storage; @@ -151,7 +151,7 @@ int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size) unsigned char *data_out = (unsigned char*)malloc(total_size); if (!data_out) { - error("ERROR: %s: Out of memory?!\n", __func__); + logger(LL_ERROR, "%s: Out of memory?!\n", __func__); return -1; } diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 9911e9d3..3dd4bb93 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -40,6 +40,7 @@ #include #include +#include #include #include "ace3.h" @@ -62,7 +63,7 @@ #define VERSION_XML "version.xml" -#ifndef IDEVICERESTORE_NOMAIN +#ifndef IDEVICERESTORE_NOMAIN static struct option longopts[] = { { "ecid", required_argument, NULL, 'i' }, { "udid", required_argument, NULL, 'u' }, @@ -89,6 +90,7 @@ static struct option longopts[] = { { "ipsw-info", no_argument, NULL, 'I' }, { "ignore-errors", no_argument, NULL, 1 }, { "variant", required_argument, NULL, 2 }, + { "logfile", required_argument, NULL, 3 }, { NULL, 0, NULL, 0 } }; @@ -133,7 +135,9 @@ static void usage(int argc, char* argv[], int err) " -h, --help Prints this usage information\n" \ " -C, --cache-path DIR Use specified directory for caching extracted or other\n" \ " reused files.\n" \ - " -d, --debug Enable communication debugging\n" \ + " --logfile=PATH Write logging output to file at PATH. If PATH equals\n" \ + " 'NULL' or 'NONE', no log file will be written.\n" \ + " -d, --debug Print additional debug output\n" \ " -v, --version Print version information\n" \ "\n" \ "Advanced/experimental options:\n" @@ -199,9 +203,9 @@ static int load_version_data(struct idevicerestore_client_t* client) if (download_to_file("http://itunes.apple.com/check/version", version_xml_tmp, 0) == 0) { remove(version_xml); if (rename(version_xml_tmp, version_xml) < 0) { - error("ERROR: Could not update '%s'\n", version_xml); + logger(LL_ERROR, "Could not update '%s'\n", version_xml); } else { - info("NOTE: Updated version data.\n"); + logger(LL_INFO, "Updated version data.\n"); } } } else { @@ -213,7 +217,7 @@ static int load_version_data(struct idevicerestore_client_t* client) read_file(version_xml, (void**)&verbuf, &verlen); if (!verbuf) { - error("ERROR: Could not load '%s'\n", version_xml); + logger(LL_ERROR, "Could not load '%s'\n", version_xml); return -1; } @@ -223,12 +227,12 @@ static int load_version_data(struct idevicerestore_client_t* client) if (!client->version_data) { remove(version_xml); - error("ERROR: Cannot parse plist data from '%s'.\n", version_xml); + logger(LL_ERROR, "Cannot parse plist data from '%s'.\n", version_xml); return -1; } if (cached) { - info("NOTE: using cached version data\n"); + logger(LL_INFO, "Using cached version data\n"); } return 0; @@ -264,21 +268,24 @@ static void idevice_event_cb(const idevice_event_t *event, void *userdata) if (normal_check_mode(client) == 0) { mutex_lock(&client->device_event_mutex); client->mode = MODE_NORMAL; - debug("%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid); + logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid); cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } else if (client->ecid && restore_check_mode(client) == 0) { mutex_lock(&client->device_event_mutex); client->mode = MODE_RESTORE; - debug("%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid); + logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid); cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } + if (!client->device) { + client->device = get_irecv_device(client); + } } else if (event->event == IDEVICE_DEVICE_REMOVE) { if (client->udid && !strcmp(event->udid, client->udid)) { mutex_lock(&client->device_event_mutex); client->mode = MODE_UNKNOWN; - debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid); + logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, client->udid); client->ignore_device_add_events = 0; cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); @@ -314,7 +321,10 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) default: client->mode = MODE_UNKNOWN; } - debug("%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string); + logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string); + if (!client->device) { + client->device = get_irecv_device(client); + } cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } @@ -322,7 +332,7 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) if (client->ecid && event->device_info->ecid == client->ecid) { mutex_lock(&client->device_event_mutex); client->mode = MODE_UNKNOWN; - debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A"); + logger(LL_DEBUG, "%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A"); if (event->mode == IRECV_K_PORT_DFU_MODE) { // We have to reset the ECID here if a port DFU device disconnects, // because when the device reconnects in a different mode, it will @@ -347,12 +357,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) { - error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n"); + logger(LL_ERROR, "FLAG_LATEST cannot be used with FLAG_CUSTOM.\n"); return -1; } if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) { - error("ERROR: no ipsw file given\n"); + logger(LL_ERROR, "no ipsw file given\n"); return -1; } @@ -367,12 +377,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client) tss_set_debug_level(client->debug_level); } + progress_reset_tag(); + idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); - irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client); + if (!client->irecv_e_ctx) { + irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client); + } - idevice_event_subscribe(idevice_event_cb, client); - client->idevice_e_ctx = idevice_event_cb; + if (!client->idevice_e_ctx) { + idevice_event_subscribe(idevice_event_cb, client); + client->idevice_e_ctx = idevice_event_cb; + } // check which mode the device is currently in so we know where to start mutex_lock(&client->device_event_mutex); @@ -380,23 +396,23 @@ int idevicerestore_start(struct idevicerestore_client_t* client) cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); + logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n"); return -1; } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1); - info("Found device in %s mode\n", client->mode->string); + logger(LL_INFO, "Found device in %s mode\n", client->mode->string); mutex_unlock(&client->device_event_mutex); if (client->mode == MODE_WTF) { unsigned int cpid = 0; if (dfu_client_new(client) != 0) { - error("ERROR: Could not open device in WTF mode\n"); + logger(LL_ERROR, "Could not open device in WTF mode\n"); return -1; } if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) { - error("ERROR: Could not get CPID for WTF mode device\n"); + logger(LL_ERROR, "Could not get CPID for WTF mode device\n"); dfu_client_free(client); return -1; } @@ -419,7 +435,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_get_string_val(wtfurl, &s_wtfurl); } if (!s_wtfurl) { - info("Using hardcoded x12220000_5_Recovery.ipsw URL\n"); + logger(LL_INFO, "Using hardcoded x12220000_5_Recovery.ipsw URL\n"); s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw"); } @@ -450,14 +466,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client) ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize); ipsw_close(wtf_ipsw); if (!wtftmp) { - error("ERROR: Could not extract WTF\n"); + logger(LL_ERROR, "Could not extract WTF\n"); } } mutex_lock(&client->device_event_mutex); if (wtftmp) { if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) { - error("ERROR: Could not send WTF...\n"); + logger(LL_ERROR, "Could not send WTF...\n"); } } dfu_client_free(client); @@ -468,7 +484,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); /* TODO: verify if it actually goes from 0x1222 -> 0x1227 */ - error("ERROR: Failed to put device into DFU from WTF mode\n"); + logger(LL_ERROR, "Failed to put device into DFU from WTF mode\n"); return -1; } mutex_unlock(&client->device_event_mutex); @@ -477,20 +493,20 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // discover the device type client->device = get_irecv_device(client); if (client->device == NULL) { - error("ERROR: Unable to discover device type\n"); + logger(LL_ERROR, "Unable to discover device type\n"); return -1; } if (client->ecid == 0) { - error("ERROR: Unable to determine ECID\n"); + logger(LL_ERROR, "Unable to determine ECID\n"); return -1; } - info("ECID: %" PRIu64 "\n", client->ecid); + logger(LL_INFO, "ECID: %" PRIu64 "\n", client->ecid); idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2); - info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type); + logger(LL_INFO, "Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type); if ((client->flags & FLAG_PWN) && (client->mode != MODE_DFU)) { - error("ERROR: you need to put your device into DFU mode to pwn it.\n"); + logger(LL_ERROR, "you need to put your device into DFU mode to pwn it.\n"); return -1; } @@ -506,38 +522,38 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_free(pver); } } - info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A"); - info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); + logger(LL_INFO, "Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A"); + logger(LL_INFO, "Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); if (client->flags & FLAG_PWN) { #ifdef HAVE_LIMERA1N recovery_client_free(client); if (client->mode != MODE_DFU) { - error("ERROR: Device needs to be in DFU mode for this option.\n"); + logger(LL_ERROR, "Device needs to be in DFU mode for this option.\n"); return -1; } - info("connecting to DFU\n"); + logger(LL_INFO, "connecting to DFU\n"); if (dfu_client_new(client) < 0) { return -1; } if (limera1n_is_supported(client->device)) { - info("exploiting with limera1n...\n"); + logger(LL_INFO, "exploiting with limera1n...\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { - error("ERROR: limera1n exploit failed\n"); + logger(LL_ERROR, "limera1n exploit failed\n"); dfu_client_free(client); return -1; } dfu_client_free(client); - info("Device should be in pwned DFU state now.\n"); + logger(LL_INFO, "Device should be in pwned DFU state now.\n"); return 0; } else { dfu_client_free(client); - error("ERROR: This device is not supported by the limera1n exploit"); + logger(LL_ERROR, "This device is not supported by the limera1n exploit"); return -1; } #endif @@ -550,30 +566,24 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t signed_fws = NULL; int res = ipsw_get_signed_firmwares(client->device->product_type, &signed_fws); if (res < 0) { - error("ERROR: Could not fetch list of signed firmwares.\n"); + logger(LL_ERROR, "Could not fetch list of signed firmwares.\n"); return res; } uint32_t count = plist_array_get_size(signed_fws); if (count == 0) { plist_free(signed_fws); - error("ERROR: No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type); + logger(LL_ERROR, "No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type); return -1; } plist_t selected_fw = NULL; if (client->flags & FLAG_INTERACTIVE) { uint32_t i = 0; - info("The following firmwares are currently being signed for %s:\n", client->device->product_type); + logger(LL_INFO, "The following firmwares are currently being signed for %s:\n", client->device->product_type); for (i = 0; i < count; i++) { plist_t fw = plist_array_get_item(signed_fws, i); plist_t p_version = plist_dict_get_item(fw, "version"); plist_t p_build = plist_dict_get_item(fw, "buildid"); - char *s_version = NULL; - char *s_build = NULL; - plist_get_string_val(p_version, &s_version); - plist_get_string_val(p_build, &s_build); - info(" [%d] %s (build %s)\n", i+1, s_version, s_build); - free(s_version); - free(s_build); + logger(LL_INFO, " [%d] %s (build %s)\n", i+1, plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL)); } while (1) { char input[64]; @@ -597,23 +607,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client) break; } } else { - info("NOTE: Running non-interactively, automatically selecting latest available version\n"); + logger(LL_NOTICE, "Running non-interactively, automatically selecting latest available version\n"); selected_fw = plist_array_get_item(signed_fws, 0); } if (!selected_fw) { - error("ERROR: failed to select latest firmware?!\n"); + logger(LL_ERROR, "failed to select latest firmware?!\n"); plist_free(signed_fws); return -1; } else { plist_t p_version = plist_dict_get_item(selected_fw, "version"); plist_t p_build = plist_dict_get_item(selected_fw, "buildid"); - char *s_version = NULL; - char *s_build = NULL; - plist_get_string_val(p_version, &s_version); - plist_get_string_val(p_build, &s_build); - info("Selected firmware %s (build %s)\n", s_version, s_build); - free(s_version); - free(s_build); + logger(LL_NOTICE, "Selected firmware %s (build %s)\n", plist_get_string_ptr(p_version, NULL), plist_get_string_ptr(p_build, NULL)); plist_t p_url = plist_dict_get_item(selected_fw, "url"); plist_t p_sha1 = plist_dict_get_item(selected_fw, "sha1sum"); char *s_sha1 = NULL; @@ -629,13 +633,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } p_fwsha1 = &fwsha1[0]; } else { - error("ERROR: unexpected size of sha1sum\n"); + logger(LL_ERROR, "unexpected size of sha1sum\n"); } } plist_free(signed_fws); if (!fwurl || !p_fwsha1) { - error("ERROR: Missing firmware URL or SHA1\n"); + logger(LL_ERROR, "Missing firmware URL or SHA1\n"); return -1; } @@ -647,7 +651,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } else { client->ipsw = ipsw_open(ipsw); if (!client->ipsw) { - error("ERROR: Failed to open ipsw '%s'\n", ipsw); + logger(LL_ERROR, "Failed to open ipsw '%s'\n", ipsw); free(ipsw); return -1; } @@ -662,15 +666,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // extract buildmanifest if (client->flags & FLAG_CUSTOM) { - info("Extracting Restore.plist from IPSW\n"); + logger(LL_INFO, "Extracting Restore.plist from IPSW\n"); if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); + logger(LL_ERROR, "Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } else { - info("Extracting BuildManifest from IPSW\n"); + logger(LL_INFO, "Extracting BuildManifest from IPSW\n"); if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); + logger(LL_ERROR, "Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } @@ -678,13 +682,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->flags & FLAG_CUSTOM) { // prevent attempt to sign custom firmware tss_enabled = 0; - info("Custom firmware requested; TSS has been disabled.\n"); + logger(LL_INFO, "Custom firmware requested; TSS has been disabled.\n"); } if (client->mode == MODE_RESTORE) { if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) { if (restore_reboot(client) < 0) { - error("ERROR: Unable to exit restore mode\n"); + logger(LL_ERROR, "Unable to exit restore mode\n"); return -2; } @@ -693,10 +697,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client) cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); + logger(LL_ERROR, "Unable to discover device mode. Please make sure a device is attached.\n"); return -1; } - info("Found device in %s mode\n", client->mode->string); + logger(LL_INFO, "Found device in %s mode\n", client->mode->string); mutex_unlock(&client->device_event_mutex); } } @@ -707,39 +711,39 @@ int idevicerestore_start(struct idevicerestore_client_t* client) unsigned int prev = 0; if (dfu_get_bdid(client, &pdfu_bdid) < 0) { - error("ERROR: Failed to get bdid for Port DFU device!\n"); + logger(LL_ERROR, "Failed to get bdid for Port DFU device!\n"); return -1; } if (dfu_get_cpid(client, &pdfu_cpid) < 0) { - error("ERROR: Failed to get cpid for Port DFU device!\n"); + logger(LL_ERROR, "Failed to get cpid for Port DFU device!\n"); return -1; } if (dfu_get_prev(client, &prev) < 0) { - error("ERROR: Failed to get PREV for Port DFU device!\n"); + logger(LL_ERROR, "Failed to get PREV for Port DFU device!\n"); return -1; } unsigned char* pdfu_nonce = NULL; unsigned int pdfu_nsize = 0; if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) { - error("ERROR: Failed to get nonce for Port DFU device!\n"); + logger(LL_ERROR, "Failed to get nonce for Port DFU device!\n"); return -1; } plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0); if (!build_identity) { - error("ERORR: Failed to get build identity\n"); + logger(LL_ERROR, "ERORR: Failed to get build identity\n"); return -1; } unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); if (b_pdfu_cpid != pdfu_cpid) { - error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); + logger(LL_ERROR, "cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); return -1; } unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); if (b_pdfu_bdid != pdfu_bdid) { - error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); + logger(LL_ERROR, "bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); return -1; } @@ -754,26 +758,26 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); if (!usbf) { plist_free(parameters); - error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n"); + logger(LL_ERROR, "Unable to find USBPortController1,USBFirmware in build identity\n"); return -1; } plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path"); if (!p_fwpath) { plist_free(parameters); - error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n"); + logger(LL_ERROR, "Unable to find path of USBPortController1,USBFirmware component\n"); return -1; } const char* fwpath = plist_get_string_ptr(p_fwpath, NULL); if (!fwpath) { plist_free(parameters); - error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n"); + logger(LL_ERROR, "Unable to get path of USBPortController1,USBFirmware component\n"); return -1; } unsigned char* uarp_buf = NULL; unsigned int uarp_size = 0; if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) { plist_free(parameters); - error("ERROR: Unable to extract '%s' from IPSW\n", fwpath); + logger(LL_ERROR, "Unable to extract '%s' from IPSW\n", fwpath); return -1; } usbf = plist_copy(usbf); @@ -784,7 +788,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t request = tss_request_new(NULL); if (request == NULL) { plist_free(parameters); - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); return -1; } plist_dict_merge(&request, parameters); @@ -794,16 +798,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to send TSS request\n"); + logger(LL_ERROR, "Unable to send TSS request\n"); return -1; } - info("Received USBPortController1,Ticket\n"); + logger(LL_INFO, "Received USBPortController1,Ticket\n"); - info("Creating Ace3Binary\n"); + logger(LL_INFO, "Creating Ace3Binary\n"); unsigned char* ace3bin = NULL; size_t ace3bin_size = 0; if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) { - error("ERROR: Could not create Ace3Binary\n"); + logger(LL_ERROR, "Could not create Ace3Binary\n"); return -1; } plist_free(response); @@ -814,37 +818,37 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) { - error("ERROR: Could not send Ace3Buffer to device\n"); + logger(LL_ERROR, "Could not send Ace3Buffer to device\n"); return -1; } - debug("Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not disconnect. Port DFU failed.\n"); + logger(LL_ERROR, "Device did not disconnect. Port DFU failed.\n"); } return -2; } dfu_client_free(client); - debug("Waiting for device to reconnect in DFU mode...\n"); + logger(LL_DEBUG, "Waiting for device to reconnect in DFU mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 20000); if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n"); + logger(LL_ERROR, "Device did not reconnect in DFU mode. Port DFU failed.\n"); } return -2; } mutex_unlock(&client->device_event_mutex); if (client->flags & FLAG_NOACTION) { - info("Port DFU restore successful.\n"); + logger(LL_INFO, "Port DFU restore successful.\n"); return 0; } else { - info("Port DFU restore successful. Continuing.\n"); + logger(LL_INFO, "Port DFU restore successful. Continuing.\n"); } } @@ -852,18 +856,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* check if device type is supported by the given build manifest */ if (build_manifest_check_compatibility(client->build_manifest, client->device->product_type) < 0) { - error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n"); + logger(LL_ERROR, "Could not make sure this firmware is suitable for the current device. Refusing to continue.\n"); return -1; } /* print iOS information from the manifest */ build_manifest_get_version_information(client->build_manifest, client); - info("IPSW Product Version: %s\n", client->version); - info("IPSW Product Build: %s Major: %d\n", client->build, client->build_major); + logger(LL_INFO, "IPSW Product Version: %s\n", client->version); + logger(LL_INFO, "IPSW Product Build: %s Major: %d\n", client->build, client->build_major); client->image4supported = is_image4_supported(client); - info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); + logger(LL_INFO, "Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); // choose whether this is an upgrade or a restore (default to upgrade) client->tss = NULL; @@ -897,7 +901,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) char *fmanifest = NULL; uint32_t msize = 0; if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) { - error("ERROR: could not extract %s from IPSW\n", tmpstr); + logger(LL_ERROR, "could not extract %s from IPSW\n", tmpstr); free(build_identity); return -1; } @@ -930,7 +934,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_dict_set_item(manifest, "RestoreDeviceTree", plist_copy(comp)); } } else { - error("WARNING: unhandled component %s\n", files[x]); + logger(LL_WARNING, "Unhandled component %s\n", files[x]); plist_free(comp); } free(files[x]); @@ -1000,11 +1004,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // add OS filesystem node = plist_dict_get_item(client->build_manifest, "SystemRestoreImages"); if (!node) { - error("ERROR: missing SystemRestoreImages in Restore.plist\n"); + logger(LL_ERROR, "missing SystemRestoreImages in Restore.plist\n"); } plist_t os = plist_dict_get_item(node, "User"); if (!os) { - error("ERROR: missing filesystem in Restore.plist\n"); + logger(LL_ERROR, "missing filesystem in Restore.plist\n"); } else { inf = plist_new_dict(); plist_dict_set_item(inf, "Path", plist_copy(os)); @@ -1033,7 +1037,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } if (build_identity == NULL) { - error("ERROR: Unable to find a matching build identity\n"); + logger(LL_ERROR, "Unable to find a matching build identity\n"); return -1; } @@ -1043,47 +1047,37 @@ int idevicerestore_start(struct idevicerestore_client_t* client) build_identity_print_information(build_identity); if (client->macos_variant) { - info("Performing macOS restore\n"); + logger(LL_INFO, "Performing macOS restore\n"); } if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) { if (client->flags & FLAG_INTERACTIVE) { - char input[64]; - char spaces[16]; - int num_spaces = 13 - strlen(client->version) - strlen(client->device_version); - memset(spaces, ' ', num_spaces); - spaces[num_spaces] = '\0'; - printf("################################ [ WARNING ] #################################\n" - "# You are trying to DOWNGRADE a %s device with an IPSW for %s while%s #\n" - "# trying to preserve the user data (Upgrade restore). This *might* work, but #\n" - "# there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS. #\n" - "# Hit CTRL+C now if you want to abort the restore. #\n" - "# If you want to take the risk (and have a backup of your important data!) #\n" - "# type YES and press ENTER to continue. You have been warned. #\n" - "##############################################################################\n", - client->device_version, client->version, spaces); - while (1) { - printf("> "); - fflush(stdout); - fflush(stdin); - input[0] = '\0'; - get_user_input(input, 63, 0); - if (client->flags & FLAG_QUIT) { - return -1; - } - if (*input != '\0' && !strcmp(input, "YES")) { - break; - } else { - printf("Invalid input. Please type YES or hit CTRL+C to abort.\n"); - continue; - } + char msgtext[512]; + snprintf(msgtext, 512, "You are trying to DOWNGRADE a %s device with an IPSW for %s while\n" + "trying to preserve the user data (Upgrade restore). This *might* work, but\n" + "there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS.\n" + "If you want to take the risk (and have a backup of your important data!) you may continue.\n" + "You have been warned.\n", client->device_version, client->version); + int pres = prompt_user("WARNING", msgtext); + if (pres < 0) { + client->flags |= FLAG_QUIT; + return -1; } } } } if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) { + int pres = prompt_user( + "WARNING", + "You are about to perform an *ERASE* restore. ALL DATA on the target device will be IRREVERSIBLY DESTROYED. If you want to update your device without erasing the user data, cancel now and restart without -e or --erase command line switch.\n" + ); + if (pres < 0) { + client->flags |= FLAG_QUIT; + return -1; + } +#if 0 char input[64]; printf("################################ [ WARNING ] #################################\n" "# You are about to perform an *ERASE* restore. ALL DATA on the target device #\n" @@ -1108,22 +1102,23 @@ int idevicerestore_start(struct idevicerestore_client_t* client) continue; } } +#endif } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0); /* check if all components we need are actually there */ - info("Checking IPSW for required components...\n"); + logger(LL_INFO, "Checking IPSW for required components...\n"); if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) { - error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw->path); + logger(LL_ERROR, "Could not find all required components in IPSW %s\n", client->ipsw->path); return -1; } - info("All required components found in IPSW\n"); + logger(LL_INFO, "All required components found in IPSW\n"); /* Get OS (filesystem) name from build identity */ char* os_path = NULL; if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) { - error("ERROR: Unable to get path for filesystem component\n"); + logger(LL_ERROR, "Unable to get path for filesystem component\n"); return -1; } @@ -1168,16 +1163,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) memset(&st, '\0', sizeof(struct stat)); if (stat(tmpf, &st) == 0) { if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { - info("Using cached filesystem from '%s'\n", tmpf); + logger(LL_INFO, "Using cached filesystem from '%s'\n", tmpf); client->filesystem = tmpf; } } if (!client->filesystem) { - info("Extracting filesystem from IPSW: %s\n", os_path); + logger(LL_INFO, "Extracting filesystem from IPSW: %s\n", os_path); if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - info("Removing %s\n", tmpf); + logger(LL_ERROR, "Unable to extract filesystem from IPSW\n"); + logger(LL_INFO, "Removing %s\n", tmpf); unlink(tmpf); free(tmpf); return -1; @@ -1199,19 +1194,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_get_bool_val(node, &needs_preboard); } if (needs_preboard) { - info("Checking if device requires stashbag...\n"); + logger(LL_INFO, "Checking if device requires stashbag...\n"); plist_t manifest; if (get_preboard_manifest(client, build_identity, &manifest) < 0) { - error("ERROR: Unable to create preboard manifest.\n"); + logger(LL_ERROR, "Unable to create preboard manifest.\n"); return -1; } - debug("DEBUG: creating stashbag...\n"); + logger(LL_DEBUG, "creating stashbag...\n"); int err = normal_handle_create_stashbag(client, manifest); if (err < 0) { if (err == -2) { - error("ERROR: Could not create stashbag (timeout).\n"); + logger(LL_ERROR, "Could not create stashbag (timeout).\n"); } else { - error("ERROR: An error occurred while creating the stashbag.\n"); + logger(LL_ERROR, "An error occurred while creating the stashbag.\n"); } return -1; } else if (err == 1) { @@ -1226,7 +1221,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) unsigned int nonce_size = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { /* the first nonce request with older firmware releases can fail and it's OK */ - info("NOTE: Unable to get nonce from device\n"); + logger(LL_NOTICE, "Unable to get nonce from device\n"); } if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) { @@ -1248,12 +1243,8 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce"); uint64_t sep_nonce_size = 0; const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size); - info("Getting SepNonce in normal mode... "); - int i = 0; - for (i = 0; i < sep_nonce_size; i++) { - info("%02x ", (unsigned char)sep_nonce[i]); - } - info("\n"); + logger(LL_INFO, "Getting SepNonce in normal mode... "); + logger_dump_hex(LL_INFO, sep_nonce, sep_nonce_size); plist_free(ap_params); } plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot"); @@ -1270,27 +1261,27 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode == MODE_RESTORE && client->root_ticket) { plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len); if (!ap_ticket) { - error("ERROR: Failed to create ApImg4Ticket node value.\n"); + logger(LL_ERROR, "Failed to create ApImg4Ticket node value.\n"); return -1; } client->tss = plist_new_dict(); if (!client->tss) { - error("ERROR: Failed to create ApImg4Ticket node.\n"); + logger(LL_ERROR, "Failed to create ApImg4Ticket node.\n"); return -1; } plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket); } else { if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); + logger(LL_ERROR, "Unable to get SHSH blobs for this device\n"); return -1; } if (client->macos_variant) { if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + logger(LL_ERROR, "Unable to get SHSH blobs for this device (local policy)\n"); return -1; } if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + logger(LL_ERROR, "Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); return -1; } } else { @@ -1299,11 +1290,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL); client->recovery_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); if (!client->recovery_variant) { - error("ERROR: Variant '%s' not found in BuildManifest\n", recovery_variant_str); + logger(LL_ERROR, "Variant '%s' not found in BuildManifest\n", recovery_variant_str); return -1; } if (get_tss_response(client, client->recovery_variant, &client->tss_recoveryos_root_ticket) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); + logger(LL_ERROR, "Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); return -1; } } @@ -1313,13 +1304,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (stashbag_commit_required) { plist_t ticket = plist_dict_get_item(client->tss, "ApImg4Ticket"); if (!ticket || plist_get_node_type(ticket) != PLIST_DATA) { - error("ERROR: Missing ApImg4Ticket in TSS response for stashbag commit\n"); + logger(LL_ERROR, "Missing ApImg4Ticket in TSS response for stashbag commit\n"); return -1; } - info("Committing stashbag...\n"); + logger(LL_INFO, "Committing stashbag...\n"); int err = normal_handle_commit_stashbag(client, ticket); if (err < 0) { - error("ERROR: Could not commit stashbag (%d). Aborting.\n", err); + logger(LL_ERROR, "Could not commit stashbag (%d). Aborting.\n", err); return -1; } } @@ -1330,11 +1321,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->flags & FLAG_SHSHONLY) { if (!tss_enabled) { - info("This device does not require a TSS record\n"); + logger(LL_INFO, "This device does not require a TSS record\n"); return 0; } if (!client->tss) { - error("ERROR: could not fetch TSS record\n"); + logger(LL_ERROR, "could not fetch TSS record\n"); return -1; } else { char *bin = NULL; @@ -1355,13 +1346,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) gzFile zf = gzopen(zfn, "wb"); gzwrite(zf, bin, blen); gzclose(zf); - info("SHSH saved to '%s'\n", zfn); + logger(LL_INFO, "SHSH saved to '%s'\n", zfn); } else { - info("SHSH '%s' already present.\n", zfn); + logger(LL_INFO, "SHSH '%s' already present.\n", zfn); } free(bin); } else { - error("ERROR: could not get TSS record data\n"); + logger(LL_ERROR, "could not get TSS record data\n"); } plist_free(client->tss); return 0; @@ -1370,7 +1361,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* verify if we have tss records if required */ if ((tss_enabled) && (client->tss == NULL)) { - error("ERROR: Unable to proceed without a TSS record.\n"); + logger(LL_ERROR, "Unable to proceed without a TSS record.\n"); return -1; } @@ -1385,9 +1376,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // if the device is in normal mode, place device into recovery mode if (client->mode == MODE_NORMAL) { - info("Entering recovery mode...\n"); + logger(LL_INFO, "Entering recovery mode...\n"); if (normal_enter_recovery(client) < 0) { - error("ERROR: Unable to place device into recovery mode from normal mode\n"); + logger(LL_ERROR, "Unable to place device into recovery mode from normal mode\n"); if (client->tss) plist_free(client->tss); return -5; @@ -1405,22 +1396,22 @@ int idevicerestore_start(struct idevicerestore_client_t* client) recovery_client_free(client); #ifdef HAVE_LIMERA1N if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) { - info("connecting to DFU\n"); + logger(LL_INFO, "connecting to DFU\n"); if (dfu_client_new(client) < 0) { return -1; } - info("exploiting with limera1n\n"); + logger(LL_INFO, "exploiting with limera1n\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { - error("ERROR: limera1n exploit failed\n"); + logger(LL_ERROR, "limera1n exploit failed\n"); dfu_client_free(client); return -1; } dfu_client_free(client); - info("exploited\n"); + logger(LL_INFO, "exploited\n"); } #endif if (dfu_enter_recovery(client, build_identity) < 0) { - error("ERROR: Unable to place device into recovery mode from DFU mode\n"); + logger(LL_ERROR, "Unable to place device into recovery mode from DFU mode\n"); if (client->tss) plist_free(client->tss); return -2; @@ -1431,7 +1422,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!client->image4supported) { /* send ApTicket */ if (recovery_send_ticket(client) < 0) { - error("ERROR: Unable to send APTicket\n"); + logger(LL_ERROR, "Unable to send APTicket\n"); return -2; } } @@ -1442,28 +1433,28 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* now we load the iBEC */ if (recovery_send_ibec(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send iBEC\n"); + logger(LL_ERROR, "Unable to send iBEC\n"); return -2; } recovery_client_free(client); - debug("Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n"); + logger(LL_ERROR, "Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n"); } return -2; } recovery_client_free(client); - debug("Waiting for device to reconnect in recovery mode...\n"); + logger(LL_DEBUG, "Waiting for device to reconnect in recovery mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { - error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n"); + logger(LL_ERROR, "Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n"); } return -2; } @@ -1480,7 +1471,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) unsigned int nonce_size = 0; int nonce_changed = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { - error("ERROR: Unable to get nonce from device!\n"); + logger(LL_ERROR, "Unable to get nonce from device!\n"); recovery_send_reset(client); return -2; } @@ -1500,11 +1491,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // Welcome iOS5. We have to re-request the TSS with our nonce. plist_free(client->tss); if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); + logger(LL_ERROR, "Unable to get SHSH blobs for this device\n"); return -1; } if (!client->tss) { - error("ERROR: can't continue without TSS\n"); + logger(LL_ERROR, "can't continue without TSS\n"); return -1; } fixup_tss(client->tss); @@ -1518,7 +1509,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // now finally do the magic to put the device into restore mode if (client->mode == MODE_RECOVERY) { if (recovery_enter_restore(client, build_identity) < 0) { - error("ERROR: Unable to place device into restore mode\n"); + logger(LL_ERROR, "Unable to place device into restore mode\n"); if (client->tss) plist_free(client->tss); return -2; @@ -1529,15 +1520,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode != MODE_RESTORE) { mutex_lock(&client->device_event_mutex); - info("Waiting for device to enter restore mode...\n"); + logger(LL_INFO, "Waiting for device to enter restore mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000); if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Device failed to enter restore mode.\n"); + logger(LL_ERROR, "Device failed to enter restore mode.\n"); if (client->mode == MODE_UNKNOWN) { - error("Make sure that usbmuxd is running.\n"); - } else if (client->mode == MODE_RECOVERY) { - error("Device reconnected in recovery mode, most likely image personalization failed.\n"); + logger(LL_ERROR, "Make sure that usbmuxd is running.\n"); + } else if (client->mode == MODE_RECOVERY || client->mode == MODE_DFU) { + logger(LL_ERROR, "Device reconnected in %s mode, most likely image personalization failed.\n", client->mode->string); } return -1; } @@ -1547,14 +1538,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // device is finally in restore mode, let's do this if (client->mode == MODE_RESTORE) { if ((client->flags & FLAG_NO_RESTORE) != 0) { - info("Device is now in restore mode. Exiting as requested.\n"); + logger(LL_INFO, "Device is now in restore mode. Exiting as requested.\n"); return 0; } client->ignore_device_add_events = 1; - info("About to restore device... \n"); + logger(LL_INFO, "About to restore device... \n"); result = restore_device(client, build_identity); if (result < 0) { - error("ERROR: Unable to restore device\n"); + logger(LL_ERROR, "Unable to restore device\n"); return result; } } @@ -1565,18 +1556,18 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (recovery_set_autoboot(client, 1) == 0) { recovery_send_reset(client); } else { - error("Setting auto-boot failed?!\n"); + logger(LL_ERROR, "Setting auto-boot failed?!\n"); } } else { - error("Could not connect to device in recovery mode.\n"); + logger(LL_ERROR, "Could not connect to device in recovery mode.\n"); } } if (result == 0) { - info("DONE\n"); + logger(LL_INFO, "DONE\n"); idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0); } else { - info("RESTORE FAILED\n"); + logger(LL_INFO, "RESTORE FAILED\n"); } if (build_identity_needs_free) @@ -1589,7 +1580,7 @@ struct idevicerestore_client_t* idevicerestore_client_new(void) { struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t)); if (client == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return NULL; } memset(client, '\0', sizeof(struct idevicerestore_client_t)); @@ -1732,6 +1723,7 @@ static void handle_signal(int sig) { if (idevicerestore_client) { idevicerestore_client->flags |= FLAG_QUIT; + global_quit_flag++; ipsw_cancel(); } } @@ -1742,16 +1734,52 @@ void plain_progress_cb(int step, double step_progress, void* userdata) fflush(stdout); } -int main(int argc, char* argv[]) { +static void plain_progress_func(struct progress_info_entry** progress_info, int count) +{ + int i = 0; + for (i = 0; i < count; i++) { + if (!progress_info[i]) continue; + printf("%s: %5.1f\n", progress_info[i]->label, progress_info[i]->progress); + fflush(stdout); + } +} + +static void tty_print(int level, const char* format, va_list varglist) +{ + switch (level) { + case 0: + cprintf(FG_RED STYLE_BRIGHT); + break; + case 1: + cprintf(FG_YELLOW STYLE_BRIGHT); + break; + case 2: + cprintf(STYLE_BRIGHT); + break; + default: + break; + } + + cvfprintf(stdout, format, varglist); + + cprintf(COLOR_RESET); +} + +int main(int argc, char* argv[]) +{ int opt = 0; int optindex = 0; char* ipsw = NULL; int ipsw_info = 0; int result = 0; + int is_terminal = 0; + const char* logfile = NULL; + + logger_set_print_func(tty_print); struct idevicerestore_client_t* client = idevicerestore_client_new(); if (client == NULL) { - error("ERROR: could not create idevicerestore client\n"); + logger(LL_ERROR, "Could not create idevicerestore client\n"); return EXIT_FAILURE; } @@ -1776,6 +1804,7 @@ int main(int argc, char* argv[]) { client->flags &= ~FLAG_INTERACTIVE; } else { client->flags |= FLAG_INTERACTIVE; + is_terminal = 1; } #ifdef HAVE_LIMERA1N @@ -1793,6 +1822,9 @@ int main(int argc, char* argv[]) { case 'd': client->flags |= FLAG_DEBUG; client->debug_level++; + if (client->debug_level > 0) { + log_level = LL_DEBUG; + } break; case 'e': @@ -1805,7 +1837,7 @@ int main(int argc, char* argv[]) { case 's': { if (!*optarg) { - error("ERROR: URL argument for --server must not be empty!\n"); + logger(LL_ERROR, "URL argument for --server must not be empty!\n"); usage(argc, argv, 1); return EXIT_FAILURE; } @@ -1828,7 +1860,7 @@ int main(int argc, char* argv[]) { client->tss_url = strdup(optarg); } } else { - error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n"); + logger(LL_ERROR, "URL argument for --server is invalid, must start with http:// or https://\n"); usage(argc, argv, 1); return EXIT_FAILURE; } @@ -1851,7 +1883,7 @@ int main(int argc, char* argv[]) { client->ecid = 0; } if (client->ecid == 0) { - error("ERROR: Could not parse ECID from '%s'\n", optarg); + logger(LL_ERROR, "Could not parse ECID from '%s'\n", optarg); return EXIT_FAILURE; } } @@ -1859,7 +1891,7 @@ int main(int argc, char* argv[]) { case 'u': if (!*optarg) { - error("ERROR: UDID must not be empty!\n"); + logger(LL_ERROR, "UDID must not be empty!\n"); usage(argc, argv, 1); return EXIT_FAILURE; } @@ -1894,6 +1926,8 @@ int main(int argc, char* argv[]) { case 'P': idevicerestore_set_progress_callback(client, plain_progress_cb, NULL); + set_update_progress_func(plain_progress_func); + set_progress_granularity(0.01); // 1% granularity break; case 'R': @@ -1905,7 +1939,7 @@ int main(int argc, char* argv[]) { break; case 'v': - info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); + printf("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); return EXIT_SUCCESS; case 'T': { @@ -1916,7 +1950,7 @@ int main(int argc, char* argv[]) { } client->root_ticket = root_ticket; client->root_ticket_len = (int)root_ticket_len; - info("Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len); + logger(LL_INFO, "Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len); break; } @@ -1933,6 +1967,15 @@ int main(int argc, char* argv[]) { client->restore_variant = strdup(optarg); break; + case 3: + if (!*optarg) { + logger(LL_ERROR, "logfile must not be empty!\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + logfile = optarg; + break; + default: usage(argc, argv, 1); return EXIT_FAILURE; @@ -1941,7 +1984,7 @@ int main(int argc, char* argv[]) { if (ipsw_info) { if (argc-optind != 1) { - error("ERROR: --ipsw-info requires an IPSW path.\n"); + logger(LL_ERROR, "--ipsw-info requires an IPSW path.\n"); usage(argc, argv, 1); return EXIT_FAILURE; } @@ -1959,24 +2002,41 @@ int main(int argc, char* argv[]) { } if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) { - error("ERROR: You can't use --custom and --latest options at the same time.\n"); + logger(LL_ERROR, "You can't use --custom and --latest options at the same time.\n"); return EXIT_FAILURE; } - info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); + if (!logfile) { + char logfn[256]; + int64_t timestamp = time(NULL); + if (client->ecid) { + snprintf(logfn, sizeof(logfn), "restore_%016" PRIx64 "_%" PRIi64 ".log", client->ecid, timestamp); + } else if (client->udid) { + snprintf(logfn, sizeof(logfn), "restore_%s_%" PRIi64 ".log", client->udid, timestamp); + } else { + snprintf(logfn, sizeof(logfn), "restore_%" PRIi64 ".log", timestamp); + } + logger_set_logfile(logfn); + } else { + logger_set_logfile(logfile); + } + + logger(LL_INFO, "%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); if (ipsw) { // verify if ipsw file exists client->ipsw = ipsw_open(ipsw); if (!client->ipsw) { - error("ERROR: Firmware file %s cannot be opened.\n", ipsw); + logger(LL_ERROR, "Firmware file %s cannot be opened.\n", ipsw); return -1; } } curl_global_init(CURL_GLOBAL_ALL); + client->flags |= FLAG_IN_PROGRESS; result = idevicerestore_start(client); + client->flags &= ~FLAG_IN_PROGRESS; idevicerestore_client_free(client); @@ -2034,7 +2094,7 @@ int is_image4_supported(struct idevicerestore_client_t* client) res = recovery_is_image4_supported(client); break; default: - error("ERROR: Device is in an invalid state\n"); + logger(LL_ERROR, "Device is in an invalid state\n"); return 0; } return res; @@ -2047,7 +2107,7 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, *nonce = NULL; *nonce_size = 0; - info("Getting ApNonce "); + logger(LL_INFO, "Getting ApNonce "); if (client->mode) { mode = client->mode->index; @@ -2055,38 +2115,34 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, switch (mode) { case _MODE_NORMAL: - info("in normal mode... "); + logger(LL_INFO, "Getting ApNonce in Normal mode... "); if (normal_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_DFU: - info("in dfu mode... "); + logger(LL_INFO, "Getting ApNonce in DFU mode... "); if (dfu_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_RECOVERY: - info("in recovery mode... "); + logger(LL_INFO, "Getting ApNonce in Recovery mode... "); if (recovery_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; default: - info("failed\n"); - error("ERROR: Device is in an invalid state\n"); + logger(LL_INFO, "Getting ApNonce failed\n"); + logger(LL_ERROR, "Device is in an invalid state\n"); return -1; } - int i = 0; - for (i = 0; i < *nonce_size; i++) { - info("%02x ", (*nonce)[i]); - } - info("\n"); + logger_dump_hex(LL_INFO, *nonce, *nonce_size); return 0; } @@ -2098,7 +2154,7 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, *nonce = NULL; *nonce_size = 0; - info("Getting SepNonce "); + logger(LL_INFO, "Getting SepNonce "); if (client->mode) { mode = client->mode->index; @@ -2106,38 +2162,34 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, switch (mode) { case _MODE_NORMAL: - info("in normal mode... "); + logger(LL_INFO, "in normal mode... "); if (normal_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_DFU: - info("in dfu mode... "); + logger(LL_INFO, "in dfu mode... "); if (dfu_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_RECOVERY: - info("in recovery mode... "); + logger(LL_INFO, "in recovery mode... "); if (recovery_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); + logger(LL_INFO, "failed\n"); return -1; } break; default: - info("failed\n"); - error("ERROR: Device is in an invalid state\n"); + logger(LL_INFO, "failed\n"); + logger(LL_ERROR, "Device is in an invalid state\n"); return -1; } - int i = 0; - for (i = 0; i < *nonce_size; i++) { - info("%02x ", (*nonce)[i]); - } - info("\n"); + logger_dump_hex(LL_INFO, *nonce, *nonce_size); return 0; } @@ -2146,7 +2198,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m { plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { - error("ERROR: Unable to find build identities node\n"); + logger(LL_ERROR, "Unable to find build identities node\n"); return NULL; } @@ -2222,14 +2274,14 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ /* create basic request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); plist_free(parameters); return -1; } /* add common tags from manifest */ if (tss_request_add_common_tags(request, parameters, overrides) < 0) { - error("ERROR: Unable to add common tags\n"); + logger(LL_ERROR, "Unable to add common tags\n"); plist_free(request); plist_free(parameters); return -1; @@ -2239,7 +2291,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add ap tags\n"); + logger(LL_ERROR, "Unable to add ap tags\n"); plist_free(request); plist_free(parameters); return -1; @@ -2264,7 +2316,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident *tss = NULL; if ((client->build_major <= 8) || (client->flags & FLAG_CUSTOM)) { - error("checking for local shsh\n"); + logger(LL_ERROR, "checking for local shsh\n"); /* first check for local copy */ char zfn[1024]; @@ -2286,7 +2338,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident do { int bytes_read = gzread(zf, p, readsize); if (bytes_read < 0) { - fprintf(stderr, "Error reading gz compressed data\n"); + logger(LL_ERROR, "Error reading gz compressed data\n"); exit(EXIT_FAILURE); } blen += bytes_read; @@ -2311,18 +2363,18 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident free(bin); } } else { - error("no local file %s\n", zfn); + logger(LL_ERROR, "no local file %s\n", zfn); } } else { - error("No version found?!\n"); + logger(LL_ERROR, "No version found?!\n"); } } if (*tss) { - info("Using cached SHSH\n"); + logger(LL_INFO, "Using cached SHSH\n"); return 0; } else { - info("Trying to fetch new SHSH blob\n"); + logger(LL_INFO, "Trying to fetch new SHSH blob\n"); } /* populate parameters */ @@ -2357,14 +2409,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident /* create basic request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); plist_free(parameters); return -1; } /* add common tags from manifest */ if (tss_request_add_common_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2372,7 +2424,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2381,7 +2433,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident if (client->image4supported) { /* add personalized parameters */ if (tss_request_add_ap_img4_tags(request, parameters) < 0) { - error("ERROR: Unable to add img4 tags to TSS request\n"); + logger(LL_ERROR, "Unable to add img4 tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2389,7 +2441,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident } else { /* add personalized parameters */ if (tss_request_add_ap_img3_tags(request, parameters) < 0) { - error("ERROR: Unable to add img3 tags to TSS request\n"); + logger(LL_ERROR, "Unable to add img3 tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2432,13 +2484,13 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident /* send request and grab response */ response = tss_request_send(request, client->tss_url); if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); + logger(LL_INFO, "ERROR: Unable to send TSS request\n"); plist_free(request); plist_free(parameters); return -1; } - info("Received SHSH blobs\n"); + logger(LL_INFO, "Received SHSH blobs\n"); plist_free(request); plist_free(parameters); @@ -2492,7 +2544,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* Adds @HostPlatformInfo, @VersionInfo, @UUID */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); plist_free(parameters); return -1; } @@ -2500,7 +2552,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* add common tags from manifest */ /* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */ if (tss_request_add_ap_img4_tags(request, parameters) < 0) { - error("ERROR: Unable to add AP IMG4 tags to TSS request\n"); + logger(LL_ERROR, "Unable to add AP IMG4 tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2508,7 +2560,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* add AP tags from manifest */ if (tss_request_add_common_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2517,7 +2569,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* add AP tags from manifest */ /* Fills digests & co */ if (tss_request_add_ap_recovery_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2526,14 +2578,14 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* send request and grab response */ response = tss_request_send(request, client->tss_url); if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); + logger(LL_INFO, "ERROR: Unable to send TSS request\n"); plist_free(request); plist_free(parameters); return -1; } // request_add_ap_tags - info("Received SHSH blobs\n"); + logger(LL_INFO, "Received SHSH blobs\n"); plist_free(request); plist_free(parameters); @@ -2585,7 +2637,7 @@ int get_recovery_os_local_policy_tss_response( unsigned int vuuid[16]; unsigned char vol_uuid[16]; if (sscanf(vol_uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", &vuuid[0], &vuuid[1], &vuuid[2], &vuuid[3], &vuuid[4], &vuuid[5], &vuuid[6], &vuuid[7], &vuuid[8], &vuuid[9], &vuuid[10], &vuuid[11], &vuuid[12], &vuuid[13], &vuuid[14], &vuuid[15]) != 16) { - error("ERROR: Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str); + logger(LL_ERROR, "Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str); free(vol_uuid_str); return -1; } @@ -2599,14 +2651,14 @@ int get_recovery_os_local_policy_tss_response( /* create basic request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); plist_free(parameters); return -1; } /* add common tags from manifest */ if (tss_request_add_local_policy_tags(request, parameters) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2615,13 +2667,13 @@ int get_recovery_os_local_policy_tss_response( /* send request and grab response */ response = tss_request_send(request, client->tss_url); if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); + logger(LL_INFO, "ERROR: Unable to send TSS request\n"); plist_free(request); plist_free(parameters); return -1; } - info("Received SHSH blobs\n"); + logger(LL_INFO, "Received SHSH blobs\n"); plist_free(request); plist_free(parameters); @@ -2684,14 +2736,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ /* create basic request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + logger(LL_ERROR, "Unable to create TSS request\n"); plist_free(parameters); return -1; } /* add common tags from manifest */ if (tss_request_add_local_policy_tags(request, parameters) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); + logger(LL_ERROR, "Unable to add common tags to TSS request\n"); plist_free(request); plist_free(parameters); return -1; @@ -2700,13 +2752,13 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ /* send request and grab response */ response = tss_request_send(request, client->tss_url); if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); + logger(LL_INFO, "ERROR: Unable to send TSS request\n"); plist_free(request); plist_free(parameters); return -1; } - info("Received SHSH blobs\n"); + logger(LL_INFO, "Received SHSH blobs\n"); plist_free(request); plist_free(parameters); @@ -2751,7 +2803,7 @@ int build_manifest_get_identity_count(plist_t build_manifest) // fetch build identities array from BuildManifest plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { - error("ERROR: Unable to find build identities node\n"); + logger(LL_ERROR, "Unable to find build identities node\n"); return -1; } return plist_array_get_size(build_identities_array); @@ -2770,9 +2822,9 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com else component_name = (char*) path; - info("Extracting %s (%s)...\n", component_name, path); + logger(LL_INFO, "Extracting %s (%s)...\n", component_name, path); if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", component_name, ipsw->path); + logger(LL_ERROR, "Unable to extract %s from %s\n", component_name, ipsw->path); return -1; } @@ -2792,17 +2844,17 @@ int personalize_component(struct idevicerestore_client_t* client, const char *co } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { - debug("NOTE: No SHSH blob found for component %s\n", component_name); + logger(LL_DEBUG, "NOTE: No SHSH blob found for component %s\n", component_name); } if (component_blob != NULL) { if (img3_stitch_component(component_name, component_data, component_size, component_blob, 64, &stitched_component, &stitched_component_size) < 0) { - error("ERROR: Unable to replace %s IMG3 signature\n", component_name); + logger(LL_ERROR, "Unable to replace %s IMG3 signature\n", component_name); free(component_blob); return -1; } } else { - info("Not personalizing component %s...\n", component_name); + logger(LL_INFO, "Not personalizing component %s...\n", component_name); stitched_component = (unsigned char*)malloc(component_size); if (stitched_component) { stitched_component_size = component_size; @@ -2826,9 +2878,9 @@ int build_manifest_check_compatibility(plist_t build_manifest, const char* produ int res = -1; plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes"); if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) { - debug("%s: ERROR: SupportedProductTypes key missing\n", __func__); - debug("%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the", __func__); - debug("%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.", __func__); + logger(LL_DEBUG, "%s: ERROR: SupportedProductTypes key missing\n", __func__); + logger(LL_DEBUG, "%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the\n", __func__); + logger(LL_DEBUG, "%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.\n", __func__); return -1; } uint32_t pc = plist_array_get_size(node); @@ -2856,14 +2908,14 @@ void build_manifest_get_version_information(plist_t build_manifest, struct idevi node = plist_dict_get_item(build_manifest, "ProductVersion"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find ProductVersion node\n"); + logger(LL_ERROR, "Unable to find ProductVersion node\n"); return; } plist_get_string_val(node, &client->version); node = plist_dict_get_item(build_manifest, "ProductBuildVersion"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find ProductBuildVersion node\n"); + logger(LL_ERROR, "Unable to find ProductBuildVersion node\n"); return; } plist_get_string_val(node, &client->build); @@ -2879,25 +2931,25 @@ void build_identity_print_information(plist_t build_identity) info_node = plist_dict_get_item(build_identity, "Info"); if (!info_node || plist_get_node_type(info_node) != PLIST_DICT) { - error("ERROR: Unable to find Info node\n"); + logger(LL_ERROR, "Unable to find Info node\n"); return; } node = plist_dict_get_item(info_node, "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find Variant node\n"); + logger(LL_ERROR, "Unable to find Variant node\n"); return; } plist_get_string_val(node, &value); - info("Variant: %s\n", value); + logger(LL_INFO, "Variant: %s\n", value); if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL)) - info("This restore will update the device without erasing user data.\n"); + logger(LL_INFO, "This restore will update the device without erasing user data.\n"); else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL)) - info("This restore will erase all device data.\n"); + logger(LL_INFO, "This restore will erase all device data.\n"); else - info("Unknown Variant '%s'\n", value); + logger(LL_INFO, "Unknown Variant '%s'\n", value); free(value); @@ -2927,7 +2979,7 @@ int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive plist_get_string_val(path, &comp_path); if (comp_path) { if (!ipsw_file_exists(ipsw, comp_path)) { - error("ERROR: %s file %s not found in IPSW\n", key, comp_path); + logger(LL_ERROR, "%s file %s not found in IPSW\n", key, comp_path); res = -1; } free(comp_path); @@ -2960,7 +3012,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon 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"); + logger(LL_ERROR, "Unable to find manifest node\n"); if (filename) free(filename); return -1; @@ -2968,7 +3020,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon plist_t component_node = plist_dict_get_item(manifest_node, component); if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) { - error("ERROR: Unable to find component node for %s\n", component); + logger(LL_ERROR, "Unable to find component node for %s\n", component); if (filename) free(filename); return -1; @@ -2976,7 +3028,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon plist_t component_info_node = plist_dict_get_item(component_node, "Info"); if (!component_info_node || plist_get_node_type(component_info_node) != PLIST_DICT) { - error("ERROR: Unable to find component info node for %s\n", component); + logger(LL_ERROR, "Unable to find component info node for %s\n", component); if (filename) free(filename); return -1; @@ -2984,7 +3036,7 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon plist_t component_info_path_node = plist_dict_get_item(component_info_node, "Path"); if (!component_info_path_node || plist_get_node_type(component_info_path_node) != PLIST_STRING) { - error("ERROR: Unable to find component info path node for %s\n", component); + logger(LL_ERROR, "Unable to find component info path node for %s\n", component); if (filename) free(filename); return -1; @@ -3029,6 +3081,6 @@ const char* get_component_name(const char* filename) } i++; } - error("WARNING: Unhandled component '%s'", filename); + logger(LL_WARNING, "Unhandled component '%s'", filename); return NULL; } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index fe9d11f2..1e016726 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -46,6 +46,7 @@ extern "C" { #define FLAG_ALLOW_RESTORE_MODE (1 << 10) #define FLAG_NO_RESTORE (1 << 11) #define FLAG_IGNORE_ERRORS (1 << 12) +#define FLAG_IN_PROGRESS (1 << 30) #define RESTORE_VARIANT_ERASE_INSTALL "Erase Install (IPSW)" #define RESTORE_VARIANT_UPGRADE_INSTALL "Upgrade Install (IPSW)" @@ -83,9 +84,6 @@ void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags) void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path); void idevicerestore_set_cache_path(struct idevicerestore_client_t* client, const char* path); void idevicerestore_set_progress_callback(struct idevicerestore_client_t* client, idevicerestore_progress_cb_t cbfunc, void* userdata); -void idevicerestore_set_info_stream(FILE* strm); -void idevicerestore_set_error_stream(FILE* strm); -void idevicerestore_set_debug_stream(FILE* strm); int idevicerestore_start(struct idevicerestore_client_t* client); const char* idevicerestore_get_error(void); diff --git a/src/img3.c b/src/img3.c index fb8d49e7..a7008390 100644 --- a/src/img3.c +++ b/src/img3.c @@ -38,13 +38,13 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size) img3_element* element; img3_header* header = (img3_header*) data; if (header->signature != kImg3Container) { - error("ERROR: Invalid IMG3 file\n"); + logger(LL_ERROR, "Invalid IMG3 file\n"); return NULL; } img3_file* image = (img3_file*) malloc(sizeof(img3_file)); if (image == NULL) { - error("ERROR: Unable to allocate memory for IMG3 file\n"); + logger(LL_ERROR, "Unable to allocate memory for IMG3 file\n"); return NULL; } memset(image, '\0', sizeof(img3_file)); @@ -54,7 +54,7 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size) image->header = (img3_header*) malloc(sizeof(img3_header)); if (image->header == NULL) { - error("ERROR: Unable to allocate memory for IMG3 header\n"); + logger(LL_ERROR, "Unable to allocate memory for IMG3 header\n"); img3_free(image); return NULL; } @@ -68,129 +68,129 @@ static img3_file* img3_parse_file(const unsigned char* data, unsigned int size) case kTypeElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse TYPE element\n"); + logger(LL_ERROR, "Unable to parse TYPE element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed TYPE element\n"); + logger(LL_DEBUG, "Parsed TYPE element\n"); break; case kDataElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse DATA element\n"); + logger(LL_ERROR, "Unable to parse DATA element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed DATA element\n"); + logger(LL_DEBUG, "Parsed DATA element\n"); break; case kVersElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse VERS element\n"); + logger(LL_ERROR, "Unable to parse VERS element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed VERS element\n"); + logger(LL_DEBUG, "Parsed VERS element\n"); break; case kSepoElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse SEPO element\n"); + logger(LL_ERROR, "Unable to parse SEPO element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed SEPO element\n"); + logger(LL_DEBUG, "Parsed SEPO element\n"); break; case kBordElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse BORD element\n"); + logger(LL_ERROR, "Unable to parse BORD element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed BORD element\n"); + logger(LL_DEBUG, "Parsed BORD element\n"); break; case kChipElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse CHIP element\n"); + logger(LL_ERROR, "Unable to parse CHIP element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed CHIP element\n"); + logger(LL_DEBUG, "Parsed CHIP element\n"); break; case kKbagElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse first KBAG element\n"); + logger(LL_ERROR, "Unable to parse first KBAG element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed KBAG element\n"); + logger(LL_DEBUG, "Parsed KBAG element\n"); break; case kEcidElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse ECID element\n"); + logger(LL_ERROR, "Unable to parse ECID element\n"); img3_free(image); return NULL; } image->idx_ecid_element = image->num_elements; image->elements[image->num_elements++] = element; - debug("Parsed ECID element\n"); + logger(LL_DEBUG, "Parsed ECID element\n"); break; case kShshElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse SHSH element\n"); + logger(LL_ERROR, "Unable to parse SHSH element\n"); img3_free(image); return NULL; } image->idx_shsh_element = image->num_elements; image->elements[image->num_elements++] = element; - debug("Parsed SHSH element\n"); + logger(LL_DEBUG, "Parsed SHSH element\n"); break; case kCertElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse CERT element\n"); + logger(LL_ERROR, "Unable to parse CERT element\n"); img3_free(image); return NULL; } image->idx_cert_element = image->num_elements; image->elements[image->num_elements++] = element; - debug("Parsed CERT element\n"); + logger(LL_DEBUG, "Parsed CERT element\n"); break; case kUnknElement: element = img3_parse_element(&data[data_offset]); if (element == NULL) { - error("ERROR: Unable to parse UNKN element\n"); + logger(LL_ERROR, "Unable to parse UNKN element\n"); img3_free(image); return NULL; } image->elements[image->num_elements++] = element; - debug("Parsed UNKN element\n"); + logger(LL_DEBUG, "Parsed UNKN element\n"); break; default: - error("ERROR: Unknown IMG3 element type %08x\n", current->signature); + logger(LL_ERROR, "Unknown IMG3 element type %08x\n", current->signature); img3_free(image); return NULL; } @@ -204,14 +204,14 @@ static img3_element* img3_parse_element(const unsigned char* data) { img3_element_header* element_header = (img3_element_header*) data; img3_element* element = (img3_element*) malloc(sizeof(img3_element)); if (element == NULL) { - error("ERROR: Unable to allocate memory for IMG3 element\n"); + logger(LL_ERROR, "Unable to allocate memory for IMG3 element\n"); return NULL; } memset(element, '\0', sizeof(img3_element)); element->data = (unsigned char*) malloc(element_header->full_size); if (element->data == NULL) { - error("ERROR: Unable to allocate memory for IMG3 element data\n"); + logger(LL_ERROR, "Unable to allocate memory for IMG3 element data\n"); free(element); return NULL; } @@ -254,21 +254,21 @@ static int img3_replace_signature(img3_file* image, const unsigned char* signatu int offset = 0; img3_element* ecid = img3_parse_element(&signature[offset]); if (ecid == NULL || ecid->type != kEcidElement) { - error("ERROR: Unable to find ECID element in signature\n"); + logger(LL_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) { - error("ERROR: Unable to find SHSH element in signature\n"); + logger(LL_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) { - error("ERROR: Unable to find CERT element in signature\n"); + logger(LL_ERROR, "Unable to find CERT element in signature\n"); return -1; } offset += cert->header->full_size; @@ -364,11 +364,11 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int* size += image->elements[i]->header->full_size; } - info("reconstructed size: %d\n", size); + logger(LL_INFO, "reconstructed size: %d\n", size); unsigned char* data = (unsigned char*) malloc(size); if (data == NULL) { - error("ERROR: Unable to allocate memory for IMG3 data\n"); + logger(LL_ERROR, "Unable to allocate memory for IMG3 data\n"); return -1; } @@ -390,7 +390,7 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int* } if (offset != size) { - error("ERROR: Incorrectly sized image data\n"); + logger(LL_ERROR, "Incorrectly sized image data\n"); free(data); *pdata = 0; *psize = 0; @@ -412,31 +412,31 @@ int img3_stitch_component(const char* component_name, const unsigned char* compo return -1; } - info("Personalizing IMG3 component %s...\n", component_name); + logger(LL_INFO, "Personalizing IMG3 component %s...\n", component_name); /* parse current component as img3 */ img3 = img3_parse_file(component_data, component_size); if (img3 == NULL) { - error("ERROR: Unable to parse %s IMG3 file\n", component_name); + logger(LL_ERROR, "Unable to parse %s IMG3 file\n", component_name); return -1; } if (((img3_element_header*)blob)->full_size != blob_size) { - error("ERROR: Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %d\n", component_name, ((img3_element_header*)blob)->full_size, blob_size); + logger(LL_ERROR, "Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %d\n", component_name, ((img3_element_header*)blob)->full_size, blob_size); img3_free(img3); return -1; } /* personalize the component using the blob */ if (img3_replace_signature(img3, blob) < 0) { - error("ERROR: Unable to replace %s IMG3 signature\n", component_name); + logger(LL_ERROR, "Unable to replace %s IMG3 signature\n", component_name); img3_free(img3); return -1; } /* get the img3 file as data */ if (img3_get_data(img3, &outbuf, &outsize) < 0) { - error("ERROR: Unable to reconstruct %s IMG3\n", component_name); + logger(LL_ERROR, "Unable to reconstruct %s IMG3\n", component_name); img3_free(img3); return -1; } diff --git a/src/img4.c b/src/img4.c index e9d4ccac..b23775a7 100644 --- a/src/img4.c +++ b/src/img4.c @@ -204,7 +204,7 @@ static void asn1_write_element(unsigned char **p, unsigned int *length, unsigned } } break; default: - fprintf(stderr, "ERROR: %s: type %02x is not implemented\n", __func__, type); + logger(LL_ERROR, "%s: type %02x is not implemented\n", __func__, type); return; } } @@ -415,15 +415,15 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo } if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) { - error("ERROR: %s: Failed to get ApImg4Ticket from TSS response\n", __func__); + logger(LL_ERROR, "%s: Failed to get ApImg4Ticket from TSS response\n", __func__); return -1; } - info("Personalizing IMG4 component %s...\n", component_name); + logger(LL_INFO, "Personalizing IMG4 component %s...\n", component_name); /* first we need check if we have to change the tag for the given component */ const void *tag = asn1_find_element(1, ASN1_IA5_STRING, component_data); if (tag) { - debug("Tag found\n"); + logger(LL_DEBUG, "Tag found\n"); if (strcmp(component_name, "RestoreKernelCache") == 0) { memcpy((void*)tag, "rkrn", 4); } else if (strcmp(component_name, "RestoreDeviceTree") == 0) { @@ -467,22 +467,22 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo if (tbm_dict) { plist_t dt = plist_dict_get_item(tbm_dict, "ucon"); if (!dt) { - error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); + logger(LL_ERROR, "%s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); return -1; } ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { - error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); + logger(LL_ERROR, "%s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; } dt = plist_dict_get_item(tbm_dict, "ucer"); if (!dt) { - error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); + logger(LL_ERROR, "%s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); return -1; } ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { - error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); + logger(LL_ERROR, "%s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; } } @@ -683,7 +683,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo free(img4header); } free(additional_data); - error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name); + logger(LL_ERROR, "out of memory when personalizing IMG4 component %s\n", component_name); return -1; } p = outbuf; @@ -825,7 +825,7 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c tbmtag = "tbmr"; } if (!tbmtag) { - error("ERROR: Unexpected TMBDigests for comp '%s'\n", tag); + logger(LL_ERROR, "Unexpected TMBDigests for comp '%s'\n", tag); } else { _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, (void*)data, datalen); } @@ -918,10 +918,10 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* comp = _img4_get_component_tag(key); } if (!comp) { - debug("DEBUG: %s: Unhandled component '%s'\n", __func__, key); + logger(LL_DEBUG, "%s: Unhandled component '%s'\n", __func__, key); _manifest_write_component(&p, &length, key, val); } else { - debug("DEBUG: found component %s (%s)\n", comp, key); + logger(LL_DEBUG, "found component %s (%s)\n", comp, key); _manifest_write_component(&p, &length, comp, val); } } diff --git a/src/ipsw.c b/src/ipsw.c index da7528d0..201f9cd3 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -69,7 +69,7 @@ int ipsw_print_info(const char* path) struct stat fst; if (stat(path, &fst) != 0) { - error("ERROR: '%s': %s\n", path, strerror(errno)); + logger(LL_ERROR, "'%s': %s\n", path, strerror(errno)); return -1; } @@ -78,7 +78,7 @@ int ipsw_print_info(const char* path) if (S_ISDIR(fst.st_mode)) { snprintf(thepath, sizeof(thepath), "%s/BuildManifest.plist", path); if (stat(thepath, &fst) != 0) { - error("ERROR: '%s': %s\n", thepath, strerror(errno)); + logger(LL_ERROR, "'%s': %s\n", thepath, strerror(errno)); return -1; } } else { @@ -87,13 +87,13 @@ int ipsw_print_info(const char* path) FILE* f = fopen(thepath, "r"); if (!f) { - error("ERROR: Can't open '%s': %s\n", thepath, strerror(errno)); + logger(LL_ERROR, "Can't open '%s': %s\n", thepath, strerror(errno)); return -1; } uint32_t magic; if (fread(&magic, 1, 4, f) != 4) { fclose(f); - fprintf(stderr, "Failed to read from '%s'\n", path); + logger(LL_ERROR, "Failed to read from '%s'\n", path); return -1; } fclose(f); @@ -106,7 +106,7 @@ int ipsw_print_info(const char* path) unsigned int rlen = 0; if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { ipsw_close(ipsw); - error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n"); + logger(LL_ERROR, "Failed to extract BuildManifest.plist from IPSW!\n"); return -1; } ipsw_close(ipsw); @@ -114,7 +114,7 @@ int ipsw_print_info(const char* path) } else { size_t rlen = 0; if (read_file(thepath, (void**)&plist_buf, &rlen) < 0) { - error("ERROR: Failed to read BuildManifest.plist!\n"); + logger(LL_ERROR, "Failed to read BuildManifest.plist!\n"); return -1; } plist_len = (uint32_t)rlen; @@ -302,13 +302,13 @@ ipsw_archive_t ipsw_open(const char* ipsw) int err = 0; ipsw_archive_t archive = (ipsw_archive_t)calloc(1, sizeof(struct ipsw_archive)); if (archive == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return NULL; } struct stat fst; if (stat(ipsw, &fst) != 0) { - error("ERROR: ipsw_open %s: %s\n", ipsw, strerror(errno)); + logger(LL_ERROR, "ipsw_open %s: %s\n", ipsw, strerror(errno)); return NULL; } if (S_ISDIR(fst.st_mode)) { @@ -316,7 +316,7 @@ ipsw_archive_t ipsw_open(const char* ipsw) } else { struct zip *zip = zip_open(ipsw, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw, err); free(archive); return NULL; } @@ -347,7 +347,7 @@ int ipsw_is_directory(const char* ipsw) int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) { if (ipsw == NULL) { - error("ERROR: Invalid archive\n"); + logger(LL_ERROR, "Invalid archive\n"); return -1; } @@ -355,12 +355,12 @@ int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return -1; } int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { - error("ERROR: zip_name_locate: %s\n", infile); + logger(LL_ERROR, "zip_name_locate: %s\n", infile); zip_unchange_all(zip); zip_close(zip); return -1; @@ -369,7 +369,7 @@ int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) struct zip_stat zstat; zip_stat_init(&zstat); if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index: %s\n", infile); + logger(LL_ERROR, "zip_stat_index: %s\n", infile); zip_unchange_all(zip); zip_close(zip); return -1; @@ -398,7 +398,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, int ret = 0; if (!ipsw || !infile || !outfile) { - error("ERROR: Invalid argument\n"); + logger(LL_ERROR, "Invalid argument\n"); return -1; } @@ -408,7 +408,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return -1; } @@ -416,7 +416,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, if (zindex < 0) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_name_locate: %s\n", infile); + logger(LL_ERROR, "zip_name_locate: %s\n", infile); return -1; } @@ -425,7 +425,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_stat_index: %s\n", infile); + logger(LL_ERROR, "zip_stat_index: %s\n", infile); return -1; } @@ -433,7 +433,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, if (buffer == NULL) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: Unable to allocate memory\n"); + logger(LL_ERROR, "Unable to allocate memory\n"); return -1; } @@ -441,7 +441,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, if (zfile == NULL) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_fopen_index: %s\n", infile); + logger(LL_ERROR, "zip_fopen_index: %s\n", infile); return -1; } @@ -450,13 +450,15 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, zip_fclose(zfile); zip_unchange_all(zip); zip_close(zip); - error("ERROR: Unable to open output file: %s\n", outfile); + logger(LL_ERROR, "Unable to open output file: %s\n", outfile); return -1; } + if (print_progress) { + register_progress('IPSW', "Extracting"); + } uint64_t i, bytes = 0; int count, size = BUFSIZE; - double progress; for(i = zstat.size; i > 0; i -= count) { if (cancel_flag) { break; @@ -468,23 +470,26 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, int zep = 0; int sep = 0; zip_file_error_get(zfile, &zep, &sep); - error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); + logger(LL_ERROR, "zip_fread: %s %d %d\n", infile, zep, sep); ret = -1; break; } if (fwrite(buffer, 1, count, fd) != count) { - error("ERROR: Writing to '%s' failed: %s\n", outfile, strerror(errno)); + logger(LL_ERROR, "Writing to '%s' failed: %s\n", outfile, strerror(errno)); ret = -1; break; } bytes += size; if (print_progress) { - progress = ((double)bytes / (double)zstat.size) * 100.0; - print_progress_bar(progress); + double progress = ((double)bytes / (double)zstat.size); + set_progress('IPSW', progress); } } free(buffer); + if (print_progress) { + finalize_progress('IPSW'); + } fclose(fd); zip_fclose(zfile); zip_unchange_all(zip); @@ -498,7 +503,7 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, goto leave; } if (!realpath(filepath, actual_filepath)) { - error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno)); + logger(LL_ERROR, "realpath failed on %s: %s\n", filepath, strerror(errno)); ret = -1; goto leave; } else { @@ -512,21 +517,21 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, } FILE *fi = fopen(actual_filepath, "rb"); if (!fi) { - error("ERROR: fopen: %s: %s\n", actual_filepath, strerror(errno)); + logger(LL_ERROR, "fopen: %s: %s\n", actual_filepath, strerror(errno)); ret = -1; goto leave; } struct stat fst; if (fstat(fileno(fi), &fst) != 0) { fclose(fi); - error("ERROR: fstat: %s: %s\n", actual_filepath, strerror(errno)); + logger(LL_ERROR, "fstat: %s: %s\n", actual_filepath, strerror(errno)); ret = -1; goto leave; } FILE *fo = fopen(actual_outfile, "wb"); if (!fo) { fclose(fi); - error("ERROR: fopen: %s: %s\n", actual_outfile, strerror(errno)); + logger(LL_ERROR, "fopen: %s: %s\n", actual_outfile, strerror(errno)); ret = -1; goto leave; } @@ -534,34 +539,39 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, if (buffer == NULL) { fclose(fi); fclose(fo); - error("ERROR: Unable to allocate memory\n"); + logger(LL_ERROR, "Unable to allocate memory\n"); ret = -1; goto leave;; } + if (print_progress) { + register_progress('IPSW', "Extracting"); + } uint64_t bytes = 0; - double progress; while (!feof(fi)) { if (cancel_flag) { break; } ssize_t r = fread(buffer, 1, BUFSIZE, fi); if (r < 0) { - error("ERROR: fread failed: %s\n", strerror(errno)); + logger(LL_ERROR, "fread failed: %s\n", strerror(errno)); ret = -1; break; } if (fwrite(buffer, 1, r, fo) != r) { - error("ERROR: Writing to '%s' failed: %s\n", actual_outfile, strerror(errno)); + logger(LL_ERROR, "Writing to '%s' failed: %s\n", actual_outfile, strerror(errno)); ret = -1; break; } bytes += r; if (print_progress) { - progress = ((double)bytes / (double)fst.st_size) * 100.0; - print_progress_bar(progress); + double progress = ((double)bytes / (double)fst.st_size); + set_progress('IPSW', progress); } } + if (print_progress) { + finalize_progress('IPSW'); + } free(buffer); fclose(fi); @@ -592,7 +602,7 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return 0; } int zindex = zip_name_locate(zip, infile, 0); @@ -618,7 +628,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha size_t size = 0; unsigned char* buffer = NULL; if (ipsw == NULL) { - error("ERROR: Invalid archive\n"); + logger(LL_ERROR, "Invalid archive\n"); return -1; } @@ -626,7 +636,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return -1; } @@ -634,7 +644,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha if (zindex < 0) { zip_unchange_all(zip); zip_close(zip); - debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); + logger(LL_DEBUG, "zip_name_locate: '%s' not found in archive.\n", infile); return -1; } @@ -643,7 +653,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_stat_index: %s\n", infile); + logger(LL_ERROR, "zip_stat_index: %s\n", infile); return -1; } @@ -651,14 +661,14 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha if (zfile == NULL) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_fopen_index: %s\n", infile); + logger(LL_ERROR, "zip_fopen_index: %s\n", infile); return -1; } size = zstat.size; buffer = (unsigned char*) malloc(size+1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); zip_fclose(zfile); zip_unchange_all(zip); zip_close(zip); @@ -673,11 +683,11 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha int zep = 0; int sep = 0; zip_file_error_get(zfile, &zep, &sep); - error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); + logger(LL_ERROR, "zip_fread: %s %d %d\n", infile, zep, sep); free(buffer); return -1; } else if (zr != size) { - error("ERROR: zip_fread: %s got only %lld of %zu\n", infile, zr, size); + logger(LL_ERROR, "zip_fread: %s got only %lld of %zu\n", infile, zr, size); free(buffer); return -1; } @@ -691,14 +701,14 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha #else if (lstat(filepath, &fst) != 0) { #endif - error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); return -1; } size = fst.st_size; buffer = (unsigned char*)malloc(size+1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); free(filepath); return -1; } @@ -706,7 +716,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha #ifndef WIN32 if (S_ISLNK(fst.st_mode)) { if (readlink(filepath, (char*)buffer, size) < 0) { - error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); return -1; @@ -715,14 +725,14 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha #endif FILE *f = fopen(filepath, "rb"); if (!f) { - error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); return -2; } if (fread(buffer, 1, size, f) != size) { fclose(f); - error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); return -1; @@ -748,7 +758,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip size_t total_size = 0; if (ipsw == NULL) { - error("ERROR: Invalid archive\n"); + logger(LL_ERROR, "Invalid archive\n"); return -1; } @@ -756,7 +766,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return -1; } @@ -764,7 +774,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (zindex < 0) { zip_unchange_all(zip); zip_close(zip); - debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); + logger(LL_DEBUG, "zip_name_locate: '%s' not found in archive.\n", infile); return -1; } @@ -773,7 +783,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_stat_index: %s\n", infile); + logger(LL_ERROR, "zip_stat_index: %s\n", infile); return -1; } @@ -781,7 +791,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (zfile == NULL) { zip_unchange_all(zip); zip_close(zip); - error("ERROR: zip_fopen_index: %s\n", infile); + logger(LL_ERROR, "zip_fopen_index: %s\n", infile); return -1; } @@ -791,7 +801,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip zip_fclose(zfile); zip_unchange_all(zip); zip_close(zip); - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } @@ -800,14 +810,14 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (size > blocksize) size = blocksize; zip_int64_t zr = zip_fread(zfile, buffer, size); if (zr < 0) { - error("ERROR: %s: zip_fread: %s\n", __func__, infile); + logger(LL_ERROR, "%s: zip_fread: %s\n", __func__, infile); break; } else if (zr == 0) { // EOF break; } if (send_callback(ctx, buffer, zr, done, total_size) < 0) { - error("ERROR: %s: send failed\n", __func__); + logger(LL_ERROR, "%s: send failed\n", __func__); break; } done += zr; @@ -824,14 +834,14 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip #else if (lstat(filepath, &fst) != 0) { #endif - error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); return -1; } total_size = fst.st_size; buffer = (unsigned char*)malloc(blocksize); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); free(filepath); return -1; } @@ -840,7 +850,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (S_ISLNK(fst.st_mode)) { ssize_t rl = readlink(filepath, (char*)buffer, (total_size > blocksize) ? blocksize : total_size); if (rl < 0) { - error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); return -1; @@ -850,7 +860,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip #endif FILE *f = fopen(filepath, "rb"); if (!f) { - error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); return -2; @@ -861,11 +871,11 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip if (size > blocksize) size = blocksize; size_t fr = fread(buffer, 1, size, f); if (fr != size) { - error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); + logger(LL_ERROR, "%s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); break; } if (send_callback(ctx, buffer, fr, done, total_size) < 0) { - error("ERROR: %s: send failed\n", __func__); + logger(LL_ERROR, "%s: send failed\n", __func__); break; } done += fr; @@ -879,7 +889,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip } if (done < total_size) { - error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); + logger(LL_ERROR, "%s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); return -1; } @@ -941,7 +951,7 @@ static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ips DIR *dirp = opendir(base); if (!dirp) { - error("ERROR: failed to open directory %s\n", base); + logger(LL_ERROR, "failed to open directory %s\n", base); free(base); return -1; } @@ -968,7 +978,7 @@ static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ips ret = lstat(fpath, &st); #endif if (ret != 0) { - error("ERROR: %s: stat failed for %s: %s\n", __func__, fpath, strerror(errno)); + logger(LL_ERROR, "%s: stat failed for %s: %s\n", __func__, fpath, strerror(errno)); free(fpath); free(subpath); break; @@ -993,7 +1003,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) int ret = 0; if (ipsw == NULL) { - error("ERROR: Invalid IPSW archive\n"); + logger(LL_ERROR, "Invalid IPSW archive\n"); return -1; } @@ -1001,13 +1011,13 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return -1; } int64_t entries = zip_get_num_entries(zip, 0); if (entries < 0) { - error("ERROR: zip_get_num_entries failed\n"); + logger(LL_ERROR, "zip_get_num_entries failed\n"); return -1; } @@ -1016,7 +1026,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) zip_stat_init(&stat); if (zip_stat_index(zip, index, 0, &stat) < 0) { - error("ERROR: zip_stat_index failed for %s\n", stat.name); + logger(LL_ERROR, "zip_stat_index failed for %s\n", stat.name); ret = -1; continue; } @@ -1024,12 +1034,12 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) uint8_t opsys; uint32_t attributes; if (zip_file_get_external_attributes(zip, index, 0, &opsys, &attributes) < 0) { - error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name); + logger(LL_ERROR, "zip_file_get_external_attributes failed for %s\n", stat.name); ret = -1; continue; } if (opsys != ZIP_OPSYS_UNIX) { - error("ERROR: File %s does not have UNIX attributes\n", stat.name); + logger(LL_ERROR, "File %s does not have UNIX attributes\n", stat.name); ret = -1; continue; } @@ -1079,32 +1089,32 @@ int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares) snprintf(url, sizeof(url), "https://api.ipsw.me/v4/device/%s", product); if (download_to_buffer(url, &jdata, &jsize) < 0) { - error("ERROR: Download from %s failed.\n", url); + logger(LL_ERROR, "Download from %s failed.\n", url); return -1; } plist_from_json(jdata, jsize, &dict); free(jdata); if (!dict || plist_get_node_type(dict) != PLIST_DICT) { - error("ERROR: Failed to parse json data.\n"); + logger(LL_ERROR, "Failed to parse json data.\n"); plist_free(dict); return -1; } node = plist_dict_get_item(dict, "identifier"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unexpected json data returned - missing 'identifier'\n"); + logger(LL_ERROR, "Unexpected json data returned - missing 'identifier'\n"); plist_free(dict); return -1; } product_type = plist_get_string_ptr(node, NULL); if (!product_type || strcmp(product_type, product) != 0) { - error("ERROR: Unexpected json data returned - failed to read identifier\n"); + logger(LL_ERROR, "Unexpected json data returned - failed to read identifier\n"); plist_free(dict); return -1; } fws = plist_dict_get_item(dict, "firmwares"); if (!fws || plist_get_node_type(fws) != PLIST_ARRAY) { - error("ERROR: Unexpected json data returned - missing 'firmwares'\n"); + logger(LL_ERROR, "Unexpected json data returned - missing 'firmwares'\n"); plist_free(dict); return -1; } @@ -1136,14 +1146,14 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, plist_t n1 = plist_dict_get_item(version_data, "MobileDeviceSoftwareVersionsByVersion"); if (!n1) { - error("%s: ERROR: Can't find MobileDeviceSoftwareVersionsByVersion dict in version data\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't find MobileDeviceSoftwareVersionsByVersion dict in version data\n", __func__); return -1; } plist_dict_iter iter = NULL; plist_dict_new_iter(n1, &iter); if (!iter) { - error("%s: ERROR: Can't get dict iter\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't get dict iter\n", __func__); return -1; } char* key = NULL; @@ -1164,7 +1174,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, free(iter); if (major == 0) { - error("%s: ERROR: Can't find major version?!\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't find major version?!\n", __func__); return -1; } @@ -1172,13 +1182,13 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, snprintf(majstr, sizeof(majstr), "%"PRIu64, (uint64_t)major); n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore"); if (!n1) { - error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); return -1; } plist_t n2 = plist_dict_get_item(n1, "BuildVersion"); if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { - error("%s: ERROR: Can't get build version node?!\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't get build version node?!\n", __func__); return -1; } @@ -1187,7 +1197,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); if (!n1) { - error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval); + logger(LL_ERROR, "%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval); free(strval); return -1; } @@ -1203,7 +1213,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, free(strval); strval = NULL; if (!n1 || (plist_dict_get_size(n1) == 0)) { - error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product); + logger(LL_ERROR, "%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product); return -1; } } @@ -1221,7 +1231,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, n2 = plist_access_path(n1, 2, "Restore", "FirmwareURL"); if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { - error("%s: ERROR: Can't get FirmwareURL node\n", __func__); + logger(LL_ERROR, "%s: ERROR: Can't get FirmwareURL node\n", __func__); return -1; } @@ -1254,13 +1264,23 @@ static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) { unsigned char tsha1[20]; char buf[8192]; + size_t total = 0; + struct stat fst; + int lastprog = 0; if (!f) return 0; sha1_context sha1ctx; sha1_init(&sha1ctx); rewind(f); + fstat(fileno(f), &fst); while (!feof(f)) { size_t sz = fread(buf, 1, 8192, f); sha1_update(&sha1ctx, buf, sz); + total += sz; + double p = (double)total / (double)fst.st_size; + if ((int)(p*100) > lastprog) { + set_progress('SHA1', p); + lastprog = (int)(p*100); + } } sha1_final(&sha1ctx, tsha1); return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; @@ -1270,7 +1290,7 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, { char* fwfn = strrchr(fwurl, '/'); if (!fwfn) { - error("ERROR: can't get local filename for firmware ipsw\n"); + logger(LL_ERROR, "can't get local filename for firmware ipsw\n"); return -2; } fwfn++; @@ -1288,7 +1308,7 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, lock_info_t lockinfo; if (lock_file(fwlock, &lockinfo) != 0) { - error("WARNING: Could not lock file '%s'\n", fwlock); + logger(LL_WARNING, "Could not lock file '%s'\n", fwlock); } int need_dl = 0; @@ -1296,13 +1316,15 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, FILE* f = fopen(fwlfn, "rb"); if (f) { if (memcmp(zsha1, isha1, 20) != 0) { - info("Verifying '%s'...\n", fwlfn); + logger(LL_INFO, "Verifying '%s'...\n", fwlfn); + register_progress('SHA1', "Verifying"); if (sha1_verify_fp(f, isha1)) { - info("Checksum matches.\n"); + logger(LL_INFO, "Checksum matches.\n"); } else { - info("Checksum does not match.\n"); + logger(LL_INFO, "Checksum does not match.\n"); need_dl = 1; } + finalize_progress('SHA1'); } fclose(f); } else { @@ -1312,29 +1334,35 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, int res = 0; if (need_dl) { if (strncmp(fwurl, "protected:", 10) == 0) { - error("ERROR: Can't download '%s' because it needs a purchase.\n", fwfn); + logger(LL_ERROR, "Can't download '%s' because it needs a purchase.\n", fwfn); res = -3; } else { remove(fwlfn); - info("Downloading firmware (%s)\n", fwurl); + logger(LL_INFO, "Downloading firmware (%s)\n", fwurl); download_to_file(fwurl, fwlfn, 1); + if (global_quit_flag > 0) { + logger(LL_NOTICE, "Download aborted by user\n"); + return -1; + } if (memcmp(isha1, zsha1, 20) != 0) { - info("\nVerifying '%s'...\n", fwlfn); + logger(LL_INFO, "Verifying '%s'...\n", fwlfn); FILE* f = fopen(fwlfn, "rb"); if (f) { + register_progress('SHA1', "Verifying"); if (sha1_verify_fp(f, isha1)) { - info("Checksum matches.\n"); + logger(LL_INFO, "Checksum matches.\n"); } else { - error("ERROR: File download failed (checksum mismatch).\n"); + logger(LL_ERROR, "File download failed (checksum mismatch).\n"); res = -4; } + finalize_progress('SHA1'); fclose(f); // make sure to remove invalid files if (res < 0) remove(fwlfn); } else { - error("ERROR: Can't open '%s' for checksum verification\n", fwlfn); + logger(LL_ERROR, "Can't open '%s' for checksum verification\n", fwlfn); res = -5; } } @@ -1345,7 +1373,7 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, } if (unlock_file(&lockinfo) != 0) { - error("WARNING: Could not unlock file '%s'\n", fwlock); + logger(LL_WARNING, "Could not unlock file '%s'\n", fwlock); } return res; @@ -1359,17 +1387,17 @@ int ipsw_download_latest_fw(plist_t version_data, const char* product, const cha *ipswfile = NULL; if ((ipsw_get_latest_fw(version_data, product, &fwurl, isha1) < 0) || !fwurl) { - error("ERROR: can't get URL for latest firmware\n"); + logger(LL_ERROR, "can't get URL for latest firmware\n"); return -1; } char* fwfn = strrchr(fwurl, '/'); if (!fwfn) { - error("ERROR: can't get local filename for firmware ipsw\n"); + logger(LL_ERROR, "can't get local filename for firmware ipsw\n"); return -2; } fwfn++; - info("Latest firmware is %s\n", fwfn); + logger(LL_INFO, "Latest firmware is %s\n", fwfn); int res = ipsw_download_fw(fwurl, isha1, todir, ipswfile); @@ -1390,14 +1418,14 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) int err = 0; struct zip *zip = zip_open(ipsw->path, 0, &err); if (zip == NULL) { - error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + logger(LL_ERROR, "zip_open: %s: %d\n", ipsw->path, err); return NULL; } zip_stat_t zst; zip_int64_t zindex = zip_name_locate(zip, path, 0); if (zindex < 0) { - error("ERROR: zip_name_locate: %s not found\n", path); + logger(LL_ERROR, "zip_name_locate: %s not found\n", path); zip_unchange_all(zip); zip_close(zip); free(handle); @@ -1405,7 +1433,7 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) } handle->zfile = zip_fopen_index(zip, zindex, 0); if (handle->zfile == NULL) { - error("ERROR: zip_fopen_index: %s could not be opened\n", path); + logger(LL_ERROR, "zip_fopen_index: %s could not be opened\n", path); zip_unchange_all(zip); zip_close(zip); free(handle); @@ -1422,7 +1450,7 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) handle->file = fopen(filepath, "rb"); free(filepath); if (!handle->file) { - error("ERROR: fopen: %s could not be opened\n", path); + logger(LL_ERROR, "fopen: %s could not be opened\n", path); free(handle); return NULL; } @@ -1461,7 +1489,7 @@ int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size) } else if (handle && handle->file) { return fread(buffer, 1, size, handle->file); } else { - error("ERROR: %s: Invalid file handle\n", __func__); + logger(LL_ERROR, "%s: Invalid file handle\n", __func__); return -1; } } @@ -1480,7 +1508,7 @@ int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence) return fseeko(handle->file, offset, whence); #endif } else { - error("ERROR: %s: Invalid file handle\n", __func__); + logger(LL_ERROR, "%s: Invalid file handle\n", __func__); return -1; } } @@ -1496,7 +1524,7 @@ int64_t ipsw_file_tell(ipsw_file_handle_t handle) return ftello(handle->file); #endif } else { - error("ERROR: %s: Invalid file handle\n", __func__); + logger(LL_ERROR, "%s: Invalid file handle\n", __func__); return -1; } } diff --git a/src/limera1n.c b/src/limera1n.c index da4a7d5d..f2052871 100644 --- a/src/limera1n.c +++ b/src/limera1n.c @@ -78,7 +78,7 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient) stack_address = 0x84033F98; shellcode_address = 0x84023001; } else { - error("Unsupported ChipID 0x%04x. Can't exploit with limera1n.\n", device->chip_id); + logger(LL_ERROR, "Unsupported ChipID 0x%04x. Can't exploit with limera1n.\n", device->chip_id); return -1; } @@ -87,10 +87,10 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient) irecv_client_t client = *pclient; - debug("Resetting device counters\n"); + logger(LL_DEBUG, "Resetting device counters\n"); err = irecv_reset_counters(client); if (err != IRECV_E_SUCCESS) { - error("%s\n", irecv_strerror(err)); + logger(LL_ERROR, "%s\n", irecv_strerror(err)); return -1; } @@ -103,7 +103,7 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient) heap[3] = stack_address; } - debug("Sending chunk headers\n"); + logger(LL_DEBUG, "Sending chunk headers\n"); irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000); memset(buf, 0xCC, 0x800); @@ -111,32 +111,32 @@ int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient) irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000); } - debug("Sending exploit payload\n"); + logger(LL_DEBUG, "Sending exploit payload\n"); irecv_usb_control_transfer(client, 0x21, 1, 0, 0, shellcode, 0x800, 1000); - debug("Sending fake data\n"); + logger(LL_DEBUG, "Sending fake data\n"); memset(buf, 0xBB, 0x800); irecv_usb_control_transfer(client, 0xA1, 1, 0, 0, buf, 0x800, 1000); irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 10); - //debug("Executing exploit\n"); + //logger(LL_DEBUG, "Executing exploit\n"); irecv_usb_control_transfer(client, 0x21, 2, 0, 0, buf, 0, 1000); irecv_reset(client); irecv_finish_transfer(client); - debug("Exploit sent\n"); + logger(LL_DEBUG, "Exploit sent\n"); - debug("Reconnecting to device\n"); + logger(LL_DEBUG, "Reconnecting to device\n"); *pclient = irecv_reconnect(client, 7); if (*pclient == NULL) { - error("Unable to reconnect\n"); + logger(LL_ERROR, "Unable to reconnect\n"); return -1; } irecv_get_mode((*pclient), &mode); if (mode != IRECV_K_DFU_MODE) { - error("Device reconnected in non-DFU mode\n"); + logger(LL_ERROR, "Device reconnected in non-DFU mode\n"); return -1; } diff --git a/src/locking.c b/src/locking.c index dbbbd7c8..05f0e4f6 100644 --- a/src/locking.c +++ b/src/locking.c @@ -35,7 +35,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo) #ifdef WIN32 lockinfo->fp = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (lockinfo->fp == INVALID_HANDLE_VALUE) { - debug("ERROR: could not open or create lockfile '%s'\n", filename); + logger(LL_DEBUG, "ERROR: could not open or create lockfile '%s'\n", filename); return -1; } @@ -43,7 +43,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo) lockinfo->ldata.OffsetHigh = 0; if (!LockFileEx(lockinfo->fp, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &lockinfo->ldata)) { - debug("ERROR: can't lock file, error %d\n", GetLastError()); + logger(LL_DEBUG, "ERROR: can't lock file, error %d\n", GetLastError()); CloseHandle(lockinfo->fp); lockinfo->fp = INVALID_HANDLE_VALUE; return -1; @@ -52,7 +52,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo) lockinfo->fp = fopen(filename, "a+"); if (!lockinfo->fp) { - debug("ERROR: could not open or create lockfile '%s'\n", filename); + logger(LL_DEBUG, "ERROR: could not open or create lockfile '%s'\n", filename); return -1; } @@ -62,7 +62,7 @@ int lock_file(const char* filename, lock_info_t* lockinfo) lockinfo->ldata.l_len = 0; if (fcntl(fileno(lockinfo->fp), F_SETLKW, &lockinfo->ldata) < 0) { - debug("ERROR: can't lock file, error %d\n", errno); + logger(LL_DEBUG, "ERROR: can't lock file, error %d\n", errno); fclose(lockinfo->fp); lockinfo->fp = NULL; return -1; @@ -85,7 +85,7 @@ int unlock_file(lock_info_t* lockinfo) lockinfo->ldata.OffsetHigh = 0; if (!UnlockFileEx(lockinfo->fp, 0, 1, 0, &lockinfo->ldata)) { - debug("ERROR: can't unlock file, error %d\n", GetLastError()); + logger(LL_DEBUG, "ERROR: can't unlock file, error %d\n", GetLastError()); CloseHandle(lockinfo->fp); lockinfo->fp = INVALID_HANDLE_VALUE; return -1; @@ -103,7 +103,7 @@ int unlock_file(lock_info_t* lockinfo) lockinfo->ldata.l_len = 0; if (fcntl(fileno(lockinfo->fp), F_SETLK, &lockinfo->ldata) < 0) { - debug("ERROR: can't unlock file, error %d\n", errno); + logger(LL_DEBUG, "ERROR: can't unlock file, error %d\n", errno); fclose(lockinfo->fp); lockinfo->fp = NULL; return -1; diff --git a/src/log.c b/src/log.c new file mode 100644 index 00000000..e6a3c8a3 --- /dev/null +++ b/src/log.c @@ -0,0 +1,210 @@ +/* + * log.c + * + * Copyright (c) 2024 Nikias Bassen. 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#include + +#include +#include + +#include "log.h" + +static int stderr_enabled = 1; + +int log_level = LL_VERBOSE; +int print_level = LL_INFO; + +static void (*print_func)(int level, const char* fmt, va_list) = NULL; + +const char *_level_label[6] = { + " ", + "", + " ", + " ", + "", + " " +}; + +// Reference: https://stackoverflow.com/a/2390626/1806760 +// Initializer/finalizer sample for MSVC and GCC/Clang. +// 2010-2016 Joe Lowe. Released into the public domain. + +#ifdef __cplusplus + #define INITIALIZER(f) \ + static void f(void); \ + struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \ + static void f(void) +#elif defined(_MSC_VER) + #pragma section(".CRT$XCU",read) + #define INITIALIZER2_(f,p) \ + static void f(void); \ + __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ + __pragma(comment(linker,"/include:" p #f "_")) \ + static void f(void) + #ifdef _WIN64 + #define INITIALIZER(f) INITIALIZER2_(f,"") + #else + #define INITIALIZER(f) INITIALIZER2_(f,"_") + #endif +#else + #define INITIALIZER(f) \ + static void f(void) __attribute__((__constructor__)); \ + static void f(void) +#endif + +static mutex_t log_mutex; + +static void logger_deinit(void) +{ + mutex_destroy(&log_mutex); +} + +INITIALIZER(logger_init) +{ + mutex_init(&log_mutex); + atexit(logger_deinit); +} + +void logger(enum loglevel level, const char *fmt, ...) +{ + va_list ap; + char *fs; + + if (level > log_level) + return; + + mutex_lock(&log_mutex); + + size_t fslen = 24 + strlen(fmt); + fs = malloc(fslen); + +#ifdef _WIN32 + SYSTEMTIME lt; + GetLocalTime(<); + snprintf(fs, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); +#else + struct timeval ts; + struct tm tp_; + struct tm *tp; + + gettimeofday(&ts, NULL); +#ifdef HAVE_LOCALTIME_R + tp = localtime_r(&ts.tv_sec, &tp_); +#else + tp = localtime(&ts.tv_sec); +#endif + + strftime(fs, 9, "%H:%M:%S", tp); + snprintf(fs+8, fslen-8, ".%03d %s %s", (int)(ts.tv_usec / 1000), _level_label[level], fmt); +#endif + + va_start(ap, fmt); + if (print_func) { + if (stderr_enabled) { + vfprintf(stderr, fs, ap); + fflush(stderr); + } + if (level <= print_level) { + // skip the timestamp and log level string + print_func(level, fs+23, ap); + } + } else { + vprintf(fs, ap); + } + + va_end(ap); + + free(fs); + + mutex_unlock(&log_mutex); +} + +void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len) +{ + char *fs; + + if (level > log_level) + return; + + mutex_lock(&log_mutex); + + fs = (char*)malloc(len * 3 + 1); + for (unsigned int i = 0; i < len; i++) { + snprintf(fs + i*3, 3, "%02x%c", ((unsigned char*)buf)[i], (i < len-1) ? ' ' : '\n'); + } + if (print_func) { + if (stderr_enabled) { + fprintf(stderr, "%s", fs); + fflush(stderr); + } + if (level <= print_level) { + print_func(level, "%s", fs); + } + } else { + printf("%s", fs); + } + free(fs); + + mutex_unlock(&log_mutex); +} + +void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable) +{ + if (level > log_level) + return; + mutex_lock(&log_mutex); + plist_write_to_stream(plist, stderr_enabled ? stderr : stdout, (human_readable) ? PLIST_FORMAT_PRINT : PLIST_FORMAT_XML, PLIST_OPT_NONE); + mutex_unlock(&log_mutex); +} + +int logger_set_logfile(const char* path) +{ + if (!path || !strcasecmp(path, "NULL") || !strcasecmp(path, "NONE")) { + stderr_enabled = 0; + return 0; + } + stderr_enabled = 1; + if (strcmp(path, "-")) { + FILE* newf = freopen(path, "w", stderr); + if (!newf) { + logger(LL_ERROR, "Could not open logfile '%s': %s\n", path, strerror(errno)); + return -1; + } + } + return 0; +} + +void logger_set_print_func(void (*func)(int, const char*, va_list)) +{ + print_func = func; +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 00000000..80642c0e --- /dev/null +++ b/src/log.h @@ -0,0 +1,41 @@ +/* + * log.h + * + * Copyright (c) 2024 Nikias Bassen. 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 LOG_H +#define LOG_H + +enum loglevel { + LL_ERROR = 0, + LL_WARNING, + LL_NOTICE, + LL_INFO, + LL_VERBOSE, + LL_DEBUG +}; + +extern int log_level; + +void logger(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +int logger_set_logfile(const char* path); +void logger_set_print_func(void (*func)(int level, const char*, va_list)); +void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len); +void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable); + +#endif diff --git a/src/mbn.c b/src/mbn.c index 101e29f9..b7d3527e 100644 --- a/src/mbn.c +++ b/src/mbn.c @@ -54,10 +54,10 @@ mbn_file* mbn_parse(unsigned char* data, unsigned int size) // we cheat here since we don't parse the actual ELF file mbn->parsed_size = mbn->size; } else { - debug("DEBUG: Unknown file format passed to %s\n", __func__); + logger(LL_DEBUG, "Unknown file format passed to %s\n", __func__); } if (mbn->parsed_size != mbn->size) { - info("WARNING: size mismatch when parsing MBN file. Continuing anyway.\n"); + logger(LL_WARNING, "Size mismatch when parsing MBN file. Continuing anyway.\n"); } return mbn; } @@ -75,12 +75,12 @@ void mbn_free(mbn_file* mbn) int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* sigdata, unsigned int siglen) { if (!mbn) { - error("ERROR: %s: no data\n", __func__); + logger(LL_ERROR, "%s: no data\n", __func__); return -1; } mbn->parsed_sig_offset = mbn->size - siglen; if ((mbn->parsed_sig_offset + siglen) > mbn->size) { - error("ERROR: %s: signature is larger than mbn file size\n", __func__); + logger(LL_ERROR, "%s: signature is larger than mbn file size\n", __func__); return -1; } diff --git a/src/normal.c b/src/normal.c index 9e460803..7d689e1d 100644 --- a/src/normal.c +++ b/src/normal.c @@ -49,12 +49,12 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t* if (client->udid) { device_error = idevice_new(&dev, client->udid); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, client->udid); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, client->udid); return -1; } if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) { - error("ERROR: %s: can't connect to lockdownd on device with UDID %s\n", __func__, client->udid); + logger(LL_ERROR, "%s: can't connect to lockdownd on device with UDID %s\n", __func__, client->udid); return -1; } @@ -94,12 +94,12 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t* } device_error = idevice_new(&dev, devices[j]); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, devices[j]); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, devices[j]); continue; } if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) { - error("ERROR: %s: can't connect to lockdownd on device with UDID %s\n", __func__, devices[j]); + logger(LL_ERROR, "%s: can't connect to lockdownd on device with UDID %s\n", __func__, devices[j]); continue; } @@ -170,10 +170,7 @@ irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client) lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); if (!(client->flags & FLAG_ERASE) && lockdown_error == LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING) { - info("*** Device is not paired with this computer. Please trust this computer on the device to continue. ***\n"); - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(0); - } + show_banner("Device is not paired with this computer. Please trust this computer on the device to continue.\n"); while (!(client->flags & FLAG_QUIT)) { lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); if (lockdown_error != LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING) { @@ -181,9 +178,7 @@ irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client) } sleep(1); } - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(1); - } + hide_banner(); if (client->flags & FLAG_QUIT) { return NULL; } @@ -223,13 +218,13 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) device_error = idevice_new(&device, client->udid); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to find device\n"); + logger(LL_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: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); + logger(LL_ERROR, "Unable to connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); idevice_free(device); return -1; } @@ -239,14 +234,14 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) lockdownd_client_free(lockdown); lockdown = NULL; if (LOCKDOWN_E_SUCCESS != (lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"))) { - error("ERROR: Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); + logger(LL_ERROR, "Could not connect to lockdownd: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); 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: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); + logger(LL_ERROR, "Unable to place device in recovery mode: %s (%d)\n", lockdownd_strerror(lockdown_error), lockdown_error); lockdownd_client_free(lockdown); idevice_free(device); return -1; @@ -258,25 +253,25 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) device = NULL; mutex_lock(&client->device_event_mutex); - debug("DEBUG: Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode == MODE_NORMAL || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Failed to place device in recovery mode\n"); + logger(LL_ERROR, "Failed to place device in recovery mode\n"); return -1; } - debug("DEBUG: Waiting for device to connect in recovery mode...\n"); + logger(LL_DEBUG, "Waiting for device to connect in recovery mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Failed to enter recovery mode\n"); + logger(LL_ERROR, "Failed to enter recovery mode\n"); return -1; } mutex_unlock(&client->device_event_mutex); if (recovery_client_new(client) < 0) { - error("ERROR: Unable to enter recovery mode\n"); + logger(LL_ERROR, "Unable to enter recovery mode\n"); return -1; } @@ -296,20 +291,20 @@ plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const device_error = idevice_new(&device, client->udid); if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to connect to device?!\n"); + logger(LL_ERROR, "Unable to connect to device?!\n"); return NULL; } lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("ERROR: Unable to connect to lockdownd\n"); + logger(LL_ERROR, "Unable to connect to lockdownd\n"); idevice_free(device); return NULL; } lockdown_error = lockdownd_get_value(lockdown, domain, key, &node); if (lockdown_error != LOCKDOWN_E_SUCCESS) { - debug("ERROR: Unable to get %s-%s from lockdownd\n", domain, key); + logger(LL_DEBUG, "ERROR: Unable to get %s-%s from lockdownd\n", domain, key); lockdownd_client_free(lockdown); idevice_free(device); return NULL; @@ -328,7 +323,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const plist_t nonce_node = normal_get_lockdown_value(client, NULL, key); if (!nonce_node || plist_get_node_type(nonce_node) != PLIST_DATA) { - error("Unable to get %s\n", key); + logger(LL_ERROR, "Unable to get %s\n", key); return -1; } @@ -389,12 +384,12 @@ int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, p if (has_telephony_capability) { node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo"); if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to get FirmwarePreflightInfo\n"); + logger(LL_ERROR, "Unable to get FirmwarePreflightInfo\n"); return -1; } *preflight_info = node; } else { - debug("DEBUG: Device does not have TelephonyCapability, no FirmwarePreflightInfo\n"); + logger(LL_DEBUG, "Device does not have TelephonyCapability, no FirmwarePreflightInfo\n"); *preflight_info = NULL; } @@ -407,7 +402,7 @@ int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *p if (PLIST_IS_DICT(node)) { *preflight_info = node; } else { - debug("DEBUG: No PreflightInfo available.\n"); + logger(LL_DEBUG, "No PreflightInfo available.\n"); *preflight_info = NULL; } return 0; @@ -427,20 +422,25 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ device_err = idevice_new(&device, client->udid); if (device_err != IDEVICE_E_SUCCESS) { - error("ERROR: Could not connect to device (%d)\n", device_err); + logger(LL_ERROR, "Could not connect to device (%d)\n", device_err); return -1; } lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); + if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { + logger(LL_ERROR, "Device is locked. Unlock device and try again.\n"); + idevice_free(device); + return -1; + } if (lerr != LOCKDOWN_E_SUCCESS) { - error("ERROR: Could not connect to lockdownd (%d)\n", lerr); + logger(LL_ERROR, "Could not connect to lockdownd (%d)\n", lerr); idevice_free(device); return -1; } lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service); if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { - info("*** Device is locked. Please unlock the device to continue. ***\n"); + show_banner("Device is locked. Please unlock the device to continue.\n"); while (1) { lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service); if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) { @@ -451,7 +451,7 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ } if (lerr != LOCKDOWN_E_SUCCESS) { - error("ERROR: Could not start preboard service (%d)\n", lerr); + logger(LL_ERROR, "Could not start preboard service (%d)\n", lerr); lockdownd_client_free(lockdown); idevice_free(device); return -1; @@ -461,14 +461,14 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ lockdownd_service_descriptor_free(service); lockdownd_client_free(lockdown); if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: Could not connect to preboard service (%d)\n", perr); + logger(LL_ERROR, "Could not connect to preboard service (%d)\n", perr); idevice_free(device); return -1; } perr = preboard_create_stashbag(preboard, manifest, NULL, NULL); if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: Failed to trigger stashbag creation (%d)\n", perr); + logger(LL_ERROR, "Failed to trigger stashbag creation (%d)\n", perr); preboard_client_free(preboard); idevice_free(device); return -1; @@ -481,25 +481,25 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ if (perr == PREBOARD_E_TIMEOUT) { continue; } else if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: could not receive from preboard service\n"); + logger(LL_ERROR, "could not receive from preboard service\n"); break; } else { plist_t node; if (plist_dict_get_bool(pl, "Skip")) { result = 0; - info("Device does not require stashbag.\n"); + logger(LL_INFO, "Device does not require stashbag.\n"); break; } if (plist_dict_get_bool(pl, "ShowDialog")) { - info("Device requires stashbag.\n"); - printf("******************************************************************************\n" - "* Please enter your passcode on the device. The device will store a token *\n" - "* that will be used after restore to access the user data partition. This *\n" - "* prevents an 'Attempting data recovery' process occurring after reboot that *\n" - "* may take a long time to complete and will _also_ require the passcode. *\n" - "******************************************************************************\n"); + logger(LL_INFO, "Device requires stashbag.\n"); + show_banner( + "Please enter your passcode on the device. The device will store a token\n" + "that will be used after restore to access the user data partition. This\n" + "prevents an 'Attempting data recovery' process occurring after reboot that\n" + "may take a long time to complete and will _also_ require the passcode." + ); plist_free(pl); continue; } @@ -510,13 +510,13 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ if (node) { plist_get_string_val(node, &strval); } - error("ERROR: Could not create stashbag: %s\n", (strval) ? strval : "(Unknown error)"); + logger(LL_ERROR, "Could not create stashbag: %s\n", (strval) ? strval : "(Unknown error)"); free(strval); plist_free(pl); break; } if (plist_dict_get_bool(pl, "Timeout")) { - error("ERROR: Timeout while waiting for user to enter passcode.\n"); + logger(LL_ERROR, "Timeout while waiting for user to enter passcode.\n"); result = -2; plist_free(pl); break; @@ -525,12 +525,15 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ plist_free(pl); /* hide dialog */ result = 1; - info("Stashbag created.\n"); + logger(LL_INFO, "Stashbag created.\n"); break; } } plist_free(pl); } + + hide_banner(); + preboard_client_free(preboard); idevice_free(device); @@ -552,20 +555,20 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ device_err = idevice_new(&device, client->udid); if (device_err != IDEVICE_E_SUCCESS) { - error("ERROR: Could not connect to device (%d)\n", device_err); + logger(LL_ERROR, "Could not connect to device (%d)\n", device_err); return -1; } lerr = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); if (lerr != LOCKDOWN_E_SUCCESS) { - error("ERROR: Could not connect to lockdownd (%d)\n", lerr); + logger(LL_ERROR, "Could not connect to lockdownd (%d)\n", lerr); idevice_free(device); return -1; } lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service); if (lerr == LOCKDOWN_E_PASSWORD_PROTECTED) { - info("*** Device is locked. Please unlock the device to continue. ***\n"); + show_banner("Device is locked. Please unlock the device to continue.\n"); while (1) { lerr = lockdownd_start_service(lockdown, PREBOARD_SERVICE_NAME, &service); if (lerr != LOCKDOWN_E_PASSWORD_PROTECTED) { @@ -573,10 +576,11 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ } sleep(1); } + hide_banner(); } if (lerr != LOCKDOWN_E_SUCCESS) { - error("ERROR: Could not start preboard service (%d)\n", lerr); + logger(LL_ERROR, "Could not start preboard service (%d)\n", lerr); lockdownd_client_free(lockdown); idevice_free(device); return -1; @@ -586,14 +590,14 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ lockdownd_service_descriptor_free(service); lockdownd_client_free(lockdown); if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: Could not connect to preboard service (%d)\n", perr); + logger(LL_ERROR, "Could not connect to preboard service (%d)\n", perr); idevice_free(device); return -1; } perr = preboard_commit_stashbag(preboard, manifest, NULL, NULL); if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: Failed to trigger stashbag creation (%d)\n", perr); + logger(LL_ERROR, "Failed to trigger stashbag creation (%d)\n", perr); preboard_client_free(preboard); idevice_free(device); return -1; @@ -601,7 +605,7 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ perr = preboard_receive_with_timeout(preboard, &pl, 30000); if (perr != PREBOARD_E_SUCCESS) { - error("ERROR: could not receive from preboard service (%d)\n", perr); + logger(LL_ERROR, "could not receive from preboard service (%d)\n", perr); } else { plist_t node = plist_dict_get_item(pl, "Error"); if (node) { @@ -610,14 +614,14 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ if (node) { plist_get_string_val(node, &strval); } - error("ERROR: Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)"); + logger(LL_ERROR, "Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)"); free(strval); } else if (plist_dict_get_bool(pl, "StashbagCommitComplete")) { - info("Stashbag committed!\n"); + logger(LL_INFO, "Stashbag committed!\n"); result = 0; } else { - error("ERROR: Unexpected reply from preboard service\n"); - debug_plist(pl); + logger(LL_ERROR, "Unexpected reply from preboard service\n"); + logger_dump_plist(LL_VERBOSE, pl, 1); } plist_free(pl); } diff --git a/src/recovery.c b/src/recovery.c index c4513502..3c0027fc 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -39,14 +39,15 @@ static int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { if (event->type == IRECV_PROGRESS) { - //print_progress_bar(event->progress); + set_progress('RECV', (double)(event->progress/100.0)); } return 0; } void recovery_client_free(struct idevicerestore_client_t* client) { - if(client) { + if (client) { + finalize_progress('RECV'); if (client->recovery) { if(client->recovery->client) { irecv_close(client->recovery->client); @@ -68,7 +69,7 @@ int recovery_client_new(struct idevicerestore_client_t* client) if(client->recovery == NULL) { client->recovery = (struct recovery_client_t*)malloc(sizeof(struct recovery_client_t)); if (client->recovery == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } memset(client->recovery, 0, sizeof(struct recovery_client_t)); @@ -81,23 +82,24 @@ int recovery_client_new(struct idevicerestore_client_t* client) } if (i >= attempts) { - error("ERROR: Unable to connect to device in recovery mode\n"); + logger(LL_ERROR, "Unable to connect to device in recovery mode\n"); return -1; } sleep(4); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } if (client->srnm == NULL) { const struct irecv_device_info *device_info = irecv_get_device_info(recovery); if (device_info && device_info->srnm) { client->srnm = strdup(device_info->srnm); - info("INFO: device serial number is %s\n", client->srnm); + logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm); } } irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); + register_progress('RECV', "Uploading"); client->recovery->client = recovery; return 0; } @@ -108,13 +110,13 @@ int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable) recovery_error = irecv_send_command(client->recovery->client, (enable) ? "setenv auto-boot true" : "setenv auto-boot false"); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to set auto-boot environmental variable\n"); + logger(LL_ERROR, "Unable to set auto-boot environmental variable\n"); return -1; } recovery_error = irecv_send_command(client->recovery->client, "saveenv"); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to save environmental variable\n"); + logger(LL_ERROR, "Unable to save environmental variable\n"); return -1; } @@ -124,7 +126,7 @@ int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable) int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity) { if (client->build_major >= 8) { - client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress"); + client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1rogress"); } else if (client->macos_variant) { client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore"); } @@ -141,21 +143,21 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build if (!client->image4supported) { /* send ApTicket */ if (recovery_send_ticket(client) < 0) { - error("ERROR: Unable to send APTicket\n"); + logger(LL_ERROR, "Unable to send APTicket\n"); return -1; } } } - info("Recovery Mode Environment:\n"); + logger(LL_INFO, "Recovery Mode Environment:\n"); char* value = NULL; irecv_getenv(client->recovery->client, "build-version", &value); - info("iBoot build-version=%s\n", (value) ? value : "(unknown)"); + logger(LL_INFO, "iBoot build-version=%s\n", (value) ? value : "(unknown)"); free(value); value = NULL; irecv_getenv(client->recovery->client, "build-style", &value); - info("iBoot build-style=%s\n", (value) ? value : "(unknown)"); + logger(LL_INFO, "iBoot build-style=%s\n", (value) ? value : "(unknown)"); free(value); value = NULL; @@ -165,11 +167,11 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build boot_stage = strtoul(value, NULL, 0); } if (boot_stage > 0) { - info("iBoot boot-stage=%s\n", value); + logger(LL_INFO, "iBoot boot-stage=%s\n", value); free(value); value = NULL; if (boot_stage != 2) { - error("ERROR: iBoot should be at boot stage 2, continuing anyway...\n"); + logger(LL_ERROR, "iBoot should be at boot stage 2, continuing anyway...\n"); } } @@ -179,12 +181,12 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build radio_error = strtoul(value, NULL, 0); } if (radio_error > 0) { - info("radio-error=%s\n", value); + logger(LL_INFO, "radio-error=%s\n", value); free(value); value = NULL; irecv_getenv(client->recovery->client, "radio-error-string", &value); if (value) { - info("radio-error-string=%s\n", value); + logger(LL_INFO, "radio-error-string=%s\n", value); free(value); value = NULL; } @@ -196,32 +198,32 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build /* send logo and show it */ if (recovery_send_applelogo(client, build_identity) < 0) { - error("ERROR: Unable to send AppleLogo\n"); + logger(LL_ERROR, "Unable to send AppleLogo\n"); return -1; } /* send components loaded by iBoot */ if (recovery_send_loaded_by_iboot(client, build_identity) < 0) { - error("ERROR: Unable to send components supposed to be loaded by iBoot\n"); + logger(LL_ERROR, "Unable to send components supposed to be loaded by iBoot\n"); return -1; } /* send ramdisk and run it */ if (recovery_send_ramdisk(client, build_identity) < 0) { - error("ERROR: Unable to send Ramdisk\n"); + logger(LL_ERROR, "Unable to send Ramdisk\n"); return -1; } /* send devicetree and load it */ if (recovery_send_component_and_command(client, build_identity, "RestoreDeviceTree", "devicetree") < 0) { - error("ERROR: Unable to send DeviceTree\n"); + logger(LL_ERROR, "Unable to send DeviceTree\n"); return -1; } if (build_identity_has_component(build_identity, "RestoreSEP")) { /* send rsepfirmware and load it */ if (recovery_send_component_and_command(client, build_identity, "RestoreSEP", "rsepfirmware") < 0) { - error("ERROR: Unable to send RestoreSEP\n"); + logger(LL_ERROR, "Unable to send RestoreSEP\n"); return -1; } } @@ -229,15 +231,15 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build mutex_lock(&client->device_event_mutex); if (recovery_send_kernelcache(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to send KernelCache\n"); + logger(LL_ERROR, "Unable to send KernelCache\n"); return -1; } - debug("DEBUG: Waiting for device to disconnect...\n"); + logger(LL_DEBUG, "Waiting for device to disconnect...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 30000); if (client->mode == MODE_RECOVERY || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); - error("ERROR: Failed to place device in restore mode\n"); + logger(LL_ERROR, "Failed to place device in restore mode\n"); return -1; } mutex_unlock(&client->device_event_mutex); @@ -248,28 +250,28 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build int recovery_send_ticket(struct idevicerestore_client_t* client) { if (!client->tss) { - error("ERROR: ApTicket requested but no TSS present\n"); + logger(LL_ERROR, "ApTicket requested but no TSS present\n"); return -1; } unsigned char* data = NULL; uint32_t size = 0; if (tss_response_get_ap_ticket(client->tss, &data, &size) < 0) { - error("ERROR: Unable to get ApTicket from TSS request\n"); + logger(LL_ERROR, "Unable to get ApTicket from TSS request\n"); return -1; } - info("Sending APTicket (%d bytes)\n", size); + logger(LL_INFO, "Sending APTicket (%d bytes)\n", size); irecv_error_t err = irecv_send_buffer(client->recovery->client, data, size, 0); free(data); if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send APTicket: %s\n", irecv_strerror(err)); + logger(LL_ERROR, "Unable to send APTicket: %s\n", irecv_strerror(err)); return -1; } err = irecv_send_command(client->recovery->client, "ticket"); if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send ticket command\n"); + logger(LL_ERROR, "Unable to send ticket command\n"); return -1; } @@ -285,12 +287,12 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build_identity\n", component); } } if (!path) { if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to get path for component '%s'\n", component); + logger(LL_ERROR, "Unable to get path for component '%s'\n", component); free(path); return -1; } @@ -301,24 +303,24 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } - info("Sending %s (%d bytes)...\n", component, size); + logger(LL_INFO, "Sending %s (%d bytes)...\n", component, size); // FIXME: Did I do this right???? err = irecv_send_buffer(client->recovery->client, data, size, 0); free(data); if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); + logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err)); return -1; } @@ -330,13 +332,13 @@ int recovery_send_component_and_command(struct idevicerestore_client_t* client, irecv_error_t recovery_error = IRECV_E_SUCCESS; if (recovery_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } recovery_error = irecv_send_command(client->recovery->client, command); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", component); + logger(LL_ERROR, "Unable to execute %s\n", component); return -1; } @@ -355,13 +357,13 @@ int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_ide } if (recovery_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } recovery_error = irecv_send_command_breq(client->recovery->client, "go", 1); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", component); + logger(LL_ERROR, "Unable to execute %s\n", component); return -1; } irecv_usb_control_transfer(client->recovery->client, 0x21, 1, 0, 0, 0, 0, 5000); @@ -378,7 +380,7 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t buil return 0; } - info("Sending %s...\n", component); + logger(LL_INFO, "Sending %s...\n", component); if (client->recovery == NULL) { if (recovery_client_new(client) < 0) { return -1; @@ -386,19 +388,19 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t buil } if (recovery_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } recovery_error = irecv_send_command(client->recovery->client, "setpicture 4"); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to set %s\n", component); + logger(LL_ERROR, "Unable to set %s\n", component); return -1; } recovery_error = irecv_send_command(client->recovery->client, "bgcolor 0 0 0"); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to display %s\n", component); + logger(LL_ERROR, "Unable to display %s\n", component); return -1; } @@ -415,7 +417,7 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_ 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"); + logger(LL_ERROR, "Unable to find manifest node\n"); return -1; } @@ -439,9 +441,9 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_ uint8_t b = 0; plist_get_bool_val(iboot_node, &b); if (b) { - debug("DEBUG: %s is loaded by iBoot.\n", key); + logger(LL_DEBUG, "%s is loaded by iBoot.\n", key); if (recovery_send_component_and_command(client, build_identity, key, "firmware") < 0) { - error("ERROR: Unable to send component '%s' to device.\n", key); + logger(LL_ERROR, "Unable to send component '%s' to device.\n", key); err++; } } @@ -466,12 +468,12 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_ char* value = NULL; irecv_getenv(client->recovery->client, "ramdisk-size", &value); - info("ramdisk-size=%s\n", (value ? value : "(unknown)")); + logger(LL_INFO, "ramdisk-size=%s\n", (value ? value : "(unknown)")); free(value); value = NULL; if (recovery_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } @@ -479,7 +481,7 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_ recovery_error = irecv_send_command(client->recovery->client, "ramdisk"); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", component); + logger(LL_ERROR, "Unable to execute %s\n", component); return -1; } @@ -500,7 +502,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu } if (recovery_send_component(client, build_identity, component) < 0) { - error("ERROR: Unable to send %s to device.\n", component); + logger(LL_ERROR, "Unable to send %s to device.\n", component); return -1; } @@ -515,7 +517,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", 1); if (recovery_error != IRECV_E_SUCCESS) { - error("ERROR: Unable to execute %s\n", component); + logger(LL_ERROR, "Unable to execute %s\n", component); return -1; } diff --git a/src/restore.c b/src/restore.c index 2daeea2b..8f4e0237 100644 --- a/src/restore.c +++ b/src/restore.c @@ -127,7 +127,7 @@ int restore_client_new(struct idevicerestore_client_t* client) { struct restore_client_t* restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); if (restore == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } @@ -184,12 +184,12 @@ static int restore_idevice_new(struct idevicerestore_client_t* client, idevice_t } device_error = idevice_new(&dev, devices[j]); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, devices[j]); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, devices[j]); continue; } if (restored_client_new(dev, &restore, "idevicerestore") != RESTORE_E_SUCCESS) { - debug("%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]); + logger(LL_DEBUG, "%s: can't connect to restored on device with UDID %s\n", __func__, devices[j]); continue; } @@ -285,7 +285,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client) if (client->srnm == NULL) { if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) { plist_get_string_val(node, &client->srnm); - info("INFO: device serial number is %s\n", client->srnm); + logger(LL_INFO, "INFO: device serial number is %s\n", client->srnm); plist_free(node); node = NULL; } @@ -295,7 +295,7 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client) restored_client_free(restore); idevice_free(device); if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to get HardwareModel from restored\n"); + logger(LL_ERROR, "Unable to get HardwareModel from restored\n"); plist_free(node); return NULL; } @@ -316,7 +316,7 @@ int restore_is_image4_supported(struct idevicerestore_client_t* client) restored_error_t restore_error = RESTORE_E_SUCCESS; if (idevice_new(&device, client->udid) != IDEVICE_E_SUCCESS) { - error("ERROR: Could not connect to device %s\n", client->udid); + logger(LL_ERROR, "Could not connect to device %s\n", client->udid); return -1; } @@ -351,14 +351,14 @@ int restore_reboot(struct idevicerestore_client_t* client) { if(client->restore == NULL) { if (restore_open_with_timeout(client) < 0) { - error("ERROR: Unable to open device in restore mode\n"); + logger(LL_ERROR, "Unable to open device in restore mode\n"); return -1; } } mutex_lock(&client->device_event_mutex); - info("Rebooting restore mode device...\n"); + logger(LL_INFO, "Rebooting restore mode device...\n"); restored_reboot(client->restore->client); restored_client_free(client->restore->client); @@ -379,7 +379,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con return 0; } if (!client->ecid) { - error("ERROR: %s: no ECID given in client data\n", __func__); + logger(LL_ERROR, "%s: no ECID given in client data\n", __func__); return 0; } @@ -392,21 +392,21 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con device_error = idevice_new(&device, udid); if (device_error != IDEVICE_E_SUCCESS) { - debug("%s: can't open device with UDID %s\n", __func__, udid); + logger(LL_DEBUG, "%s: can't open device with UDID %s\n", __func__, udid); return 0; } restore_error = restored_client_new(device, &restored, "idevicerestore"); if (restore_error != RESTORE_E_SUCCESS) { - debug("%s: can't connect to restored\n", __func__); + logger(LL_DEBUG, "%s: can't connect to restored\n", __func__); idevice_free(device); return 0; } restore_error = restored_query_type(restored, &type, &version); if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) { - debug("%s: Connected to %s, version %d\n", __func__, type, (int)version); + logger(LL_DEBUG, "%s: Connected to %s, version %d\n", __func__, type, (int)version); } else { - debug("%s: device %s is not in restore mode\n", __func__, udid); + logger(LL_DEBUG, "%s: device %s is not in restore mode\n", __func__, udid); restored_client_free(restored); idevice_free(device); return 0; @@ -415,7 +415,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con plist_t hwinfo = NULL; restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo); if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) { - error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__); + logger(LL_ERROR, "%s: Unable to get HardwareInfo from restored\n", __func__); restored_client_free(restored); idevice_free(device); plist_free(hwinfo); @@ -432,7 +432,7 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con plist_free(hwinfo); if (this_ecid == 0) { - error("ERROR: %s: Unable to get ECID from restored\n", __func__); + logger(LL_ERROR, "%s: Unable to get ECID from restored\n", __func__); return 0; } @@ -454,7 +454,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) } if (client->ecid == 0) { - error("ERROR: no ECID in client data!\n"); + logger(LL_ERROR, "no ECID in client data!\n"); return -1; } @@ -462,7 +462,7 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) if (client->restore == NULL) { client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t)); if(client->restore == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); return -1; } memset(client->restore, '\0', sizeof(struct restore_client_t)); @@ -471,11 +471,11 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) restore_device_connected = 0; if (!restore_is_current_device(client, client->udid)) { - error("ERROR: Unable to connect to device in restore mode\n"); + logger(LL_ERROR, "Unable to connect to device in restore mode\n"); return -1; } - info("Connecting now...\n"); + logger(LL_INFO, "Connecting now...\n"); device_error = idevice_new(&device, client->udid); if (device_error != IDEVICE_E_SUCCESS) { return -1; @@ -490,9 +490,9 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client) restore_error = restored_query_type(restored, &type, &version); if ((restore_error == RESTORE_E_SUCCESS) && type && (strcmp(type, "com.apple.mobile.restored") == 0)) { client->restore->protocol_version = version; - info("Connected to %s, version %d\n", type, (int)version); + logger(LL_INFO, "Connected to %s, version %d\n", type, (int)version); } else { - error("ERROR: Unable to connect to restored, error=%d\n", restore_error); + logger(LL_ERROR, "Unable to connect to restored, error=%d\n", restore_error); restored_client_free(restored); idevice_free(device); return -1; @@ -668,9 +668,9 @@ static void* _restore_get_service_client_for_data_request(struct idevicerestore_ (char*)data_type_str }; property_list_service_client_t plclient = NULL; - info("Connecting to %s data port %u\n", data_type_str, data_port); + logger(LL_INFO, "Connecting to %s data port %u\n", data_type_str, data_port); if (property_list_service_client_new(client->restore->device, &svcdesc, &plclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { - error("ERROR: Failed to start service connection for %s on port %u\n", data_type_str, data_port); + logger(LL_ERROR, "Failed to start service connection for %s on port %u\n", data_type_str, data_port); free(service); return NULL; } @@ -747,12 +747,12 @@ static int restore_handle_previous_restore_log_msg(restored_client_t client, pli node = plist_dict_get_item(msg, "PreviousRestoreLog"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse restore log from PreviousRestoreLog plist\n"); + logger(LL_DEBUG, "Failed to parse restore log from PreviousRestoreLog plist\n"); return -1; } plist_get_string_val(node, &restorelog); - info("Previous Restore Log Received:\n%s\n", restorelog); + logger(LL_INFO, "Previous Restore Log Received:\n%s\n", restorelog); free(restorelog); return 0; @@ -766,14 +766,14 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t node = plist_dict_get_item(msg, "Operation"); if (!node || plist_get_node_type(node) != PLIST_UINT) { - debug("Failed to parse operation from ProgressMsg plist\n"); + logger(LL_DEBUG, "Failed to parse operation from ProgressMsg plist\n"); return -1; } plist_get_uint_val(node, &operation); node = plist_dict_get_item(msg, "Progress"); if (!node || plist_get_node_type(node) != PLIST_UINT) { - debug("Failed to parse progress from ProgressMsg plist \n"); + logger(LL_DEBUG, "Failed to parse progress from ProgressMsg plist \n"); return -1; } plist_get_uint_val(node, &progress); @@ -788,7 +788,7 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t if ((progress > 0) && (progress <= 100)) { if ((int)operation != lastop) { - info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); + logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } switch (adapted_operation) { case RESTORE_IMAGE: @@ -812,11 +812,11 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t case REQUESTING_EAN_DATA: break; default: - debug("Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation); + logger(LL_DEBUG, "Unhandled progress operation %d (%d)\n", adapted_operation, (int)operation); break; } } else { - info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); + logger(LL_INFO, "%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } lastop = (int)operation; @@ -828,7 +828,7 @@ int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t ms int result = 0; uint64_t value = 0; char* log = NULL; - info("Got status message\n"); + logger(LL_INFO, "Got status message\n"); // read status code plist_t node = plist_dict_get_item(msg, "Status"); @@ -836,34 +836,34 @@ int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t ms switch(value) { case 0: - info("Status: Restore Finished\n"); + logger(LL_INFO, "Status: Restore Finished\n"); restore_finished = 1; break; case 0xFFFFFFFFFFFFFFFFLL: - info("Status: Verification Error\n"); + logger(LL_INFO, "Status: Verification Error\n"); break; case 6: - info("Status: Disk Failure\n"); + logger(LL_INFO, "Status: Disk Failure\n"); break; case 14: - info("Status: Fail\n"); + logger(LL_INFO, "Status: Fail\n"); break; case 27: - info("Status: Failed to mount filesystems.\n"); + logger(LL_INFO, "Status: Failed to mount filesystems.\n"); break; case 50: case 51: - info("Status: Failed to load SEP Firmware.\n"); + logger(LL_INFO, "Status: Failed to load SEP Firmware.\n"); break; case 53: - info("Status: Failed to recover FDR data.\n"); + logger(LL_INFO, "Status: Failed to recover FDR data.\n"); break; case 1015: - info("Status: X-Gold Baseband Update Failed. Defective Unit?\n"); + logger(LL_INFO, "Status: X-Gold Baseband Update Failed. Defective Unit?\n"); break; default: - info("Unhandled status message (%" PRIu64 ")\n", value); - debug_plist(msg); + logger(LL_INFO, "Unhandled status message (%" PRIu64 ")\n", value); + logger_dump_plist(LL_VERBOSE, msg, 1); break; } @@ -881,7 +881,7 @@ int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t ms node = plist_dict_get_item(msg, "Log"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &log); - info("Log is available:\n%s\n", log); + logger(LL_INFO, "Log is available:\n%s\n", log); free(log); log = NULL; } @@ -902,47 +902,47 @@ static int restore_handle_baseband_updater_output_data(struct idevicerestore_cli idevice_error_t device_error = IDEVICE_E_SUCCESS; if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - debug("Connecting to baseband updater data port\n"); + logger(LL_DEBUG, "Connecting to baseband updater data port\n"); while (--attempts > 0) { device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } sleep(1); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to connect to baseband updater data port\n"); + logger(LL_ERROR, "Unable to connect to baseband updater data port\n"); return result; } int fl = snprintf(NULL, 0, "updater_output-%s.cpio", client->udid); if (fl < 0) { idevice_disconnect(connection); - error("ERROR: snprintf failed?!\n"); + logger(LL_ERROR, "snprintf failed?!\n"); return result; } char* updater_out_fn = malloc(fl+1); if (!updater_out_fn) { idevice_disconnect(connection); - error("ERROR: Could not allocate buffer for filename\n"); + logger(LL_ERROR, "Could not allocate buffer for filename\n"); return result; } snprintf(updater_out_fn, fl+1, "updater_output-%s.cpio", client->udid); FILE* f = fopen(updater_out_fn, "wb"); if (!f) { - error("Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn); + logger(LL_ERROR, "Could not open %s for writing, will not write baseband updater output data.\n", updater_out_fn); } const int bufsize = 65536; char* buf = malloc(bufsize); if (!buf) { free(updater_out_fn); idevice_disconnect(connection); - error("ERROR: Could not allocate buffer\n"); + logger(LL_ERROR, "Could not allocate buffer\n"); return result; } uint32_t size = 0; @@ -953,7 +953,7 @@ static int restore_handle_baseband_updater_output_data(struct idevicerestore_cli } if (f) { fclose(f); - info("Wrote baseband updater output data to %s\n", updater_out_fn); + logger(LL_INFO, "Wrote baseband updater output data to %s\n", updater_out_fn); } free(updater_out_fn); free(buf); @@ -971,7 +971,7 @@ static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* c plist_get_bool_val(node, &accepted); if (!accepted) { - error("ERROR: device didn't accept BasebandData\n"); + logger(LL_ERROR, "device didn't accept BasebandData\n"); return result; } @@ -982,27 +982,32 @@ static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* c } if (done) { - info("Updating Baseband completed.\n"); + logger(LL_INFO, "Updating Baseband completed.\n"); plist_t provisioning = plist_access_path(message, 2, "Output", "provisioning"); if (provisioning && plist_get_node_type(provisioning) == PLIST_DICT) { char* sval = NULL; node = plist_dict_get_item(provisioning, "IMEI"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Provisioning:\n"); - info("IMEI:%s\n", sval); + logger(LL_INFO, "Provisioning:\n"); + logger(LL_INFO, "IMEI:%s\n", sval); free(sval); sval = NULL; } } } else { - info("Updating Baseband in progress...\n"); + logger(LL_INFO, "Updating Baseband in progress...\n"); } result = 0; return result; } +struct _restore_asr_progress_data { + struct idevicerestore_client_t* client; + uint32_t tag; +}; + static void restore_asr_progress_cb(double progress, void* userdata) { struct idevicerestore_client_t* client = (struct idevicerestore_client_t*)userdata; @@ -1019,14 +1024,14 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t mess char* fsname = NULL; if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - info("About to send filesystem...\n"); + logger(LL_INFO, "About to send filesystem...\n"); if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) { - error("ERROR: Unable to get path for filesystem component\n"); + logger(LL_ERROR, "Unable to get path for filesystem component\n"); return -1; } if (client->filesystem) { @@ -1040,7 +1045,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t mess file = ipsw_file_open(client->ipsw, fsname); } if (!file) { - error("ERROR: Unable to open '%s' in ipsw\n", fsname); + logger(LL_ERROR, "Unable to open '%s' in ipsw\n", fsname); free(fsname); } @@ -1051,41 +1056,41 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t mess if (asr_open_with_timeout(client->restore->device, &asr, asr_port) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: Unable to connect to ASR\n"); + logger(LL_ERROR, "Unable to connect to ASR\n"); return -1; } - info("Connected to ASR\n"); - - if (asr_port == ASR_DEFAULT_PORT) { - asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); - } + logger(LL_INFO, "Connected to ASR\n"); // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it - info("Validating the filesystem\n"); + logger(LL_INFO, "Validating the filesystem\n"); if (asr_perform_validation(asr, file) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: ASR was unable to validate the filesystem\n"); + logger(LL_ERROR, "ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; } - info("Filesystem validated\n"); + logger(LL_INFO, "Filesystem validated\n"); + + if (asr_port == ASR_DEFAULT_PORT) { + asr_set_progress_callback(asr, restore_asr_progress_cb, client); + } // once the target filesystem has been validated, ASR then requests the // entire filesystem to be sent. - info("Sending filesystem now...\n"); + logger(LL_INFO, "Sending filesystem now...\n"); if (asr_send_payload(asr, file) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); - error("ERROR: Unable to send payload to ASR\n"); + logger(LL_ERROR, "Unable to send payload to ASR\n"); asr_free(asr); return -1; } ipsw_file_close(file); ipsw_close(ipsw_dummy); - info("Done sending filesystem\n"); + logger(LL_INFO, "Done sending filesystem\n"); asr_free(asr); return 0; @@ -1096,7 +1101,7 @@ int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, restored_error_t restore_error; plist_t dict; - info("About to send RecoveryOSRootTicket...\n"); + logger(LL_INFO, "About to send RecoveryOSRootTicket...\n"); if (client->root_ticket) { dict = plist_new_dict(); @@ -1106,18 +1111,18 @@ int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, unsigned int len = 0; if (!client->tss_recoveryos_root_ticket && !(client->flags & FLAG_CUSTOM)) { - error("ERROR: Cannot send RootTicket without TSS\n"); + logger(LL_ERROR, "Cannot send RootTicket without TSS\n"); return -1; } if (client->image4supported) { if (tss_response_get_ap_img4_ticket(client->tss_recoveryos_root_ticket, &data, &len) < 0) { - error("ERROR: Unable to get ApImg4Ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n"); return -1; } } else { if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) { - error("ERROR: Unable to get ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ticket from TSS\n"); return -1; } } @@ -1126,27 +1131,27 @@ int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, if (data && (len > 0)) { plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { - info("NOTE: not sending RootTicketData (no data present)\n"); + logger(LL_NOTICE, "Not sending RootTicketData (no data present)\n"); } free(data); } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending RecoveryOSRootTicket now...\n"); + logger(LL_INFO, "Sending RecoveryOSRootTicket now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send RootTicket (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error); return -1; } - info("Done sending RecoveryOS RootTicket\n"); + logger(LL_INFO, "Done sending RecoveryOS RootTicket\n"); return 0; } @@ -1156,7 +1161,7 @@ int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t mes restored_error_t restore_error; plist_t dict; - info("About to send RootTicket...\n"); + logger(LL_INFO, "About to send RootTicket...\n"); if (client->root_ticket) { dict = plist_new_dict(); @@ -1166,18 +1171,18 @@ int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t mes unsigned int len = 0; if (!client->tss && !(client->flags & FLAG_CUSTOM)) { - error("ERROR: Cannot send RootTicket without TSS\n"); + logger(LL_ERROR, "Cannot send RootTicket without TSS\n"); return -1; } if (client->image4supported) { if (tss_response_get_ap_img4_ticket(client->tss, &data, &len) < 0) { - error("ERROR: Unable to get ApImg4Ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ApImg4Ticket from TSS\n"); return -1; } } else { if (!(client->flags & FLAG_CUSTOM) && (tss_response_get_ap_ticket(client->tss, &data, &len) < 0)) { - error("ERROR: Unable to get ticket from TSS\n"); + logger(LL_ERROR, "Unable to get ticket from TSS\n"); return -1; } } @@ -1186,27 +1191,27 @@ int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t mes if (data && (len > 0)) { plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { - info("NOTE: not sending RootTicketData (no data present)\n"); + logger(LL_INFO, "Not sending RootTicketData (no data present)\n"); } free(data); } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending RootTicket now...\n"); + logger(LL_INFO, "Sending RootTicket now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send RootTicket (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send RootTicket (%d)\n", restore_error); return -1; } - info("Done sending RootTicket\n"); + logger(LL_INFO, "Done sending RootTicket\n"); return 0; } @@ -1259,29 +1264,29 @@ static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, vo int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message) { - debug("DEBUG: %s\n", __func__); + logger(LL_DEBUG, "%s\n", __func__); plist_t arguments = plist_dict_get_item(message, "Arguments"); if (!PLIST_IS_DICT(arguments)) { - error("ERROR: %s: Unexpected arguments\n", __func__); - debug_plist(arguments); + logger(LL_ERROR, "%s: Unexpected arguments\n", __func__); + logger_dump_plist(LL_VERBOSE, arguments, 1); return -1; } const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); if (!request_method) { - error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__); return -1; } if (strcmp(request_method, "GET")) { - error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); return -1; } const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); if (!request_url) { - error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__); return -1; } - info("Requesting URLAsset from %s\n", request_url); + logger(LL_INFO, "Requesting URLAsset from %s\n", request_url); char curl_error_message[CURL_ERROR_SIZE]; CURL* handle = curl_easy_init(); @@ -1290,7 +1295,7 @@ int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t messa query_response* response = malloc(sizeof(query_response)); if (response == NULL) { - error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__); return -1; } @@ -1305,7 +1310,7 @@ int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t messa plist_t response_headers = plist_new_dict(); curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - if (idevicerestore_debug) { + if (client->debug_level > 0) { curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); } curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); @@ -1327,7 +1332,7 @@ int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t messa restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } @@ -1339,26 +1344,26 @@ int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t messa int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* client, plist_t message) { - debug("DEBUG: %s\n", __func__); + logger(LL_DEBUG, "%s\n", __func__); plist_t arguments = plist_dict_get_item(message, "Arguments"); if (!PLIST_IS_DICT(arguments)) { - error("ERROR: %s: Unexpected arguments\n", __func__); - debug_plist(arguments); + logger(LL_ERROR, "%s: Unexpected arguments\n", __func__); + logger_dump_plist(LL_VERBOSE, arguments, 1); return -1; } const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); if (!request_method) { - error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + logger(LL_ERROR, "%s: Unable to extract RequestMethod from Arguments\n", __func__); return -1; } if (strcmp(request_method, "POST")) { - error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + logger(LL_ERROR, "%s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); return -1; } const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); if (!request_url) { - error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + logger(LL_ERROR, "%s: Unable to extract RequestURL from Arguments\n", __func__); return -1; } @@ -1366,18 +1371,18 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c plist_t headers = plist_dict_get_item(arguments, "RequestAdditionalHeaders"); if (!headers) { - error("ERROR: %s: Missing 'RequestAdditionalHeaders'\n", __func__); + logger(LL_ERROR, "%s: Missing 'RequestAdditionalHeaders'\n", __func__); return -1; } uint64_t request_body_size = 0; const char* request_body = plist_get_data_ptr(plist_dict_get_item(arguments, "RequestBody"), &request_body_size); if (!request_body) { - error("ERROR: %s: Missing 'RequestBody'\n", __func__); + logger(LL_ERROR, "%s: Missing 'RequestBody'\n", __func__); return -1; } - info("Requesting image decryption key from %s\n", request_url); + logger(LL_INFO, "Requesting image decryption key from %s\n", request_url); char curl_error_message[CURL_ERROR_SIZE]; char header_tmp[1024]; @@ -1399,7 +1404,7 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c query_response* response = malloc(sizeof(query_response)); if (response == NULL) { - error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + logger(LL_ERROR, "%s: Unable to allocate sufficient memory\n", __func__); return -1; } @@ -1416,7 +1421,7 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body); curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, request_body_size); - if (idevicerestore_debug) { + if (client->debug_level > 0) { curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); } curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); @@ -1439,7 +1444,7 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } @@ -1459,7 +1464,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa restored_error_t restore_error = RESTORE_E_SUCCESS; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } @@ -1467,16 +1472,16 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa component_name = component; } - info("About to send %s...\n", component_name); + logger(LL_INFO, "About to send %s...\n", component_name); if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } @@ -1487,7 +1492,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); + logger(LL_ERROR, "Unable to extract component %s\n", component); return -1; } @@ -1495,7 +1500,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } @@ -1508,20 +1513,20 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending %s now...\n", component_name); + logger(LL_INFO, "Sending %s now...\n", component_name); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + logger(LL_ERROR, "Unable to send component %s data\n", component_name); return -1; } - info("Done sending %s\n", component_name); + logger(LL_INFO, "Done sending %s\n", component_name); return 0; } @@ -1546,11 +1551,11 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) int flash_version_1 = 0; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - info("About to send NORData...\n"); + logger(LL_INFO, "About to send NORData...\n"); plist_t arguments = plist_dict_get_item(message, "Arguments"); if (arguments && plist_get_node_type(arguments) == PLIST_DICT) { @@ -1559,26 +1564,26 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) if (client->tss) { if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) { - debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n"); + logger(LL_DEBUG, "Could not get LLB path from TSS data, will fetch from build identity\n"); } } if (llb_path == NULL) { if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) { - error("ERROR: Unable to get component path for LLB\n"); + logger(LL_ERROR, "Unable to get component path for LLB\n"); return -1; } } llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { - error("ERROR: Unable to extract firmware path from LLB filename\n"); + logger(LL_ERROR, "Unable to extract firmware path from LLB filename\n"); free(llb_path); return -1; } 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); + logger(LL_INFO, "Found firmware path %s\n", firmware_path); memset(manifest_file, '\0', sizeof(manifest_file)); snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); @@ -1588,7 +1593,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) ipsw_extract_to_memory(client->ipsw, manifest_file, &manifest_data, &manifest_size); } if (manifest_data && manifest_size > 0) { - info("Getting firmware manifest from %s\n", manifest_file); + logger(LL_INFO, "Getting firmware manifest from %s\n", manifest_file); char *manifest_p = (char*)manifest_data; char *filename = NULL; while ((filename = strsep(&manifest_p, "\r\n")) != NULL) { @@ -1601,7 +1606,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) } free(manifest_data); } else { - info("Getting firmware manifest from build identity\n"); + logger(LL_INFO, "Getting firmware manifest from build identity\n"); plist_dict_iter iter = NULL; plist_t build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { @@ -1649,7 +1654,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) } if (plist_dict_get_size(firmware_files) == 0) { - error("ERROR: Unable to get list of firmware files.\n"); + logger(LL_ERROR, "Unable to get list of firmware files.\n"); return -1; } @@ -1659,7 +1664,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) int ret = extract_component(client->ipsw, llb_path, &component_data, &component_size); free(llb_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } @@ -1668,7 +1673,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } @@ -1715,7 +1720,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) free(comp); free(comppath); plist_free(firmware_files); - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } @@ -1725,7 +1730,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) free(comppath); free(component_data); plist_free(firmware_files); - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } free(component_data); @@ -1762,7 +1767,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) ret = extract_component(client->ipsw, restore_sep_path, &component_data, &component_size); free(restore_sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } @@ -1771,7 +1776,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } @@ -1787,7 +1792,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } @@ -1796,7 +1801,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } @@ -1812,7 +1817,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); return -1; } @@ -1821,7 +1826,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) component_data = NULL; component_size = 0; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); return -1; } @@ -1831,25 +1836,25 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) personalized_size = 0; } - if (idevicerestore_debug) - debug_plist(dict); + if (client->debug_level > 1) + logger_dump_plist(LL_DEBUG, dict, 0); restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending NORData now...\n"); + logger(LL_INFO, "Sending NORData now...\n"); restored_error_t restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send NORData\n"); + logger(LL_ERROR, "Unable to send NORData\n"); return -1; } - info("Done sending NORData\n"); + logger(LL_INFO, "Done sending NORData\n"); return 0; } @@ -1900,13 +1905,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // check for BBTicket in result plist_t bbticket = plist_dict_get_item(bbtss, "BBTicket"); if (!bbticket || plist_get_node_type(bbticket) != PLIST_DATA) { - error("ERROR: Could not find BBTicket in Baseband TSS response\n"); + logger(LL_ERROR, "Could not find BBTicket in Baseband TSS response\n"); return -1; } plist_t bbfw_dict = plist_dict_get_item(bbtss, "BasebandFirmware"); if (!bbfw_dict || plist_get_node_type(bbfw_dict) != PLIST_DICT) { - error("ERROR: Could not find BasebandFirmware Dictionary node in Baseband TSS response\n"); + logger(LL_ERROR, "Could not find BasebandFirmware Dictionary node in Baseband TSS response\n"); return -1; } @@ -1926,14 +1931,14 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned za = zip_open(bbfwtmp, 0, &zerr); if (!za) { - error("ERROR: Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr); + logger(LL_ERROR, "Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr); goto leave; } plist_dict_iter iter = NULL; plist_dict_new_iter(bbfw_dict, &iter); if (!iter) { - error("ERROR: Could not create dict iter for BasebandFirmware Dictionary\n"); + logger(LL_ERROR, "Could not create dict iter for BasebandFirmware Dictionary\n"); return -1; } @@ -1951,7 +1956,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned *ptr = '\0'; const char* signfn = restore_get_bbfw_fn_for_element(key); if (!signfn) { - error("ERROR: can't match element name '%s' to baseband firmware file name.\n", key); + logger(LL_ERROR, "can't match element name '%s' to baseband firmware file name.\n", key); goto leave; } char* ext = strrchr(signfn, '.'); @@ -1961,30 +1966,30 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zindex = zip_name_locate(za, signfn, 0); if (zindex < 0) { - error("ERROR: can't locate '%s' in '%s'\n", signfn, bbfwtmp); + logger(LL_ERROR, "can't locate '%s' in '%s'\n", signfn, bbfwtmp); goto leave; } zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } buffer = (unsigned char*) malloc(zstat.size + 1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); goto leave; } if (zip_fread(zfile, buffer, zstat.size) != zstat.size) { - error("ERROR: zip_fread: failed\n"); + logger(LL_ERROR, "zip_fread: failed\n"); goto leave; } buffer[zstat.size] = '\0'; @@ -1995,13 +2000,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned if (is_fls) { fls = fls_parse(buffer, zstat.size); if (!fls) { - error("ERROR: could not parse fls file\n"); + logger(LL_ERROR, "could not parse fls file\n"); goto leave; } } else { mbn = mbn_parse(buffer, zstat.size); if (!mbn) { - error("ERROR: could not parse mbn file\n"); + logger(LL_ERROR, "could not parse mbn file\n"); goto leave; } } @@ -2011,18 +2016,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob_size = 0; blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size); if (!blob) { - error("ERROR: could not get %s-Blob data\n", key); + logger(LL_ERROR, "could not get %s-Blob data\n", key); goto leave; } if (is_fls) { if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not sign %s\n", signfn); + logger(LL_ERROR, "could not sign %s\n", signfn); goto leave; } } else { if (mbn_update_sig_blob(mbn, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not sign %s\n", signfn); + logger(LL_ERROR, "could not sign %s\n", signfn); goto leave; } } @@ -2030,7 +2035,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned fsize = (is_fls ? fls->size : mbn->size); fdata = (unsigned char*)malloc(fsize); if (fdata == NULL) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); goto leave; } if (is_fls) { @@ -2045,13 +2050,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zs = zip_source_buffer(za, fdata, fsize, 1); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); free(fdata); goto leave; } if (zip_file_replace(za, zindex, zs, 0) == -1) { - error("ERROR: could not update signed '%s' in archive\n", signfn); + logger(LL_ERROR, "could not update signed '%s' in archive\n", signfn); goto leave; } @@ -2099,30 +2104,30 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // add BBTicket to file ebl.fls zindex = zip_name_locate(za, "ebl.fls", 0); if (zindex < 0) { - error("ERROR: can't locate 'ebl.fls' in '%s'\n", bbfwtmp); + logger(LL_ERROR, "can't locate 'ebl.fls' in '%s'\n", bbfwtmp); goto leave; } zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); + logger(LL_ERROR, "zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } buffer = (unsigned char*) malloc(zstat.size + 1); if (buffer == NULL) { - error("ERROR: Out of memory\n"); + logger(LL_ERROR, "Out of memory\n"); goto leave; } if (zip_fread(zfile, buffer, zstat.size) != zstat.size) { - error("ERROR: zip_fread: failed\n"); + logger(LL_ERROR, "zip_fread: failed\n"); goto leave; } buffer[zstat.size] = '\0'; @@ -2134,26 +2139,26 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(buffer); buffer = NULL; if (!fls) { - error("ERROR: could not parse fls file\n"); + logger(LL_ERROR, "could not parse fls file\n"); goto leave; } blob_size = 0; blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { - error("ERROR: could not get BBTicket data\n"); + logger(LL_ERROR, "could not get BBTicket data\n"); goto leave; } if (fls_insert_ticket(fls, blob, (unsigned int)blob_size) != 0) { - error("ERROR: could not insert BBTicket to ebl.fls\n"); + logger(LL_ERROR, "could not insert BBTicket to ebl.fls\n"); goto leave; } fsize = fls->size; fdata = (unsigned char*)malloc(fsize); if (!fdata) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); goto leave; } memcpy(fdata, fls->data, fsize); @@ -2162,13 +2167,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zs = zip_source_buffer(za, fdata, fsize, 1); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); free(fdata); goto leave; } if (zip_file_replace(za, zindex, zs, 0) == -1) { - error("ERROR: could not update archive with ticketed ebl.fls\n"); + logger(LL_ERROR, "could not update archive with ticketed ebl.fls\n"); goto leave; } } else { @@ -2176,18 +2181,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob_size = 0; blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { - error("ERROR: could not get BBTicket data\n"); + logger(LL_ERROR, "could not get BBTicket data\n"); goto leave; } zs = zip_source_buffer(za, blob, blob_size, 0); if (!zs) { - error("ERROR: out of memory\n"); + logger(LL_ERROR, "out of memory\n"); goto leave; } if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { - error("ERROR: could not add bbticket.der to archive\n"); + logger(LL_ERROR, "could not add bbticket.der to archive\n"); goto leave; } } @@ -2195,7 +2200,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // this will write out the modified zip if (zip_close(za) == -1) { - error("ERROR: could not close and write modified archive: %s\n", zip_strerror(za)); + logger(LL_ERROR, "could not close and write modified archive: %s\n", zip_strerror(za)); res = -1; } else { res = 0; @@ -2236,11 +2241,11 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl plist_t dict = NULL; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - info("About to send BasebandData...\n"); + logger(LL_INFO, "About to send BasebandData...\n"); // NOTE: this function is called 2 or 3 times! @@ -2281,7 +2286,7 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl /* create baseband request */ plist_t request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Baseband TSS request\n"); + logger(LL_ERROR, "Unable to create Baseband TSS request\n"); plist_free(parameters); return -1; } @@ -2299,34 +2304,31 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl plist_dict_set_item(request, "ApSecurityMode", plist_new_bool(1)); } } - if (idevicerestore_debug) - debug_plist(request); + logger_dump_plist(LL_DEBUG, request, 0); - info("Sending Baseband TSS request...\n"); + logger(LL_INFO, "Sending Baseband TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); plist_free(parameters); if (response == NULL) { - error("ERROR: Unable to fetch Baseband TSS\n"); + logger(LL_ERROR, "Unable to fetch Baseband TSS\n"); return -1; } - info("Received Baseband SHSH blobs\n"); - - if (idevicerestore_debug) - debug_plist(response); + logger(LL_INFO, "Received Baseband SHSH blobs\n"); + logger_dump_plist(LL_DEBUG, response, 0); } // get baseband firmware file path from build identity plist_t bbfw_path = plist_access_path(client->restore->build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) { - error("ERROR: Unable to get BasebandFirmware/Info/Path node\n"); + logger(LL_ERROR, "Unable to get BasebandFirmware/Info/Path node\n"); plist_free(response); return -1; } char* bbfwpath = NULL; plist_get_string_val(bbfw_path, &bbfwpath); if (!bbfwpath) { - error("ERROR: Unable to get baseband path\n"); + logger(LL_ERROR, "Unable to get baseband path\n"); plist_free(response); return -1; } @@ -2339,10 +2341,10 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl strcpy(bbfwtmp, "bbfw_"); strncpy(bbfwtmp + 5, client->udid, l); strcpy(bbfwtmp + 5 + l, ".tmp"); - error("WARNING: Could not generate temporary filename, using %s in current directory\n", bbfwtmp); + logger(LL_WARNING, "Could not generate temporary filename, using %s in current directory\n", bbfwtmp); } if (ipsw_extract_to_file(client->ipsw, bbfwpath, bbfwtmp) != 0) { - error("ERROR: Unable to extract baseband firmware from ipsw\n"); + logger(LL_ERROR, "Unable to extract baseband firmware from ipsw\n"); goto leave; } @@ -2361,7 +2363,7 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl size_t sz = 0; if (read_file(bbfwtmp, (void**)&buffer, &sz) < 0) { - error("ERROR: could not read updated bbfw archive\n"); + logger(LL_ERROR, "could not read updated bbfw archive\n"); goto leave; } @@ -2373,19 +2375,19 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending BasebandData now...\n"); + logger(LL_INFO, "Sending BasebandData now...\n"); if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send BasebandData data\n"); + logger(LL_ERROR, "Unable to send BasebandData data\n"); goto leave; } _restore_service_free(service); - info("Done sending BasebandData\n"); + logger(LL_INFO, "Done sending BasebandData\n"); res = 0; leave: @@ -2405,7 +2407,7 @@ int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t restored_error_t restore_error; plist_t dict; - info("About to send FDR Trust data...\n"); + logger(LL_INFO, "About to send FDR Trust data...\n"); // FIXME: What should we send here? /* Sending an empty dict makes it continue with FDR @@ -2414,20 +2416,20 @@ int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending FDR Trust data now...\n"); + logger(LL_INFO, "Sending FDR Trust data now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: During sending FDR Trust data (%d)\n", restore_error); + logger(LL_ERROR, "During sending FDR Trust data (%d)\n", restore_error); return -1; } - info("Done sending FDR Trust Data\n"); + logger(LL_INFO, "Done sending FDR Trust Data\n"); return 0; } @@ -2446,7 +2448,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist int want_image_list = 0; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } @@ -2463,12 +2465,12 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist } } if (!image_type_k) { - error("ERROR: missing ImageType"); + logger(LL_ERROR, "Missing ImageType\n"); return -1; } if (!want_image_list && !image_name) { - info("About to send %s...\n", image_data_k); + logger(LL_INFO, "About to send %s...\n", image_data_k); } if (want_image_list) { @@ -2496,7 +2498,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist } if (is_image_type) { if (want_image_list) { - info("Found %s component %s\n", image_type_k, component); + logger(LL_INFO, "Found %s component %s\n", image_type_k, component); plist_array_append_item(matched_images, plist_new_string(component)); } else if (!image_name || !strcmp(image_name, component)) { char *path = NULL; @@ -2507,7 +2509,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist int ret = -1; if (!image_name) { - info("Found %s component '%s'\n", image_type_k, component); + logger(LL_INFO, "Found %s component '%s'\n", image_type_k, component); } build_identity_get_component_path(client->restore->build_identity, component, &path); if (path) { @@ -2516,14 +2518,14 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component: %s\n", component); + logger(LL_ERROR, "Unable to extract component: %s\n", component); } ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component: %s\n", component); + logger(LL_ERROR, "Unable to get personalized component: %s\n", component); } plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); @@ -2538,14 +2540,14 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } dict = plist_new_dict(); if (want_image_list) { plist_dict_set_item(dict, image_list_k, matched_images); - info("Sending %s image list\n", image_type_k); + logger(LL_INFO, "Sending %s image list\n", image_type_k); } else { if (image_name) { node = plist_dict_get_item(data_dict, image_name); @@ -2553,10 +2555,10 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist plist_dict_set_item(dict, image_data_k, plist_copy(node)); } plist_dict_set_item(dict, "ImageName", plist_new_string(image_name)); - info("Sending %s for %s...\n", image_type_k, image_name); + logger(LL_INFO, "Sending %s for %s...\n", image_type_k, image_name); } else { plist_dict_set_item(dict, image_data_k, data_dict); - info("Sending %s now...\n", image_type_k); + logger(LL_INFO, "Sending %s now...\n", image_type_k); } } @@ -2565,13 +2567,13 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { if (want_image_list) { - error("ERROR: Failed to send %s image list (%d)\n", image_type_k, restore_error); + logger(LL_ERROR, "Failed to send %s image list (%d)\n", image_type_k, restore_error); } else { if (image_name) { - error("ERROR: Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error); + logger(LL_ERROR, "Failed to send %s for %s (%d)\n", image_type_k, image_name, restore_error); free(image_name); } else { - error("ERROR: Failed to send %s (%d)\n", image_type_k, restore_error); + logger(LL_ERROR, "Failed to send %s (%d)\n", image_type_k, restore_error); } } return -1; @@ -2581,7 +2583,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist if (image_name) { free(image_name); } else { - info("Done sending %s\n", image_type_k); + logger(LL_INFO, "Done sending %s\n", image_type_k); } } @@ -2624,7 +2626,7 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie uint64_t chip_id = 0; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } @@ -2637,30 +2639,30 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { comp_name = "SE,UpdatePayload"; } else { - info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); + logger(LL_WARNING, "Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); if (build_identity_has_component(client->restore->build_identity, "SE,UpdatePayload")) comp_name = "SE,UpdatePayload"; else if (build_identity_has_component(client->restore->build_identity, "SE,Firmware")) comp_name = "SE,Firmware"; else { - error("ERROR: Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); + logger(LL_ERROR, "Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); } p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!p_dgr) { - info("NOTE: %s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); + logger(LL_NOTICE, "%s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); } else if (!PLIST_IS_DICT(p_dgr)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create SE request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create SE TSS request\n"); + logger(LL_ERROR, "Unable to create SE TSS request\n"); free(component_data); return NULL; } @@ -2678,32 +2680,32 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie plist_free(parameters); - info("Sending SE TSS request...\n"); + logger(LL_INFO, "Sending SE TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch SE ticket\n"); + logger(LL_ERROR, "Unable to fetch SE ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "SE2,Ticket")) { - info("Received SE2,Ticket\n"); + logger(LL_INFO, "Received SE2,Ticket\n"); } else if (plist_dict_get_item(response, "SE,Ticket")) { - info("Received SE,Ticket\n"); + logger(LL_INFO, "Received SE,Ticket\n"); } else { - error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'SE ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2712,7 +2714,7 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie comp_path = NULL; if (ret < 0) { plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -2737,20 +2739,20 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Savage TSS request\n"); + logger(LL_ERROR, "Unable to create Savage TSS request\n"); return NULL; } @@ -2768,37 +2770,37 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* plist_free(parameters); if (!comp_name) { - error("ERROR: Could not determine Savage firmware component\n"); + logger(LL_ERROR, "Could not determine Savage firmware component\n"); plist_free(request); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); - info("Sending Savage TSS request...\n"); + logger(LL_INFO, "Sending Savage TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Savage ticket\n"); + logger(LL_ERROR, "Unable to fetch Savage ticket\n"); free(comp_name); return NULL; } if (plist_dict_get_item(response, "Savage,Ticket")) { - info("Received Savage ticket\n"); + logger(LL_INFO, "Received Savage ticket\n"); } else { - error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Savage,Ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } /* now get actual component data */ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2808,7 +2810,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* comp_path = NULL; if (ret < 0) { plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2847,20 +2849,20 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Yonkers TSS request\n"); + logger(LL_ERROR, "Unable to create Yonkers TSS request\n"); return NULL; } @@ -2878,37 +2880,37 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* plist_free(parameters); if (!comp_name) { - error("ERROR: Could not determine Yonkers firmware component\n"); + logger(LL_ERROR, "Could not determine Yonkers firmware component\n"); plist_free(request); return NULL; } - debug("DEBUG: %s: using %s\n", __func__, comp_name); + logger(LL_DEBUG, "%s: using %s\n", __func__, comp_name); - info("Sending Yonkers TSS request...\n"); + logger(LL_INFO, "Sending Yonkers TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Yonkers ticket\n"); + logger(LL_ERROR, "Unable to fetch Yonkers ticket\n"); free(comp_name); return NULL; } if (plist_dict_get_item(response, "Yonkers,Ticket")) { - info("Received Yonkers ticket\n"); + logger(LL_INFO, "Received Yonkers ticket\n"); } else { - error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Yonkers,Ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); free(comp_name); return response; } if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2919,7 +2921,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* comp_path = NULL; if (ret < 0) { plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; } @@ -2952,14 +2954,14 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } /* create Rose request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Rose TSS request\n"); + logger(LL_ERROR, "Unable to create Rose TSS request\n"); return NULL; } @@ -2990,30 +2992,30 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl plist_free(parameters); - info("Sending Rose TSS request...\n"); + logger(LL_INFO, "Sending Rose TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Rose ticket\n"); + logger(LL_ERROR, "Unable to fetch Rose ticket\n"); return NULL; } if (plist_dict_get_item(response, "Rap,Ticket")) { - info("Received Rose ticket\n"); + logger(LL_INFO, "Received Rose ticket\n"); } else { - error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Rap,Ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } comp_name = "Rap,RTKitOS"; if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); @@ -3021,20 +3023,20 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl comp_path = NULL; if (ret < 0) { plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { plist_free(response); free(component_data); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } comp_name = "Rap,RestoreRTKitOS"; @@ -3042,7 +3044,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); @@ -3051,7 +3053,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (ret < 0) { ftab_free(ftab); plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3060,26 +3062,26 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl free(component_data); ftab_free(ftab); plist_free(response); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { ftab_add_entry(ftab, 'rrko', component_data, component_size); } else { - error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n"); } ftab_free(rftab); component_data = NULL; component_size = 0; } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } ftab_write(ftab, &component_data, &component_size); @@ -3105,20 +3107,20 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Veridian TSS request\n"); + logger(LL_ERROR, "Unable to create Veridian TSS request\n"); free(component_data); return NULL; } @@ -3136,30 +3138,30 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t plist_free(parameters); - info("Sending Veridian TSS request...\n"); + logger(LL_INFO, "Sending Veridian TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Veridian ticket\n"); + logger(LL_ERROR, "Unable to fetch Veridian ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "BMU,Ticket")) { - info("Received Veridian ticket\n"); + logger(LL_INFO, "Received Veridian ticket\n"); } else { - error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'BMU,Ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3169,7 +3171,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t comp_path = NULL; if (ret < 0) { plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3185,7 +3187,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t if (!fw_map) { plist_free(response); - error("ERROR: Unable to parse '%s' component data as plist\n", comp_name); + logger(LL_ERROR, "Unable to parse '%s' component data as plist\n", comp_name); return NULL; } @@ -3193,7 +3195,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t if (!fw_map_digest) { plist_free(fw_map); plist_free(response); - error("ERROR: Unable to get Digest for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get Digest for '%s' component\n", comp_name); return NULL; } @@ -3227,39 +3229,39 @@ static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* } } if (response_ticket == NULL) { - error("ERROR: Unable to determine response ticket from device generated tags"); + logger(LL_ERROR, "Unable to determine response ticket from device generated tags\n"); return NULL; } /* create TSS request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create %s TSS request\n", s_updater_name); + logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name); return NULL; } /* add device generated request data to request */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { - error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(request); return NULL; } plist_dict_merge(&request, device_generated_request); - info("Sending %s TSS request...\n", s_updater_name); + logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name); return NULL; } if (plist_dict_get_item(response, response_ticket)) { - info("Received %s\n", response_ticket); + logger(LL_INFO, "Received %s\n", response_ticket); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); - debug_plist(response); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket); + logger_dump_plist(LL_VERBOSE, response, 0); } return response; @@ -3277,20 +3279,20 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Baobab TSS request\n"); + logger(LL_ERROR, "Unable to create Baobab TSS request\n"); free(component_data); return NULL; } @@ -3308,29 +3310,29 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl plist_free(parameters); - info("Sending Baobab TSS request...\n"); + logger(LL_INFO, "Sending Baobab TSS request...\n"); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Baobab ticket\n"); + logger(LL_ERROR, "Unable to fetch Baobab ticket\n"); free(component_data); return NULL; } if (plist_dict_get_item(response, "Baobab,Ticket")) { - info("Received Baobab ticket\n"); + logger(LL_INFO, "Received Baobab ticket\n"); } else { - error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); + logger(LL_ERROR, "No 'Baobab,Ticket' in TSS response, this might not work\n"); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); plist_free(response); return NULL; } @@ -3340,7 +3342,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); plist_free(response); return NULL; } @@ -3370,20 +3372,20 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c int ret; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { - error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + logger(LL_ERROR, "%s: DeviceGeneratedRequest has invalid type!\n", __func__); return NULL; } /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Timer TSS request\n"); + logger(LL_ERROR, "Unable to create Timer TSS request\n"); return NULL; } @@ -3403,7 +3405,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c /* add Timer,* tags from info dictionary to parameters */ plist_t info_array = plist_dict_get_item(p_info, "InfoArray"); if (!info_array) { - error("ERROR: Could not find InfoArray in info dictionary\n"); + logger(LL_ERROR, "Could not find InfoArray in info dictionary\n"); plist_free(parameters); return NULL; } else { @@ -3442,7 +3444,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); if (!ap_info) { - error("ERROR: Could not find APInfo in info dictionary\n"); + logger(LL_ERROR, "Could not find APInfo in info dictionary\n"); plist_free(parameters); return NULL; } else { @@ -3454,23 +3456,23 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c plist_free(parameters); - info("Sending %s TSS request...\n", ticket_name); + logger(LL_INFO, "Sending %s TSS request...\n", ticket_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s\n", ticket_name); + logger(LL_ERROR, "Unable to fetch %s\n", ticket_name); return NULL; } if (plist_dict_get_item(response, ticket_name)) { - info("Received %s\n", ticket_name); + logger(LL_INFO, "Received %s\n", ticket_name); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", ticket_name); } /* don't add FirmwareData if not requested via ResponseTags */ if (!_wants_firmware_data(arguments)) { - debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + logger(LL_DEBUG, "Not adding FirmwareData as it was not requested\n"); return response; } @@ -3478,31 +3480,31 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); free(comp_path); comp_path = NULL; if (ret < 0) { - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); plist_free(response); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { free(component_data); plist_free(response); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } snprintf(comp_name, sizeof(comp_name), "Timer,RestoreRTKitOS,%u", tag); @@ -3510,7 +3512,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); plist_free(response); - error("ERROR: Unable to get path for '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to get path for '%s' component\n", comp_name); return NULL; } ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); @@ -3519,7 +3521,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (ret < 0) { ftab_free(ftab); plist_free(response); - error("ERROR: Unable to extract '%s' component\n", comp_name); + logger(LL_ERROR, "Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3528,26 +3530,26 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c free(component_data); ftab_free(ftab); plist_free(response); - error("ERROR: Failed to parse '%s' component data.\n", comp_name); + logger(LL_ERROR, "Failed to parse '%s' component data.\n", comp_name); return NULL; } free(component_data); component_data = NULL; component_size = 0; if (ftag != 'rkos') { - error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + logger(LL_WARNING, "Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); } if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { ftab_add_entry(ftab, 'rrko', component_data, component_size); } else { - error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + logger(LL_ERROR, "Could not find 'rrko' entry in ftab. This will probably break things.\n"); } ftab_free(rftab); component_data = NULL; component_size = 0; } else { - info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + logger(LL_NOTICE, "Build identity does not have a '%s' component.\n", comp_name); } ftab_write(ftab, &component_data, &component_size); @@ -3568,7 +3570,7 @@ static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t plist_t response = NULL; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return NULL; } @@ -3587,7 +3589,7 @@ static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t /* create Cryptex1 request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create %s TSS request\n", s_updater_name); + logger(LL_ERROR, "Unable to create %s TSS request\n", s_updater_name); return NULL; } @@ -3627,7 +3629,7 @@ static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t /* add device generated request data to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { - error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + logger(LL_ERROR, "Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(parameters); return NULL; } @@ -3638,19 +3640,19 @@ static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t plist_free(parameters); - info("Sending %s TSS request...\n", s_updater_name); + logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name); return NULL; } if (plist_dict_get_item(response, response_ticket)) { - info("Received %s\n", response_ticket); + logger(LL_INFO, "Received %s\n", response_ticket); } else { - error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); - debug_plist(response); + logger(LL_ERROR, "No '%s' in TSS response, this might not work\n", response_ticket); + logger_dump_plist(LL_VERBOSE, response, 0); } return response; @@ -3661,29 +3663,29 @@ static int restore_send_firmware_updater_preflight(struct idevicerestore_client_ plist_t dict = NULL; int restore_error; - if (idevicerestore_debug) { - debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got FirmwareUpdaterPreflight request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } dict = plist_new_dict(); - info("Sending FirmwareResponsePreflight now...\n"); + logger(LL_INFO, "Sending FirmwareResponsePreflight now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); return -1; } - info("Done sending FirmwareUpdaterPreflight response\n"); + logger(LL_INFO, "Done sending FirmwareUpdaterPreflight response\n"); return 0; } @@ -3699,30 +3701,30 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl int restore_error; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - if (idevicerestore_debug) { - debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got FirmwareUpdaterData request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } arguments = plist_dict_get_item(message, "Arguments"); if (!arguments || plist_get_node_type(arguments) != PLIST_DICT) { - error("ERROR: %s: Arguments missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: Arguments missing or has invalid type!\n", __func__); goto error_out; } p_type = plist_dict_get_item(arguments, "MessageArgType"); if (!p_type || (plist_get_node_type(p_type) != PLIST_STRING)) { - error("ERROR: %s: MessageArgType missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgType missing or has invalid type!\n", __func__); goto error_out; } p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); if (!p_updater_name || (plist_get_node_type(p_updater_name) != PLIST_STRING)) { - error("ERROR: %s: MessageArgUpdaterName missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgUpdaterName missing or has invalid type!\n", __func__); goto error_out; } @@ -3734,7 +3736,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl plist_get_string_val(p_type, &s_type); if (!s_type || strcmp(s_type, "FirmwareResponseData")) { - error("ERROR: %s: MessageArgType has unexpected value '%s'\n", __func__, s_type); + logger(LL_ERROR, "%s: MessageArgType has unexpected value '%s'\n", __func__, s_type); goto error_out; } free(s_type); @@ -3742,7 +3744,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl p_info = plist_dict_get_item(arguments, "MessageArgInfo"); if (!p_info || (plist_get_node_type(p_info) != PLIST_DICT)) { - error("ERROR: %s: MessageArgInfo missing or has invalid type!\n", __func__); + logger(LL_ERROR, "%s: MessageArgInfo missing or has invalid type!\n", __func__); goto error_out; } @@ -3751,7 +3753,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl if (strcmp(s_updater_name, "SE") == 0) { fwdict = restore_get_se_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get SE firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get SE firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "Savage") == 0) { @@ -3764,56 +3766,56 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl fwdict = restore_get_savage_firmware_data(client, p_info, arguments); } if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { fwdict = restore_get_rose_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { fwdict = restore_get_veridian_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { fwdict = restore_get_tcon_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get PCON1 firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { fwdict = restore_get_timer_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + logger(LL_ERROR, "%s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { - error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } @@ -3822,23 +3824,23 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } dict = plist_new_dict(); plist_dict_set_item(dict, "FirmwareResponseData", fwdict); - info("Sending FirmwareResponse data now...\n"); + logger(LL_INFO, "Sending FirmwareResponse data now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send FirmwareResponse data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send FirmwareResponse data (%d)\n", restore_error); goto error_out; } - info("Done sending FirmwareUpdater data\n"); + logger(LL_INFO, "Done sending FirmwareUpdater data\n"); return 0; @@ -3855,35 +3857,35 @@ static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, int restore_error; if (!client || !client->restore || !client->restore->build_identity) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } plist_t manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (!manifest) { - error("failed to get Manifest node from build_identity"); + logger(LL_ERROR, "%s: Failed to get Manifest node from build_identity\n", __func__); goto error_out; } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } dict = plist_new_dict(); plist_dict_set_item(dict, "ReceiptManifest", plist_copy(manifest)); - info("Sending ReceiptManifest data now...\n"); + logger(LL_INFO, "Sending ReceiptManifest data now...\n"); restore_error = _restore_service_send(service, dict, 0); plist_free(dict); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error); + logger(LL_ERROR, "Couldn't send ReceiptManifest data (%d)\n", restore_error); goto error_out; } - info("Done sending ReceiptManifest data\n"); + logger(LL_INFO, "Done sending ReceiptManifest data\n"); return 0; @@ -3937,20 +3939,20 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str device_error = idevice_connection_send(connection, (void *)&hdr, sizeof(hdr), &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != sizeof(hdr)) { - error("ERROR: BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr)); + logger(LL_ERROR, "BootabilityBundle unable to send header. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)sizeof(hdr)); return -1; } device_error = idevice_connection_send(connection, (void *)name, name_len, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != name_len) { - error("ERROR: BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len); + logger(LL_ERROR, "BootabilityBundle unable to send filename. (%d) Sent %u of %u bytes.\n", device_error, bytes, name_len); return -1; } if (st->st_size && data) { device_error = idevice_connection_send(connection, data, st->st_size, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != st->st_size) { - error("ERROR: BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size); + logger(LL_ERROR, "BootabilityBundle unable to send data. (%d) Sent %u of %lu bytes.\n", device_error, bytes, (long)st->st_size); return -1; } } @@ -3972,7 +3974,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch subpath = name + strlen(prefix); } - debug("DEBUG: BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath); + logger(LL_DEBUG, "BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath); unsigned char *buf = NULL; unsigned int size = 0; @@ -3980,7 +3982,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch if ((S_ISLNK(stat->st_mode) || S_ISREG(stat->st_mode)) && stat->st_size != 0) { ipsw_extract_to_memory(ipsw, name, &buf, &size); if (size != stat->st_size) { - error("ERROR: expected %ld bytes but got %d for file %s\n", (long)stat->st_size, size, name); + logger(LL_ERROR, "expected %ld bytes but got %d for file %s\n", (long)stat->st_size, size, name); free(buf); return -1; } @@ -3996,9 +3998,9 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got BootabilityBundle request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } plist_t node = plist_dict_get_item(message, "DataPort"); @@ -4011,28 +4013,28 @@ static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* idevice_error_t device_error = IDEVICE_E_SUCCESS; if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { - error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + logger(LL_ERROR, "%s: idevicerestore client not initialized?!\n", __func__); return -1; } - debug("Connecting to BootabilityBundle data port\n"); + logger(LL_DEBUG, "Connecting to BootabilityBundle data port\n"); while (--attempts > 0) { device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } sleep(1); - debug("Retrying connection...\n"); + logger(LL_DEBUG, "Retrying connection...\n"); } if (device_error != IDEVICE_E_SUCCESS) { - error("ERROR: Unable to connect to BootabilityBundle data port\n"); + logger(LL_ERROR, "Unable to connect to BootabilityBundle data port\n"); return -1; } int ret = ipsw_list_contents(client->ipsw, restore_bootability_send_one, connection); if (ret < 0) { - error("ERROR: Failed to send BootabilityBundle\n"); + logger(LL_ERROR, "Failed to send BootabilityBundle\n"); return ret; } @@ -4062,7 +4064,7 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); if (unique_id_node) { - info("UniqueBuildID: "); + logger(LL_INFO, "UniqueBuildID: "); plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); } @@ -4079,13 +4081,13 @@ int extract_macos_variant(plist_t build_identity, char** output) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { - error("ERROR: build identity does not contain an 'Info' element\n"); + logger(LL_ERROR, "build identity does not contain an 'Info' element\n"); return -1; } plist_t macos_variant_node = plist_dict_get_item(build_info, "MacOSVariant"); if (!macos_variant_node) { - error("ERROR: build identity info does not contain a MacOSVariant\n"); + logger(LL_ERROR, "build identity info does not contain a MacOSVariant\n"); return -1; } plist_get_string_val(macos_variant_node, output); @@ -4097,13 +4099,13 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { - error("ERROR: build identity does not contain an 'Info' element\n"); + logger(LL_ERROR, "build identity does not contain an 'Info' element\n"); return NULL; } plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass"); if (!device_class_node) { - error("ERROR: build identity info does not contain a DeviceClass\n"); + logger(LL_ERROR, "build identity info does not contain a DeviceClass\n"); return NULL; } char *device_class = NULL; @@ -4136,13 +4138,13 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil { char* ticket_path = extract_global_manifest_path(build_identity, variant); if (!ticket_path) { - error("ERROR: failed to get global manifest path\n"); + logger(LL_ERROR, "failed to get global manifest path\n"); return -1; } int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); if (ret != 0) { free(ticket_path); - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } free(ticket_path); @@ -4154,6 +4156,7 @@ struct _restore_send_file_data_ctx { struct idevicerestore_client_t* client; restore_service_client_t service; int last_progress; + uint32_t tag; }; static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) @@ -4169,18 +4172,18 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); - error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); + logger(LL_ERROR, "%s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); /* special handling for AEA image format */ if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { - info("Encountered First Chunk in AEA image\n"); + logger(LL_INFO, "Encountered First Chunk in AEA image\n"); plist_t message = NULL; property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000); if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { - info("NOTE: No URLAsset requested, assuming it is not necessary."); + logger(LL_INFO, "No URLAsset requested, assuming it is not necessary.\n"); } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) { restore_send_url_asset(rctx->client, message); } @@ -4188,6 +4191,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; + set_progress(rctx->tag, progress); int progress_int = (int)(progress*100.0); if (progress_int > rctx->last_progress) { idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress); @@ -4199,20 +4203,20 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got PersonalizedBootObjectV3 request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } char *image_name = NULL; plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); return -1; } plist_get_string_val(node, &image_name); if (!image_name) { - debug("Failed to parse arguments from PersonalizedBootObjectV3 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from PersonalizedBootObjectV3 as string\n"); return -1; } @@ -4224,7 +4228,7 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - info("About to send %s...\n", component); + logger(LL_INFO, "About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size); @@ -4234,30 +4238,30 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli } else if (strcmp(image_name, "__RestoreVersion__") == 0) { int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size); if (ret != 0) { - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } } else if (strcmp(image_name, "__SystemVersion__") == 0) { int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size); if (ret != 0) { - error("ERROR: failed to read global manifest\n"); + logger(LL_ERROR, "failed to read global manifest\n"); return -1; } } else { // Get component path if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { plist_t build_identity = restore_get_build_identity_from_request(client, message); if (!build_identity) { - error("ERROR: Unable to find a matching build identity\n"); + logger(LL_ERROR, "Unable to find a matching build identity\n"); return -1; } if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } @@ -4269,7 +4273,7 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); + logger(LL_ERROR, "Unable to extract component %s\n", component); return -1; } @@ -4278,23 +4282,26 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } } restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); struct _restore_send_file_data_ctx rctx; rctx.client = client; rctx.service = service; rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + register_progress(rctx.tag, component); int64_t i = size; while (i > 0) { @@ -4302,7 +4309,8 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { free(data); _restore_service_free(service); - error("ERROR: Unable to send component %s data\n", component); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Unable to send component %s data\n", component); return -1; } i -= blob_size; @@ -4310,29 +4318,30 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli free(data); _restore_send_file_data(&rctx, NULL, 0, size-i, size); + finalize_progress(rctx.tag); _restore_service_free(service); - info("Done sending %s\n", component); + logger(LL_INFO, "Done sending %s\n", component); return 0; } int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) { - debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(message); + if (client->debug_level > 1) { + logger(LL_DEBUG, "%s: Got SourceBootObjectV4 request:\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); } char *image_name = NULL; plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } plist_get_string_val(node, &image_name); if (!image_name) { - debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } @@ -4346,18 +4355,18 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - info("About to send %s...\n", component); + logger(LL_INFO, "About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { - debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; } plist_get_string_val(node, &variant); if (!variant) { - debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + logger(LL_DEBUG, "Failed to parse arguments from SourceBootObjectV4 as string\n"); return -1; } @@ -4370,20 +4379,20 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p // Get component path if (client->tss) { if (tss_response_get_path_by_entry(client->tss, component, &path) < 0) { - debug("NOTE: No path for component %s in TSS, will fetch from build identity\n", component); + logger(LL_DEBUG, "No path for component %s in TSS, will fetch from build identity\n", component); } } if (!path) { plist_t build_identity = restore_get_build_identity_from_request(client, message); if (build_identity_get_component_path(build_identity, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } } } if (!path) { - error("ERROR: Failed to get path for component %s\n", component); + logger(LL_ERROR, "Failed to get path for component %s\n", component); return -1; } @@ -4392,28 +4401,33 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize); struct _restore_send_file_data_ctx rctx; rctx.client = client; rctx.service = service; rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + register_progress(rctx.tag, component); if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); _restore_service_free(service); - error("ERROR: Failed to send component %s\n", component); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Failed to send component %s\n", component); return -1; } free(path); _restore_service_free(service); + finalize_progress(rctx.tag); - info("Done sending %s\n", component); + logger(LL_INFO, "Done sending %s\n", component); return 0; } @@ -4436,7 +4450,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(message, "Arguments")); if (ret < 0) { - error("ERROR: Unable to get recovery os local policy tss response\n"); + logger(LL_ERROR, "Unable to get recovery os local policy tss response\n"); return -1; } @@ -4444,7 +4458,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s\n", component); + logger(LL_ERROR, "Unable to get personalized component %s\n", component); return -1; } @@ -4453,7 +4467,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } @@ -4461,7 +4475,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl restore_error = _restore_service_send(service, dict, 0); _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component); + logger(LL_ERROR, "Unable to send component %s data\n", component); return -1; } @@ -4478,11 +4492,11 @@ int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t m restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("About to send BuildIdentity Dict...\n"); + logger(LL_INFO, "About to send BuildIdentity Dict...\n"); plist_t build_identity = restore_get_build_identity_from_request(client, message); @@ -4496,16 +4510,16 @@ int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t m plist_dict_set_item(dict, "Variant", plist_new_string("Erase")); } - info("Sending BuildIdentityDict now...\n"); + logger(LL_INFO, "Sending BuildIdentityDict now...\n"); restore_error = _restore_service_send(service, dict, 0); _restore_service_free(service); plist_free(dict); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send BuildIdentityDict (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send BuildIdentityDict (%d)\n", restore_error); return -1; } - info("Done sending BuildIdentityDict\n"); + logger(LL_INFO, "Done sending BuildIdentityDict\n"); return 0; } @@ -4517,13 +4531,13 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl plist_get_string_val(node, &fw_override_key); } if (!fw_override_key) { - error("ERROR: Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n"); + logger(LL_ERROR, "Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n"); return -1; } plist_t dict = plist_new_dict(); if (!client->recovery_variant) { - error("ERROR: no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n"); + logger(LL_ERROR, "no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n"); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); @@ -4531,7 +4545,7 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl } if (strncmp(fw_override_key, "RecoveryOS", 10) != 0) { - error("ERROR: FWOVerrideKey has unexpected prefix\n"); + logger(LL_ERROR, "FWOVerrideKey has unexpected prefix\n"); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); @@ -4541,7 +4555,7 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl const char* component = fw_override_key+10; char* path = NULL; if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { - error("ERROR: Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component); + logger(LL_ERROR, "Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); @@ -4554,7 +4568,7 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl free(path); path = NULL; if (ret < 0) { - error("ERROR: Unable to extract component %s. Trying to continue anyway.\n", component); + logger(LL_ERROR, "Unable to extract component %s. Trying to continue anyway.\n", component); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); @@ -4567,14 +4581,14 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl free(component_data); component_data = NULL; if (ret < 0) { - error("ERROR: Unable to get personalized component %s. Trying to continue anyway.\n", component); + logger(LL_ERROR, "Unable to get personalized component %s. Trying to continue anyway.\n", component); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); return 0; } - info("Sending %s\n", fw_override_key); + logger(LL_INFO, "Sending %s\n", fw_override_key); plist_dict_set_item(dict, "AdditionalBootImages", plist_new_data((char*)data, size)); free(data); @@ -4588,7 +4602,7 @@ int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_ { plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); if (!build_id_manifest) { - error("ERROR: Missing Manifest dictionary in build identity?!\n"); + logger(LL_ERROR, "Missing Manifest dictionary in build identity?!\n"); return -1; } @@ -4646,7 +4660,7 @@ int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_ if (plist_dict_get_size(firmware_files) == 0) { plist_free(firmware_files); - info("NOTE: No iBoot firmware files. Continuing.\n"); + logger(LL_NOTICE, "No iBoot firmware files. Continuing.\n"); plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); restored_send(client->restore->client, dict); plist_free(dict); @@ -4654,7 +4668,7 @@ int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_ } - info("Sending iBoot additional firmware files\n"); + logger(LL_INFO, "Sending iBoot additional firmware files\n"); plist_dict_set_item(dict, "AdditionalBootImages", firmware_files); restored_send(client->restore->client, dict); @@ -4668,11 +4682,11 @@ int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist const char* component = "OS"; char* path = NULL; if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { - error("ERROR: Unable to find %s path from build identity\n", component); + logger(LL_ERROR, "Unable to find %s path from build identity\n", component); return -1; } if (!path) { - error("ERROR: Failed to get path for component %s\n", component); + logger(LL_ERROR, "Failed to get path for component %s\n", component); return -1; } @@ -4681,28 +4695,33 @@ int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); if (!service) { - error("ERROR: %s: Unable to connect to service client\n", __func__); + logger(LL_ERROR, "%s: Unable to connect to service client\n", __func__); return -1; } - info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + logger(LL_INFO, "Sending %s now (%" PRIu64 " bytes)\n", component, fsize); struct _restore_send_file_data_ctx rctx; rctx.client = client; rctx.service = service; rctx.last_progress = 0; + rctx.tag = progress_get_next_tag(); + + register_progress(rctx.tag, component); if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); _restore_service_free(service); - error("ERROR: Failed to send component %s\n", component); + finalize_progress(rctx.tag); + logger(LL_ERROR, "Failed to send component %s\n", component); return -1; } free(path); _restore_service_free(service); + finalize_progress(rctx.tag); - info("Done sending %s\n", component); + logger(LL_INFO, "Done sending %s\n", component); return 0; } @@ -4711,7 +4730,7 @@ int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client { plist_t build_id_info = plist_dict_get_item(client->recovery_variant, "Info"); if (!build_id_info) { - error("ERROR: Missing Info dictionary in build identity?!\n"); + logger(LL_ERROR, "Missing Info dictionary in build identity?!\n"); return -1; } plist_t version_data = plist_new_dict(); @@ -4724,7 +4743,7 @@ int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client plist_to_xml(version_data, &xml, &xml_len); plist_free(version_data); - info("Sending RecoveryOS version data\n"); + logger(LL_INFO, "Sending RecoveryOS version data\n"); plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_data(xml, xml_len)); @@ -4744,39 +4763,39 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plis node = plist_dict_get_item(message, "DataType"); if (node && PLIST_STRING == plist_get_node_type(node)) { const char *type = plist_get_string_ptr(node, NULL); -debug("%s: type = %s\n", __func__, type); +logger(LL_DEBUG, "%s: type = %s\n", __func__, type); // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { if (restore_send_filesystem(client, message) < 0) { - error("ERROR: Unable to send filesystem\n"); + logger(LL_ERROR, "Unable to send filesystem\n"); return -2; } } else if (!strcmp(type, "BuildIdentityDict")) { if (restore_send_buildidentity(client, message) < 0) { - error("ERROR: Unable to send RootTicket\n"); + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } else if (!strcmp(type, "PersonalizedBootObjectV3")) { if (restore_send_personalized_boot_object_v3(client, message) < 0) { - error("ERROR: Unable to send PersonalizedBootObjectV3\n"); + logger(LL_ERROR, "Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { if (restore_send_source_boot_object_v4(client, message) < 0) { - error("ERROR: Unable to send SourceBootObjectV4\n"); + logger(LL_ERROR, "Unable to send SourceBootObjectV4\n"); return -1; } } else if (!strcmp(type, "RecoveryOSLocalPolicy")) { if (restore_send_restore_local_policy(client, message) < 0) { - error("ERROR: Unable to send RecoveryOSLocalPolicy\n"); + logger(LL_ERROR, "Unable to send RecoveryOSLocalPolicy\n"); return -1; } } @@ -4784,7 +4803,7 @@ debug("%s: type = %s\n", __func__, type); // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { if (restore_send_filesystem(client, message) < 0) { - error("ERROR: Unable to send filesystem\n"); + logger(LL_ERROR, "Unable to send filesystem\n"); return -2; } } @@ -4792,7 +4811,7 @@ debug("%s: type = %s\n", __func__, type); // Send RecoveryOS RTD else if(!strcmp(type, "RecoveryOSRootTicketData")) { if (restore_send_recovery_os_root_ticket(client, message) < 0) { - error("ERROR: Unable to send RootTicket\n"); + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } @@ -4800,35 +4819,35 @@ debug("%s: type = %s\n", __func__, type); // send RootTicket (== APTicket from the TSS request) else if (!strcmp(type, "RootTicket")) { if (restore_send_root_ticket(client, message) < 0) { - error("ERROR: Unable to send RootTicket\n"); + logger(LL_ERROR, "Unable to send RootTicket\n"); return -1; } } // send KernelCache else if (!strcmp(type, "KernelCache")) { if (restore_send_component(client, message, "KernelCache", NULL) < 0) { - error("ERROR: Unable to send kernelcache\n"); + logger(LL_ERROR, "Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { if (restore_send_component(client, message, "DeviceTree", NULL) < 0) { - error("ERROR: Unable to send DeviceTree\n"); + logger(LL_ERROR, "Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { if (restore_send_component(client, message, "SystemVolume", type) < 0) { - error("ERROR: Unable to send SystemImageRootHash data\n"); + logger(LL_ERROR, "Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { - error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); + logger(LL_ERROR, "Unable to send SystemImageCanonicalMetadata data\n"); return -1; } } @@ -4836,132 +4855,131 @@ debug("%s: type = %s\n", __func__, type); else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { if(restore_send_nor(client, message) < 0) { - error("ERROR: Unable to send NOR data\n"); + logger(LL_ERROR, "Unable to send NOR data\n"); return -1; } } else { - info("Not sending NORData... Quitting...\n"); + logger(LL_INFO, "Not sending NORData... Quitting...\n"); client->flags |= FLAG_QUIT; } } else if (!strcmp(type, "BasebandData")) { if(restore_send_baseband_data(client, message) < 0) { - error("ERROR: Unable to send baseband data\n"); + logger(LL_ERROR, "Unable to send baseband data\n"); return -1; } } else if (!strcmp(type, "FDRTrustData")) { if(restore_send_fdr_trust_data(client, message) < 0) { - error("ERROR: Unable to send FDR Trust data\n"); + logger(LL_ERROR, "Unable to send FDR Trust data\n"); return -1; } } else if (!strcmp(type, "FUDData")) { if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { - error("ERROR: Unable to send FUD data\n"); + logger(LL_ERROR, "Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { if(restore_send_firmware_updater_preflight(client, message) < 0) { - error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); + logger(LL_ERROR, "Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { if(restore_send_firmware_updater_data(client, message) < 0) { - error("ERROR: Unable to send FirmwareUpdater data\n"); + logger(LL_ERROR, "Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) { - error("ERROR: Unable to send Personalized data\n"); + logger(LL_ERROR, "Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { - error("ERROR: Unable to send Personalized data\n"); + logger(LL_ERROR, "Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { if (restore_send_bootability_bundle_data(client, message) < 0) { - error("ERROR: Unable to send BootabilityBundle data\n"); + logger(LL_ERROR, "Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { if (restore_send_receipt_manifest(client, message) < 0) { - error("ERROR: Unable to send ReceiptManifest data\n"); + logger(LL_ERROR, "Unable to send ReceiptManifest data\n"); return -1; } } else if (!strcmp(type, "BasebandUpdaterOutputData")) { if (restore_handle_baseband_updater_output_data(client, message) < 0) { - error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); + logger(LL_ERROR, "Unable to send BasebandUpdaterOutputData data\n"); return -1; } } else if (!strcmp(type, "URLAsset")) { if (restore_send_url_asset(client, message) < 0) { - error("ERROR: Unable to send URLAsset data\n"); + logger(LL_ERROR, "Unable to send URLAsset data\n"); return -1; } } else if (!strcmp(type, "StreamedImageDecryptionKey")) { if (restore_send_streamed_image_decryption_key(client, message) < 0) { - error("ERROR: Unable to send StreamedImageDecryptionKey data\n"); + logger(LL_ERROR, "Unable to send StreamedImageDecryptionKey data\n"); return -1; } } else if (!strcmp(type, "RecoveryOSFileAssetImage")) { if (restore_send_recovery_os_file_asset_image(client, message) < 0) { - error("ERROR: Unable to send RecoveryOSFileImageAssetImage data\n"); + logger(LL_ERROR, "Unable to send RecoveryOSFileImageAssetImage data\n"); return -1; } } else if (!strcmp(type, "RecoveryOSIBootFWFilesImages")) { if (restore_send_recovery_os_iboot_fw_files_images(client, message) < 0) { - error("ERROR: Unable to send RecoveryOSIBootFWFilesImages data\n"); + logger(LL_ERROR, "Unable to send RecoveryOSIBootFWFilesImages data\n"); return -1; } } else if (!strcmp(type, "RecoveryOSImage")) { if (restore_send_recovery_os_image(client, message) < 0) { - error("ERROR: Unable to send RecoveryOSImage data\n"); + logger(LL_ERROR, "Unable to send RecoveryOSImage data\n"); return -1; } } else if (!strcmp(type, "RecoveryOSVersionData")) { if (restore_send_recovery_os_version_data(client, message) < 0) { - error("ERROR: Unable to send RecoveryOSVersionData data\n"); + logger(LL_ERROR, "Unable to send RecoveryOSVersionData data\n"); return -1; } } else { // Unknown DataType!! - error("Unknown data request '%s' received\n", type); - if (idevicerestore_debug) - debug_plist(message); + logger(LL_ERROR, "Unknown data request '%s' received\n", type); + logger_dump_plist(LL_VERBOSE, message, 1); } } return 0; @@ -4992,40 +5010,38 @@ static void* _restore_handle_async_data_request(void* args) static int restore_handle_restored_crash(struct idevicerestore_client_t* client, plist_t message) { plist_t backtrace = plist_dict_get_item(message, "RestoredBacktrace"); - info("*** restored crashed, backtrace following ***"); + logger(LL_INFO, "*** restored crashed, backtrace following ***\n"); if (PLIST_IS_STRING(backtrace)) { - info("%s\n", plist_get_string_ptr(backtrace, NULL)); + logger(LL_INFO, "%s\n", plist_get_string_ptr(backtrace, NULL)); } else if (PLIST_IS_ARRAY(backtrace)) { uint32_t i = 0; for (i = 0; i < plist_array_get_size(backtrace); i++) { plist_t line = plist_array_get_item(backtrace, i); - info("\t%s\n", plist_get_string_ptr(line, NULL)); + logger(LL_INFO, "\t%s\n", plist_get_string_ptr(line, NULL)); } } else { - debug_plist(message); + logger_dump_plist(LL_VERBOSE, message, 1); } return 0; } static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message) { - debug("AsyncWait\n"); - if (idevicerestore_debug) - debug_plist(message); + logger(LL_DEBUG, "AsyncWait\n"); + logger_dump_plist(LL_DEBUG, message, 1); return 0; } static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message) { - if (idevicerestore_debug) - debug_plist(message); - debug("Sending RestoreShouldAttest: false\n"); + logger_dump_plist(LL_DEBUG, message, 1); + logger(LL_DEBUG, "Sending RestoreShouldAttest: false\n"); plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "RestoreShouldAttest", plist_new_bool(0)); restored_error_t restore_error = restored_send(client->restore->client, dict); plist_free(dict); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send RestoreShouldAttest (%d)\n", restore_error); + logger(LL_ERROR, "Unable to send RestoreShouldAttest (%d)\n", restore_error); return -1; } return 0; @@ -5075,7 +5091,7 @@ static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_ const char* path = plist_get_string_ptr(p_path, NULL); uint64_t fsize = 0; if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) { - debug("%s: Adding %s (%s, %llu bytes)\n", __func__, component, path, fsize); + logger(LL_DEBUG, "%s: Adding %s (%s, %llu bytes)\n", __func__, component, path, fsize); total_size += (double)fsize / 0x100000; } } @@ -5190,12 +5206,12 @@ plist_t restore_supported_message_types() #ifdef HAVE_REVERSE_PROXY static void rp_log_cb(reverse_proxy_client_t client, const char* log_msg, void* user_data) { - info("ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); + logger(LL_INFO, "ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); } static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t status, const char* status_msg, void* user_data) { - info("ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); + logger(LL_INFO, "ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); } #endif @@ -5218,10 +5234,10 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // open our connection to the device and verify we're in restore mode err = restore_open_with_timeout(client); if (err < 0) { - error("ERROR: Unable to open device in restore mode\n"); + logger(LL_ERROR, "Unable to open device in restore mode\n"); return (err == -2) ? -1: -2; } - info("Device %s has successfully entered restore mode\n", client->udid); + logger(LL_INFO, "Device %s has successfully entered restore mode\n", client->udid); client->restore->build_identity = build_identity; restore = client->restore->client; @@ -5231,30 +5247,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit if (restore_error == RESTORE_E_SUCCESS) { uint64_t i = 0; uint8_t b = 0; - info("Hardware Information:\n"); + logger(LL_INFO, "Hardware Information:\n"); node = plist_dict_get_item(hwinfo, "BoardID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("BoardID: %d\n", (int)i); + logger(LL_INFO, "BoardID: %d\n", (int)i); } node = plist_dict_get_item(hwinfo, "ChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("ChipID: %d\n", (int)i); + logger(LL_INFO, "ChipID: %d\n", (int)i); } node = plist_dict_get_item(hwinfo, "UniqueChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &i); - info("UniqueChipID: %" PRIu64 "\n", i); + logger(LL_INFO, "UniqueChipID: %" PRIu64 "\n", i); } node = plist_dict_get_item(hwinfo, "ProductionMode"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { plist_get_bool_val(node, &b); - info("ProductionMode: %s\n", (b==1) ? "true":"false"); + logger(LL_INFO, "ProductionMode: %s\n", (b==1) ? "true":"false"); } plist_free(hwinfo); } @@ -5266,7 +5282,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "PreviousExitStatus"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Previous restore exit status: %s\n", sval); + logger(LL_INFO, "Previous restore exit status: %s\n", sval); free(sval); sval = NULL; } @@ -5274,7 +5290,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "USBLog"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("USB log is available:\n%s\n", sval); + logger(LL_INFO, "USB log is available:\n%s\n", sval); free(sval); sval = NULL; } @@ -5282,7 +5298,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(hwinfo, "PanicLog"); if (node && plist_get_node_type(node) == PLIST_STRING) { plist_get_string_val(node, &sval); - info("Panic log is available:\n%s\n", sval); + logger(LL_INFO, "Panic log is available:\n%s\n", sval); free(sval); sval = NULL; } @@ -5294,42 +5310,42 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } #ifdef HAVE_REVERSE_PROXY - info("Starting Reverse Proxy\n"); + logger(LL_INFO, "Starting Reverse Proxy\n"); reverse_proxy_client_t rproxy = NULL; if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) { - error("Could not create Reverse Proxy\n"); + logger(LL_ERROR, "Could not create Reverse Proxy\n"); } else { if (client->flags & FLAG_DEBUG) { reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL); } reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL); if (reverse_proxy_client_start_proxy(rproxy, 2) != REVERSE_PROXY_E_SUCCESS) { - error("Device didn't accept new reverse proxy protocol, trying to use old one\n"); + logger(LL_ERROR, "Device didn't accept new reverse proxy protocol, trying to use old one\n"); reverse_proxy_client_free(rproxy); rproxy = NULL; if (reverse_proxy_client_create_with_port(device, &rproxy, REVERSE_PROXY_DEFAULT_PORT) != REVERSE_PROXY_E_SUCCESS) { - error("Could not create Reverse Proxy\n"); + logger(LL_ERROR, "Could not create Reverse Proxy\n"); } else { if (client->flags & FLAG_DEBUG) { reverse_proxy_client_set_log_callback(rproxy, rp_log_cb, NULL); } reverse_proxy_client_set_status_callback(rproxy, rp_status_cb, NULL); if (reverse_proxy_client_start_proxy(rproxy, 1) != REVERSE_PROXY_E_SUCCESS) { - error("ReverseProxy: Device didn't accept old protocol, giving up\n"); + logger(LL_ERROR, "ReverseProxy: Device didn't accept old protocol, giving up\n"); } } } } #else fdr_client_t fdr_control_channel = NULL; - info("Starting FDR listener thread\n"); + logger(LL_INFO, "Starting FDR listener thread\n"); if (!fdr_connect(device, FDR_CTRL, &fdr_control_channel)) { if(thread_new(&fdr_thread, fdr_listener_thread, fdr_control_channel)) { - error("ERROR: Failed to start FDR listener thread\n"); + logger(LL_ERROR, "Failed to start FDR listener thread\n"); fdr_thread = THREAD_T_NULL; /* undefined after failure */ } } else { - error("ERROR: Failed to start FDR Ctrl channel\n"); + logger(LL_ERROR, "Failed to start FDR Ctrl channel\n"); // FIXME: We might want to return failure here as it will likely fail } #endif @@ -5429,16 +5445,16 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit uint64_t max_size = 0; uint64_t min_size = 0; _restore_calculate_recovery_os_partition_size(client, &min_size, &max_size); - info("Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size); - info("Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size); + logger(LL_INFO, "Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size); + logger(LL_INFO, "Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size); plist_dict_set_item(opts, "recoveryOSMaxPartitionSize", plist_new_uint(max_size)); plist_dict_set_item(opts, "recoveryOSPartitionSize", plist_new_uint(min_size)); } if (plist_dict_get_bool(client->parameters, "RequiresNonceSlot")) { - info("Device will use nonce slots.\n"); + logger(LL_INFO, "Device will use nonce slots.\n"); } else { - info("Device will not use nonce slots.\n"); + logger(LL_INFO, "Device will not use nonce slots.\n"); } // Added for iOS 18.0 beta 1 @@ -5452,7 +5468,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit if (node && plist_get_node_type(node) == PLIST_STRING) { char* sval = NULL; plist_get_string_val(node, &sval); - debug("TZ0RequiredCapacity: %s\n", sval); + logger(LL_DEBUG, "TZ0RequiredCapacity: %s\n", sval); plist_dict_set_item(opts, "TZ0RequiredCapacity", plist_copy(node)); free(sval); sval = NULL; @@ -5504,7 +5520,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // start the restore process restore_error = restored_start_restore(restore, opts, client->restore->protocol_version); if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to start the restore process\n"); + logger(LL_ERROR, "Unable to start the restore process\n"); plist_free(opts); restore_client_free(client); return -1; @@ -5516,30 +5532,30 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // restored and passes that data on to it's specific handler while (!(client->flags & FLAG_QUIT)) { if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) { - error("WARNING: Attempting to continue after critical error, restore might fail...\n"); + logger(LL_WARNING, "Attempting to continue after critical error, restore might fail...\n"); err = 0; } // finally, if any of these message handlers returned -1 then we encountered // an unrecoverable error, so we need to bail. if (err < 0) { - error("ERROR: Unable to successfully restore device\n"); + logger(LL_ERROR, "Unable to successfully restore device\n"); client->flags |= FLAG_QUIT; } restore_error = restored_receive(restore, &message); #ifdef HAVE_RESTORE_E_RECEIVE_TIMEOUT if (restore_error == RESTORE_E_RECEIVE_TIMEOUT) { - debug("No data to read (timeout)\n"); + logger(LL_DEBUG, "No data to read (timeout)\n"); message = NULL; continue; } else if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Could not read data (%d). Aborting.\n", restore_error); + logger(LL_ERROR, "Could not read data (%d). Aborting.\n", restore_error); err = -11; break; } #else if (restore_error != RESTORE_E_SUCCESS) { - debug("No data to read\n"); + logger(LL_DEBUG, "No data to read\n"); message = NULL; continue; } @@ -5548,9 +5564,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // 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"); - //if (idevicerestore_debug) - debug_plist(message); + logger(LL_DEBUG, "Unknown message received:\n"); + logger_dump_plist(LL_DEBUG, message, 1); plist_free(message); message = NULL; continue; @@ -5572,7 +5587,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit args->message = plist_copy(message); if (thread_new(&t, _restore_handle_async_data_request, args) < 0) { free(args); - error("ERROR: Failed to start async data request handler thread!\n"); + logger(LL_ERROR, "Failed to start async data request handler thread!\n"); err = -1; if (client->flags & FLAG_IGNORE_ERRORS) { client->flags &= ~FLAG_IGNORE_ERRORS; @@ -5614,7 +5629,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // Get checkpoint id node = plist_dict_get_item(message, "CHECKPOINT_ID"); if (!node || plist_get_node_type(node) != PLIST_INT) { - debug("Failed to parse checkpoint id from checkpoint plist\n"); + logger(LL_DEBUG, "Failed to parse checkpoint id from checkpoint plist\n"); err = -1; break; } @@ -5625,7 +5640,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // Get checkpoint result node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); if (!node || plist_get_node_type(node) != PLIST_INT) { - debug("Failed to parse checkpoint result from checkpoint plist\n"); + logger(LL_DEBUG, "Failed to parse checkpoint result from checkpoint plist\n"); err = -1; break; } @@ -5637,17 +5652,17 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } if (ckpt_complete) { - info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); + logger(LL_VERBOSE, "Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); } else { - info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); + logger(LL_VERBOSE, "Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); } node = plist_dict_get_item(message, "CHECKPOINT_WARNING"); if (node) { - info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + logger(LL_VERBOSE, "Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); if (node) { - info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + logger(LL_VERBOSE, "Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } } @@ -5678,9 +5693,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // 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"); - //if (idevicerestore_debug) - debug_plist(message); + logger(LL_DEBUG, "Unknown message type received\n"); + logger_dump_plist(LL_DEBUG, message, 1); } free(type); From 8d0563380db8f3412de1fabf5ad74ccde1159eac Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+VisualEhrmanntraut@users.noreply.github.com> Date: Fri, 27 Jun 2025 12:16:04 +0300 Subject: [PATCH 124/159] Improve type safety of new logging system and its handling of varargs - Replaced loglevel arguments and globals using the `int` type with the `loglevel` enum. - Moved logging print func handler function declaration to typedef. - Fixed misuse of `print_func` where a char* was passed in place of `va_list` via a wrapper function `print_funcf`. - Fixed reuse of varargs in `logger` causing a segfault when `stderr_enabled` is true. - Fixed length in `snprintf` call inside `logger_hex_dump` truncating the printed text. --- src/idevicerestore.c | 4 ++-- src/log.c | 26 +++++++++++++++++++------- src/log.h | 6 ++++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3dd4bb93..f4ced47f 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1744,7 +1744,7 @@ static void plain_progress_func(struct progress_info_entry** progress_info, int } } -static void tty_print(int level, const char* format, va_list varglist) +static void tty_print(enum loglevel level, const char* fmt, va_list ap) { switch (level) { case 0: @@ -1760,7 +1760,7 @@ static void tty_print(int level, const char* format, va_list varglist) break; } - cvfprintf(stdout, format, varglist); + cvfprintf(stdout, fmt, ap); cprintf(COLOR_RESET); } diff --git a/src/log.c b/src/log.c index e6a3c8a3..978cf0bf 100644 --- a/src/log.c +++ b/src/log.c @@ -41,10 +41,10 @@ static int stderr_enabled = 1; -int log_level = LL_VERBOSE; -int print_level = LL_INFO; +enum loglevel log_level = LL_VERBOSE; +enum loglevel print_level = LL_INFO; -static void (*print_func)(int level, const char* fmt, va_list) = NULL; +static logger_print_func print_func = NULL; const char *_level_label[6] = { " ", @@ -98,6 +98,7 @@ INITIALIZER(logger_init) void logger(enum loglevel level, const char *fmt, ...) { va_list ap; + va_list ap2; char *fs; if (level > log_level) @@ -129,6 +130,7 @@ void logger(enum loglevel level, const char *fmt, ...) #endif va_start(ap, fmt); + va_copy(ap2, ap); if (print_func) { if (stderr_enabled) { vfprintf(stderr, fs, ap); @@ -136,19 +138,29 @@ void logger(enum loglevel level, const char *fmt, ...) } if (level <= print_level) { // skip the timestamp and log level string - print_func(level, fs+23, ap); + print_func(level, fs+23, ap2); } } else { vprintf(fs, ap); } va_end(ap); + va_end(ap2); free(fs); mutex_unlock(&log_mutex); } +static void print_funcf(enum loglevel level, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); +static void print_funcf(enum loglevel level, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + print_func(level, fmt, ap); + va_end(ap); +} + void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len) { char *fs; @@ -160,7 +172,7 @@ void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len) fs = (char*)malloc(len * 3 + 1); for (unsigned int i = 0; i < len; i++) { - snprintf(fs + i*3, 3, "%02x%c", ((unsigned char*)buf)[i], (i < len-1) ? ' ' : '\n'); + snprintf(fs + i*3, 4, "%02x%c", ((unsigned char*)buf)[i], (i < len-1) ? ' ' : '\n'); } if (print_func) { if (stderr_enabled) { @@ -168,7 +180,7 @@ void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len) fflush(stderr); } if (level <= print_level) { - print_func(level, "%s", fs); + print_funcf(level, "%s", fs); } } else { printf("%s", fs); @@ -204,7 +216,7 @@ int logger_set_logfile(const char* path) return 0; } -void logger_set_print_func(void (*func)(int, const char*, va_list)) +void logger_set_print_func(logger_print_func func) { print_func = func; } diff --git a/src/log.h b/src/log.h index 80642c0e..ad3da140 100644 --- a/src/log.h +++ b/src/log.h @@ -30,11 +30,13 @@ enum loglevel { LL_DEBUG }; -extern int log_level; +extern enum loglevel log_level; + +typedef void (*logger_print_func)(enum loglevel level, const char*, va_list); void logger(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); int logger_set_logfile(const char* path); -void logger_set_print_func(void (*func)(int level, const char*, va_list)); +void logger_set_print_func(logger_print_func func); void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len); void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable); From 0aa3cbdc82b45e19ac9bac42397b9b8f123a521a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Jun 2025 16:20:32 +0200 Subject: [PATCH 125/159] log: Make sure to only add compiler attribute for supported compilers --- src/log.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/log.c b/src/log.c index 978cf0bf..515bea1f 100644 --- a/src/log.c +++ b/src/log.c @@ -152,7 +152,12 @@ void logger(enum loglevel level, const char *fmt, ...) mutex_unlock(&log_mutex); } +#if defined(__GNUC__) || defined(__clang__) static void print_funcf(enum loglevel level, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); +#else +static void print_funcf(enum loglevel level, const char* fmt, ...); +#endif + static void print_funcf(enum loglevel level, const char* fmt, ...) { va_list ap; From 7ba50eb7c73d0b5ddacbd6b31c3ba2a114f02188 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Jun 2025 18:47:50 +0200 Subject: [PATCH 126/159] [github-actions] Update build workflow for Windows build to use windows-latest --- .github/workflows/build.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 70287669..1cf86364 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -193,7 +193,7 @@ jobs: name: idevicerestore-latest_macOS path: idevicerestore.tar build-windows: - runs-on: windows-2019 + runs-on: windows-latest defaults: run: shell: msys2 {0} @@ -218,7 +218,10 @@ jobs: libtool autoconf automake-wrapper - liblzma + mingw-w64-${{ matrix.arch }}-xz + mingw-w64-${{ matrix.arch }}-bzip2 + mingw-w64-${{ matrix.arch }}-openssl + pkg-config - name: prepare environment run: | dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]` @@ -291,7 +294,7 @@ jobs: echo "LIBCURL_LIBS=`pwd`/deps/lib/libcurl.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" >> $GITHUB_ENV - name: autogen run: | - ./autogen.sh CC=gcc CXX=g++ \ + ./autogen.sh PKG_CONFIG_PATH=/${{env.dest}}/lib/pkgconfig \ libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" \ zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="${{env.LIBCURL_CFLAGS}}" libcurl_LIBS="$LIBCURL_LIBS" - name: make From f89dea1aa863d09078650ab744b939e02924e411 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Jun 2025 19:07:33 +0200 Subject: [PATCH 127/159] restore: Fix curl_easy_setopt compiler warning --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 8f4e0237..31291767 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1420,7 +1420,7 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body); - curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, request_body_size); + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, (long)request_body_size); if (client->debug_level > 0) { curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); } From c17f9d6b17daa6121ec1ef0284d701cd3d1387b2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 27 Jun 2025 19:08:39 +0200 Subject: [PATCH 128/159] download: Use new CURLOPT_XFERINFOFUNCTION for libcurl >= 7.32 --- src/download.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/download.c b/src/download.c index d9fac45e..2f3a8361 100644 --- a/src/download.c +++ b/src/download.c @@ -86,9 +86,13 @@ int download_to_buffer(const char* url, char** buf, uint32_t* length) return res; } +#if LIBCURL_VERSION_NUM >= 0x072000 +static int download_progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +#else static int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) +#endif { - double p = (dlnow / dltotal); + double p = ((double)dlnow / (double)dltotal); set_progress('DNLD', p); @@ -125,7 +129,11 @@ int download_to_file(const char* url, const char* filename, int enable_progress) if (enable_progress > 0) { register_progress('DNLD', "Downloading"); +#if LIBCURL_VERSION_NUM >= 0x072000 + curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, (curl_progress_callback)&download_progress); +#else curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress); +#endif } curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1); From c752e8780b043c8822be2417cc5596b8f2ad9c0b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 1 Jul 2025 00:45:50 +0200 Subject: [PATCH 129/159] Update codebase to use (const) void* and size_t where applicable --- src/ace3.c | 6 +-- src/ace3.h | 2 +- src/asr.c | 4 +- src/asr.h | 2 +- src/dfu.c | 18 +++---- src/dfu.h | 4 +- src/download.c | 2 +- src/download.h | 2 +- src/fls.c | 12 ++--- src/fls.h | 8 +-- src/ftab.c | 8 +-- src/ftab.h | 8 +-- src/idevicerestore.c | 32 ++++++------ src/idevicerestore.h | 4 +- src/img3.c | 4 +- src/img3.h | 16 +----- src/img4.c | 2 +- src/img4.h | 2 +- src/ipsw.c | 42 +++++++++------ src/ipsw.h | 4 +- src/log.c | 2 +- src/log.h | 2 +- src/mbn.c | 4 +- src/mbn.h | 4 +- src/recovery.c | 10 ++-- src/restore.c | 122 ++++++++++++++++++++----------------------- 26 files changed, 158 insertions(+), 168 deletions(-) diff --git a/src/ace3.c b/src/ace3.c index 9bbc8b63..d3da3723 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -78,7 +78,7 @@ static int uarp_version_convert(uint32_t* version_data, uint32_t* version_out) return 0; } -int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size) +int ace3_create_binary(const void* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, void** bin_out, size_t* bin_size) { struct ace3bin_header { uint32_t magic; // 0xACE00003 @@ -220,7 +220,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); uint32_t toc_size = be32toh(uarp_hdr->toc_size); const unsigned char* p = uarp_fw + uarp_hdr_size; - while (p < uarp_fw + toc_size) { + while (p < (const unsigned char*)uarp_fw + toc_size) { struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p; uint32_t te_size = be32toh(entry->this_size); if (strncmp((char*)&(entry->fourcc), payload_4cc, 4) == 0) { @@ -244,7 +244,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint32_t content_size = data1_size + data2_size + im4m_size + dl_size; - *bin_out = (unsigned char*)malloc(0x40 + content_size); + *bin_out = malloc(0x40 + content_size); struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out); hdr->magic = htole32(0xACE00003); hdr->version = htole32(data1_version); diff --git a/src/ace3.h b/src/ace3.h index 2ef65a7c..6c93e1e2 100644 --- a/src/ace3.h +++ b/src/ace3.h @@ -8,7 +8,7 @@ extern "C" { #include #include -int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size); +int ace3_create_binary(const void* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, void** bin_out, size_t* bin_size); #ifdef __cplusplus } diff --git a/src/asr.c b/src/asr.c index fba59d9d..e140980e 100644 --- a/src/asr.c +++ b/src/asr.c @@ -175,14 +175,14 @@ int asr_send(asr_client_t asr, plist_t data) return 0; } -int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size) +int asr_send_buffer(asr_client_t asr, const void* data, size_t size) { uint32_t bytes = 0; idevice_error_t device_error = IDEVICE_E_SUCCESS; device_error = idevice_connection_send(asr->connection, data, size, &bytes); if (device_error != IDEVICE_E_SUCCESS || bytes != size) { - logger(LL_ERROR, "Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size); + logger(LL_ERROR, "Unable to send data to ASR. Sent %u of %zu bytes.\n", bytes, size); return -1; } diff --git a/src/asr.h b/src/asr.h index 4473fbb4..52e8d75d 100644 --- a/src/asr.h +++ b/src/asr.h @@ -50,7 +50,7 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port); void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); int asr_send(asr_client_t asr, plist_t data); int asr_receive(asr_client_t asr, plist_t* data); -int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size); +int asr_send_buffer(asr_client_t asr, const void* data, size_t size); void asr_free(asr_client_t asr); int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file); int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file); diff --git a/src/dfu.c b/src/dfu.c index 83046b96..4650e9a5 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -105,13 +105,13 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) return device; } -int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, const void* buffer, size_t size, unsigned int irecv_options) { irecv_error_t err = 0; - logger(LL_INFO, "Sending data (%d bytes)...\n", size); + logger(LL_INFO, "Sending data (%zu bytes)...\n", size); - err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); + err = irecv_send_buffer(client->dfu->client, (unsigned char*)buffer, size, irecv_options); if (err != IRECV_E_SUCCESS) { logger(LL_ERROR, "Unable to send data: %s\n", irecv_strerror(err)); return -1; @@ -120,7 +120,7 @@ int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigne return 0; } -int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) +int dfu_send_buffer(struct idevicerestore_client_t* client, const void* buffer, size_t size) { return dfu_send_buffer_with_options(client, buffer, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); } @@ -135,8 +135,8 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide tss = client->tss_localpolicy; } - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; if (strcmp(component, "Ap,LocalPolicy") == 0) { // If Ap,LocalPolicy => Inject an empty policy @@ -166,8 +166,8 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide path = NULL; } - unsigned char* data = NULL; - uint32_t size = 0; + void* data = NULL; + size_t size = 0; if (personalize_component(client, component, component_data, component_size, tss, &data, &size) < 0) { logger(LL_ERROR, "Unable to get personalized component: %s\n", component); @@ -198,7 +198,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide size += fillsize; } - logger(LL_INFO, "Sending %s (%d bytes)...\n", component, size); + logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size); irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); if (err != IRECV_E_SUCCESS) { diff --git a/src/dfu.h b/src/dfu.h index 4590dbd7..7b1d092f 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -40,8 +40,8 @@ struct dfu_client_t { int dfu_client_new(struct idevicerestore_client_t* client); void dfu_client_free(struct idevicerestore_client_t* client); irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client); -int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size); -int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options); +int dfu_send_buffer(struct idevicerestore_client_t* client, const void* buffer, size_t size); +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, const void* buffer, size_t size, unsigned int irecv_options); int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid); int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); diff --git a/src/download.c b/src/download.c index 2f3a8361..0b6b076b 100644 --- a/src/download.c +++ b/src/download.c @@ -43,7 +43,7 @@ static size_t download_write_buffer_callback(char* data, size_t size, size_t nme return total; } -int download_to_buffer(const char* url, char** buf, uint32_t* length) +int download_to_buffer(const char* url, void** buf, size_t* length) { int res = 0; CURL* handle = curl_easy_init(); diff --git a/src/download.h b/src/download.h index 1edde5be..bbb5aa08 100644 --- a/src/download.h +++ b/src/download.h @@ -28,7 +28,7 @@ extern "C" { #include -int download_to_buffer(const char* url, char** buf, uint32_t* length); +int download_to_buffer(const char* url, void** buf, size_t* length); int download_to_file(const char* url, const char* filename, int enable_progress); #ifdef __cplusplus diff --git a/src/fls.c b/src/fls.c index cc75c54d..8b747a93 100644 --- a/src/fls.c +++ b/src/fls.c @@ -101,7 +101,7 @@ static void fls_parse_elements(fls_file* fls) } } -fls_file* fls_parse(unsigned char* data, unsigned int size) +fls_file* fls_parse(const void* data, size_t size) { fls_file* fls = (fls_file*)malloc(sizeof(fls_file)); if (!fls) { @@ -132,7 +132,7 @@ void fls_free(fls_file* fls) } } -int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen) +int fls_update_sig_blob(fls_file* fls, const void* sigdata, size_t siglen) { /* FIXME: the code in this function is not big endian safe */ if (!fls || !fls->num_elements) { @@ -155,8 +155,8 @@ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned in return -1; } - uint32_t oldsiglen = datasize - sigoffset; - uint32_t newsize = fls->size - oldsiglen + siglen; + size_t oldsiglen = datasize - sigoffset; + size_t newsize = fls->size - oldsiglen + siglen; unsigned int i; uint32_t offset = 0; @@ -239,7 +239,7 @@ int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned in return 0; } -int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size) +int fls_insert_ticket(fls_file* fls, const void* data, size_t size) { /* FIXME: the code in this function is not big endian safe */ if (!fls || !fls->num_elements) { @@ -255,7 +255,7 @@ int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int siz if (size%4 != 0) { padding = 4-(size%4); } - uint32_t newsize = fls->size + size + padding; + size_t newsize = fls->size + size + padding; unsigned int i; uint32_t offset = 0; void* newdata = malloc(newsize); diff --git a/src/fls.h b/src/fls.h index 57b3869b..2db9029e 100644 --- a/src/fls.h +++ b/src/fls.h @@ -74,12 +74,12 @@ typedef struct { fls_element** elements; const fls_0c_element* c_element; void* data; - uint32_t size; + size_t size; } fls_file; -fls_file* fls_parse(unsigned char* data, unsigned int size); +fls_file* fls_parse(const void* data, size_t size); void fls_free(fls_file* fls); -int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size); -int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size); +int fls_update_sig_blob(fls_file* fls, const void* data, size_t size); +int fls_insert_ticket(fls_file* fls, const void* data, size_t size); #endif diff --git a/src/ftab.c b/src/ftab.c index cc742516..d0fc26b8 100644 --- a/src/ftab.c +++ b/src/ftab.c @@ -28,7 +28,7 @@ #include "common.h" #include "endianness.h" -int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag) +int ftab_parse(const void *data, size_t data_size, ftab_t *ftab, uint32_t *tag) { if (!data || !data_size || !ftab) { return -1; @@ -81,7 +81,7 @@ int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32 return 0; } -int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size) +int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, void **data, size_t *data_size) { if (!ftab || !tag || !data || !data_size) { return -1; @@ -99,7 +99,7 @@ int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned return res; } -int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size) +int ftab_add_entry(ftab_t ftab, uint32_t tag, const void *data, size_t data_size) { if (!ftab || !tag || !data || !data_size) { return -1; @@ -140,7 +140,7 @@ int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int return 0; } -int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size) +int ftab_write(ftab_t ftab, void **data, size_t *data_size) { uint32_t i; unsigned int total_size = sizeof(struct ftab_header); diff --git a/src/ftab.h b/src/ftab.h index a6ec6a44..d5d4d928 100644 --- a/src/ftab.h +++ b/src/ftab.h @@ -58,10 +58,10 @@ struct ftab_fmt { typedef struct ftab_fmt *ftab_t; -int ftab_parse(unsigned char *data, unsigned int data_size, ftab_t *ftab, uint32_t *tag); -int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, unsigned char **data, unsigned int *data_size); -int ftab_add_entry(ftab_t ftab, uint32_t tag, unsigned char *data, unsigned int data_size); -int ftab_write(ftab_t ftab, unsigned char **data, unsigned int *data_size); +int ftab_parse(const void *data, size_t data_size, ftab_t *ftab, uint32_t *tag); +int ftab_get_entry_ptr(ftab_t ftab, uint32_t tag, void **data, size_t *data_size); +int ftab_add_entry(ftab_t ftab, uint32_t tag, const void *data, size_t data_size); +int ftab_write(ftab_t ftab, void **data, size_t *data_size); int ftab_free(ftab_t ftab); #ifdef __cplusplus diff --git a/src/idevicerestore.c b/src/idevicerestore.c index f4ced47f..7be50ea9 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -419,8 +419,8 @@ int idevicerestore_start(struct idevicerestore_client_t* client) char wtfname[256]; snprintf(wtfname, sizeof(wtfname), "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); - unsigned char* wtftmp = NULL; - unsigned int wtfsize = 0; + void* wtftmp = NULL; + size_t wtfsize = 0; // Prefer to get WTF file from the restore IPSW ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize); @@ -773,8 +773,8 @@ int idevicerestore_start(struct idevicerestore_client_t* client) logger(LL_ERROR, "Unable to get path of USBPortController1,USBFirmware component\n"); return -1; } - unsigned char* uarp_buf = NULL; - unsigned int uarp_size = 0; + void* uarp_buf = NULL; + size_t uarp_size = 0; if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) { plist_free(parameters); logger(LL_ERROR, "Unable to extract '%s' from IPSW\n", fwpath); @@ -804,7 +804,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) logger(LL_INFO, "Received USBPortController1,Ticket\n"); logger(LL_INFO, "Creating Ace3Binary\n"); - unsigned char* ace3bin = NULL; + void* ace3bin = NULL; size_t ace3bin_size = 0; if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) { logger(LL_ERROR, "Could not create Ace3Binary\n"); @@ -814,7 +814,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) free(uarp_buf); if (idevicerestore_keep_pers) { - write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size); + write_file("Ace3Binary", ace3bin, ace3bin_size); } if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) { @@ -898,9 +898,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // get all_flash file manifest char *files[16]; - char *fmanifest = NULL; - uint32_t msize = 0; - if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) { + void *fmanifest = NULL; + size_t msize = 0; + if (ipsw_extract_to_memory(client->ipsw, tmpstr, &fmanifest, &msize) < 0) { logger(LL_ERROR, "could not extract %s from IPSW\n", tmpstr); free(build_identity); return -1; @@ -2809,7 +2809,7 @@ int build_manifest_get_identity_count(plist_t build_manifest) return plist_array_get_size(build_identities_array); } -int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) +int extract_component(ipsw_archive_t ipsw, const char* path, void** component_data, size_t* component_size) { char* component_name = NULL; if (!ipsw || !path || !component_data || !component_size) { @@ -2831,19 +2831,19 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com return 0; } -int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) +int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size) { - unsigned char* component_blob = NULL; - unsigned int component_blob_size = 0; - unsigned char* stitched_component = NULL; - unsigned int stitched_component_size = 0; + void* component_blob = NULL; + size_t component_blob_size = 0; + void* stitched_component = NULL; + size_t stitched_component_size = 0; if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ img4_stitch_component(component_name, component_data, component_size, client->parameters, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ - if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { + if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, (unsigned char**)&component_blob) < 0) { logger(LL_DEBUG, "NOTE: No SHSH blob found for component %s\n", component_name); } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 1e016726..9d6f5af2 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -112,8 +112,8 @@ void build_identity_print_information(plist_t build_identity); int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem); -int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); -int personalize_component(struct idevicerestore_client_t* client, const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); +int extract_component(ipsw_archive_t ipsw, const char* path, void** component_data, size_t* component_size); +int personalize_component(struct idevicerestore_client_t* client, const char *component, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size); int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest); const char* get_component_name(const char* filename); diff --git a/src/img3.c b/src/img3.c index a7008390..db50703f 100644 --- a/src/img3.c +++ b/src/img3.c @@ -402,7 +402,7 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int* return 0; } -int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size) +int img3_stitch_component(const char* component_name, const void* component_data, size_t component_size, const void* blob, size_t blob_size, void** img3_data, size_t *img3_size) { img3_file *img3 = NULL; unsigned char* outbuf = NULL; @@ -422,7 +422,7 @@ int img3_stitch_component(const char* component_name, const unsigned char* compo } if (((img3_element_header*)blob)->full_size != blob_size) { - logger(LL_ERROR, "Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %d\n", component_name, ((img3_element_header*)blob)->full_size, blob_size); + logger(LL_ERROR, "Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %zu\n", component_name, ((img3_element_header*)blob)->full_size, blob_size); img3_free(img3); return -1; } diff --git a/src/img3.h b/src/img3.h index 20d92485..b8e30e9d 100644 --- a/src/img3.h +++ b/src/img3.h @@ -79,23 +79,9 @@ typedef struct { int idx_ecid_element; int idx_shsh_element; int idx_cert_element; -/* img3_element* type_element; - img3_element* data_element; - img3_element* vers_element; - img3_element* sepo_element; - img3_element* bord_element; - img3_element* sepo2_element; - img3_element* chip_element; - img3_element* bord2_element; - img3_element* kbag1_element; - img3_element* kbag2_element; - img3_element* ecid_element; - img3_element* shsh_element; - img3_element* cert_element; - img3_element* unkn_element;*/ } img3_file; -int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size); +int img3_stitch_component(const char* component_name, const void* component_data, size_t component_size, const void* blob, size_t blob_size, void** img3_data, size_t *img3_size); #ifdef __cplusplus } diff --git a/src/img4.c b/src/img4.c index b23775a7..e58dd267 100644 --- a/src/img4.c +++ b/src/img4.c @@ -396,7 +396,7 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) +int img4_stitch_component(const char* component_name, const void* component_data, size_t component_size, plist_t parameters, plist_t tss_response, void** img4_data, size_t *img4_size) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; diff --git a/src/img4.h b/src/img4.h index 19c1c84e..1c5ef36b 100644 --- a/src/img4.h +++ b/src/img4.h @@ -26,7 +26,7 @@ extern "C" { #endif -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); +int img4_stitch_component(const char* component_name, const void* component_data, size_t component_size, plist_t parameters, plist_t tss_response, void** img4_data, size_t *img4_size); int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest); #ifdef __cplusplus diff --git a/src/ipsw.c b/src/ipsw.c index 201f9cd3..cebfa493 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -98,13 +98,13 @@ int ipsw_print_info(const char* path) } fclose(f); - char* plist_buf = NULL; + void* plist_buf = NULL; uint32_t plist_len = 0; if (memcmp(&magic, "PK\x03\x04", 4) == 0) { ipsw_archive_t ipsw = ipsw_open(thepath); - unsigned int rlen = 0; - if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { + size_t rlen = 0; + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &plist_buf, &rlen) < 0) { ipsw_close(ipsw); logger(LL_ERROR, "Failed to extract BuildManifest.plist from IPSW!\n"); return -1; @@ -113,7 +113,7 @@ int ipsw_print_info(const char* path) plist_len = (uint32_t)rlen; } else { size_t rlen = 0; - if (read_file(thepath, (void**)&plist_buf, &rlen) < 0) { + if (read_file(thepath, &plist_buf, &rlen) < 0) { logger(LL_ERROR, "Failed to read BuildManifest.plist!\n"); return -1; } @@ -623,7 +623,7 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) return 1; } -int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, void** pbuffer, size_t* psize) { size_t size = 0; unsigned char* buffer = NULL; @@ -666,6 +666,13 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha } size = zstat.size; + if ((uint64_t)size != (uint64_t)zstat.size) { + logger(LL_ERROR, "Not enough memory to allocate a buffer of size %" PRIu64 "\n", (uint64_t)zstat.size); + zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + return -1; + } buffer = (unsigned char*) malloc(size+1); if (buffer == NULL) { logger(LL_ERROR, "Out of memory\n"); @@ -687,7 +694,7 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha free(buffer); return -1; } else if (zr != size) { - logger(LL_ERROR, "zip_fread: %s got only %lld of %zu\n", infile, zr, size); + logger(LL_ERROR, "zip_fread: %s got only %zu of %zu\n", infile, (size_t)zr, size); free(buffer); return -1; } @@ -706,6 +713,11 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha return -1; } size = fst.st_size; + if ((uint64_t)size != (uint64_t)fst.st_size) { + logger(LL_ERROR, "Not enough memory to allocate a buffer of size %" PRIu64 "\n", (uint64_t)fst.st_size); + free(filepath); + return -1; + } buffer = (unsigned char*)malloc(size+1); if (buffer == NULL) { logger(LL_ERROR, "Out of memory\n"); @@ -901,15 +913,15 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; *tss_enabled = 0; /* older devices don't require personalized firmwares and use a BuildManifesto.plist */ if (ipsw_file_exists(ipsw, "BuildManifesto.plist")) { if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) { - plist_from_xml((char*)data, size, buildmanifest); + plist_from_memory((char*)data, size, buildmanifest, NULL); free(data); return 0; } @@ -921,7 +933,7 @@ int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int /* whereas newer devices do not require personalized firmwares and use a BuildManifest.plist */ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) == 0) { *tss_enabled = 1; - plist_from_xml((char*)data, size, buildmanifest); + plist_from_memory((char*)data, size, buildmanifest, NULL); free(data); return 0; } @@ -931,11 +943,11 @@ int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; if (ipsw_extract_to_memory(ipsw, "Restore.plist", &data, &size) == 0) { - plist_from_xml((char*)data, size, restore_plist); + plist_from_memory((char*)data, size, restore_plist, NULL); free(data); return 0; } @@ -1073,7 +1085,7 @@ int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares) { char url[256]; char *jdata = NULL; - uint32_t jsize = 0; + size_t jsize = 0; plist_t dict = NULL; plist_t node = NULL; plist_t fws = NULL; @@ -1088,7 +1100,7 @@ int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares) *firmwares = NULL; snprintf(url, sizeof(url), "https://api.ipsw.me/v4/device/%s", product); - if (download_to_buffer(url, &jdata, &jsize) < 0) { + if (download_to_buffer(url, (void**)&jdata, &jsize) < 0) { logger(LL_ERROR, "Download from %s failed.\n", url); return -1; } diff --git a/src/ipsw.h b/src/ipsw.h index 8cb25612..b22e614f 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -44,7 +44,7 @@ void ipsw_close(ipsw_archive_t ipsw); int ipsw_print_info(const char* ipsw); typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat); -typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, size_t total_size); +typedef int (*ipsw_send_cb)(void *ctx, const void *data, size_t size, size_t done, size_t total_size); struct ipsw_file_handle { FILE* file; @@ -69,7 +69,7 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile); int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size); int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile); int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress); -int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, void** pbuffer, size_t* psize); int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled); int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist); diff --git a/src/log.c b/src/log.c index 515bea1f..5a0ff948 100644 --- a/src/log.c +++ b/src/log.c @@ -166,7 +166,7 @@ static void print_funcf(enum loglevel level, const char* fmt, ...) va_end(ap); } -void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len) +void logger_dump_hex(enum loglevel level, const void* buf, size_t len) { char *fs; diff --git a/src/log.h b/src/log.h index ad3da140..2563af3e 100644 --- a/src/log.h +++ b/src/log.h @@ -37,7 +37,7 @@ typedef void (*logger_print_func)(enum loglevel level, const char*, va_list); void logger(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); int logger_set_logfile(const char* path); void logger_set_print_func(logger_print_func func); -void logger_dump_hex(enum loglevel level, const void* buf, unsigned int len); +void logger_dump_hex(enum loglevel level, const void* buf, size_t len); void logger_dump_plist(enum loglevel level, plist_t plist, int human_readable); #endif diff --git a/src/mbn.c b/src/mbn.c index b7d3527e..409d9ebc 100644 --- a/src/mbn.c +++ b/src/mbn.c @@ -25,7 +25,7 @@ #include "mbn.h" #include "common.h" -mbn_file* mbn_parse(unsigned char* data, unsigned int size) +mbn_file* mbn_parse(const void* data, size_t size) { mbn_file* mbn = (mbn_file*)malloc(sizeof(mbn_file)); if (!mbn) { @@ -72,7 +72,7 @@ void mbn_free(mbn_file* mbn) } } -int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* sigdata, unsigned int siglen) +int mbn_update_sig_blob(mbn_file* mbn, const void* sigdata, size_t siglen) { if (!mbn) { logger(LL_ERROR, "%s: no data\n", __func__); diff --git a/src/mbn.h b/src/mbn.h index 008ba616..a3281289 100644 --- a/src/mbn.h +++ b/src/mbn.h @@ -100,8 +100,8 @@ typedef struct { uint32_t size; } mbn_file; -mbn_file* mbn_parse(unsigned char* data, unsigned int size); +mbn_file* mbn_parse(const void* data, size_t size); void mbn_free(mbn_file* mbn); -int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* data, unsigned int size); +int mbn_update_sig_blob(mbn_file* mbn, const void* data, size_t size); #endif diff --git a/src/recovery.c b/src/recovery.c index 3c0027fc..ccea4238 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -280,8 +280,8 @@ int recovery_send_ticket(struct idevicerestore_client_t* client) int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; char* path = NULL; irecv_error_t err = 0; @@ -298,8 +298,8 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil } } - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); if (ret < 0) { @@ -314,7 +314,7 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil return -1; } - logger(LL_INFO, "Sending %s (%d bytes)...\n", component, size); + logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size); // FIXME: Did I do this right???? err = irecv_send_buffer(client->recovery->client, data, size, 0); diff --git a/src/restore.c b/src/restore.c index 31291767..bb4bbb58 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1246,7 +1246,7 @@ static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, vo strncpy(key, buffer, i); key[i] = '\0'; i++; - while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++; + while (i < len && (buffer[i] == ' ' || buffer[i] == '\t')) i++; val = malloc(len-i+1); strncpy(val, buffer+i, len-i); val[len-i] = '\0'; @@ -1456,8 +1456,8 @@ int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* c int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; char* path = NULL; plist_t blob = NULL; plist_t dict = NULL; @@ -1486,8 +1486,8 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa } } - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); path = NULL; @@ -1538,14 +1538,14 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) char* restore_sep_path = NULL; char firmware_path[PATH_MAX - 9]; char manifest_file[PATH_MAX]; - unsigned int manifest_size = 0; - unsigned char* manifest_data = NULL; + size_t manifest_size = 0; + void* manifest_data = NULL; char firmware_filename[PATH_MAX]; - unsigned int llb_size = 0; - unsigned char* llb_data = NULL; + size_t llb_size = 0; + void* llb_data = NULL; plist_t dict = NULL; - unsigned int nor_size = 0; - unsigned char* nor_data = NULL; + size_t nor_size = 0; + void* nor_data = NULL; plist_t norimage = NULL; plist_t firmware_files = NULL; int flash_version_1 = 0; @@ -1659,8 +1659,8 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) } const char* component = "LLB"; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, llb_path, &component_data, &component_size); free(llb_path); if (ret < 0) { @@ -1713,7 +1713,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) } component_data = NULL; - unsigned int component_size = 0; + component_size = 0; if (extract_component(client->ipsw, comppath, &component_data, &component_size) < 0) { free(iter); @@ -1758,8 +1758,8 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) plist_free(firmware_files); plist_dict_set_item(dict, "NorImageData", norimage); - unsigned char* personalized_data = NULL; - unsigned int personalized_size = 0; + void* personalized_data = NULL; + size_t personalized_size = 0; if (build_identity_has_component(client->restore->build_identity, "RestoreSEP") && build_identity_get_component_path(client->restore->build_identity, "RestoreSEP", &restore_sep_path) == 0) { @@ -2502,10 +2502,10 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist plist_array_append_item(matched_images, plist_new_string(component)); } else if (!image_name || !strcmp(image_name, component)) { char *path = NULL; - unsigned char* data = NULL; - unsigned int size = 0; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* data = NULL; + size_t size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = -1; if (!image_name) { @@ -2616,8 +2616,8 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie { const char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; @@ -2730,9 +2730,9 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; - unsigned char* component_data_tmp = NULL; + void* component_data = NULL; + size_t component_size = 0; + void* component_data_tmp = NULL; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; @@ -2841,8 +2841,8 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; @@ -2943,8 +2943,8 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl { char *comp_name = NULL; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; ftab_t ftab = NULL; ftab_t rftab = NULL; uint32_t ftag = 0; @@ -3099,8 +3099,8 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; @@ -3271,8 +3271,8 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; @@ -3359,8 +3359,8 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c { char comp_name[64]; char *comp_path = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; ftab_t ftab = NULL; ftab_t rftab = NULL; uint32_t ftag = 0; @@ -3976,13 +3976,13 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch logger(LL_DEBUG, "BootabilityBundle send m=%07o s=%10ld %s\n", stat->st_mode, (long)stat->st_size, subpath); - unsigned char *buf = NULL; - unsigned int size = 0; + void *buf = NULL; + size_t size = 0; if ((S_ISLNK(stat->st_mode) || S_ISREG(stat->st_mode)) && stat->st_size != 0) { ipsw_extract_to_memory(ipsw, name, &buf, &size); if (size != stat->st_size) { - logger(LL_ERROR, "expected %ld bytes but got %d for file %s\n", (long)stat->st_size, size, name); + logger(LL_ERROR, "expected %zu bytes but got %zu for file %s\n", (size_t)stat->st_size, size, name); free(buf); return -1; } @@ -4134,7 +4134,7 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) return ticket_path; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, void** pbuffer, size_t* psize) { char* ticket_path = extract_global_manifest_path(build_identity, variant); if (!ticket_path) { @@ -4159,7 +4159,7 @@ struct _restore_send_file_data_ctx { uint32_t tag; }; -static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) +static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, const void* data, size_t size, size_t done, size_t total_size) { plist_t dict = plist_new_dict(); if (data != NULL) { @@ -4221,12 +4221,9 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli } char *component = image_name; - unsigned int size = 0; - unsigned char *data = NULL; + size_t size = 0; + void *data = NULL; char *path = NULL; - plist_t blob = NULL; - plist_t dict = NULL; - restored_error_t restore_error = RESTORE_E_SUCCESS; logger(LL_INFO, "About to send %s...\n", component); @@ -4267,8 +4264,8 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli } // Extract component - unsigned char *component_data = NULL; - unsigned int component_size = 0; + void *component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); path = NULL; @@ -4306,7 +4303,7 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { + if (_restore_send_file_data(&rctx, ((char*)data + size - i), blob_size, size-i, size) < 0) { free(data); _restore_service_free(service); finalize_progress(rctx.tag); @@ -4348,12 +4345,7 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p char *component = image_name; // Fork from restore_send_component // - unsigned int size = 0; - unsigned char *data = NULL; char *path = NULL; - plist_t blob = NULL; - plist_t dict = NULL; - restored_error_t restore_error = RESTORE_E_SUCCESS; logger(LL_INFO, "About to send %s...\n", component); @@ -4433,11 +4425,11 @@ int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, p int restore_send_restore_local_policy(struct idevicerestore_client_t* client, plist_t message) { - unsigned int size = 0; - unsigned char* data = NULL; + size_t size = 0; + void* data = NULL; - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; char* component = "Ap,LocalPolicy"; @@ -4562,8 +4554,8 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl return 0; } - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); free(path); path = NULL; @@ -4575,8 +4567,8 @@ int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* cl return 0; } - unsigned char* data = NULL; - unsigned int size = 0; + void* data = NULL; + size_t size = 0; ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); free(component_data); component_data = NULL; @@ -4634,12 +4626,12 @@ int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_ plist_t comp_path = plist_access_path(manifest_entry, 2, "Info", "Path"); if (comp_path) { const char* path = plist_get_string_ptr(comp_path, NULL); - unsigned char* component_data = NULL; - unsigned int component_size = 0; + void* component_data = NULL; + size_t component_size = 0; int ret = extract_component(client->ipsw, path, &component_data, &component_size); if (ret == 0) { - unsigned char* data = NULL; - unsigned int size = 0; + void* data = NULL; + size_t size = 0; ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); free(component_data); component_data = NULL; From 460d8f14a1a343351a212ba96e16157cdc88d069 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 1 Jul 2025 01:06:50 +0200 Subject: [PATCH 130/159] Fix a couple of compiler warnings and remove unused variables --- src/ace3.c | 5 ++--- src/common.c | 1 - src/idevicerestore.c | 3 --- src/log.c | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ace3.c b/src/ace3.c index d3da3723..d51613dc 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -70,10 +70,10 @@ static int uarp_version_convert(uint32_t* version_data, uint32_t* version_out) return 0; } if (version_out) { - *version_out = ((((0x147B * (unsigned int)((uint16_t)part3 >> 2)) >> 9) & 0x3FF00 | (0x10 * (((uint8_t)((uint16_t)part3 / 0xA) % 0xA) & 0xF)) | ((uint16_t)part3 % 0xA)) << 8) + *version_out = (((((0x147B * (unsigned int)((uint16_t)part3 >> 2)) >> 9) & 0x3FF00) | (0x10 * (((uint8_t)((uint16_t)part3 / 0xA) % 0xA) & 0xF)) | ((uint16_t)part3 % 0xA)) << 8) | ((((uint8_t)part1 % 0xA) | (0x10 * ((uint8_t)part1 / 0xA)) | part2) << 20) | ((uint8_t)part4 % 0xA) - | ((0xCD * (unsigned int)(uint8_t)part4) >> 7) & 0xF0; + | (((0xCD * (unsigned int)(uint8_t)part4) >> 7) & 0xF0); } return 0; } @@ -217,7 +217,6 @@ int ace3_create_binary(const void* uarp_fw, size_t uarp_size, uint64_t bdid, uns uint32_t data1_version = 0; uint32_t data2_offset = 0; uint32_t data2_size = 0; - uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); uint32_t toc_size = be32toh(uarp_hdr->toc_size); const unsigned char* p = uarp_fw + uarp_hdr_size; while (p < (const unsigned char*)uarp_fw + toc_size) { diff --git a/src/common.c b/src/common.c index 4c99a3a9..70f07428 100644 --- a/src/common.c +++ b/src/common.c @@ -264,7 +264,6 @@ int prompt_user(const char* title, const char* text) int titlelen = (title) ? strlen(title) : 0; if (titlelen > 0) { int lefttitlelen = (titlelen+4)/2; - int righttitlelen = titlelen+4 - lefttitlelen; int leftpounds = outerlen/2 - lefttitlelen; int rightpounds = outerlen-(titlelen+4) - leftpounds; printf("%.*s[ %.*s ]%.*s\n", leftpounds, POUNDS, titlelen, title, rightpounds, POUNDS); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 7be50ea9..1465f879 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1772,7 +1772,6 @@ int main(int argc, char* argv[]) char* ipsw = NULL; int ipsw_info = 0; int result = 0; - int is_terminal = 0; const char* logfile = NULL; logger_set_print_func(tty_print); @@ -1804,7 +1803,6 @@ int main(int argc, char* argv[]) client->flags &= ~FLAG_INTERACTIVE; } else { client->flags |= FLAG_INTERACTIVE; - is_terminal = 1; } #ifdef HAVE_LIMERA1N @@ -2834,7 +2832,6 @@ int extract_component(ipsw_archive_t ipsw, const char* path, void** component_da int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const void* component_data, size_t component_size, plist_t tss_response, void** personalized_component, size_t* personalized_component_size) { void* component_blob = NULL; - size_t component_blob_size = 0; void* stitched_component = NULL; size_t stitched_component_size = 0; diff --git a/src/log.c b/src/log.c index 5a0ff948..990dcaff 100644 --- a/src/log.c +++ b/src/log.c @@ -115,11 +115,11 @@ void logger(enum loglevel level, const char *fmt, ...) snprintf(fs, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); #else struct timeval ts; - struct tm tp_; struct tm *tp; gettimeofday(&ts, NULL); #ifdef HAVE_LOCALTIME_R + struct tm tp_; tp = localtime_r(&ts.tv_sec, &tp_); #else tp = localtime(&ts.tv_sec); From e574eaeb9f1055793dd276caaa75ce9449db3fed Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 1 Jul 2025 03:26:42 +0200 Subject: [PATCH 131/159] Silence more compiler warnings --- src/fdr.c | 2 +- src/restore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fdr.c b/src/fdr.c index 378d4f95..9dbe59c6 100644 --- a/src/fdr.c +++ b/src/fdr.c @@ -181,7 +181,7 @@ int fdr_poll_and_handle_message(fdr_client_t fdr) void *fdr_listener_thread(void *cdata) { fdr_client_t fdr = cdata; - int res; + int res = 0; while (fdr && fdr->connection) { logger(LL_DEBUG, "FDR %p waiting for message...\n", fdr); diff --git a/src/restore.c b/src/restore.c index bb4bbb58..aa9bf890 100644 --- a/src/restore.c +++ b/src/restore.c @@ -5083,7 +5083,7 @@ static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_ const char* path = plist_get_string_ptr(p_path, NULL); uint64_t fsize = 0; if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) { - logger(LL_DEBUG, "%s: Adding %s (%s, %llu bytes)\n", __func__, component, path, fsize); + logger(LL_DEBUG, "%s: Adding %s (%s, %" PRIu64 " bytes)\n", __func__, component, path, fsize); total_size += (double)fsize / 0x100000; } } From 038a49362570ac56bae330fda8a30635134fc509 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 1 Jul 2025 03:34:01 +0200 Subject: [PATCH 132/159] Removed unused 'entries' member from struct idevicerestore_client_t --- src/common.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/common.h b/src/common.h index 08675a2c..3bb648ae 100644 --- a/src/common.h +++ b/src/common.h @@ -82,16 +82,6 @@ struct idevicerestore_mode_t { const char* string; }; -struct idevicerestore_entry_t { - char* name; - char* path; - char* filename; - char* blob_data; - uint32_t blob_size; - struct idevicerestore_entry* next; - struct idevicerestore_entry* prev; -}; - struct idevicerestore_client_t { int flags; int debug_level; @@ -115,7 +105,6 @@ struct idevicerestore_client_t { struct restore_client_t* restore; struct recovery_client_t* recovery; irecv_device_t device; - struct idevicerestore_entry_t** entries; struct idevicerestore_mode_t* mode; char* version; char* build; From 197c9619b39f978a3400d2bbb3684fd3a222b268 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 15 Jul 2025 09:33:32 +0200 Subject: [PATCH 133/159] restore: Adapt log level of previous restore log and reverse proxy messages We do not want to write these to terminal by default. --- src/restore.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/restore.c b/src/restore.c index aa9bf890..92abadb0 100644 --- a/src/restore.c +++ b/src/restore.c @@ -752,7 +752,7 @@ static int restore_handle_previous_restore_log_msg(restored_client_t client, pli } plist_get_string_val(node, &restorelog); - logger(LL_INFO, "Previous Restore Log Received:\n%s\n", restorelog); + logger(LL_VERBOSE, "Previous Restore Log Received:\n%s\n", restorelog); free(restorelog); return 0; @@ -5198,12 +5198,12 @@ plist_t restore_supported_message_types() #ifdef HAVE_REVERSE_PROXY static void rp_log_cb(reverse_proxy_client_t client, const char* log_msg, void* user_data) { - logger(LL_INFO, "ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); + logger(LL_VERBOSE, "ReverseProxy[%s]: %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", log_msg); } static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t status, const char* status_msg, void* user_data) { - logger(LL_INFO, "ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); + logger(LL_VERBOSE, "ReverseProxy[%s]: (status=%d) %s\n", (reverse_proxy_get_type(client) == RP_TYPE_CTRL) ? "Ctrl" : "Conn", status, status_msg); } #endif From 2914bf66cfb28c6d0fde43655dac05ea044d2907 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Aug 2025 20:56:13 +0200 Subject: [PATCH 134/159] img4: Add RestoreDCP2 -> rdc2 mapping --- src/img4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/img4.c b/src/img4.c index e58dd267..67351618 100644 --- a/src/img4.c +++ b/src/img4.c @@ -356,6 +356,7 @@ static const char *_img4_get_component_tag(const char *compname) { "RecoveryMode", "recm" }, { "RestoreANS", "rans" }, { "RestoreDCP", "rdcp" }, + { "RestoreDCP2", "rdc2", }, { "RestoreDeviceTree", "rdtr" }, { "RestoreExtDCP", "recp" }, { "RestoreKernelCache", "rkrn" }, From d2cf14fa316b1637bbf3e347f674d6bcdfaa1a43 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 5 Sep 2025 23:18:53 +0200 Subject: [PATCH 135/159] img4: Fix Ap,RestoreDCP2 -> rdc2 mapping The component is called `Ap,RestoreDCP2` and not `RestoreDCP2` --- src/img4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/img4.c b/src/img4.c index 67351618..e1a3c61a 100644 --- a/src/img4.c +++ b/src/img4.c @@ -300,6 +300,7 @@ static const char *_img4_get_component_tag(const char *compname) { "Ap,RestoreANE2", "ran2" }, { "Ap,RestoreANE3", "ran3" }, { "Ap,RestoreCIO", "rcio" }, + { "Ap,RestoreDCP2", "rdc2", }, { "Ap,RestoreTMU", "rtmu" }, { "Ap,Scorpius", "scpf" }, { "Ap,SystemVolumeCanonicalMetadata", "msys" }, @@ -356,7 +357,6 @@ static const char *_img4_get_component_tag(const char *compname) { "RecoveryMode", "recm" }, { "RestoreANS", "rans" }, { "RestoreDCP", "rdcp" }, - { "RestoreDCP2", "rdc2", }, { "RestoreDeviceTree", "rdtr" }, { "RestoreExtDCP", "recp" }, { "RestoreKernelCache", "rkrn" }, @@ -441,6 +441,8 @@ int img4_stitch_component(const char* component_name, const void* component_data memcpy((void*)tag, "rtmu", 4); } else if (strcmp(component_name, "Ap,RestoreCIO") == 0) { memcpy((void*)tag, "rcio", 4); + } else if (strcmp(component_name, "Ap,RestoreDCP2") == 0) { + memcpy((void*)tag, "rdc2", 4); } else if (strcmp(component_name, "Ap,DCP2") == 0) { memcpy((void*)tag, "dcp2", 4); } else if (strcmp(component_name, "Ap,RestoreSecureM3Firmware") == 0) { From 75fb578c161aea212f6a09714be02ba013a015fb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 5 Sep 2025 23:27:24 +0200 Subject: [PATCH 136/159] img4: Use lookup table to retrieve tag name in img4_stitch_component() Instead of maintaining another component -> tag mapping, we use the already existing function _img4_get_component_tag() to retrieve the corresponding tag name. --- src/img4.c | 65 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/img4.c b/src/img4.c index e1a3c61a..d9e3b069 100644 --- a/src/img4.c +++ b/src/img4.c @@ -291,6 +291,7 @@ static const char *_img4_get_component_tag(const char *compname) { "Ap,AudioPowerAttachChime", "aupr" }, { "Ap,BootabilityBrainTrustCache", "trbb" }, { "Ap,CIO", "ciof" }, + { "Ap,DCP2", "dcp2" }, { "Ap,HapticAssets", "hpas" }, { "Ap,LocalBoot", "lobo" }, { "Ap,LocalPolicy", "lpol" }, @@ -303,6 +304,10 @@ static const char *_img4_get_component_tag(const char *compname) { "Ap,RestoreDCP2", "rdc2", }, { "Ap,RestoreTMU", "rtmu" }, { "Ap,Scorpius", "scpf" }, + { "Ap,RestoreSecureM3Firmware", "rsm3" }, + { "Ap,RestoreSecurePageTableMonitor", "rspt" }, + { "Ap,RestoreTrustedExecutionMonitor", "rtrx" }, + { "Ap,RestorecL4", "rxcl" }, { "Ap,SystemVolumeCanonicalMetadata", "msys" }, { "Ap,TMU", "tmuf" }, { "Ap,VolumeUUID", "vuid" }, @@ -425,35 +430,39 @@ int img4_stitch_component(const char* component_name, const void* component_data const void *tag = asn1_find_element(1, ASN1_IA5_STRING, component_data); if (tag) { logger(LL_DEBUG, "Tag found\n"); - if (strcmp(component_name, "RestoreKernelCache") == 0) { - memcpy((void*)tag, "rkrn", 4); - } else if (strcmp(component_name, "RestoreDeviceTree") == 0) { - memcpy((void*)tag, "rdtr", 4); - } else if (strcmp(component_name, "RestoreSEP") == 0) { - memcpy((void*)tag, "rsep", 4); - } else if (strcmp(component_name, "RestoreLogo") == 0) { - memcpy((void*)tag, "rlgo", 4); - } else if (strcmp(component_name, "RestoreTrustCache") == 0) { - memcpy((void*)tag, "rtsc", 4); - } else if (strcmp(component_name, "RestoreDCP") == 0) { - memcpy((void*)tag, "rdcp", 4); - } else if (strcmp(component_name, "Ap,RestoreTMU") == 0) { - memcpy((void*)tag, "rtmu", 4); - } else if (strcmp(component_name, "Ap,RestoreCIO") == 0) { - memcpy((void*)tag, "rcio", 4); - } else if (strcmp(component_name, "Ap,RestoreDCP2") == 0) { - memcpy((void*)tag, "rdc2", 4); - } else if (strcmp(component_name, "Ap,DCP2") == 0) { - memcpy((void*)tag, "dcp2", 4); - } else if (strcmp(component_name, "Ap,RestoreSecureM3Firmware") == 0) { - memcpy((void*)tag, "rsm3", 4); - } else if (strcmp(component_name, "Ap,RestoreSecurePageTableMonitor") == 0) { - memcpy((void*)tag, "rspt", 4); - } else if (strcmp(component_name, "Ap,RestoreTrustedExecutionMonitor") == 0) { - memcpy((void*)tag, "rtrx", 4); - } else if (strcmp(component_name, "Ap,RestorecL4") == 0) { - memcpy((void*)tag, "rxcl", 4); + const char* matches[] = { + "RestoreKernelCache", + "RestoreKernelCache", + "RestoreSEP", + "RestoreLogo", + "RestoreTrustCache", + "RestoreDCP", + "Ap,RestoreDCP2", + "Ap,RestoreTMU", + "Ap,RestoreCIO", + "Ap,DCP2", + "Ap,RestoreSecureM3Firmware", + "Ap,RestoreSecurePageTableMonitor", + "Ap,RestoreTrustedExecutionMonitor", + "Ap,RestorecL4", + NULL + }; + int i = 0; + while (matches[i]) { + if (!strcmp(matches[i], component_name)) { + const char* comptag = _img4_get_component_tag(component_name); + if (comptag) { + memcpy((void*)tag, comptag, 4); + } else { + logger(LL_WARNING, "Cannot find tag for component '%s'\n", component_name); + } + break; + } + i++; } + } else { + logger(LL_ERROR, "Personalization failed for component '%s': Tag not found\n", component_name); + return -1; } // check if we have a *-TBM entry for the given component From 5d9bd621eb60cab5303b72b4b35388fb515ffa87 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 6 Sep 2025 00:38:21 +0200 Subject: [PATCH 137/159] Print message about USB port for macOS restores in case Port DFU fails Depending on the model, a specific USB Port has to be used for a restore. When using a different one, Port DFU fails to switch to DFU mode. We use this fact to print a message with an official link that shows the correct USB port to use for the restore. --- src/idevicerestore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 1465f879..9c414230 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -755,6 +755,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); + int is_mac = plist_access_path(build_identity, 2, "Info", "MacOSVariant") != NULL; plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); if (!usbf) { plist_free(parameters); @@ -839,6 +840,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { logger(LL_ERROR, "Device did not reconnect in DFU mode. Port DFU failed.\n"); + if (is_mac) { + logger(LL_ERROR, "Make sure to use the correct USB port for this model, see https://support.apple.com/120694\n"); + } } return -2; } From ddaf2613afe39f607f6cdff13eebbeb7b95f7e0d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 7 Sep 2025 23:53:52 +0200 Subject: [PATCH 138/159] Add FUNDING --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..f7aeb3e1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: nikias +patreon: nikias From d7e26cf72b510c5ccb5199a58ac866548db4cba8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 8 Sep 2025 00:08:46 +0200 Subject: [PATCH 139/159] Updated FUNDING --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index f7aeb3e1..e995b30c 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ github: nikias patreon: nikias +custom: ["https://www.paypal.me/NikiasBassen"] From 6c5e5b6237a00a95bfd840d048762512cb5b0309 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 8 Sep 2025 17:55:13 +0200 Subject: [PATCH 140/159] img4: Fix wrong entry in matching array for component stitching --- src/img4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/img4.c b/src/img4.c index d9e3b069..732ef69e 100644 --- a/src/img4.c +++ b/src/img4.c @@ -432,7 +432,7 @@ int img4_stitch_component(const char* component_name, const void* component_data logger(LL_DEBUG, "Tag found\n"); const char* matches[] = { "RestoreKernelCache", - "RestoreKernelCache", + "RestoreDeviceTree", "RestoreSEP", "RestoreLogo", "RestoreTrustCache", From ae1539e534d9d9c78ed54573d831519cfcb8741b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 11 Sep 2025 01:56:12 +0200 Subject: [PATCH 141/159] [Windows] Fix log output --- src/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log.c b/src/log.c index 990dcaff..b9c2c51c 100644 --- a/src/log.c +++ b/src/log.c @@ -112,7 +112,7 @@ void logger(enum loglevel level, const char *fmt, ...) #ifdef _WIN32 SYSTEMTIME lt; GetLocalTime(<); - snprintf(fs, 24, "%02d:%02d:%02d.%03d", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds); + snprintf(fs, fslen, "%02d:%02d:%02d.%03d %s %s", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds, _level_label[level], fmt); #else struct timeval ts; struct tm *tp; From bb701b87a5b63046308b0e75f512107cc7170bcc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 11 Sep 2025 03:24:03 +0200 Subject: [PATCH 142/159] Increase timeout for device to enter restore mode --- src/idevicerestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 9c414230..dcdf1a6a 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1525,7 +1525,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode != MODE_RESTORE) { mutex_lock(&client->device_event_mutex); logger(LL_INFO, "Waiting for device to enter restore mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 300000); if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); logger(LL_ERROR, "Device failed to enter restore mode.\n"); From 34d07e0c51cf18a3d82fd601fa96b5a2cc1e310a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 11 Sep 2025 05:29:52 +0200 Subject: [PATCH 143/159] Fix log output of get_ap_nonce/get_sep_nonce --- src/idevicerestore.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index dcdf1a6a..e3774bb6 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2109,8 +2109,6 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, *nonce = NULL; *nonce_size = 0; - logger(LL_INFO, "Getting ApNonce "); - if (client->mode) { mode = client->mode->index; } @@ -2156,29 +2154,27 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, *nonce = NULL; *nonce_size = 0; - logger(LL_INFO, "Getting SepNonce "); - if (client->mode) { mode = client->mode->index; } switch (mode) { case _MODE_NORMAL: - logger(LL_INFO, "in normal mode... "); + logger(LL_INFO, "Getting SepNonce in normal mode... "); if (normal_get_sep_nonce(client, nonce, nonce_size) < 0) { logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_DFU: - logger(LL_INFO, "in dfu mode... "); + logger(LL_INFO, "Getting SepNonce in dfu mode... "); if (dfu_get_sep_nonce(client, nonce, nonce_size) < 0) { logger(LL_INFO, "failed\n"); return -1; } break; case _MODE_RECOVERY: - logger(LL_INFO, "in recovery mode... "); + logger(LL_INFO, "Getting SepNonce in recovery mode... "); if (recovery_get_sep_nonce(client, nonce, nonce_size) < 0) { logger(LL_INFO, "failed\n"); return -1; @@ -2186,7 +2182,7 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, break; default: - logger(LL_INFO, "failed\n"); + logger(LL_INFO, "Getting SepNonce failed\n"); logger(LL_ERROR, "Device is in an invalid state\n"); return -1; } From e41ff993f7d4c4b9f18b63348eb232fb5c5aaae9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 11 Sep 2025 17:35:57 +0200 Subject: [PATCH 144/159] Updated README --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38d227c2..4e61940a 100644 --- a/README.md +++ b/README.md @@ -223,9 +223,29 @@ Configuration for idevicerestore 1.1.0: and then 'make install' for installation. ``` +### Building and installation + +If you followed all the steps successfully, and `autogen.sh` or `configure` did not print any errors, +you are ready to build the project. This is simply done with + +```shell +make +``` + +If no errors are emitted you are ready for installation. Depending on whether +the current user has permissions to write to the destination directory or not, +you would either run +```shell +make install +``` +_OR_ +```shell +sudo make install +``` + **Important** -idevicerestore requires a properly installed [usbmuxd](https://github.com/libimobiledevice/usbmuxd.git) +On Linux, idevicerestore requires a properly installed [usbmuxd](https://github.com/libimobiledevice/usbmuxd.git) for the restore procedure. Please make sure that it is either running or configured to be started automatically as soon as a device is detected in normal and/or restore mode. If properly installed this will be handled @@ -311,4 +331,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2024-10-22 +README Updated on: 2025-09-11 From 8d1e798ea5578a110502c50d474c7b403f3a4579 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 12 Sep 2025 17:18:15 +0200 Subject: [PATCH 145/159] Add SE,ChipID for M4 --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 92abadb0..f5403fc5 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2636,7 +2636,7 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36 || chip_id == 0x37) { comp_name = "SE,UpdatePayload"; } else { logger(LL_WARNING, "Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); From a0cec3b34fb112168aaae9fbb024e15302563b34 Mon Sep 17 00:00:00 2001 From: H-Sofie Date: Sun, 14 Sep 2025 00:48:11 +0800 Subject: [PATCH 146/159] Fix boot-args string and handling The logging refactoring introduced a spelling error in the boot-args string. This commit fixes that, and also changes the boot-args handling code to priotize Apple Silicon/MacOS recovery path before the generic iOS path. --- src/recovery.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/recovery.c b/src/recovery.c index ccea4238..4f7520a2 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -125,11 +125,11 @@ int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable) int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity) { - if (client->build_major >= 8) { - client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1rogress"); - } else if (client->macos_variant) { - client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore"); - } + if (client->macos_variant) { + client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore"); + } else if (client->build_major >= 8) { + client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress"); + } /* upload data to make device boot restore mode */ From eda43ac44e13384402a88fa83e6b21e46d7fac55 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 23 Sep 2025 00:07:28 +0200 Subject: [PATCH 147/159] Fix progress bar for DFU/Recovery image upload --- src/dfu.c | 3 ++- src/recovery.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 4650e9a5..6ba23e7f 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -61,7 +61,6 @@ int dfu_client_new(struct idevicerestore_client_t* client) irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL); client->dfu->client = dfu; - register_progress('DFUP', "Uploading"); return 0; } @@ -200,7 +199,9 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size); + register_progress('DFUP', "Uploading"); irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); + finalize_progress('DFUP'); if (err != IRECV_E_SUCCESS) { logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err)); free(data); diff --git a/src/recovery.c b/src/recovery.c index 4f7520a2..b843f1ed 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -99,7 +99,6 @@ int recovery_client_new(struct idevicerestore_client_t* client) } irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); - register_progress('RECV', "Uploading"); client->recovery->client = recovery; return 0; } @@ -317,8 +316,10 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil logger(LL_INFO, "Sending %s (%zu bytes)...\n", component, size); // FIXME: Did I do this right???? + register_progress('RECV', "Uploading"); err = irecv_send_buffer(client->recovery->client, data, size, 0); free(data); + finalize_progress('RECV'); if (err != IRECV_E_SUCCESS) { logger(LL_ERROR, "Unable to send %s component: %s\n", component, irecv_strerror(err)); return -1; From fcbf936ca92b83e1df6b51e6204e7489eb7353d4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 25 Sep 2025 23:53:44 +0200 Subject: [PATCH 148/159] restore: Silence messages around AEA first chunk / URLAsset handling Newer iOS version would cause an Error message despite being able to continue, so we just ignore it. --- src/restore.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/restore.c b/src/restore.c index f5403fc5..397cae71 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1264,11 +1264,10 @@ static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, vo int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message) { - logger(LL_DEBUG, "%s\n", __func__); plist_t arguments = plist_dict_get_item(message, "Arguments"); if (!PLIST_IS_DICT(arguments)) { logger(LL_ERROR, "%s: Unexpected arguments\n", __func__); - logger_dump_plist(LL_VERBOSE, arguments, 1); + logger_dump_plist(LL_VERBOSE, message, 1); return -1; } @@ -4179,13 +4178,18 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, con /* special handling for AEA image format */ if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { - logger(LL_INFO, "Encountered First Chunk in AEA image\n"); + logger(LL_VERBOSE, "Encountered First Chunk in AEA image\n"); plist_t message = NULL; property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000); if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { - logger(LL_INFO, "No URLAsset requested, assuming it is not necessary.\n"); + logger(LL_VERBOSE, "No URLAsset requested, assuming it is not necessary.\n"); } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) { - restore_send_url_asset(rctx->client, message); + if (PLIST_IS_DICT(message) && plist_dict_get_item(message, "Arguments")) { + restore_send_url_asset(rctx->client, message); + } else { + logger(LL_DEBUG, "%s: Unexpected message received\n", __func__); + logger_dump_plist(LL_DEBUG, message, 1); + } } } From 105ac0c399dd043a8c300b89019f6ea0befc1e51 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 26 Sep 2025 00:05:12 +0200 Subject: [PATCH 149/159] restore: Dump TSS requests and responses in debug log level --- src/restore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index 397cae71..aa92cf24 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2303,9 +2303,8 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl plist_dict_set_item(request, "ApSecurityMode", plist_new_bool(1)); } } - logger_dump_plist(LL_DEBUG, request, 0); - logger(LL_INFO, "Sending Baseband TSS request...\n"); + logger_dump_plist(LL_DEBUG, request, 0); response = tss_request_send(request, client->tss_url); plist_free(request); plist_free(parameters); @@ -3249,12 +3248,14 @@ static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* plist_dict_merge(&request, device_generated_request); logger(LL_INFO, "Sending %s TSS request...\n", s_updater_name); + logger_dump_plist(LL_DEBUG, request, 0); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { logger(LL_ERROR, "Unable to fetch %s ticket\n", s_updater_name); return NULL; } + logger_dump_plist(LL_DEBUG, response, 0); if (plist_dict_get_item(response, response_ticket)) { logger(LL_INFO, "Received %s\n", response_ticket); From 47bf8b5f4cd8f4b1fdfdd2cf834b40ae1dc14e0d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 26 Sep 2025 00:08:09 +0200 Subject: [PATCH 150/159] restore: Handle new Centauri and Jasmine (Savage) updaters Also Vinyl shows up with some devices, so we handle this too. --- src/restore.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/restore.c b/src/restore.c index aa92cf24..46e56f34 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3749,6 +3749,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl } plist_get_string_val(p_updater_name, &s_updater_name); + logger_dump_plist(LL_DEBUG, p_info, 1); if (strcmp(s_updater_name, "SE") == 0) { fwdict = restore_get_se_firmware_data(client, p_info, arguments); @@ -3758,10 +3759,14 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl } } else if (strcmp(s_updater_name, "Savage") == 0) { const char *fwtype = "Savage"; - plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); - if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { + plist_t p_info_yonkers = plist_dict_get_item(p_info, "YonkersDeviceInfo"); + plist_t p_info_jasmine = plist_dict_get_item(p_info, "JasmineIR1DeviceInfo"); + if (PLIST_IS_DICT(p_info_yonkers)) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(client, p_info2, arguments); + fwdict = restore_get_yonkers_firmware_data(client, p_info_yonkers, arguments); + } else if (PLIST_IS_DICT(p_info_jasmine)) { + fwtype = "Jasmine"; + fwdict = restore_get_generic_firmware_data(client, p_info_jasmine, arguments); } else { fwdict = restore_get_savage_firmware_data(client, p_info, arguments); } @@ -3811,6 +3816,18 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } + } else if (strcmp(s_updater_name, "Centauri") == 0) { + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); + if (fwdict == NULL) { + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } + } else if (strcmp(s_updater_name, "Vinyl") == 0) { + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); + if (fwdict == NULL) { + logger(LL_ERROR, "%s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } else { logger(LL_ERROR, "%s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); fwdict = restore_get_generic_firmware_data(client, p_info, arguments); From 1aea4df8c83053fcd4ef8826c19c0ed58aec323a Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 26 Sep 2025 00:12:54 +0200 Subject: [PATCH 151/159] restore: Suppress progress bars for smaller PersonalizedBootObjectV3 images --- src/restore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 46e56f34..09cbe16d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4320,7 +4320,9 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli rctx.last_progress = 0; rctx.tag = progress_get_next_tag(); - register_progress(rctx.tag, component); + if (size > 0x2000000) { + register_progress(rctx.tag, component); + } int64_t i = size; while (i > 0) { From 4cf940b9680b94f8d2f1dbd573f1eb2d56574b0a Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+VisualEhrmanntraut@users.noreply.github.com> Date: Fri, 26 Sep 2025 18:42:11 +0200 Subject: [PATCH 152/159] Add support for Mav25 baseband firmware (iPhone 17 family) Co-authored-by: Nikias Bassen --- src/mbn.c | 490 ++++++++++++++++++++++++++++++++++++++++++++------ src/mbn.h | 85 +-------- src/restore.c | 73 ++++---- 3 files changed, 484 insertions(+), 164 deletions(-) diff --git a/src/mbn.c b/src/mbn.c index 409d9ebc..2ba5e656 100644 --- a/src/mbn.c +++ b/src/mbn.c @@ -1,9 +1,10 @@ /* * mbn.c - * support for .mbn file format (found in .bbfw files) + * support for Qualcomm MBN (Modem Binary) formats * * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. + * Copyright (c) 2025 Visual Ehrmanntraut . 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 @@ -25,67 +26,456 @@ #include "mbn.h" #include "common.h" -mbn_file* mbn_parse(const void* data, size_t size) +#define MBN_V1_MAGIC "\x0A\x00\x00\x00" +#define MBN_V1_MAGIC_SIZE 4 + +#pragma pack(push, 1) +typedef struct { + uint32_t type; // the signed .mbn files have 0xA as value. + uint32_t unk_0x04; + uint32_t unk_0x08; + uint32_t unk_0x0c; + uint32_t data_size; // data_size = total_size - sizeof(mbn_header) + uint32_t sig_offset; // real offset = enc_sig_offset & 0xFFFFFF00 + uint32_t unk_0x18; + uint32_t unk_0x1c; + uint32_t unk_0x20; + uint32_t unk_0x24; +} mbn_header_v1; + +#define MBN_V2_MAGIC "\xD1\xDC\x4B\x84\x34\x10\xD7\x73" +#define MBN_V2_MAGIC_SIZE 8 + +typedef struct { + unsigned char magic1[8]; + uint32_t unk_0x08; + uint32_t unk_0x0c; // 0xFFFFFFFF + uint32_t unk_0x10; // 0xFFFFFFFF + uint32_t header_size; + uint32_t unk_0x18; + uint32_t data_size; // data_size = total_size - sizeof(mbn_header_v2) + uint32_t sig_offset; + uint32_t unk_0x24; + uint32_t unk_0x28; + uint32_t unk_0x2c; + uint32_t unk_0x30; + uint32_t unk_0x34; // 0x1 + uint32_t unk_0x38; // 0x1 + uint32_t unk_0x3c; // 0xFFFFFFFF + uint32_t unk_0x40; // 0xFFFFFFFF + uint32_t unk_0x44; // 0xFFFFFFFF + uint32_t unk_0x48; // 0xFFFFFFFF + uint32_t unk_0x4c; // 0xFFFFFFFF +} mbn_header_v2; + +#define MBN_BIN_MAGIC "\x04\x00\xEA\x6C\x69\x48\x55" +#define MBN_BIN_MAGIC_SIZE 7 +#define MBN_BIN_MAGIC_OFFSET 1 // we ignore the first byte + +typedef struct { + unsigned char magic[8]; + uint32_t unk_0x08; + uint32_t version; + uint32_t total_size; // size including header + uint32_t unk_0x14; // some offset +} mbn_bin_header; + +typedef struct +{ + uint32_t reserved; + uint32_t version; + uint32_t common_metadata_size; + uint32_t qti_metadata_size; + uint32_t oem_metadata_size; + uint32_t hash_table_size; + uint32_t qti_signature_size; + uint32_t qti_certificate_chain_size; + uint32_t oem_signature_size; + uint32_t oem_certificate_chain_size; +} mbn_v7_header; + +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +typedef struct +{ + uint8_t e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} elf32_header; + +typedef struct +{ + uint8_t e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} elf64_header; + +typedef struct +{ + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +} elf32_pheader; + +typedef struct +{ + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} elf64_pheader; +#pragma pack(pop) + +static int mbn_is_valid_elf(const uint8_t* e_ident, size_t size) +{ + return size >= EI_NIDENT && e_ident[EI_MAG0] == ELFMAG0 && + e_ident[EI_MAG1] == ELFMAG1 && e_ident[EI_MAG2] == ELFMAG2 && + e_ident[EI_MAG3] == ELFMAG3 && e_ident[EI_CLASS] != ELFCLASSNONE; +} + +static int mbn_is_64bit_elf(const uint8_t* e_ident) { - mbn_file* mbn = (mbn_file*)malloc(sizeof(mbn_file)); - if (!mbn) { - return NULL; - } - memset(mbn, '\0', sizeof(mbn_file)); - mbn->data = malloc(size); - mbn->size = size; - memcpy(mbn->data, data, size); - /* FIXME: header parsing is not big endian safe */ - if (memcmp(data, MBN_V2_MAGIC, MBN_V2_MAGIC_SIZE) == 0) { - mbn->version = 2; - memcpy(&mbn->header.v2, data, sizeof(mbn_header_v2)); - mbn->parsed_size = mbn->header.v2.data_size + sizeof(mbn_header_v2); - } else if (memcmp(data, MBN_V1_MAGIC, MBN_V1_MAGIC_SIZE) == 0) { - mbn->version = 1; - memcpy(&mbn->header.v1, data, sizeof(mbn_header_v1)); - mbn->parsed_size = mbn->header.v1.data_size + sizeof(mbn_header_v1); - } else if (memcmp(data, BIN_MAGIC, BIN_MAGIC_SIZE) == 0) { - mbn->version = 3; - memcpy(&mbn->header.bin, data, sizeof(bin_header)); - mbn->parsed_size = mbn->header.bin.total_size; - } else if (memcmp(data, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) { - mbn->version = 4; - memcpy(&mbn->header.elf, data, sizeof(elf_header)); - // we cheat here since we don't parse the actual ELF file - mbn->parsed_size = mbn->size; + return e_ident[EI_CLASS] == ELFCLASS64; +} + +void* mbn_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size) +{ + if (!data) { + logger(LL_ERROR, "%s: data is NULL\n", __func__); + return NULL; + } + + if (!data_size) { + logger(LL_ERROR, "%s: data size is 0\n", __func__); + return NULL; + } + + if (!blob) { + logger(LL_ERROR, "%s: blob is NULL\n", __func__); + return NULL; + } + + if (!blob_size) { + logger(LL_ERROR, "%s: blob size is 0\n", __func__); + return NULL; + } + + size_t parsed_size = 0; + if (data_size > MBN_V2_MAGIC_SIZE && memcmp(data, MBN_V2_MAGIC, MBN_V2_MAGIC_SIZE) == 0) { + parsed_size = ((mbn_header_v2*)data)->data_size + sizeof(mbn_header_v2); + logger(LL_DEBUG, "%s: encountered MBN v2 image, parsed_size = 0x%zx\n", __func__, parsed_size); + } else if (data_size > MBN_V1_MAGIC_SIZE && memcmp(data, MBN_V1_MAGIC, MBN_V1_MAGIC_SIZE) == 0) { + parsed_size = ((mbn_header_v1*)data)->data_size + sizeof(mbn_header_v1); + logger(LL_DEBUG, "%s: encountered MBN v1 image, parsed_size = 0x%zx\n", __func__, parsed_size); + } else if (data_size > MBN_BIN_MAGIC_SIZE+MBN_BIN_MAGIC_OFFSET && memcmp((uint8_t*)data+MBN_BIN_MAGIC_OFFSET, (uint8_t*)MBN_BIN_MAGIC, MBN_BIN_MAGIC_SIZE) == 0) { + parsed_size = ((mbn_bin_header*)data)->total_size; + logger(LL_DEBUG, "%s: encountered MBN BIN image, parsed_size = 0x%zx\n", __func__, parsed_size); + } else if (mbn_is_valid_elf(data, data_size)) { + if (mbn_is_64bit_elf(data)) { + const elf64_header* ehdr = data; + const elf64_pheader* phdr = data + ehdr->e_phoff; + if (ehdr->e_phnum == 0) { + logger(LL_ERROR, "%s: ELF has no program sections\n", __func__); + return NULL; + } + uint64_t last_off = 0; + uint16_t last_index = 0; + for (uint16_t i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_offset > last_off) { + last_off = phdr[i].p_offset; + last_index = i; + } + } + parsed_size = last_off + phdr[last_index].p_filesz; + } else { + const elf32_header* ehdr = data; + const elf32_pheader* phdr = data + ehdr->e_phoff; + if (ehdr->e_phnum == 0) { + logger(LL_ERROR, "%s: ELF has no program sections\n", __func__); + return NULL; + } + uint32_t last_off = 0; + uint16_t last_index = 0; + for (uint16_t i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_offset > last_off) { + last_off = phdr[i].p_offset; + last_index = i; + } + } + parsed_size = last_off + phdr[last_index].p_filesz; + } + logger(LL_DEBUG, "%s: encountered ELF image, parsed_size = 0x%zx\n", __func__, parsed_size); } else { - logger(LL_DEBUG, "Unknown file format passed to %s\n", __func__); + logger(LL_WARNING, "Unknown file format passed to %s\n", __func__); } - if (mbn->parsed_size != mbn->size) { - logger(LL_WARNING, "Size mismatch when parsing MBN file. Continuing anyway.\n"); + if (parsed_size != data_size) { + logger(LL_WARNING, "%s: size mismatch for MBN data, expected 0x%zx, input size 0x%zx\n", __func__, parsed_size, data_size); } - return mbn; + + off_t stitch_offset = data_size - blob_size; + if (stitch_offset + blob_size > data_size) { + logger(LL_ERROR, "%s: stitch offset (0x%llx) + size (0x%zx) is larger than the destination (0x%zx)\n", __func__, stitch_offset, blob_size, data_size); + return NULL; + } + + void* buf = malloc(data_size); + if (buf == NULL) { + logger(LL_ERROR, "out of memory\n"); + return NULL; + } + + memcpy(buf, data, data_size); + logger(LL_DEBUG, "%s: stitching mbn at 0x%llx, size 0x%zx\n", __func__, stitch_offset, blob_size); + memcpy(buf + stitch_offset, blob, blob_size); + + return buf; } -void mbn_free(mbn_file* mbn) +// the sum of header size and all sizes inside it must fit within the size of +// the data +static int mbn_v7_header_sizes_valid(const mbn_v7_header* header, size_t size) { - if (mbn) { - if (mbn->data) { - free(mbn->data); - } - free(mbn); - } + return (sizeof(*header) + header->common_metadata_size + + header->qti_metadata_size + header->oem_metadata_size + + header->hash_table_size + header->qti_signature_size + + header->qti_certificate_chain_size + header->oem_signature_size + + header->oem_certificate_chain_size) <= size; +} + +// 0xE0 == sizeof(mav25_authority_meta_field_t), 0x68 == +// kExpectedOEMSignatureSize, 0xD20 == kExpectedOEMCertChainSize +static int mbn_v7_header_sizes_expected(const mbn_v7_header* header) +{ + return (header->qti_metadata_size == 0 || header->qti_metadata_size == 0xE0) && + (header->oem_metadata_size == 0 || header->oem_metadata_size == 0xE0) && + (header->oem_signature_size == 0 || header->oem_signature_size == 0x68) && + (header->oem_certificate_chain_size == 0 || header->oem_certificate_chain_size == 0xD20); +} + +static void mbn_v7_log_header(const mbn_v7_header* header, const char* func, const char* prefix) +{ + logger(LL_DEBUG, + "%s: %s header {version=0x%x, common_metadata_size=0x%x, " + "qti_metadata_size=0x%x, oem_metadata_size=0x%x, hash_table_size=0x%x, " + "qti_signature_size=0x%x, qti_certificate_chain_size=0x%x, " + "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x}", + func, + prefix, + header->version, + header->common_metadata_size, + header->qti_metadata_size, + header->oem_metadata_size, + header->hash_table_size, + header->qti_signature_size, + header->qti_certificate_chain_size, + header->oem_signature_size, + header->oem_certificate_chain_size + ); } -int mbn_update_sig_blob(mbn_file* mbn, const void* sigdata, size_t siglen) +void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size) { - if (!mbn) { - logger(LL_ERROR, "%s: no data\n", __func__); - return -1; + if (!data) { + logger(LL_ERROR, "%s: data is NULL\n", __func__); + return NULL; } - mbn->parsed_sig_offset = mbn->size - siglen; - if ((mbn->parsed_sig_offset + siglen) > mbn->size) { - logger(LL_ERROR, "%s: signature is larger than mbn file size\n", __func__); - return -1; + + if (!data_size) { + logger(LL_ERROR, "%s: data size is 0\n", __func__); + return NULL; } - memcpy(mbn->data + mbn->parsed_sig_offset, sigdata, siglen); + if (!blob) { + logger(LL_ERROR, "%s: blob is NULL\n", __func__); + return NULL; + } - return 0; -} + if (!blob_size) { + logger(LL_ERROR, "%s: blob size is 0\n", __func__); + return NULL; + } + + if (!mbn_is_valid_elf(data, data_size)) { + logger(LL_ERROR, "%s: data is not a valid ELF\n", __func__); + return NULL; + } + + if (sizeof(mbn_v7_header) > blob_size) { + logger(LL_ERROR, "%s: header is bigger than blob\n", __func__); + return NULL; + } + + const mbn_v7_header* src_header = blob; + mbn_v7_log_header(src_header, __func__, "src"); + + if (src_header->version != 7) { + logger(LL_ERROR, "%s: src header version (0x%x) is incorrect\n", __func__, src_header->version); + return NULL; + } + + // NOTE: Apple does weird stuff, in this case blob is smaller than + // the sizes the header reports, so we can't check their validity. + if (!mbn_v7_header_sizes_expected(src_header)) { + logger(LL_WARNING, "%s: header sizes in header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, src_header->qti_metadata_size, src_header->oem_metadata_size, src_header->oem_signature_size, src_header->oem_certificate_chain_size); + } + + off_t sect_off; + size_t sect_size; + if (mbn_is_64bit_elf(data)) { + const elf64_header* ehdr = data; + const elf64_pheader* phdr = data + ehdr->e_phoff; + if (ehdr->e_phnum == 0) { + logger(LL_ERROR, "%s: ELF has no program sections\n", __func__); + return NULL; + } + if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(elf32_pheader)) > data_size) { + logger(LL_ERROR, "%s: Last ELF program section is out of bounds\n", __func__); + return NULL; + } + sect_off = phdr[ehdr->e_phnum-1].p_offset; + sect_size = phdr[ehdr->e_phnum-1].p_filesz; + } else { + const elf32_header* ehdr = data; + const elf32_pheader* phdr = data + ehdr->e_phoff; + if (ehdr->e_phnum == 0) { + logger(LL_ERROR, "%s: ELF has no program sections\n", __func__); + return NULL; + } + if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(elf64_pheader)) > data_size) { + logger(LL_ERROR, "%s: Last ELF program section is out of bounds\n", __func__); + return NULL; + } + sect_off = phdr[ehdr->e_phnum-1].p_offset; + sect_size = phdr[ehdr->e_phnum-1].p_filesz; + } + + if (sect_off == 0) { + logger(LL_ERROR, "%s: section has 0 offset\n", __func__); + return NULL; + } + + if (sect_size == 0) { + logger(LL_ERROR, "%s: section has 0 size\n", __func__); + return NULL; + } + + if (sect_off + sect_size > data_size) { + logger(LL_ERROR, "%s: section (0x%llx+0x%zx) is bigger than the data\n", __func__, sect_off, sect_size); + return NULL; + } + if (sizeof(mbn_v7_header) > sect_size) { + logger(LL_ERROR, "%s: dest header is bigger than the section (0x%zx)\n", __func__, sect_size); + return NULL; + } + + const mbn_v7_header* header = data + sect_off; + mbn_v7_log_header(header, __func__, "dest"); + if (header->version != 7) { + logger(LL_ERROR, "%s: dest header version (0x%x) is incorrect\n", __func__, header->version); + return NULL; + } + + if (!mbn_v7_header_sizes_valid(header, sect_size)) { + logger(LL_ERROR, "%s: sizes in dest header are invalid (common_metadata_size=0x%x, qti_metadata_size=0x%x, oem_metadata_size=0x%x, hash_table_size=0x%x, qti_signature_size=0x%x, qti_certificate_chain_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, header->common_metadata_size, header->qti_metadata_size, header->oem_metadata_size, header->hash_table_size, header->qti_signature_size, header->qti_certificate_chain_size, header->oem_signature_size, header->oem_certificate_chain_size); + return NULL; + } + + if (!mbn_v7_header_sizes_expected(header)) { + logger(LL_WARNING, "%s: header sizes in dest header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)\n", __func__, header->qti_metadata_size, header->oem_metadata_size, header->oem_signature_size, header->oem_certificate_chain_size); + } + + size_t new_metadata_size = + sizeof(*src_header) + src_header->common_metadata_size + + src_header->qti_metadata_size + src_header->oem_metadata_size; + size_t new_metadata_and_hash_table_size = + new_metadata_size + src_header->hash_table_size; + size_t new_oem_sig_and_cert_chain_size = + src_header->oem_signature_size + src_header->oem_certificate_chain_size; + off_t new_oem_sig_and_cert_chain_off = new_metadata_and_hash_table_size + + header->qti_signature_size + + header->qti_certificate_chain_size; + + if (new_metadata_and_hash_table_size > blob_size) { + logger(LL_ERROR, "%s: new metadata (0x%zx) and hash table (0x%x) are bigger than the source (0x%zx)\n", __func__, new_metadata_size, src_header->hash_table_size, blob_size); + return NULL; + } + + if (new_metadata_and_hash_table_size > sect_size) { + logger(LL_ERROR, "%s: new metadata (0x%zx) and hash table (0x%x) are bigger than the destination (0x%zx)\n", __func__, new_metadata_size, src_header->hash_table_size, sect_size); + return NULL; + } + + if (new_metadata_and_hash_table_size + new_oem_sig_and_cert_chain_size > blob_size) { + logger(LL_ERROR, "%s: new OEM signature and certificate chain are bigger than the source\n", __func__); + return NULL; + } + + if (new_oem_sig_and_cert_chain_off + new_oem_sig_and_cert_chain_size > sect_size) { + logger(LL_ERROR, "%s: new OEM signature and certificate chain are outside the bounds of the destination\n", __func__); + return NULL; + } + + void* buf = malloc(data_size); + if (buf == NULL) { + logger(LL_ERROR, "out of memory\n"); + return NULL; + } + + memcpy(buf, data, data_size); + logger(LL_DEBUG, "%s: stitching mbn at 0x%llx (0x%zx bytes)\n", __func__, sect_off, new_metadata_and_hash_table_size); + memcpy(buf + sect_off, blob, new_metadata_and_hash_table_size); + logger(LL_DEBUG, "%s: stitching mbn at 0x%llx (0x%zx bytes)\n", __func__, sect_off + new_oem_sig_and_cert_chain_off, new_oem_sig_and_cert_chain_size); + memcpy(buf + sect_off + new_oem_sig_and_cert_chain_off, blob + new_metadata_and_hash_table_size, new_oem_sig_and_cert_chain_size); + + return buf; +} diff --git a/src/mbn.h b/src/mbn.h index a3281289..ff447978 100644 --- a/src/mbn.h +++ b/src/mbn.h @@ -1,8 +1,9 @@ /* * mbn.h - * support for .mbn file format (found in .bbfw files) + * support for Qualcomm MBN (Modem Binary) formats * * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. + * Copyright (c) 2025 Visual Ehrmanntraut . 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 @@ -23,85 +24,7 @@ #include -#define MBN_V1_MAGIC "\x0A\x00\x00\x00" -#define MBN_V1_MAGIC_SIZE 4 - -struct _mbn_header_v1 { - uint32_t type; // the signed .mbn files have 0xA as value. - uint32_t unk_0x04; - uint32_t unk_0x08; - uint32_t unk_0x0c; - uint32_t data_size; // data_size = total_size - sizeof(mbn_header) - uint32_t sig_offset; // real offset = enc_sig_offset & 0xFFFFFF00 - uint32_t unk_0x18; - uint32_t unk_0x1c; - uint32_t unk_0x20; - uint32_t unk_0x24; -} __attribute__((packed)); -typedef struct _mbn_header_v1 mbn_header_v1; - -#define MBN_V2_MAGIC "\xD1\xDC\x4B\x84\x34\x10\xD7\x73" -#define MBN_V2_MAGIC_SIZE 8 - -struct _mbn_header_v2 { - unsigned char magic1[8]; - uint32_t unk_0x08; - uint32_t unk_0x0c; // 0xFFFFFFFF - uint32_t unk_0x10; // 0xFFFFFFFF - uint32_t header_size; - uint32_t unk_0x18; - uint32_t data_size; // data_size = total_size - sizeof(mbn_header_v2) - uint32_t sig_offset; - uint32_t unk_0x24; - uint32_t unk_0x28; - uint32_t unk_0x2c; - uint32_t unk_0x30; - uint32_t unk_0x34; // 0x1 - uint32_t unk_0x38; // 0x1 - uint32_t unk_0x3c; // 0xFFFFFFFF - uint32_t unk_0x40; // 0xFFFFFFFF - uint32_t unk_0x44; // 0xFFFFFFFF - uint32_t unk_0x48; // 0xFFFFFFFF - uint32_t unk_0x4c; // 0xFFFFFFFF -} __attribute__((packed)); -typedef struct _mbn_header_v2 mbn_header_v2; - -#define BIN_MAGIC "\x7D\x04\x00\xEA\x6C\x69\x48\x55" -#define BIN_MAGIC_SIZE 8 - -struct _bin_header { - unsigned char magic[8]; - uint32_t unk_0x08; - uint32_t version; - uint32_t total_size; // size including header - uint32_t unk_0x14; // some offset -} __attribute__((packed)); -typedef struct _bin_header bin_header; - -#define ELF_MAGIC "\x7F\x45\x4C\x46\x01\x01\x01\x00" // ELF magic, 32bit, little endian, SYSV -#define ELF_MAGIC_SIZE 8 - -struct _elf_header { - unsigned char magic[8]; -} __attribute__((packed)); -typedef struct _elf_header elf_header; - -typedef struct { - uint32_t version; - union { - mbn_header_v1 v1; - mbn_header_v2 v2; - bin_header bin; - elf_header elf; - } header; - uint32_t parsed_size; - uint32_t parsed_sig_offset; - void* data; - uint32_t size; -} mbn_file; - -mbn_file* mbn_parse(const void* data, size_t size); -void mbn_free(mbn_file* mbn); -int mbn_update_sig_blob(mbn_file* mbn, const void* data, size_t size); +void* mbn_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size); +void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, size_t blob_size); #endif diff --git a/src/restore.c b/src/restore.c index 09cbe16d..f2fd9bec 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1857,7 +1857,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return 0; } -static const char* restore_get_bbfw_fn_for_element(const char* elem) +static const char* restore_get_bbfw_fn_for_element(const char* elem, uint32_t bb_chip_id) { struct bbfw_fn_elem_t { const char* element; @@ -1888,16 +1888,30 @@ static const char* restore_get_bbfw_fn_for_element(const char* elem) { NULL, NULL } }; + struct bbfw_fn_elem_t bbfw_fn_elem_mav25[] = { + // Mav25 Firmware files + { "Misc", "multi_image.mbn" }, + { "RestoreSBL1", "restorexbl_sc.elf" }, + { "SBL1", "xbl_sc.elf" }, + { "TME", "signed_firmware_soc_view.elf" }, + { NULL, NULL } + }; + + struct bbfw_fn_elem_t* bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem; + if (bb_chip_id == 0x1F30E1) { + bbfw_fn_elems = (struct bbfw_fn_elem_t*)bbfw_fn_elem_mav25; + } + int i; - for (i = 0; bbfw_fn_elem[i].element != NULL; i++) { - if (strcmp(bbfw_fn_elem[i].element, elem) == 0) { - return bbfw_fn_elem[i].fn; + for (i = 0; bbfw_fn_elems[i].element != NULL; i++) { + if (strcmp(bbfw_fn_elems[i].element, elem) == 0) { + return bbfw_fn_elems[i].fn; } } return NULL; } -static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce) +static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned char* bb_nonce, uint32_t bb_chip_id) { int res = -1; @@ -1925,7 +1939,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned struct zip_file* zfile = NULL; struct zip* za = NULL; struct zip_source* zs = NULL; - mbn_file* mbn = NULL; fls_file* fls = NULL; za = zip_open(bbfwtmp, 0, &zerr); @@ -1953,7 +1966,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned if (node && (strcmp(key + (strlen(key) - 5), "-Blob") == 0) && (plist_get_node_type(node) == PLIST_DATA)) { char *ptr = strchr(key, '-'); *ptr = '\0'; - const char* signfn = restore_get_bbfw_fn_for_element(key); + const char* signfn = restore_get_bbfw_fn_for_element(key, bb_chip_id); if (!signfn) { logger(LL_ERROR, "can't match element name '%s' to baseband firmware file name.\n", key); goto leave; @@ -2002,12 +2015,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned logger(LL_ERROR, "could not parse fls file\n"); goto leave; } - } else { - mbn = mbn_parse(buffer, zstat.size); - if (!mbn) { - logger(LL_ERROR, "could not parse mbn file\n"); - goto leave; - } } free(buffer); buffer = NULL; @@ -2019,32 +2026,33 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } + logger(LL_VERBOSE, "Stitching %s\n", signfn); if (is_fls) { - if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { - logger(LL_ERROR, "could not sign %s\n", signfn); + if (fls_update_sig_blob(fls, blob, (size_t)blob_size) != 0) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); goto leave; } - } else { - if (mbn_update_sig_blob(mbn, blob, (unsigned int)blob_size) != 0) { - logger(LL_ERROR, "could not sign %s\n", signfn); + fsize = fls->size; + fdata = (unsigned char*)malloc(fsize); + if (fdata == NULL) { + logger(LL_ERROR, "out of memory\n"); goto leave; } - } - - fsize = (is_fls ? fls->size : mbn->size); - fdata = (unsigned char*)malloc(fsize); - if (fdata == NULL) { - logger(LL_ERROR, "out of memory\n"); - goto leave; - } - if (is_fls) { memcpy(fdata, fls->data, fsize); fls_free(fls); fls = NULL; + } else if (bb_chip_id == 0x1F30E1) { // Mav25 - Qualcomm Snapdragon X80 5G Modem + fdata = mbn_mav25_stitch(buffer, zstat.size, blob, (size_t)blob_size); + if (!fdata) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); + goto leave; + } } else { - memcpy(fdata, mbn->data, fsize); - mbn_free(mbn); - mbn = NULL; + fdata = mbn_stitch(buffer, zstat.size, blob, (size_t)blob_size); + if (!fdata) { + logger(LL_ERROR, "Could not stitch %s\n", signfn); + goto leave; + } } zs = zip_source_buffer(za, fdata, fsize, 1); @@ -2055,7 +2063,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } if (zip_file_replace(za, zindex, zs, 0) == -1) { - logger(LL_ERROR, "could not update signed '%s' in archive\n", signfn); + logger(LL_ERROR, "Could not update signed '%s' in archive\n", signfn); goto leave; } @@ -2218,7 +2226,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_unchange_all(za); zip_close(za); } - mbn_free(mbn); fls_free(fls); free(buffer); @@ -2352,7 +2359,7 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl response = NULL; } - res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce); + res = restore_sign_bbfw(bbfwtmp, (client->restore->bbtss) ? client->restore->bbtss : response, bb_nonce, bb_chip_id); if (res != 0) { goto leave; } From 551dba57e3d38c721f474ae0cdbb4fe42ec4d66b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 29 Sep 2025 15:46:49 +0200 Subject: [PATCH 153/159] Fix Mav baseband stitching --- src/mbn.c | 15 +++++++-------- src/restore.c | 6 ++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mbn.c b/src/mbn.c index 2ba5e656..ca51fdf3 100644 --- a/src/mbn.c +++ b/src/mbn.c @@ -263,11 +263,11 @@ void* mbn_stitch(const void* data, size_t data_size, const void* blob, size_t bl off_t stitch_offset = data_size - blob_size; if (stitch_offset + blob_size > data_size) { - logger(LL_ERROR, "%s: stitch offset (0x%llx) + size (0x%zx) is larger than the destination (0x%zx)\n", __func__, stitch_offset, blob_size, data_size); + logger(LL_ERROR, "%s: stitch offset (0x%lx) + size (0x%zx) is larger than the destination (0x%zx)\n", __func__, (unsigned long)stitch_offset, blob_size, data_size); return NULL; } - void* buf = malloc(data_size); + unsigned char* buf = malloc(data_size); if (buf == NULL) { logger(LL_ERROR, "out of memory\n"); return NULL; @@ -409,7 +409,7 @@ void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, siz } if (sect_off + sect_size > data_size) { - logger(LL_ERROR, "%s: section (0x%llx+0x%zx) is bigger than the data\n", __func__, sect_off, sect_size); + logger(LL_ERROR, "%s: section (0x%lx+0x%zx) is bigger than the data\n", __func__, (unsigned long)sect_off, sect_size); return NULL; } @@ -442,8 +442,7 @@ void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, siz size_t new_oem_sig_and_cert_chain_size = src_header->oem_signature_size + src_header->oem_certificate_chain_size; off_t new_oem_sig_and_cert_chain_off = new_metadata_and_hash_table_size + - header->qti_signature_size + - header->qti_certificate_chain_size; + header->qti_signature_size + header->qti_certificate_chain_size; if (new_metadata_and_hash_table_size > blob_size) { logger(LL_ERROR, "%s: new metadata (0x%zx) and hash table (0x%x) are bigger than the source (0x%zx)\n", __func__, new_metadata_size, src_header->hash_table_size, blob_size); @@ -465,16 +464,16 @@ void* mbn_mav25_stitch(const void* data, size_t data_size, const void* blob, siz return NULL; } - void* buf = malloc(data_size); + unsigned char* buf = malloc(data_size); if (buf == NULL) { logger(LL_ERROR, "out of memory\n"); return NULL; } memcpy(buf, data, data_size); - logger(LL_DEBUG, "%s: stitching mbn at 0x%llx (0x%zx bytes)\n", __func__, sect_off, new_metadata_and_hash_table_size); + logger(LL_DEBUG, "%s: stitching mbn at 0x%lx (0x%zx bytes)\n", __func__, (unsigned long)sect_off, new_metadata_and_hash_table_size); memcpy(buf + sect_off, blob, new_metadata_and_hash_table_size); - logger(LL_DEBUG, "%s: stitching mbn at 0x%llx (0x%zx bytes)\n", __func__, sect_off + new_oem_sig_and_cert_chain_off, new_oem_sig_and_cert_chain_size); + logger(LL_DEBUG, "%s: stitching mbn at 0x%lx (0x%zx bytes)\n", __func__, (unsigned long)(sect_off + new_oem_sig_and_cert_chain_off), new_oem_sig_and_cert_chain_size); memcpy(buf + sect_off + new_oem_sig_and_cert_chain_off, blob + new_metadata_and_hash_table_size, new_oem_sig_and_cert_chain_size); return buf; diff --git a/src/restore.c b/src/restore.c index f2fd9bec..deeaf437 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2016,8 +2016,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } } - free(buffer); - buffer = NULL; blob_size = 0; blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size); @@ -2043,17 +2041,21 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned fls = NULL; } else if (bb_chip_id == 0x1F30E1) { // Mav25 - Qualcomm Snapdragon X80 5G Modem fdata = mbn_mav25_stitch(buffer, zstat.size, blob, (size_t)blob_size); + fsize = zstat.size; if (!fdata) { logger(LL_ERROR, "Could not stitch %s\n", signfn); goto leave; } } else { fdata = mbn_stitch(buffer, zstat.size, blob, (size_t)blob_size); + fsize = zstat.size; if (!fdata) { logger(LL_ERROR, "Could not stitch %s\n", signfn); goto leave; } } + free(buffer); + buffer = NULL; zs = zip_source_buffer(za, fdata, fsize, 1); if (!zs) { From d88d440f47fe27eb839c7f4c580fc743589a9313 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 1 Oct 2025 15:54:03 +0200 Subject: [PATCH 154/159] mbn: Add missing line break to debug log message --- src/mbn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbn.c b/src/mbn.c index ca51fdf3..8d9f7a48 100644 --- a/src/mbn.c +++ b/src/mbn.c @@ -307,7 +307,7 @@ static void mbn_v7_log_header(const mbn_v7_header* header, const char* func, con "%s: %s header {version=0x%x, common_metadata_size=0x%x, " "qti_metadata_size=0x%x, oem_metadata_size=0x%x, hash_table_size=0x%x, " "qti_signature_size=0x%x, qti_certificate_chain_size=0x%x, " - "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x}", + "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x}\n", func, prefix, header->version, From fb46a9db2d8d11dc98d2bf6d61754e4c8f185460 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 Oct 2025 20:54:37 +0200 Subject: [PATCH 155/159] Do not try to print SEP nonce if none was retrieved --- src/idevicerestore.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index e3774bb6..809f9350 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1247,8 +1247,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce"); uint64_t sep_nonce_size = 0; const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size); - logger(LL_INFO, "Getting SepNonce in normal mode... "); - logger_dump_hex(LL_INFO, sep_nonce, sep_nonce_size); + if (sep_nonce) { + logger(LL_INFO, "Getting SepNonce in normal mode... "); + logger_dump_hex(LL_INFO, sep_nonce, sep_nonce_size); + } plist_free(ap_params); } plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot"); From 460bf2e85b4e1dd01a3b87d18bc932805642079c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 Oct 2025 20:56:18 +0200 Subject: [PATCH 156/159] Fix baseband processing with Mav25 (and possibly others too) --- src/idevicerestore.c | 8 +++----- src/idevicerestore.h | 1 + src/restore.c | 17 +++++++++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 809f9350..04070a17 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -171,8 +171,6 @@ const uint8_t lpol_file[22] = { }; const uint32_t lpol_file_length = 22; -static int idevicerestore_keep_pers = 0; - static int load_version_data(struct idevicerestore_client_t* client) { if (!client) { @@ -814,7 +812,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_free(response); free(uarp_buf); - if (idevicerestore_keep_pers) { + if (client->flags & FLAG_KEEP_PERS) { write_file("Ace3Binary", ace3bin, ace3bin_size); } @@ -1907,7 +1905,7 @@ int main(int argc, char* argv[]) break; case 'k': - idevicerestore_keep_pers = 1; + client->flags |= FLAG_KEEP_PERS; break; #ifdef HAVE_LIMERA1N @@ -2863,7 +2861,7 @@ int personalize_component(struct idevicerestore_client_t* client, const char *co } free(component_blob); - if (idevicerestore_keep_pers) { + if (client->flags & FLAG_KEEP_PERS) { write_file(component_name, stitched_component, stitched_component_size); } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 9d6f5af2..ce8686f3 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -46,6 +46,7 @@ extern "C" { #define FLAG_ALLOW_RESTORE_MODE (1 << 10) #define FLAG_NO_RESTORE (1 << 11) #define FLAG_IGNORE_ERRORS (1 << 12) +#define FLAG_KEEP_PERS (1 << 13) #define FLAG_IN_PROGRESS (1 << 30) #define RESTORE_VARIANT_ERASE_INSTALL "Erase Install (IPSW)" diff --git a/src/restore.c b/src/restore.c index deeaf437..12f837ce 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2094,8 +2094,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } // check for anything but .mbn and .fls if bb_nonce is set - if (bb_nonce && !keep) { - const char* fn = zip_get_name(za, i, 0); + const char* fn = zip_get_name(za, i, 0); + if (!keep) { if (fn) { char* ext = strrchr(fn, '.'); if (ext && (!strcmp(ext, ".fls") || !strcmp(ext, ".mbn") || !strcmp(ext, ".elf") || !strcmp(ext, ".bin"))) { @@ -2104,11 +2104,14 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } if (!keep) { + logger(LL_DEBUG, "%s: removing %s from bbfw\n", __func__, fn); zip_delete(za, i); + } else { + logger(LL_DEBUG, "%s: keeping %s in bbfw\n", __func__, fn); } } - if (bb_nonce) { + if (bbticket) { if (is_fls) { // add BBTicket to file ebl.fls zindex = zip_name_locate(za, "ebl.fls", 0); @@ -2401,7 +2404,13 @@ static int restore_send_baseband_data(struct idevicerestore_client_t* client, pl plist_free(dict); free(buffer); if (bbfwtmp) { - remove(bbfwtmp); + if (client->flags & FLAG_KEEP_PERS) { + const char* bbfwname = path_get_basename(bbfwtmp); + logger(LL_VERBOSE, "%s: Keeping personalized BBFW as %s\n", __func__, bbfwname); + rename(bbfwtmp, bbfwname); + } else { + remove(bbfwtmp); + } free(bbfwtmp); } plist_free(response); From f4d0f7e83105cc362527566315abee07b0840848 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 Oct 2025 20:56:49 +0200 Subject: [PATCH 157/159] log: Add missing include --- src/log.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/log.h b/src/log.h index 2563af3e..046a8d25 100644 --- a/src/log.h +++ b/src/log.h @@ -21,6 +21,8 @@ #ifndef LOG_H #define LOG_H +#include + enum loglevel { LL_ERROR = 0, LL_WARNING, From a499b625f97b8b82eec4927196894f72f79d2088 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Nov 2025 02:16:13 +0100 Subject: [PATCH 158/159] configure: Bump libimobiledevice and libirecovery version requirements --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 98516b7c..9855bde9 100644 --- a/configure.ac +++ b/configure.ac @@ -15,8 +15,8 @@ if test -z $PACKAGE_VERSION; then fi # Minimum package versions -LIBIRECOVERY_VERSION=1.2.1 -LIBIMOBILEDEVICE_VERSION=1.3.0 +LIBIRECOVERY_VERSION=1.3.0 +LIBIMOBILEDEVICE_VERSION=1.4.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.3.0 From 74e3bd9286d16fc1290abde061ee00831d5b36f8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 24 Nov 2025 01:29:18 +0100 Subject: [PATCH 159/159] endianness.h: Default to little endian --- src/endianness.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/endianness.h b/src/endianness.h index ee9a1a5a..972e51b1 100644 --- a/src/endianness.h +++ b/src/endianness.h @@ -19,6 +19,13 @@ #endif #endif +#ifndef __BYTE_ORDER +#ifndef _WIN32 +#warning __BYTE_ORDER is not defined, assuming little endian +#endif +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif + #ifndef be16toh #if __BYTE_ORDER == __BIG_ENDIAN #define be16toh(x) (x) @@ -27,6 +34,10 @@ #endif #endif +#ifndef htobe16 +#define htobe16 be16toh +#endif + #ifndef le16toh #if __BYTE_ORDER == __BIG_ENDIAN #define le16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) @@ -35,6 +46,9 @@ #endif #endif +#ifndef htole16 +#define htole16 le16toh +#endif #ifndef __bswap_32 #define __bswap_32(x) ((((x) & 0xFF000000) >> 24) \ @@ -102,4 +116,15 @@ #define htole64 le64toh #endif +#if (defined(__BIG_ENDIAN__) \ + && !defined(__FLOAT_WORD_ORDER__)) \ + || (defined(__FLOAT_WORD_ORDER__) \ + && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) +#define float_bswap64(x) __bswap_64(x) +#define float_bswap32(x) __bswap_32(x) +#else +#define float_bswap64(x) (x) +#define float_bswap32(x) (x) +#endif + #endif /* ENDIANNESS_H */