summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-05-24 18:57:15 -0400
committerGravatar Joshua Hill2010-05-24 18:57:15 -0400
commit9457cfd1b496e1e5ba48d1b387a040e9402ed80b (patch)
tree90920ef9c211bf4129bc6e58c0de48d7f79fc7c4 /src
parent78ddd2649b9303d33ab1c52b4f0f559a374d20c9 (diff)
downloadidevicerestore-9457cfd1b496e1e5ba48d1b387a040e9402ed80b.tar.gz
idevicerestore-9457cfd1b496e1e5ba48d1b387a040e9402ed80b.tar.bz2
Merged the current POC with this codebase, it /should/ work but it's not.
Seems like libirecovery isn't properly releasing the usb interface for some reason which is making usbmuxd choe trying to set the usb configuration
Diffstat (limited to 'src')
-rw-r--r--src/idevicerestore.c394
1 files changed, 385 insertions, 9 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 7e9a03d..d6551a4 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <plist/plist.h>
#include <libirecovery.h>
+#include <libimobiledevice/restore.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/libimobiledevice.h>
@@ -34,10 +35,14 @@
#include "idevicerestore.h"
#define UNKNOWN_MODE 0
-#define RECOVERY_MODE 1
-#define NORMAL_MODE 2
+#define NORMAL_MODE 1
+#define RECOVERY_MODE 2
+#define RESTORE_MODE 3
+
+#define ASR_PORT 12345
int idevicerestore_debug = 0;
+static int idevicerestore_mode = 0;
void usage(int argc, char* argv[]);
int write_file(const char* filename, char* data, int size);
@@ -47,10 +52,10 @@ int send_devicetree(char* ipsw, plist_t tss);
int send_ramdisk(char* ipsw, plist_t tss);
int send_kernelcache(char* ipsw, plist_t tss);
int get_tss_data(plist_t tss, const char* entry, char** path, char** blob);
+void device_callback(const idevice_event_t* event, void *user_data);
int main(int argc, char* argv[]) {
int opt = 0;
- int mode = 0;
char* ipsw = NULL;
char* uuid = NULL;
uint64_t ecid = 0;
@@ -104,14 +109,14 @@ int main(int argc, char* argv[]) {
return -1;
}
info("Found device in recovery mode\n");
- mode = RECOVERY_MODE;
+ idevicerestore_mode = RECOVERY_MODE;
} else {
info("Found device in normal mode\n");
- mode = NORMAL_MODE;
+ idevicerestore_mode = NORMAL_MODE;
}
- if (mode == NORMAL_MODE) {
+ if (idevicerestore_mode == NORMAL_MODE) {
lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
if (lockdown_error != LOCKDOWN_E_SUCCESS) {
error("ERROR: Unable to connect to lockdownd\n");
@@ -140,7 +145,8 @@ int main(int argc, char* argv[]) {
idevice_free(device);
lockdown = NULL;
device = NULL;
- } else if (mode == RECOVERY_MODE) {
+
+ } else if (idevicerestore_mode == RECOVERY_MODE) {
recovery_error = irecv_get_ecid(recovery, &ecid);
if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to get device ECID\n");
@@ -185,10 +191,34 @@ int main(int argc, char* argv[]) {
plist_free(tss_request);
return -1;
}
- plist_free(tss_request);
info("Got TSS response\n");
- if (mode == NORMAL_MODE) {
+ // Get name of filesystem DMG in IPSW
+ char* filesystem = NULL;
+ plist_t filesystem_node = plist_dict_get_item(tss_request, "OS");
+ if(!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) {
+ error("ERROR: Unable to find OS filesystem\n");
+ plist_free(tss_request);
+ return -1;
+ }
+
+ plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info");
+ if(!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) {
+ error("ERROR: Unable to find filesystem info node\n");
+ plist_free(tss_request);
+ return -1;
+ }
+
+ plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path");
+ if(!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) {
+ error("ERROR: Unable to find filesystem info path node\n");
+ plist_free(tss_request);
+ return -1;
+ }
+ plist_get_string_val(filesystem_info_path_node, &filesystem);
+ plist_free(tss_request);
+
+ if (idevicerestore_mode == NORMAL_MODE) {
// Place the device in recovery mode
info("Entering recovery mode...\n");
device_error = idevice_new(&device, uuid);
@@ -256,10 +286,107 @@ int main(int argc, char* argv[]) {
return -1;
}
+ idevice_event_subscribe(&device_callback, NULL);
+ info("Waiting for device to enter restore mode\n");
+ while(idevicerestore_mode != RESTORE_MODE) sleep(1);
+ device_error = idevice_new(&device, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to open device\n");
+ plist_free(tss_response);
+ return -1;
+ }
+
+ restored_client_t restore = NULL;
+ restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore");
+ if(restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to start restored client\n");
+ plist_free(tss_response);
+ idevice_free(device);
+ return -1;
+ }
+
+ char* type = NULL;
+ uint64_t version = 0;
+ if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) {
+ printf("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type);
+ plist_free(tss_response);
+ restored_client_free(restore);
+ idevice_free(device);
+ return -1;
+ }
+ info("Device has successfully entered restore mode\n");
+
+ /* start restored service and retrieve port */
+ int quit_flag = 0;
+ char* kernelcache = NULL;
+ printf("Restore protocol version is %llu.\n", version);
+ restore_error = restored_start_restore(restore);
+ if (restore_error == RESTORE_E_SUCCESS) {
+ while (!quit_flag) {
+ plist_t message = NULL;
+ restore_error = restored_receive(restore, &message);
+ plist_t msgtype_node = plist_dict_get_item(message, "MsgType");
+ if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) {
+ char *msgtype = NULL;
+ plist_get_string_val(msgtype_node, &msgtype);
+ if(!strcmp(msgtype, "ProgressMsg")) {
+ restore_error = progress_msg(restore, message);
+
+ }
+ else if(!strcmp(msgtype, "DataRequestMsg")) {
+ //restore_error = data_request_msg(device, restore, message, filesystem);
+ plist_t datatype_node = plist_dict_get_item(message, "DataType");
+ if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
+ char *datatype = NULL;
+ plist_get_string_val(datatype_node, &datatype);
+ if(!strcmp(datatype, "SystemImageData")) {
+ send_system_data(device, restore, filesystem);
+ }
+ else if(!strcmp(datatype, "KernelCache")) {
+ send_kernel_data(device, restore, kernelcache);
+ }
+ else if(!strcmp(datatype, "NORData")) {
+ send_nor_data(device, restore);
+ }
+ else {
+ // Unknown DataType!!
+ error("Unknown DataType\n");
+ return -1;
+ }
+ }
+
+ }
+ else if(!strcmp(msgtype, "StatusMsg")) {
+ restore_error = status_msg(restore, message);
+
+ }
+ else {
+ printf("Received unknown message type: %s\n", msgtype);
+ }
+ }
+
+ if (RESTORE_E_SUCCESS != restore_error) {
+ printf("Invalid return status %d\n", restore_error);
+ }
+
+ plist_free(message);
+ }
+ } else {
+ printf("ERROR: Could not start restore. %d\n", restore_error);
+ }
+
+ restored_client_free(restore);
+ idevice_free(device);
plist_free(tss_response);
return 0;
}
+void device_callback(const idevice_event_t* event, void *user_data) {
+ if(event->event == IDEVICE_DEVICE_ADD) {
+ idevicerestore_mode = RESTORE_MODE;
+ }
+}
+
void usage(int argc, char* argv[]) {
char *name = strrchr(argv[0], '/');
printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0]));
@@ -274,6 +401,255 @@ void usage(int argc, char* argv[]) {
exit(1);
}
+int progress_msg(restored_client_t client, plist_t msg) {
+ info("Got progress message\n");
+ return 0;
+}
+
+int data_request_msg(idevice_t device, restored_client_t client, plist_t msg, const char *filesystem, const char *kernel) {
+ plist_t datatype_node = plist_dict_get_item(msg, "DataType");
+ if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
+ char *datatype = NULL;
+ plist_get_string_val(datatype_node, &datatype);
+ if(!strcmp(datatype, "SystemImageData")) {
+ send_system_data(device, client, filesystem);
+ }
+ else if(!strcmp(datatype, "KernelCache")) {
+ send_kernel_data(device, client, kernel);
+ }
+ else if(!strcmp(datatype, "NORData")) {
+ send_nor_data(device, client);
+ }
+ else {
+ // Unknown DataType!!
+ error("Unknown DataType\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int status_msg(restored_client_t client, plist_t msg) {
+ info("Got status message\n");
+ return 0;
+}
+
+int send_system_data(idevice_t device, restored_client_t client, const char *filesystem) {
+ int i = 0;
+ char buffer[0x1000];
+ uint32_t recv_bytes = 0;
+ memset(buffer, '\0', 0x1000);
+ idevice_connection_t connection = NULL;
+ idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
+
+ for(i = 0; i < 5; i++) {
+ ret = idevice_connect(device, ASR_PORT, &connection);
+ if(ret == IDEVICE_E_SUCCESS)
+ break;
+
+ else
+ sleep(1);
+ }
+
+ if(ret != IDEVICE_E_SUCCESS)
+ return ret;
+
+ memset(buffer, '\0', 0x1000);
+ ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
+ if(ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+ printf("Received %d bytes\n", recv_bytes);
+ printf("%s", buffer);
+
+ FILE* fd = fopen(filesystem, "rb");
+ if(fd == NULL) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+
+ fseek(fd, 0, SEEK_END);
+ uint64_t len = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+
+ printf("Connected to ASR\n");
+ plist_t dict = plist_new_dict();
+ plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40));
+ plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450));
+ plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25));
+
+ plist_t payload = plist_new_dict();
+ plist_dict_insert_item(payload, "Port", plist_new_uint(1));
+ plist_dict_insert_item(payload, "Size", plist_new_uint(len));
+ plist_dict_insert_item(dict, "Payload", payload);
+
+ plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1));
+ plist_dict_insert_item(dict, "Version", plist_new_uint(1));
+
+ char* xml = NULL;
+ unsigned int dict_size = 0;
+ unsigned int sent_bytes = 0;
+ plist_to_xml(dict, &xml, &dict_size);
+
+ ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes);
+ if(ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+
+ printf("Sent %d bytes\n", sent_bytes);
+ printf("%s", xml);
+ plist_free(dict);
+ free(xml);
+
+ char* command = NULL;
+ do {
+ memset(buffer, '\0', 0x1000);
+ ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
+ if(ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+ info("Received %d bytes\n", recv_bytes);
+ info("%s", buffer);
+
+ plist_t request = NULL;
+ plist_from_xml(buffer, recv_bytes, &request);
+ plist_t command_node = plist_dict_get_item(request, "Command");
+ if (command_node && PLIST_STRING == plist_get_node_type(command_node)) {
+ plist_get_string_val(command_node, &command);
+ if(!strcmp(command, "OOBData")) {
+ plist_t oob_length_node = plist_dict_get_item(request, "OOB Length");
+ if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
+ printf("Error fetching OOB Length\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ uint64_t oob_length = 0;
+ plist_get_uint_val(oob_length_node, &oob_length);
+
+ plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset");
+ if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
+ error("Error fetching OOB Offset\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ uint64_t oob_offset = 0;
+ plist_get_uint_val(oob_offset_node, &oob_offset);
+
+ char* oob_data = (char*) malloc(oob_length);
+ if(oob_data == NULL) {
+ error("Out of memory\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+
+ fseek(fd, oob_offset, SEEK_SET);
+ if(fread(oob_data, 1, oob_length, fd) != oob_length) {
+ error("Unable to read filesystem offset\n");
+ idevice_disconnect(connection);
+ free(oob_data);
+ return ret;
+ }
+
+ ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes);
+ if(sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) {
+ printf("Unable to send %d bytes to asr\n", sent_bytes);
+ idevice_disconnect(connection);
+ free(oob_data);
+ return ret;
+ }
+ plist_free(request);
+ free(oob_data);
+ }
+ }
+
+ } while(strcmp(command, "Payload"));
+
+ fseek(fd, 0, SEEK_SET);
+ char data[1450];
+ for(i = len; i > 0; i -= 1450) {
+ int size = 1450;
+ if(i < 1450) {
+ size = i;
+ }
+
+ if(fread(data, 1, size, fd) != (unsigned int)size) {
+ fclose(fd);
+ idevice_disconnect(connection);
+ printf("Error reading filesystem\n");
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+
+ ret = idevice_connection_send(connection, data, size, &sent_bytes);
+ if(ret != IDEVICE_E_SUCCESS) {
+ fclose(fd);
+ }
+
+ if(i % (1450*1000) == 0) {
+ printf(".");
+ }
+ }
+
+ printf("Done sending filesystem\n");
+ fclose(fd);
+ ret = idevice_disconnect(connection);
+ return ret;
+}
+
+int send_kernel_data(idevice_t device, restored_client_t client, const char *kernel) {
+ printf("Sending kernelcache\n");
+ FILE* fd = fopen(kernel, "rb");
+ if(fd == NULL) {
+ info("Unable to open kernelcache");
+ return -1;
+ }
+
+ fseek(fd, 0, SEEK_END);
+ uint64_t len = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+
+ char* kernel_data = (char*) malloc(len);
+ if(kernel_data == NULL) {
+ error("Unable to allocate memory for kernel data");
+ fclose(fd);
+ return -1;
+ }
+
+ if(fread(kernel_data, 1, len, fd) != len) {
+ error("Unable to read kernel data\n");
+ free(kernel_data);
+ fclose(fd);
+ return -1;
+ }
+ fclose(fd);
+
+ plist_t kernelcache_node = plist_new_data(kernel_data, len);
+
+ 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) {
+ error("Unable to send kernelcache data\n");
+ free(kernel_data);
+ plist_free(dict);
+ return -1;
+ }
+
+ info("Done sending kernelcache\n");
+ free(kernel_data);
+ plist_free(dict);
+ return 0;
+}
+
+
+int send_nor_data(idevice_t device, restored_client_t client) {
+ info("Not implemented\n");
+ return 0;
+}
+
int write_file(const char* filename, char* data, int size) {
debug("Writing data to %s\n", filename);
FILE* file = fopen(filename, "wb");