summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2012-02-05 22:38:10 +0100
committerGravatar Nikias Bassen2012-02-05 22:38:10 +0100
commit99158d9fd32a4a7961bea09e78ab249c2c3752c9 (patch)
tree81984f39997b22a6cc9f92896452b38a3f786aa0 /src
parent38d2408e87fe026df316067766ad5328d4284390 (diff)
downloadidevicerestore-99158d9fd32a4a7961bea09e78ab249c2c3752c9.tar.gz
idevicerestore-99158d9fd32a4a7961bea09e78ab249c2c3752c9.tar.bz2
add support for 0x1222 wtf mode
Diffstat (limited to 'src')
-rw-r--r--src/common.h18
-rw-r--r--src/dfu.c45
-rw-r--r--src/dfu.h5
-rw-r--r--src/idevicerestore.c74
-rw-r--r--src/libirecovery.c33
-rw-r--r--src/libirecovery.h1
-rw-r--r--src/recovery.c2
7 files changed, 159 insertions, 19 deletions
diff --git a/src/common.h b/src/common.h
index 19ce881..6e1441a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -84,10 +84,11 @@ extern "C" {
#define DEVICE_IPHONE4S 14
#define MODE_UNKNOWN -1
-#define MODE_DFU 0
-#define MODE_RECOVERY 1
-#define MODE_RESTORE 2
-#define MODE_NORMAL 3
+#define MODE_WTF 0
+#define MODE_DFU 1
+#define MODE_RECOVERY 2
+#define MODE_RESTORE 3
+#define MODE_NORMAL 4
#define FLAG_QUIT 1
#define FLAG_DEBUG 2
@@ -149,10 +150,11 @@ struct idevicerestore_client_t {
};
static struct idevicerestore_mode_t idevicerestore_modes[] = {
- { 0, "DFU" },
- { 1, "Recovery" },
- { 2, "Restore" },
- { 3, "Normal" },
+ { 0, "WTF" },
+ { 1, "DFU" },
+ { 2, "Recovery" },
+ { 3, "Restore" },
+ { 4, "Normal" },
{ -1, NULL }
};
diff --git a/src/dfu.c b/src/dfu.c
index b044fa6..3e88a1d 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -83,7 +83,7 @@ void dfu_client_free(struct idevicerestore_client_t* client) {
}
}
-int dfu_check_mode() {
+int dfu_check_mode(int* mode) {
irecv_client_t dfu = NULL;
irecv_error_t dfu_error = IRECV_E_SUCCESS;
@@ -94,16 +94,40 @@ int dfu_check_mode() {
return -1;
}
- if (dfu->mode != kDfuMode) {
+ if ((dfu->mode != kDfuMode) && (dfu->mode != kWTFMode)) {
irecv_close(dfu);
return -1;
}
+ *mode = (dfu->mode == kWTFMode) ? MODE_WTF : MODE_DFU;
+
irecv_close(dfu);
return 0;
}
+int dfu_send_buffer(struct idevicerestore_client_t* client, char* buffer, uint32_t size)
+{
+ irecv_error_t error = 0;
+
+ info("Sending data (%d bytes)...\n", size);
+
+ error = irecv_send_buffer(client->dfu->client, buffer, size, 1);
+ if (error != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to send data: %s\n", irecv_strerror(error));
+ return -1;
+ }
+
+ error = irecv_reset(client->dfu->client);
+ if (error != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to reset device\n");
+ irecv_close(client->dfu->client);
+ return -1;
+ }
+
+ return 0;
+}
+
int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) {
uint32_t size = 0;
char* data = NULL;
@@ -170,6 +194,23 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
return 0;
}
+int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) {
+ irecv_error_t dfu_error = IRECV_E_SUCCESS;
+
+ if(client->dfu == NULL) {
+ if (dfu_client_new(client) < 0) {
+ return -1;
+ }
+ }
+
+ dfu_error = irecv_get_cpid(client->dfu->client, cpid);
+ if (dfu_error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ return 0;
+}
+
int dfu_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) {
irecv_error_t dfu_error = IRECV_E_SUCCESS;
diff --git a/src/dfu.h b/src/dfu.h
index 34447bf..7351013 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -37,6 +37,11 @@ struct dfu_client_t {
int dfu_client_new(struct idevicerestore_client_t* client);
void dfu_client_free(struct idevicerestore_client_t* client);
+int dfu_check_mode(int* mode);
+int dfu_send_buffer(struct idevicerestore_client_t* client, char* buffer, uint32_t size);
+int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);
+int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid);
+int dfu_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size);
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity);
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 93c6766..4efc0d4 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -217,6 +217,75 @@ int main(int argc, char* argv[]) {
}
info("Found device in %s mode\n", client->mode->string);
+ if (client->mode->index == MODE_WTF) {
+ int cpid = 0;
+
+ if (dfu_client_new(client) != 0) {
+ error("ERROR: Could not open device in WTF mode\n");
+ return -1;
+ }
+ if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) {
+ error("ERROR: Could not get CPID for WTF mode device\n");
+ dfu_client_free(client);
+ return -1;
+ }
+
+ char* s_wtfurl = NULL;
+ plist_t wtfurl = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", "5", "RecoverySoftwareVersions", "WTF", "304218112", "5", "FirmwareURL");
+ if (wtfurl && (plist_get_node_type(wtfurl) == PLIST_STRING)) {
+ plist_get_string_val(wtfurl, &s_wtfurl);
+ }
+ if (!s_wtfurl) {
+ info("Using hardcoded x12220000_5_Recovery.ipsw URL\n");
+ s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw");
+ }
+
+ // make a local file name
+ char* fnpart = strrchr(s_wtfurl, '/');
+ if (!fnpart) {
+ fnpart = "x12220000_5_Recovery.ipsw";
+ } else {
+ fnpart++;
+ }
+ struct stat fst;
+ char wtfipsw[256];
+ sprintf(wtfipsw, "cache/%s", fnpart);
+ if (stat(wtfipsw, &fst) != 0) {
+ __mkdir("cache", 0755);
+ download_to_file(s_wtfurl, wtfipsw);
+ }
+
+ char wtfname[256];
+ sprintf(wtfname, "Firmware/dfu/WTF.s5l%04dxall.RELEASE.dfu", cpid);
+ char* wtftmp = NULL;
+ uint32_t wtfsize = 0;
+ ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize);
+ if (!wtftmp) {
+ error("ERROR: Could not extract WTF\n");
+ }
+
+ char xbuf[16] = {0xff, 0xff, 0xff, 0xff, 0xac, 0x05, 0x00, 0x01, 0x55, 0x46, 0x44, 0x10, 0xcb, 0x55, 0xa4, 0x05};
+ char *wtfbuf = (char*)malloc(wtfsize + 16);
+ if (!wtfbuf) {
+ error("ERROR: Out of Memory\n");
+ return -1;
+ }
+ memcpy(wtfbuf, wtftmp, wtfsize);
+ free(wtftmp);
+ memcpy(wtfbuf+wtfsize, xbuf, 16);
+ wtfsize += 16;
+
+ if (dfu_send_buffer(client, wtfbuf, wtfsize) != 0) {
+ error("ERROR: Could not send WTF...\n");
+ }
+ dfu_client_free(client);
+
+ sleep(1);
+
+ free(wtfbuf);
+ client->mode = &idevicerestore_modes[MODE_DFU];
+ }
+
// discover the device type
if (check_device(client) < 0 || client->device->index == DEVICE_UNKNOWN) {
error("ERROR: Unable to discover device type\n");
@@ -657,13 +726,14 @@ int main(int argc, char* argv[]) {
int check_mode(struct idevicerestore_client_t* client) {
int mode = MODE_UNKNOWN;
+ int dfumode = MODE_UNKNOWN;
if (recovery_check_mode() == 0) {
mode = MODE_RECOVERY;
}
- else if (dfu_check_mode() == 0) {
- mode = MODE_DFU;
+ else if (dfu_check_mode(&dfumode) == 0) {
+ mode = dfumode;
}
else if (normal_check_mode(client->uuid) == 0) {
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 45efa85..7160669 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -338,6 +338,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
usb_descriptor.idProduct == kRecoveryMode2 ||
usb_descriptor.idProduct == kRecoveryMode3 ||
usb_descriptor.idProduct == kRecoveryMode4 ||
+ usb_descriptor.idProduct == kWTFMode ||
usb_descriptor.idProduct == kDfuMode) {
debug("opening device %04x:%04x...\n", usb_descriptor.idVendor, usb_descriptor.idProduct);
@@ -369,7 +370,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
return error;
}
- if (client->mode != kDfuMode) {
+ if ((client->mode != kDfuMode) && (client->mode != kWTFMode)) {
error = irecv_set_interface(client, 0, 0);
if (client->mode > kRecoveryMode2) {
error = irecv_set_interface(client, 1, 1);
@@ -549,7 +550,7 @@ irecv_error_t irecv_close(irecv_client_t client) {
}
#ifndef WIN32
if (client->handle != NULL) {
- if (client->mode != kDfuMode) {
+ if ((client->mode != kDfuMode) && (client->mode != kWTFMode)) {
libusb_release_interface(client->handle, client->interface);
}
libusb_close(client->handle);
@@ -683,7 +684,7 @@ irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) {
irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfuNotifyFinished) {
irecv_error_t error = 0;
- int recovery_mode = (client->mode != kDfuMode);
+ int recovery_mode = ((client->mode != kDfuMode) && (client->mode != kWTFMode));
if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;
int packet_size = recovery_mode ? 0x8000 : 0x800;
@@ -738,7 +739,17 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
}
if (!recovery_mode && status != 5) {
- return IRECV_E_USB_UPLOAD;
+ int retry = 0;
+ while (retry < 20) {
+ irecv_get_status(client, &status);
+ if (status == 5) {
+ break;
+ }
+ sleep(1);
+ }
+ if (status != 5) {
+ return IRECV_E_USB_UPLOAD;
+ }
}
count += size;
@@ -844,6 +855,16 @@ irecv_error_t irecv_getret(irecv_client_t client, unsigned int* value) {
irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid) {
if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;
+ if (client->mode == kWTFMode) {
+ char s_cpid[8] = {0,};
+ strncpy(s_cpid, client->serial, 4);
+ if (sscanf(s_cpid, "%d", cpid) != 1) {
+ *cpid = 0;
+ return IRECV_E_UNKNOWN_ERROR;
+ }
+ return IRECV_E_SUCCESS;
+ }
+
char* cpid_string = strstr(client->serial, "CPID:");
if (cpid_string == NULL) {
*cpid = 0;
@@ -1142,7 +1163,7 @@ int irecv_read_file(const char* filename, char** data, uint32_t* size) {
irecv_error_t irecv_reset_counters(irecv_client_t client) {
if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;
- if (client->mode == kDfuMode) {
+ if ((client->mode == kDfuMode) || (client->mode == kWTFMode)) {
irecv_control_transfer(client, 0x21, 4, 0, 0, 0, 0, USB_TIMEOUT);
}
return IRECV_E_SUCCESS;
@@ -1150,7 +1171,7 @@ irecv_error_t irecv_reset_counters(irecv_client_t client) {
irecv_error_t irecv_recv_buffer(irecv_client_t client, char* buffer, unsigned long length) {
irecv_error_t error = 0;
- int recovery_mode = (client->mode != kDfuMode);
+ int recovery_mode = ((client->mode != kDfuMode) && (client->mode != kWTFMode));
if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;
diff --git a/src/libirecovery.h b/src/libirecovery.h
index a4e3aa1..efd5ee8 100644
--- a/src/libirecovery.h
+++ b/src/libirecovery.h
@@ -90,6 +90,7 @@ enum {
kRecoveryMode2 = 0x1281,
kRecoveryMode3 = 0x1282,
kRecoveryMode4 = 0x1283,
+ kWTFMode = 0x1222,
kDfuMode = 0x1227
};
diff --git a/src/recovery.c b/src/recovery.c
index 9e86cc5..279fe50 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -99,7 +99,7 @@ int recovery_check_mode() {
return -1;
}
- if (recovery->mode == kDfuMode) {
+ if ((recovery->mode == kDfuMode) || (recovery->mode == kWTFMode)) {
irecv_close(recovery);
return -1;
}