Fix iPhone 16 restore from normal mode and add support for RecoveryOS

This commit is contained in:
Nikias Bassen
2024-10-15 22:09:43 +02:00
parent f4a18ee13d
commit 151c680feb
10 changed files with 570 additions and 96 deletions
+3
View File
@@ -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;
+1 -1
View File
@@ -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;
+49 -11
View File
@@ -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(&parameters, 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) {
+1 -1
View File
@@ -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);
+123 -54
View File
@@ -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;
}
}
unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16);
int nonce_slot_required = plist_dict_get_bool(parameters, "RequiresNonceSlot") && (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1") || !strcmp(component_name, "LLB"));
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");
if (ucon_data) {
// 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 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, ucon_seq_hdr_len + ucon_size, &p, &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(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen);
// 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, 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;
// 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");
if (ucer_data) {
// 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);
// 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);
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);
// 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(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen);
// 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, 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;
// 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
+1 -1
View File
@@ -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
+25 -1
View File
@@ -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;
+1
View File
@@ -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);
+1 -1
View File
@@ -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);
+365 -26
View File
@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <math.h>
#include <libimobiledevice/restore.h>
#include <libimobiledevice/property_list_service.h>
#include <libimobiledevice-glue/thread.h>
@@ -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);