diff options
-rw-r--r-- | TODO | 4 | ||||
-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 |
20 files changed, 839 insertions, 419 deletions
@@ -11,7 +11,7 @@ o) Writing restore logs to an external file for debugging would be a great help. o) Need to change some info progresses to only display the component name rather then the full path which can be messy. o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. o) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. -o) Clean up restore_send_kernelcache -o) Clean up restore_send_nor +o) Clean up refactor restore_send_kernelcache() +o) Clean up and refactor restore_send_nor() o) Finishing cleaning up asr_perform_validation o) Double check to make sure asr_send_payload looks clean
\ No newline at end of file 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 |