-
Notifications
You must be signed in to change notification settings - Fork 405
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Port DFU device restore
- Loading branch information
Showing
9 changed files
with
511 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <string.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <libimobiledevice-glue/nskeyedarchive.h> | ||
|
||
#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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef IDEVICERESTORE_ACE3_H | ||
#define IDEVICERESTORE_ACE3_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include <stdint.h> | ||
#include <plist/plist.h> | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.