diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/activate.h | 13 | ||||
-rw-r--r-- | src/asr.c | 2 | ||||
-rw-r--r-- | src/asr.h | 9 | ||||
-rw-r--r-- | src/common.c | 108 | ||||
-rw-r--r-- | src/common.h | 151 | ||||
-rw-r--r-- | src/dfu.c | 84 | ||||
-rw-r--r-- | src/dfu.h | 24 | ||||
-rw-r--r-- | src/idevicerestore.c | 306 | ||||
-rw-r--r-- | src/idevicerestore.h | 146 | ||||
-rw-r--r-- | src/img3.h | 9 | ||||
-rw-r--r-- | src/ipsw.c | 2 | ||||
-rw-r--r-- | src/ipsw.h | 8 | ||||
-rw-r--r-- | src/normal.c | 48 | ||||
-rw-r--r-- | src/normal.h | 17 | ||||
-rw-r--r-- | src/recovery.c | 47 | ||||
-rw-r--r-- | src/recovery.h | 20 | ||||
-rw-r--r-- | src/restore.c | 219 | ||||
-rw-r--r-- | src/restore.h | 32 | ||||
-rw-r--r-- | src/tss.h | 9 |
19 files changed, 837 insertions, 417 deletions
diff --git a/src/activate.h b/src/activate.h index f992d4f..00510d3 100644 --- a/src/activate.h +++ b/src/activate.h @@ -19,8 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ACTIVATE_H -#define ACTIVATE_H +#ifndef IDEVICERESTORE_ACTIVATE_H +#define IDEVICERESTORE_ACTIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif #include <plist/plist.h> #include <libimobiledevice/lockdown.h> @@ -29,4 +33,9 @@ int activate_device(const char* uuid); int activate_check_status(const char* uuid); int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record); + +#ifdef __cplusplus +} +#endif + #endif @@ -283,7 +283,7 @@ int asr_send_payload(idevice_connection_t asr, const char* filesystem) { bytes += size; progress = ((double) bytes/ (double) length) * 100.0; - print_progress_bar("Extracting", progress); + print_progress_bar(progress); } @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_ASR_H #define IDEVICERESTORE_ASR_H +#ifdef __cplusplus +extern "C" { +#endif + #include <libimobiledevice/libimobiledevice.h> int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr); @@ -33,4 +37,9 @@ int asr_perform_validation(idevice_connection_t asr, const char* filesystem); int asr_send_payload(idevice_connection_t asr, const char* filesystem); int asr_handle_oob_data_request(idevice_connection_t asr, plist_t packet, FILE* file); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..07a7075 --- /dev/null +++ b/src/common.c @@ -0,0 +1,108 @@ +/* + * common.c + * Misc functions used in idevicerestore + * + * 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 "common.h" + +int idevicerestore_debug = 0; + +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); + file = fopen(filename, "wb"); + if (file == NULL) { + error("read_file: Unable to open file %s\n", filename); + return -1; + } + + bytes = fwrite(data, 1, size, file); + fclose(file); + + if (bytes != size) { + error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size); + return -1; + } + + return size; +} + +int read_file(const char* filename, void** data, size_t* size) { + size_t bytes = 0; + size_t length = 0; + FILE* file = NULL; + char* buffer = NULL; + debug("Reading data from %s\n", filename); + + *size = 0; + *data = NULL; + + file = fopen(filename, "rb"); + if (file == NULL) { + error("read_file: File %s not found\n", filename); + return -1; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + rewind(file); + + buffer = (char*) malloc(length); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + fclose(file); + return -1; + } + bytes = fread(buffer, 1, length, file); + fclose(file); + + if (bytes != length) { + error("ERROR: Unable to read entire file\n"); + free(buffer); + return -1; + } + + *size = length; + *data = buffer; + return 0; +} + +void debug_plist(plist_t plist) { + int size = 0; + char* data = NULL; + plist_to_xml(plist, &data, &size); + info("%s", data); + free(data); +} + +void print_progress_bar(double progress) { + int i = 0; + if(progress < 0) return; + if(progress > 100) progress = 100; + info("\r["); + for(i = 0; i < 50; i++) { + if(i < progress / 2) info("="); + else info(" "); + } + info("] %3.1f%%", progress); + if(progress == 100) info("\n"); + fflush(stdout); +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..cb774a5 --- /dev/null +++ b/src/common.h @@ -0,0 +1,151 @@ +/* + * common.h + * Misc functions used in idevicerestore + * + * 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_COMMON_H +#define IDEVICERESTORE_COMMON_H + +#include <plist/plist.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define info(...) printf(__VA_ARGS__) +#define error(...) fprintf(stderr, __VA_ARGS__) +#define debug(...) if(idevicerestore_debug) fprintf(stderr, __VA_ARGS__) + +#define CPID_UNKNOWN -1 +#define CPID_IPHONE2G 8900 +#define CPID_IPOD1G 8900 +#define CPID_IPHONE3G 8900 +#define CPID_IPOD2G 8720 +#define CPID_IPHONE3GS 8920 +#define CPID_IPOD3G 8922 +#define CPID_IPAD1G 8930 + +#define BDID_UNKNOWN -1 +#define BDID_IPHONE2G 0 +#define BDID_IPOD1G 2 +#define BDID_IPHONE3G 4 +#define BDID_IPOD2G 0 +#define BDID_IPHONE3GS 0 +#define BDID_IPOD3G 2 +#define BDID_IPAD1G 2 + +#define DEVICE_UNKNOWN -1 +#define DEVICE_IPHONE2G 0 +#define DEVICE_IPOD1G 1 +#define DEVICE_IPHONE3G 2 +#define DEVICE_IPOD2G 3 +#define DEVICE_IPHONE3GS 4 +#define DEVICE_IPOD3G 5 +#define DEVICE_IPAD1G 6 + +#define MODE_UNKNOWN -1 +#define MODE_DFU 0 +#define MODE_RECOVERY 1 +#define MODE_RESTORE 2 +#define MODE_NORMAL 3 + +#define FLAG_QUIT 1 +#define FLAG_DEBUG 2 +#define FLAG_ERASE 4 +#define FLAG_CUSTOM 8 +#define FLAG_EXCLUDE 16 + +struct dfu_client_t; +struct normal_client_t; +struct restore_clien_t; +struct recovery_client_t; + +struct idevicerestore_mode_t { + int index; + 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_device_t { + int index; + const char* product; + const char* model; + uint32_t board_id; + uint32_t chip_id; +}; + +struct idevicerestore_client_t { + int flags; + plist_t tss; + uint64_t ecid; + const char* uuid; + const char* ipsw; + const char* filesystem; + struct dfu_client_t* dfu; + struct normal_client_t* normal; + struct restore_client_t* restore; + struct recovery_client_t* recovery; + struct idevicerestore_device_t* device; + struct idevicerestore_entry_t** entries; + struct idevicerestore_mode_t* mode; +}; + +static struct idevicerestore_mode_t idevicerestore_modes[] = { + { 0, "DFU" }, + { 1, "Recovery" }, + { 2, "Restore" }, + { 3, "Normal" }, + { -1, NULL } +}; + +static struct idevicerestore_device_t idevicerestore_devices[] = { + { 0, "iPhone1,1", "M68AP", 0, 8900 }, + { 1, "iPod1,1", "N45AP", 2, 8900 }, + { 2, "iPhone1,2", "N82AP", 4, 8900 }, + { 3, "iPod2,1", "N72AP", 0, 8720 }, + { 4, "iPhone2,1", "N88AP", 0, 8920 }, + { 5, "iPod3,1", "N18AP", 2, 8922 }, + { 6, "iPad1,1", "K48AP", 2, 8930 }, + { 6, "iPhone3,1", "XXXAP", 0, 0 }, + { -1, NULL, NULL, -1, -1 } +}; + +extern int idevicerestore_debug; + +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); + +extern struct idevicerestore_client_t* idevicerestore; + +#ifdef __cplusplus +} +#endif + +#endif @@ -24,29 +24,87 @@ #include <libirecovery.h> #include "dfu.h" -#include "recovery.h" +//#include "recovery.h" #include "idevicerestore.h" -int dfu_check_mode() { - irecv_client_t dfu = NULL; - irecv_error_t dfu_error = IRECV_E_SUCCESS; +int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) { + if (event->type == IRECV_PROGRESS) { + print_progress_bar(event->progress); + } + return 0; +} - dfu_error = irecv_open(&dfu); - if (dfu_error != IRECV_E_SUCCESS) { +int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout) { + struct dfu_client_t* dfu = NULL; + if(client == NULL) { return -1; } - if (dfu->mode != kDfuMode) { - irecv_close(dfu); + if(client->dfu) { + dfu_client_free(client); + } + + dfu = (struct dfu_client_t*) malloc(sizeof(struct dfu_client_t)); + if (dfu == NULL) { + error("ERROR: Out of memory\n"); return -1; } - irecv_close(dfu); - dfu = NULL; + if (dfu_open_with_timeout(dfu, timeout) < 0) { + dfu_client_free(client); + return -1; + } + + if(dfu->client->mode != kDfuMode) { + dfu_client_free(client); + return -1; + } + + client->dfu = dfu; + return 0; +} + +void dfu_client_free(struct idevicerestore_client_t* client) { + struct dfu_client_t* dfu = NULL; + if(client != NULL) { + dfu = client->dfu; + if (dfu != NULL) { + if(dfu->client != NULL) { + irecv_close(dfu->client); + dfu->client = NULL; + } + free(dfu); + } + client->dfu = NULL; + } +} + +int dfu_open_with_timeout(struct idevicerestore_client_t* client, uint32_t timeout) { + int i = 0; + irecv_client_t recovery = NULL; + irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; + + for (i = 1; i <= timeout; i++) { + recovery_error = irecv_open(&recovery); + if (recovery_error == IRECV_E_SUCCESS) { + break; + } + + if (i == timeout) { + error("ERROR: Unable to connect to device in DFU mode\n"); + return -1; + } + + sleep(1); + debug("Retrying connection...\n"); + } + + irecv_event_subscribe(recovery, IRECV_PROGRESS, &dfu_progress_callback, NULL); + client->dfu = recovery; return 0; } -int dfu_enter_recovery(const char* ipsw, plist_t tss) { +int dfu_enter_recovery(struct idevicerestore_client_t* client) { irecv_client_t dfu = NULL; const char* component = "iBSS"; irecv_error_t dfu_error = IRECV_E_SUCCESS; @@ -57,7 +115,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) { return -1; } - if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) { + if (recovery_send_signed_component(dfu, client->ipsw, client->tss, "iBSS") < 0) { error("ERROR: Unable to send %s to device\n", component); irecv_close(dfu); return -1; @@ -80,7 +138,7 @@ int dfu_enter_recovery(const char* ipsw, plist_t tss) { return -1; } - idevicerestore_mode = MODE_RECOVERY; + client->mode = &idevicerestore_modes[MODE_RECOVERY]; irecv_close(dfu); dfu = NULL; return 0; @@ -22,10 +22,26 @@ #ifndef IDEVICERESTORE_DFU_H #define IDEVICERESTORE_DFU_H -#include <stdint.h> -#include <plist/plist.h> +#ifdef __cplusplus +extern "C" { +#endif + +#include <libirecovery.h> +#include "common.h" + +struct dfu_client_t { + irecv_client_t client; + const char* ipsw; + plist_t tss; +}; -int dfu_check_mode(); -int dfu_enter_recovery(const char* ipsw, plist_t tss); +int dfu_client_new(struct idevicerestore_client_t* client, uint32_t timeout); +void dfu_client_free(struct idevicerestore_client_t* client); +int dfu_enter_recovery(struct idevicerestore_client_t* client); + + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index c801266..cdbff27 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -25,38 +25,25 @@ #include <unistd.h> #include <getopt.h> #include <plist/plist.h> -#include <libirecovery.h> -#include <libimobiledevice/restore.h> -#include <libimobiledevice/lockdown.h> -#include <libimobiledevice/libimobiledevice.h> -#include "dfu.h" -#include "tss.h" +#include "idevicerestore.h" +//#include "recovery.h" +#include "restore.h" +#include "common.h" +#include "normal.h" #include "img3.h" #include "ipsw.h" -#include "normal.h" -#include "restore.h" -#include "recovery.h" -#include "idevicerestore.h" +#include "dfu.h" +#include "tss.h" -int idevicerestore_quit = 0; -int idevicerestore_debug = 0; -int idevicerestore_erase = 0; -int idevicerestore_custom = 0; -int idevicerestore_verbose = 0; -int idevicerestore_exclude = 0; -int idevicerestore_mode = MODE_UNKNOWN; -idevicerestore_device_t* idevicerestore_device = NULL; - -static struct option long_opts[] = { - { "uuid", required_argument, NULL, 'u' }, - { "debug", no_argument, NULL, 'd' }, - { "verbose", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - { "erase", no_argument, NULL, 'e' }, - { "custom", no_argument, NULL, 'c' }, - { "exclude", no_argument, NULL, 'x' }, - { NULL, 0, NULL, 0} +static struct option longopts[] = { + { "uuid", required_argument, NULL, 'u' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "erase", no_argument, NULL, 'e' }, + { "custom", no_argument, NULL, 'c' }, + { "exclude", no_argument, NULL, 'x' }, + { NULL, 0, NULL, 0 } }; void usage(int argc, char* argv[]) { @@ -65,7 +52,6 @@ void usage(int argc, char* argv[]) { printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); printf(" -d, --debug\t\tenable communication debugging\n"); - printf(" -v, --verbose\t\tenable verbose output\n"); printf(" -h, --help\t\tprints usage information\n"); printf(" -e, --erase\t\tperform a full restore, erasing all data\n"); printf(" -c, --custom\t\trestore with a custom firmware\n"); @@ -106,30 +92,36 @@ int main(int argc, char* argv[]) { char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { + + // create an instance of our context + struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t)); + if (client == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + memset(client, '\0', sizeof(struct idevicerestore_client_t)); + idevicerestore = client; + + while ((opt = getopt_long(argc, argv, "dhcexu:", longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv); break; case 'd': - idevicerestore_debug = 1; + client->flags &= FLAG_DEBUG; break; case 'e': - idevicerestore_erase = 1; + client->flags &= FLAG_ERASE; break; case 'c': - idevicerestore_custom = 1; + client->flags &= FLAG_CUSTOM; break; case 'x': - idevicerestore_exclude = 1; - break; - - case 'v': - idevicerestore_verbose = 1; + client->flags &= FLAG_EXCLUDE; break; case 'u': @@ -152,27 +144,30 @@ int main(int argc, char* argv[]) { return -1; } - if(idevicerestore_debug) { - idevice_set_debug_level(5); + if (client->flags & FLAG_DEBUG) { + idevice_set_debug_level(1); + irecv_set_debug_level(1); } + client->uuid = uuid; + client->ipsw = ipsw; + // check which mode the device is currently in so we know where to start - idevicerestore_mode = check_mode(uuid); - if (idevicerestore_mode < 0) { + if (check_mode(client) < 0 || client->mode->index == MODE_UNKNOWN) { error("ERROR: Unable to discover current device state\n"); return -1; } + info("Found device in %s mode\n", client->mode->string); // discover the device type - int id = check_device(uuid); - if (id < 0) { + if (check_device(client) < 0 || client->device->index == DEVICE_UNKNOWN) { error("ERROR: Unable to discover device type\n"); return -1; } - idevicerestore_device = &idevicerestore_devices[id]; + info("Identified device as %s\n", client->device->product); - if (idevicerestore_mode == MODE_RESTORE) { - if (restore_reboot(uuid) < 0) { + if (client->mode->index == MODE_RESTORE) { + if (restore_reboot(client) < 0) { error("ERROR: Unable to exit restore mode\n"); return -1; } @@ -181,28 +176,28 @@ int main(int argc, char* argv[]) { // extract buildmanifest plist_t buildmanifest = NULL; info("Extracting BuildManifest from IPSW\n"); - if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { + if (extract_buildmanifest(client, ipsw, &buildmanifest) < 0) { error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); return -1; } // devices are listed in order from oldest to newest // so we'll need their ECID - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - info("Creating TSS request\n"); + if (client->device->index > DEVICE_IPOD2G) { + debug("Creating TSS request\n"); // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + if (get_ecid(client, &client->ecid) < 0) { error("ERROR: Unable to find device ECID\n"); return -1; } - debug("Found ECID %llu\n", ecid); + debug("Found ECID %llu\n", client->ecid); } // choose whether this is an upgrade or a restore (default to upgrade) plist_t tss = NULL; plist_t build_identity = NULL; - if (idevicerestore_erase) { - build_identity = get_build_identity(buildmanifest, 0); + if (client->flags & FLAG_ERASE) { + build_identity = get_build_identity(client, buildmanifest, 0); if (build_identity == NULL) { error("ERROR: Unable to find build any identities\n"); plist_free(buildmanifest); @@ -215,9 +210,10 @@ int main(int argc, char* argv[]) { int i = 0; int valid_builds = 0; int build_count = get_build_count(buildmanifest); - for(i = 0; i < build_count; i++) { - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { - if (get_shsh_blobs(ecid, buildmanifest, &tss) < 0) { + for (i = 0; i < build_count; i++) { + if (client->device->index > DEVICE_IPOD2G) { + build_identity = get_build_identity(client, buildmanifest, i); + if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) { // if this fails then no SHSH blobs have been saved // for this build identity, so check the next one continue; @@ -231,29 +227,29 @@ int main(int argc, char* argv[]) { // devices are listed in order from oldest to newest // devices that come after iPod2g require personalized firmwares plist_t tss_request = NULL; - if (idevicerestore_device->device_id > DEVICE_IPOD2G) { + if (client->device->index > DEVICE_IPOD2G) { info("Creating TSS request\n"); // fetch the device's ECID for the TSS request - if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { + if (get_ecid(client, &ecid) < 0 || ecid == 0) { error("ERROR: Unable to find device ECID\n"); return -1; } - info("Found ECID %llu\n", ecid); + debug("Found ECID %llu\n", ecid); // fetch the SHSH blobs for this build identity - if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { + if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) { // this might fail if the TSS server doesn't have the saved blobs for the // update identity, so go ahead and try again with the restore identity - if (idevicerestore_erase != 1) { + if (client->flags & FLAG_ERASE > 0) { info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); - build_identity = get_build_identity(buildmanifest, 0); + build_identity = get_build_identity(client, buildmanifest, 0); if (build_identity == NULL) { error("ERROR: Unable to find restore identity\n"); plist_free(buildmanifest); return -1; } - if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { + if (get_shsh_blobs(client, ecid, build_identity, &tss) < 0) { // if this fails then no SHSH blobs have been saved for this firmware error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); plist_free(buildmanifest); @@ -270,7 +266,7 @@ int main(int argc, char* argv[]) { // Extract filesystem from IPSW and return its name char* filesystem = NULL; - if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) { + if (extract_filesystem(client, ipsw, build_identity, &filesystem) < 0) { error("ERROR: Unable to extract filesystem from IPSW\n"); if (tss) plist_free(tss); @@ -279,7 +275,7 @@ int main(int argc, char* argv[]) { } // if the device is in normal mode, place device into recovery mode - if (idevicerestore_mode == MODE_NORMAL) { + if (client->mode->index == MODE_NORMAL) { info("Entering recovery mode...\n"); if (normal_enter_recovery(uuid) < 0) { error("ERROR: Unable to place device into recovery mode\n"); @@ -291,8 +287,8 @@ int main(int argc, char* argv[]) { } // if the device is in DFU mode, place device into recovery mode - if (idevicerestore_mode == MODE_DFU) { - if (dfu_enter_recovery(ipsw, tss) < 0) { + if (client->mode->index == MODE_DFU) { + if (dfu_enter_recovery(client) < 0) { error("ERROR: Unable to place device into recovery mode\n"); plist_free(buildmanifest); if (tss) @@ -302,7 +298,7 @@ int main(int argc, char* argv[]) { } // if the device is in recovery mode, place device into restore mode - if (idevicerestore_mode == MODE_RECOVERY) { + if (client->mode->index == MODE_RECOVERY) { if (recovery_enter_restore(uuid, ipsw, tss) < 0) { error("ERROR: Unable to place device into restore mode\n"); plist_free(buildmanifest); @@ -313,16 +309,16 @@ int main(int argc, char* argv[]) { } // device is finally in restore mode, let's do this - if (idevicerestore_mode == MODE_RESTORE) { + if (client->mode->index == MODE_RESTORE) { info("Restoring device... \n"); - if (restore_device(uuid, ipsw, tss, filesystem) < 0) { + if (restore_device(client, uuid, ipsw, tss, filesystem) < 0) { error("ERROR: Unable to restore device\n"); return -1; } } // device has finished restoring, lets see if we need to activate - if (idevicerestore_mode == MODE_NORMAL) { + if (client->mode->index == MODE_NORMAL) { info("Checking activation status\n"); int activation = activate_check_status(uuid); if (activation < 0) { @@ -347,7 +343,7 @@ int main(int argc, char* argv[]) { return 0; } -int check_mode(const char* uuid) { +int check_mode(struct idevicerestore_client_t* client) { int mode = MODE_UNKNOWN; if (recovery_check_mode() == 0) { @@ -360,34 +356,35 @@ int check_mode(const char* uuid) { mode = MODE_DFU; } - else if (normal_check_mode(uuid) == 0) { + else if (normal_check_mode(client->uuid) == 0) { info("Found device in normal mode\n"); mode = MODE_NORMAL; } - else if (restore_check_mode(uuid) == 0) { + else if (restore_check_mode(client->uuid) == 0) { info("Found device in restore mode\n"); mode = MODE_RESTORE; } + client->mode = &idevicerestore_modes[mode]; return mode; } -int check_device(const char* uuid) { +int check_device(struct idevicerestore_client_t* client) { int device = DEVICE_UNKNOWN; uint32_t bdid = 0; uint32_t cpid = 0; - switch (idevicerestore_mode) { + switch (client->mode->index) { case MODE_RESTORE: - device = restore_check_device(uuid); + device = restore_check_device(client->uuid); if (device < 0) { device = DEVICE_UNKNOWN; } break; case MODE_NORMAL: - device = normal_check_device(uuid); + device = normal_check_device(client->uuid); if (device < 0) { device = DEVICE_UNKNOWN; } @@ -395,7 +392,7 @@ int check_device(const char* uuid) { case MODE_DFU: case MODE_RECOVERY: - if (get_cpid(uuid, &cpid) < 0) { + if (get_cpid(client, &cpid) < 0) { error("ERROR: Unable to get device CPID\n"); break; } @@ -404,7 +401,7 @@ int check_device(const char* uuid) { case CPID_IPHONE2G: // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID // so we need to check the BoardID - if (get_bdid(uuid, &bdid) < 0) { + if (get_bdid(client, &bdid) < 0) { error("ERROR: Unable to get device BDID\n"); break; } @@ -456,22 +453,23 @@ int check_device(const char* uuid) { } + client->device = &idevicerestore_devices[device]; return device; } -int get_bdid(const char* uuid, uint32_t* bdid) { - switch (idevicerestore_mode) { +int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_bdid(uuid, bdid) < 0) { - *bdid = -1; + if (normal_get_bdid(client->uuid, &client->device->board_id) < 0) { + client->device->board_id = -1; return -1; } break; case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_bdid(bdid) < 0) { - *bdid = -1; + if (recovery_get_bdid(&client->device->board_id) < 0) { + client->device->board_id = -1; return -1; } break; @@ -484,19 +482,19 @@ int get_bdid(const char* uuid, uint32_t* bdid) { return 0; } -int get_cpid(const char* uuid, uint32_t* cpid) { - switch (idevicerestore_mode) { +int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_cpid(uuid, cpid) < 0) { - *cpid = 0; + if (normal_get_cpid(client->uuid, &client->device->chip_id) < 0) { + client->device->chip_id = -1; return -1; } break; case MODE_DFU: case MODE_RECOVERY: - if (recovery_get_cpid(cpid) < 0) { - *cpid = 0; + if (recovery_get_cpid(&client->device->chip_id) < 0) { + client->device->chip_id = -1; return -1; } break; @@ -509,10 +507,15 @@ int get_cpid(const char* uuid, uint32_t* cpid) { return 0; } -int get_ecid(const char* uuid, uint64_t* ecid) { - switch (idevicerestore_mode) { +int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { + if(client->device->index <= DEVICE_IPOD2G) { + *ecid = 0; + return 0; + } + + switch (client->mode->index) { case MODE_NORMAL: - if (normal_get_ecid(uuid, ecid) < 0) { + if (normal_get_ecid(client->uuid, ecid) < 0) { *ecid = 0; return -1; } @@ -534,10 +537,10 @@ int get_ecid(const char* uuid, uint64_t* ecid) { return 0; } -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { +int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest) { int size = 0; char* data = NULL; - int device = idevicerestore_device->device_id; + int device = client->device->index; if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) { // Older devices that don't require personalized firmwares use BuildManifesto.plist if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) { @@ -558,7 +561,7 @@ int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { return 0; } -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { +plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity) { // fetch build identities array from BuildManifest plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { @@ -580,7 +583,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { return plist_copy(build_identity); } -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { +int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss) { plist_t request = NULL; plist_t response = NULL; *tss = NULL; @@ -603,7 +606,33 @@ int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { return 0; } -int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { +int get_build_count(plist_t buildmanifest) { + // fetch build identities array from BuildManifest + plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); + if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { + error("ERROR: Unable to find build identities node\n"); + return -1; + } + + // check and make sure this identity exists in buildmanifest + return plist_array_get_size(build_identities_array); +} + +const char* get_build_name(plist_t build_identity, int identity) { + 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 restore manifest\n"); + return NULL; + } + + plist_t filesystem_info_node = plist_dict_get_item(manifest_node, "Info"); + if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { + error("ERROR: Unable to find filesystem info node\n"); + return NULL; + } +} + +int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t build_identity, char** filesystem) { char* filename = NULL; plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); @@ -641,7 +670,7 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst return 0; } -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { img3_file* img3 = NULL; uint32_t component_size = 0; char* component_data = NULL; @@ -649,8 +678,10 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** char* component_name = NULL; component_name = strrchr(path, '/'); - if (component_name != NULL) component_name++; - else component_name = (char*) path; + if (component_name != NULL) + component_name++; + else + component_name = (char*) path; info("Extracting %s\n", component_name); if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) { @@ -672,7 +703,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** return -1; } - if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { + if (client->device->index > DEVICE_IPOD2G && (client->flags & FLAG_CUSTOM) == 0) { if (img3_replace_signature(img3, component_blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); free(component_blob); @@ -689,7 +720,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** } img3_free(img3); - if (idevicerestore_debug) { + if (client->flags & FLAG_DEBUG) { write_file(component_name, component_data, component_size); } @@ -697,66 +728,3 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** *size = component_size; return 0; } - -int write_file(const char* filename, const void* data, size_t size) { - size_t bytes = 0; - FILE* file = NULL; - - info("Writing data to %s\n", filename); - file = fopen(filename, "wb"); - if (file == NULL) { - error("read_file: Unable to open file %s\n", filename); - return -1; - } - - bytes = fwrite(data, 1, size, file); - fclose(file); - - if (bytes != size) { - error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); - return -1; - } - - return size; -} - -int read_file(const char* filename, char** data, uint32_t* size) { - size_t bytes = 0; - size_t length = 0; - FILE* file = NULL; - char* buffer = NULL; - debug("Reading data from %s\n", filename); - - *size = 0; - *data = NULL; - - file = fopen(filename, "rb"); - if (file == NULL) { - error("read_file: File %s not found\n", filename); - return -1; - } - - fseek(file, 0, SEEK_END); - length = ftell(file); - rewind(file); - - buffer = (char*) malloc(length); - if(buffer == NULL) { - error("ERROR: Out of memory\n"); - fclose(file); - return -1; - } - bytes = fread(buffer, 1, length, file); - fclose(file); - - if(bytes != length) { - error("ERROR: Unable to read entire file\n"); - free(buffer); - return -1; - } - - *size = length; - *data = buffer; - return 0; -} - diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 20578a9..7e5873b 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -22,135 +22,31 @@ #ifndef IDEVICERESTORE_H #define IDEVICERESTORE_H -#include <stdio.h> -#include <stdlib.h> -#include <plist/plist.h> - -#define info(...) printf(__VA_ARGS__) -#define error(...) fprintf(stderr, __VA_ARGS__) -#define debug(...) if(idevicerestore_debug >= 1) fprintf(stderr, __VA_ARGS__) - -#define MODE_UNKNOWN -1 -#define MODE_DFU 0 -#define MODE_RECOVERY 1 -#define MODE_RESTORE 2 -#define MODE_NORMAL 3 - -#define CPID_UNKNOWN -1 -#define CPID_IPHONE2G 8900 -#define CPID_IPOD1G 8900 -#define CPID_IPHONE3G 8900 -#define CPID_IPOD2G 8720 -#define CPID_IPHONE3GS 8920 -#define CPID_IPOD3G 8922 -#define CPID_IPAD1G 8930 - -#define BDID_UNKNOWN -1 -#define BDID_IPHONE2G 0 -#define BDID_IPOD1G 2 -#define BDID_IPHONE3G 4 -#define BDID_IPOD2G 0 -#define BDID_IPHONE3GS 0 -#define BDID_IPOD3G 2 -#define BDID_IPAD1G 2 - -#define DEVICE_UNKNOWN -1 -#define DEVICE_IPHONE2G 0 -#define DEVICE_IPOD1G 1 -#define DEVICE_IPHONE3G 2 -#define DEVICE_IPOD2G 3 -#define DEVICE_IPHONE3GS 4 -#define DEVICE_IPOD3G 5 -#define DEVICE_IPAD1G 6 - -typedef struct idevicerestore_entry { - char* name; - char* path; - char* filename; - char* blob_data; - uint32_t blob_size; - struct idevicerestore_entry* next; - struct idevicerestore_entry* prev; -} idevicerestore_entry_t; +#ifdef __cplusplus +extern "C" { +#endif -typedef struct { - int device_id; - const char* product; - const char* model; - int board_id; - int chip_id; -} idevicerestore_device_t; -/* -typedef struct { - int mode; - idevice_t device; - irecv_client_t recovery; - restored_client_t restore; - lockdownd_client_t lockdown; - int erase; // 1 - int custom; // 2 - int exclude; // 4 - int verbose; // 8 - idevicerestore_device_t* idevicerestore_device; - idevicerestore_entry_t** entries; -} idevicerestore_context_t; -*/ -static idevicerestore_device_t idevicerestore_devices[] = { - { 0, "iPhone1,1", "M68AP", 0, 8900 }, - { 1, "iPod1,1", "N45AP", 2, 8900 }, - { 2, "iPhone1,2", "N82AP", 4, 8900 }, - { 3, "iPod2,1", "N72AP", 0, 8720 }, - { 4, "iPhone2,1", "N88AP", 0, 8920 }, - { 5, "iPod3,1", "N18AP", 2, 8922 }, - { 6, "iPad1,1", "K48AP", 2, 8930 }, - { 6, "iPhone4,1", "XXXAP", 0, 0 }, - { -1, NULL, NULL, -1, -1 } -}; +#include <stdint.h> +#include <plist/plist.h> -extern int idevicerestore_mode; -extern int idevicerestore_quit; -extern int idevicerestore_debug; -extern int idevicerestore_erase; -extern int idevicerestore_custom; -extern int idevicerestore_exclude; -extern int idevicerestore_verbose; -extern idevicerestore_device_t* idevicerestore_device; -extern idevicerestore_entry_t** idevicerestore_entries; +#include <plist/plist.h> +#include "common.h" -int check_mode(const char* uuid); -int check_device(const char* uuid); void usage(int argc, char* argv[]); -int get_ecid(const char* uuid, uint64_t* ecid); -int get_bdid(const char* uuid, uint32_t* bdid); -int get_cpid(const char* uuid, uint32_t* cpid); -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest); -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity); -int write_file(const char* filename, const void* data, size_t size); -int read_file(const char* filename, char** data, uint32_t* size); -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss); -int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem); -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); - -inline static void debug_plist(plist_t plist) { - int size = 0; - char* data = NULL; - plist_to_xml(plist, &data, &size); - debug("%s", data); - free(data); -} - -inline static void print_progress_bar(const char* operation, double progress) { - int i = 0; - if(progress < 0) return; - if(progress > 100) progress = 100; - info("\r%s [", operation); - for(i = 0; i < 50; i++) { - if(i < progress / 2) info("="); - else info(" "); - } - info("] %3.1f%%", progress); - if(progress == 100) info("\n"); - fflush(stdout); +int check_mode(struct idevicerestore_client_t* client); +int check_device(struct idevicerestore_client_t* client); +const char* get_build_name(plist_t build_identity, int identity); +int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); +int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); +int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); +int extract_buildmanifest(struct idevicerestore_client_t* client, const char* ipsw, plist_t* buildmanifest); +plist_t get_build_identity(struct idevicerestore_client_t* client, plist_t buildmanifest, uint32_t identity); +int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, plist_t build_identity, plist_t* tss); +int extract_filesystem(struct idevicerestore_client_t* client, const char* ipsw, plist_t buildmanifest, char** filesystem); +int get_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size); + +#ifdef __cplusplus } +#endif #endif @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_IMG3_H #define IDEVICERESTORE_IMG3_H +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { kNorContainer = 0x696D6733, // img3 kImg3Container = 0x496D6733, // Img3 @@ -86,4 +90,9 @@ img3_file* img3_parse_file(char* data, int size); int img3_get_data(img3_file* image, char** pdata, int* psize); int img3_replace_signature(img3_file* image, char* signature); + +#ifdef __cplusplus +}s +#endif + #endif @@ -114,7 +114,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi bytes += size; progress = ((double) bytes/ (double) zstat.size) * 100.0; - print_progress_bar("Extracting", progress); + print_progress_bar(progress); } fclose(fd); @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_IPSW_H #define IDEVICERESTORE_IPSW_H +#ifdef __cplusplus +extern "C" { +#endif + #include <zip.h> #include <stdint.h> @@ -35,4 +39,8 @@ typedef struct { int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize); void ipsw_free_file(ipsw_file* file); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/normal.c b/src/normal.c index b9270d8..7ae4774 100644 --- a/src/normal.c +++ b/src/normal.c @@ -25,9 +25,49 @@ #include <libimobiledevice/lockdown.h> #include <libimobiledevice/libimobiledevice.h> +#include "common.h" #include "normal.h" -#include "recovery.h" -#include "idevicerestore.h" +//#include "recovery.h" + +int normal_client_new(struct normal_client_t** normal) { + struct normal_client_t* client = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); + if (client == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + + if (normal_open_with_timeout(client) < 0) { + normal_client_free(client); + return -1; + } + + if(normal_check_mode(client) < 0) { + normal_client_free(client); + return -1; + } + + *normal = client; + return client; +} + +void normal_client_free(struct idevicerestore_client_t* client) { + struct normal_client_t* normal = NULL; + if (client) { + normal = client->normal; + if(normal) { + if(normal->client) { + lockdownd_client_free(normal->client); + normal->client = NULL; + } + if(normal->device) { + idevice_free(normal->device); + normal->device = NULL; + } + } + free(normal); + client->normal = NULL; + } +} int normal_check_mode(const char* uuid) { char* type = NULL; @@ -106,7 +146,7 @@ int normal_check_device(const char* uuid) { } } - return idevicerestore_devices[i].device_id; + return idevicerestore_devices[i].index; } int normal_enter_recovery(const char* uuid) { @@ -162,7 +202,7 @@ int normal_enter_recovery(const char* uuid) { return -1; } - idevicerestore_mode = MODE_RECOVERY; + //client->mode = &idevicerestore_modes[MODE_RECOVERY]; irecv_close(recovery); recovery = NULL; return 0; diff --git a/src/normal.h b/src/normal.h index cdc29ba..352e643 100644 --- a/src/normal.h +++ b/src/normal.h @@ -22,7 +22,20 @@ #ifndef IDEVICERESTORE_NORMAL_H #define IDEVICERESTORE_NORMAL_H +#ifdef __cplusplus +extern "C" { +#endif + #include <stdint.h> +#include <libimobiledevice/lockdown.h> +#include <libimobiledevice/libimobiledevice.h> + +struct normal_client_t { + idevice_t device; + lockdownd_client_t client; + const char* ipsw; + plist_t tss; +}; int normal_check_mode(const char* uuid); int normal_check_device(const char* uuid); @@ -31,4 +44,8 @@ int normal_get_cpid(const char* uuid, uint32_t* cpid); int normal_get_bdid(const char* uuid, uint32_t* cpid); int normal_get_ecid(const char* uuid, uint64_t* ecid); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/recovery.c b/src/recovery.c index 88d385f..bacfac7 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -28,16 +28,51 @@ #include "tss.h" #include "img3.h" +#include "common.h" #include "recovery.h" #include "idevicerestore.h" int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { if (event->type == IRECV_PROGRESS) { - print_progress_bar(event->data, event->progress); + print_progress_bar(event->progress); } return 0; } +int recovery_client_new(struct idevicerestore_client_t* client) { + struct recovery_client_t* recovery = (struct recovery_client_t*) malloc(sizeof(struct recovery_client_t)); + if (recovery == NULL) { + error("ERROR: Out of memory\n"); + return -1; + } + + if (recovery_open_with_timeout(recovery) < 0) { + recovery_client_free(recovery); + return -1; + } + + if(recovery_check_mode(recovery) < 0) { + recovery_client_free(recovery); + return -1; + } + + client->recovery = recovery; + return 0; +} + +void recovery_client_free(struct idevicerestore_client_t* client) { + struct recovery_client_t* recovery = client->recovery; + if (recovery) { + if(recovery->client) { + irecv_close(recovery); + recovery = NULL; + } + free(recovery); + client->recovery = NULL; + + } +} + int recovery_check_mode() { irecv_client_t recovery = NULL; irecv_error_t recovery_error = IRECV_E_SUCCESS; @@ -101,11 +136,11 @@ int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) { } restore_close(device, restore); - idevicerestore_mode = MODE_RESTORE; + client->mode = &idevicerestore_modes[MODE_RESTORE]; return 0; } -int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) { +int recovery_send_signed_component(struct idevicerestore_client_t client, const char* ipsw, plist_t tss, char* component) { int size = 0; char* data = NULL; char* path = NULL; @@ -117,7 +152,7 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis return -1; } - if (get_signed_component(ipsw, tss, path, &data, &size) < 0) { + if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { error("ERROR: Unable to get signed component: %s\n", component); free(path); return -1; @@ -157,10 +192,6 @@ int recovery_open_with_timeout(irecv_client_t* client) { debug("Retrying connection...\n"); } - if (idevicerestore_debug) { - irecv_set_debug_level(idevicerestore_debug); - } - irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); *client = recovery; return 0; diff --git a/src/recovery.h b/src/recovery.h index 1953c6a..6cd467c 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -22,12 +22,24 @@ #ifndef IDEVICERESTORE_RECOVERY_H #define IDEVICERESTORE_RECOVERY_H +#ifdef __cplusplus +extern "C" { +#endif + #include <stdint.h> #include <plist/plist.h> +#include <libirecovery.h> + +struct recovery_client_t { + irecv_client_t client; + const char* ipsw; + plist_t tss; +}; int recovery_check_mode(); -int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss); -int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component); +int recovery_client_new(struct idevicerestore_client_t* client); +void recovery_client_free(struct idevicerestore_client_t* client); +int recovery_send_signed_component(struct idevicerestore_client_t* client, const char* ipsw, plist_t tss, char* component) { irecv_error_t recovery_open_with_timeout(irecv_client_t* client); int recovery_send_ibec(const char* ipsw, plist_t tss); int recovery_send_applelogo(const char* ipsw, plist_t tss); @@ -38,4 +50,8 @@ int recovery_get_ecid(uint64_t* ecid); int recovery_get_cpid(uint32_t* cpid); int recovery_get_bdid(uint32_t* bdid); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/restore.c b/src/restore.c index fa2ccdd..b4cf0b2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -26,8 +26,8 @@ #include "asr.h" #include "tss.h" +#include "common.h" #include "restore.h" -#include "idevicerestore.h" #define CREATE_PARTITION_MAP 12 #define CREATE_FILESYSTEM 13 @@ -46,6 +46,39 @@ static int restore_device_connected = 0; +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"); + return -1; + } + + if (restore_open_with_timeout(client) < 0) { + restore_client_free(client); + return -1; + } + + client->restore = restore; + return 0; +} + +void restore_client_free(struct idevicerestore_client_t* client) { + if (client) { + if(client->restore) { + if(client->restore->client) { + restored_client_free(client->restore->client); + client->restore->client = NULL; + } + if(client->restore->device) { + idevice_free(client->restore->device); + client->restore->device = NULL; + } + free(client->restore); + client->restore = NULL; + } + } +} + int restore_check_mode(const char* uuid) { char* type = NULL; uint64_t version = 0; @@ -135,51 +168,61 @@ int restore_check_device(const char* uuid) { } } - return idevicerestore_devices[i].device_id; + return idevicerestore_devices[i].index; } -void restore_device_callback(const idevice_event_t* event, void* user_data) { +void restore_device_callback(const idevice_event_t* event, void* userdata) { + struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata; if (event->event == IDEVICE_DEVICE_ADD) { restore_device_connected = 1; } else if (event->event == IDEVICE_DEVICE_REMOVE) { restore_device_connected = 0; - idevicerestore_quit = 1; + client->flags &= FLAG_QUIT; } } -int restore_reboot(const char* uuid) { +int restore_reboot(struct idevicerestore_client_t* client) { idevice_t device = NULL; restored_client_t restore = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { - error("ERROR: Unable to open device in restore mode\n"); - return -1; + if(!client->restore) { + if (restore_open_with_timeout(client) < 0) { + error("ERROR: Unable to open device in restore mode\n"); + return -1; + } } - restore_error = restored_reboot(restore); + restore_error = restored_reboot(client); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to reboot the device from restore mode\n"); - restore_close(device, restore); return -1; } - restore_close(device, restore); - restore = NULL; - device = NULL; return 0; } -int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) { +int restore_open_with_timeout(struct idevicerestore_client_t* client) { int i = 0; int attempts = 10; - idevice_t context = NULL; - restored_client_t client = NULL; + idevice_t device = NULL; + restored_client_t restored = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; restored_error_t restore_error = RESTORE_E_SUCCESS; - *device = NULL; - *restore = NULL; + // no context exists so bail + if(client == NULL) { + return -1; + } + + // create our restore client if it doesn't yet exist + 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"); + return -1; + } + } device_error = idevice_event_subscribe(&restore_device_callback, NULL); if (device_error != IDEVICE_E_SUCCESS) { @@ -194,43 +237,37 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie if (i == attempts) { error("ERROR: Unable to connect to device in restore mode\n"); + return -1; } sleep(2); } - device_error = idevice_new(&context, uuid); + device_error = idevice_new(&device, client->uuid); if (device_error != IDEVICE_E_SUCCESS) { return -1; } - restore_error = restored_client_new(context, &client, "idevicerestore"); + restore_error = restored_client_new(device, &restored, "idevicerestore"); if (restore_error != RESTORE_E_SUCCESS) { - idevice_event_unsubscribe(); - idevice_free(context); + //idevice_event_unsubscribe(); + idevice_free(device); return -1; } - restore_error = restored_query_type(client, NULL, NULL); + restore_error = restored_query_type(restored, NULL, NULL); if (restore_error != RESTORE_E_SUCCESS) { - restored_client_free(client); - idevice_event_unsubscribe(); - idevice_free(context); + restored_client_free(restored); + //idevice_event_unsubscribe(); + idevice_free(device); return -1; } - *device = context; - *restore = client; + client->restore->device = device; + client->restore->client = restored; return 0; } -void restore_close(idevice_t device, restored_client_t restore) { - if (restore) - restored_client_free(restore); - if (device) - idevice_free(device); -} - const char* restore_progress_string(unsigned int operation) { switch (operation) { case CREATE_PARTITION_MAP: @@ -300,7 +337,7 @@ int restore_handle_progress_msg(restored_client_t client, plist_t msg) { plist_get_uint_val(node, &progress); if ((progress > 0) && (progress < 100)) { - print_progress_bar(restore_progress_string(operation), (double) progress); + print_progress_bar((double) progress); } else { info("%s\n", restore_progress_string(operation)); @@ -361,16 +398,32 @@ int restore_send_filesystem(idevice_t device, const char* filesystem) { return 0; } -int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) { +int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss) { + int size = 0; + char* data = NULL; + char* path = NULL; + plist_t blob = NULL; + plist_t dict = NULL; + restored_error_t restore_error = RESTORE_E_SUCCESS; + info("Sending kernelcache\n"); + if (tss_get_entry_path(tss, "KernelCache", &path) < 0) { + error("ERROR: Unable to find kernelcache path\n"); + return -1; + } - plist_t kernelcache_node = plist_new_data(kernel_data, len); + if (get_signed_component(client, ipsw, tss, path, &data, &size) < 0) { + error("ERROR: Unable to get kernelcache file\n"); + return -1; + } - plist_t dict = plist_new_dict(); - plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node); - restored_error_t ret = restored_send(client, dict); - if (ret != RESTORE_E_SUCCESS) { + dict = plist_new_dict(); + blob = plist_new_data(data, size); + plist_dict_insert_item(dict, "KernelCacheFile", blob); + + restore_error = restored_send(client, dict); + if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); return -1; @@ -378,52 +431,61 @@ int restore_send_kernelcache(restored_client_t client, char* kernel_data, int le info("Done sending kernelcache\n"); plist_free(dict); + free(data); return 0; } int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { char* llb_path = NULL; + char* llb_filename = NULL; + char firmware_path[256]; + char manifest_file[256]; + int manifest_size = 0; + char* manifest_data = NULL; + char firmware_filename[256]; + int llb_size = 0; + char* llb_data = NULL; + plist_t dict = NULL; + char* filename = NULL; + int nor_size = 0; + char* nor_data = NULL; + plist_t norimage_array = NULL; + restored_error_t ret = RESTORE_E_SUCCESS; + if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) { error("ERROR: Unable to get LLB info from TSS response\n"); return -1; } - char* llb_filename = strstr(llb_path, "LLB"); + llb_filename = strstr(llb_path, "LLB"); if (llb_filename == NULL) { error("ERROR: Unable to extract firmware path from LLB filename\n"); free(llb_path); return -1; } - char firmware_path[256]; memset(firmware_path, '\0', sizeof(firmware_path)); memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path); info("Found firmware path %s\n", firmware_path); - char manifest_file[256]; memset(manifest_file, '\0', sizeof(manifest_file)); snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path); info("Getting firmware manifest %s\n", manifest_file); - int manifest_size = 0; - char* manifest_data = NULL; if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) { error("ERROR: Unable to extract firmware manifest from ipsw\n"); free(llb_path); return -1; } - char firmware_filename[256]; memset(firmware_filename, '\0', sizeof(firmware_filename)); - int llb_size = 0; - char* llb_data = NULL; - plist_t dict = plist_new_dict(); - char* filename = strtok(manifest_data, "\n"); + dict = plist_new_dict(); + filename = strtok(manifest_data, "\n"); if (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { + if (get_signed_component(client, ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) { error("ERROR: Unable to get signed LLB\n"); return -1; } @@ -431,14 +493,12 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size)); } - int nor_size = 0; - char* nor_data = NULL; filename = strtok(NULL, "\n"); - plist_t norimage_array = plist_new_array(); + norimage_array = plist_new_array(); while (filename != NULL) { memset(firmware_filename, '\0', sizeof(firmware_filename)); snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename); - if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { + if (get_signed_component(client, ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) { error("ERROR: Unable to get signed firmware %s\n", firmware_filename); break; } @@ -453,7 +513,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { debug_plist(dict); - restored_error_t ret = restored_send(client, dict); + ret = restored_send(client, dict); if (ret != RESTORE_E_SUCCESS) { error("ERROR: Unable to send kernelcache data\n"); plist_free(dict); @@ -464,7 +524,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) { return 0; } -int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) { char* type = NULL; plist_t node = NULL; @@ -476,44 +536,39 @@ int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - restore_send_filesystem(device, filesystem); - - } - - else if (!strcmp(type, "KernelCache")) { - int kernelcache_size = 0; - char* kernelcache_data = NULL; - char* kernelcache_path = NULL; - if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) { - error("ERROR: Unable to find kernelcache path\n"); + if(restore_send_filesystem(device, filesystem) < 0) { + error("ERROR: Unable to send filesystem\n"); return -1; } + } - if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) { - error("ERROR: Unable to get kernelcache file\n"); + else if (!strcmp(type, "KernelCache")) { + if(restore_send_kernelcache(restore, ipsw, tss) < 0) { + error("ERROR: Unable to send kernelcache\n"); return -1; } - restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); - free(kernelcache_data); - } else if (!strcmp(type, "NORData")) { - if(!idevicerestore_exclude) { - restore_send_nor(restore, ipsw, tss); + if(client->flags & FLAG_EXCLUDE > 0) { + if(restore_send_nor(restore, ipsw, tss) < 0) { + error("ERROR: Unable to send NOR data\n"); + return -1; + } } else { - idevicerestore_quit = 1; + client->flags &= 1; } } else { // Unknown DataType!! debug("Unknown data request received\n"); + debug_plist(message); } } return 0; } -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { +int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) { int error = 0; char* type = NULL; char* kernel = NULL; @@ -525,7 +580,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* restored_error_t restore_error = RESTORE_E_SUCCESS; // open our connection to the device and verify we're in restore mode - if (restore_open_with_timeout(uuid, &device, &restore) < 0) { + if (restore_open_with_timeout(client) < 0) { error("ERROR: Unable to open device in restore mode\n"); return -1; } @@ -541,7 +596,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // this is the restore process loop, it reads each message in from // restored and passes that data on to it's specific handler - while (!idevicerestore_quit) { + while ((client->flags & FLAG_QUIT) == 0) { restore_error = restored_receive(restore, &message); if (restore_error != RESTORE_E_SUCCESS) { debug("No data to read\n"); @@ -564,7 +619,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // files sent to the server by the client. these data requests include // SystemImageData, KernelCache, and NORData requests if (!strcmp(type, "DataRequestMsg")) { - error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem); + error = restore_handle_data_request_msg(client, device, restore, message, tss, ipsw, filesystem); } // progress notification messages sent by the restored inform the client @@ -590,7 +645,7 @@ int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* // an unrecoverable error, so we need to bail. if (error < 0) { error("ERROR: Unable to successfully restore device\n"); - idevicerestore_quit = 1; + client->flags &= FLAG_QUIT; } plist_free(message); diff --git a/src/restore.h b/src/restore.h index cf9cf51..5446aa8 100644 --- a/src/restore.h +++ b/src/restore.h @@ -1,4 +1,4 @@ -/* + /* * restore.h * Functions for handling idevices in restore mode * @@ -22,21 +22,41 @@ #ifndef IDEVICERESTORE_RESTORE_H #define IDEVICERESTORE_RESTORE_H +#ifdef __cplusplus +extern "C" { +#endif + #include <plist/plist.h> #include <libimobiledevice/restore.h> #include <libimobiledevice/libimobiledevice.h> -int restore_reboot(const char* uuid); +struct restore_client_t { + plist_t tss; + idevice_t device; + const char* uuid; + unsigned int operation; + const char* filesystem; + restored_client_t client; +}; + int restore_check_mode(const char* uuid); int restore_check_device(const char* uuid); +int restore_client_new(struct idevicerestore_client_t* client); +void restore_client_free(struct idevicerestore_client_t* client); +int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); -void restore_close(idevice_t device, restored_client_t restore); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(restored_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 tss, const char* ipsw, const char* filesystem); int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss); -int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len); -int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); -int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client); +int restore_send_kernelcache(restored_client_t client, const char* ipsw, plist_t tss); +int restore_device(struct idevicerestore_client_t* client, const char* uuid, const char* ipsw, plist_t tss, const char* filesystem); +int restore_open_with_timeout(struct idevicerestore_client_t* client); int restore_send_filesystem(idevice_t device, const char* filesystem); + +#ifdef __cplusplus +} +#endif + #endif @@ -22,6 +22,10 @@ #ifndef IDEVICERESTORE_TSS_H #define IDEVICERESTORE_TSS_H +#ifdef __cplusplus +extern "C" { +#endif + #include <plist/plist.h> plist_t tss_send_request(plist_t request); @@ -30,4 +34,9 @@ int tss_get_entry_path(plist_t tss, const char* entry, char** path); int tss_get_blob_by_path(plist_t tss, const char* path, char** blob); int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob); + +#ifdef __cplusplus +} +#endif + #endif |