summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/irecovery.c118
-rw-r--r--src/libirecovery.c277
2 files changed, 225 insertions, 170 deletions
diff --git a/src/irecovery.c b/src/irecovery.c
index 98b1e90..a623579 100644
--- a/src/irecovery.c
+++ b/src/irecovery.c
@@ -43,18 +43,18 @@ void print_shell_usage() {
void parse_command(irecv_client_t client, unsigned char* command, unsigned int size) {
char* cmd = strtok(strdup(command), " ");
debug("Executing %s %s\n", cmd, command);
- if(!strcmp(cmd, "/exit")) {
+ if (!strcmp(cmd, "/exit")) {
quit = 1;
} else
-
- if(!strcmp(cmd, "/help")) {
+
+ if (!strcmp(cmd, "/help")) {
print_shell_usage();
} else
-
- if(!strcmp(cmd, "/upload")) {
+
+ if (!strcmp(cmd, "/upload")) {
char* filename = strtok(NULL, " ");
debug("Sending %s\n", filename);
- if(filename != NULL) {
+ if (filename != NULL) {
irecv_send_file(client, filename);
}
}
@@ -63,47 +63,14 @@ void parse_command(irecv_client_t client, unsigned char* command, unsigned int s
int recv_callback(irecv_client_t client, unsigned char* data, int size) {
int i = 0;
- for(i = 0; i < size; i++) {
+ for (i = 0; i < size; i++) {
printf("%c", data[i]);
}
return size;
}
int send_callback(irecv_client_t client, unsigned char* command, int size) {
- irecv_error_t error = 0;
- if(command[0] == '/') {
- parse_command(client, command, size);
- return 0;
- }
-
- if(strstr(command, "getenv") != NULL) {
- unsigned char* value = NULL;
- error = irecv_send_command(client, command);
- if(error != IRECV_E_SUCCESS) {
- debug("%s\n", irecv_strerror(error));
- return error;
- }
-
- error = irecv_getenv(client, &value);
- if(error != IRECV_E_SUCCESS) {
- debug("%s\n", irecv_strerror(error));
- return error;
- }
-
- printf("%s\n", value);
- free(value);
- return 0;
- }
- if(!strcmp(command, "reboot")) {
- error = irecv_send_command(client, command);
- if(error != IRECV_E_SUCCESS) {
- debug("%s\n", irecv_strerror(error));
- return error;
- }
- quit = 1;
- return 0;
- }
return size;
}
@@ -119,24 +86,25 @@ void append_command_to_history(char* cmd) {
void init_shell(irecv_client_t client) {
irecv_error_t error = 0;
- //load_command_history();
- irecv_set_sender(client, &send_callback);
+ load_command_history();
irecv_set_receiver(client, &recv_callback);
- while(!quit) {
+ irecv_event_subscribe(client, IRECV_PRECOMMAND, &precommand_cb, NULL);
+ irecv_event_subscribe(client, IRECV_POSTCOMMAND, &postcommand_cb, NULL);
+ while (!quit) {
error = irecv_receive(client);
- if(error != IRECV_E_SUCCESS) {
+ if (error != IRECV_E_SUCCESS) {
debug("%s\n", irecv_strerror(error));
break;
}
-
+
char* cmd = readline("> ");
- if(cmd && *cmd) {
- error = irecv_send(client, cmd);
- if(error != IRECV_E_SUCCESS) {
+ if (cmd && *cmd) {
+ error = irecv_send_command(client, cmd);
+ if (error != IRECV_E_SUCCESS) {
quit = 1;
}
-
- //append_command_to_history(cmd);
+
+ append_command_to_history(cmd);
free(cmd);
}
}
@@ -155,13 +123,43 @@ void print_usage() {
exit(1);
}
+int precommand_cb(irecv_client_t client, const irecv_event_t* event) {
+ irecv_error_t error = 0;
+ if (event->data[0] == '/') {
+ parse_command(client, event->data, strlen(event->data));
+ return -1;
+ }
+ return 0;
+}
+
+int postcommand_cb(irecv_client_t client, const irecv_event_t* event) {
+ irecv_error_t error = 0;
+ if (strstr(event->data, "getenv") != NULL) {
+ unsigned char* value = NULL;
+ error = irecv_getenv(client, &value);
+ if (error != IRECV_E_SUCCESS) {
+ debug("%s\n", irecv_strerror(error));
+ return error;
+ }
+
+ printf("%s\n", value);
+ free(value);
+ }
+
+ if (!strcmp(event->data, "reboot")) {
+ quit = 1;
+ }
+
+ return 0;
+}
+
int main(int argc, char** argv) {
int i = 0;
int opt = 0;
int action = 0;
char* argument = NULL;
irecv_error_t error = 0;
- if(argc == 1) print_usage();
+ if (argc == 1) print_usage();
while ((opt = getopt(argc, argv, "vhrsc:f:k::")) > 0) {
switch (opt) {
case 'v':
@@ -202,20 +200,22 @@ int main(int argc, char** argv) {
}
irecv_client_t client = NULL;
- for(i = 0; i <= 5; i++) {
+ for (i = 0; i <= 5; i++) {
debug("Attempting to connect... \n");
- if(irecv_open(&client) != IRECV_E_SUCCESS) sleep(1);
- else break;
+ if (irecv_open(&client) != IRECV_E_SUCCESS)
+ sleep(1);
+ else
+ break;
- if(i == 5) {
+ if (i == 5) {
return -1;
}
}
- if(verbose) irecv_set_debug(client, verbose);
+ if (verbose) irecv_set_debug(client, verbose);
- switch(action) {
+ switch (action) {
case kResetDevice:
irecv_reset(client);
break;
@@ -231,9 +231,9 @@ int main(int argc, char** argv) {
break;
case kSendExploit:
- if(argument != NULL) {
+ if (argument != NULL) {
error = irecv_send_file(client, argument);
- if(error != IRECV_E_SUCCESS) {
+ if (error != IRECV_E_SUCCESS) {
debug("%s\n", irecv_strerror(error));
break;
}
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 6587fe0..8f029ed 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -41,6 +41,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
*pclient = NULL;
libusb_init(&usb_context);
+ //libusb_init(NULL);
irecv_error_t error = IRECV_E_SUCCESS;
int usb_device_count = libusb_get_device_list(usb_context, &usb_device_list);
for (i = 0; i < usb_device_count; i++) {
@@ -48,11 +49,10 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
libusb_get_device_descriptor(usb_device, &usb_descriptor);
if (usb_descriptor.idVendor == APPLE_VENDOR_ID) {
/* verify this device is in a mode we understand */
- if (usb_descriptor.idProduct == kRecoveryMode1 ||
- usb_descriptor.idProduct == kRecoveryMode2 ||
- usb_descriptor.idProduct == kRecoveryMode3 ||
- usb_descriptor.idProduct == kRecoveryMode4 ||
- usb_descriptor.idProduct == kDfuMode) {
+ if (usb_descriptor.idProduct == kRecoveryMode1 || usb_descriptor.idProduct
+ == kRecoveryMode2 || usb_descriptor.idProduct == kRecoveryMode3
+ || usb_descriptor.idProduct == kRecoveryMode4 || usb_descriptor.idProduct
+ == kDfuMode) {
libusb_open(usb_device, &usb_handle);
if (usb_handle == NULL) {
@@ -63,7 +63,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
}
libusb_set_debug(usb_context, 3);
- libusb_free_device_list(usb_device_list, 0);
+ libusb_free_device_list(usb_device_list, 1);
irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client));
if (client == NULL) {
@@ -72,13 +72,18 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
return IRECV_E_OUT_OF_MEMORY;
}
memset(client, '\0', sizeof(struct irecv_client));
- client->interface = -1;
+ client->interface = 0;
client->handle = usb_handle;
client->context = usb_context;
client->mode = usb_descriptor.idProduct;
error = irecv_set_configuration(client, 1);
- if(error != IRECV_E_SUCCESS) {
+ if (error != IRECV_E_SUCCESS) {
+ return error;
+ }
+
+ error = irecv_set_interface(client, 1, 1);
+ if (error != IRECV_E_SUCCESS) {
return error;
}
@@ -92,30 +97,30 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
}
irecv_error_t irecv_set_configuration(irecv_client_t client, int configuration) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
debug("Setting to configuration %d", configuration);
-
+
int current = 0;
libusb_get_configuration(client->handle, &current);
- if(current != configuration) {
+ if (current != configuration) {
if (libusb_set_configuration(client->handle, configuration) < 0) {
return IRECV_E_USB_CONFIGURATION;
}
}
-
+
client->config = configuration;
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_set_interface(irecv_client_t client, int interface, int alt_interface) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
- if(client->interface == interface) {
+ if (client->interface == interface) {
return IRECV_E_SUCCESS;
}
@@ -123,11 +128,11 @@ irecv_error_t irecv_set_interface(irecv_client_t client, int interface, int alt_
if (libusb_claim_interface(client->handle, interface) < 0) {
return IRECV_E_USB_INTERFACE;
}
-
- if(libusb_set_interface_alt_setting(client->handle, interface, alt_interface) < 0) {
+
+ if (libusb_set_interface_alt_setting(client->handle, interface, alt_interface) < 0) {
return IRECV_E_USB_INTERFACE;
}
-
+
client->interface = interface;
client->alt_interface = alt_interface;
return IRECV_E_SUCCESS;
@@ -139,15 +144,48 @@ irecv_error_t irecv_reset(irecv_client_t client) {
}
libusb_reset_device(client->handle);
+
+ return IRECV_E_SUCCESS;
+}
+
+irecv_error_t irecv_event_subscribe(irecv_client_t client, irecv_event_type type, irecv_event_cb_t callback, void* user_data) {
+ switch(type) {
+ case IRECV_PRECOMMAND:
+ client->precommand_callback = callback;
+ break;
+
+ case IRECV_POSTCOMMAND:
+ client->postcommand_callback = callback;
+ break;
+
+ default:
+ return IRECV_E_UNKNOWN_ERROR;
+ }
+
+ return IRECV_E_SUCCESS;
+}
+
+irecv_error_t irecv_event_unsubscribe(irecv_client_t client, irecv_event_type type) {
+ switch(type) {
+ case IRECV_PRECOMMAND:
+ client->precommand_callback = NULL;
+ break;
+
+ case IRECV_POSTCOMMAND:
+ client->postcommand_callback = NULL;
+ break;
+
+ default:
+ return IRECV_E_UNKNOWN_ERROR;
+ }
+
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_close(irecv_client_t client) {
if (client != NULL) {
if (client->handle != NULL) {
- if(client->interface >= 0) {
- libusb_release_interface(client->handle, client->interface);
- }
+ libusb_release_interface(client->handle, 1);
libusb_close(client->handle);
client->handle = NULL;
}
@@ -165,32 +203,32 @@ irecv_error_t irecv_close(irecv_client_t client) {
}
irecv_error_t irecv_set_debug(irecv_client_t client, int level) {
- if(client == NULL || client->context == NULL) {
+ if (client == NULL || client->context == NULL) {
return IRECV_E_NO_DEVICE;
}
-
+
libusb_set_debug(client->context, level);
client->debug = level;
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_send(irecv_client_t client, unsigned char* command) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
unsigned int length = strlen(command);
- if(length >= 0x100) {
+ if (length >= 0x100) {
length = 0xFF;
}
-
- if(client->send_callback != NULL) {
+
+ if (client->send_callback != NULL) {
// Call our user defined callback first, this must return a number of bytes to send
// or zero to abort send.
length = client->send_callback(client, command, length);
}
- if(length > 0) {
+ if (length > 0) {
irecv_send_command(client, command);
}
@@ -198,32 +236,49 @@ irecv_error_t irecv_send(irecv_client_t client, unsigned char* command) {
}
irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
+ /*
+ irecv_error_t error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
+ unsigned int length = strlen(command);
+ if (length >= 0x100) {
+ length = 0xFF;
+ }
- irecv_error_t error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
+ irecv_event_t event;
+ if(client->precommand_callback != NULL) {
+ event.data = command;
+ event.type = IRECV_PRECOMMAND;
+ if(client->precommand_callback(client, &event)) {
+ return IRECV_E_SUCCESS;
+ }
}
- unsigned int length = strlen(command);
- if(length >= 0x100) {
- length = 0xFF;
+ if (length > 0) {
+ libusb_control_transfer(client->handle, 0x40, 0, 0, 0, command, length + 1, 100);
}
- if(length > 0) {
- libusb_control_transfer(client->handle, 0x40, 0, 0, 0, command, length+1, 100);
+ if(client->postcommand_callback != NULL) {
+ event.data = command;
+ event.type = IRECV_POSTCOMMAND;
+ if(client->postcommand_callback(client, &event)) {
+ return IRECV_E_SUCCESS;
+ }
}
-
+
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
-
+
FILE* file = fopen(filename, "rb");
if (file == NULL) {
return IRECV_E_FILE_NOT_FOUND;
@@ -242,7 +297,7 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) {
int bytes = fread(buffer, 1, length, file);
fclose(file);
- if(bytes != length) {
+ if (bytes != length) {
free(buffer);
return IRECV_E_UNKNOWN_ERROR;
}
@@ -253,23 +308,23 @@ irecv_error_t irecv_send_file(irecv_client_t client, const char* filename) {
}
irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* status) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
*status = 0;
return IRECV_E_NO_DEVICE;
}
-
- irecv_error_t error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
- }
-
+ /*
+ irecv_error_t error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
unsigned char buffer[6];
memset(buffer, '\0', 6);
- if(libusb_control_transfer(client->handle, 0xA1, 3, 0, 0, buffer, 6, 1000) != 6) {
+ if (libusb_control_transfer(client->handle, 0xA1, 3, 0, 0, buffer, 6, 1000) != 6) {
*status = 0;
return IRECV_E_USB_STATUS;
}
-
+
debug("status: %d\n", (unsigned int) buffer[4]);
*status = (unsigned int) buffer[4];
return IRECV_E_SUCCESS;
@@ -277,15 +332,15 @@ 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 int length) {
irecv_error_t error = 0;
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
-
- error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
- }
-
+ /*
+ error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
int last = length % 0x800;
int packets = length / 0x800;
if (last != 0) {
@@ -296,11 +351,12 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
unsigned int status = 0;
for (i = 0; i < packets; i++) {
int size = i + 1 < packets ? 0x800 : last;
- int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], size, 1000);
+ int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800],
+ size, 1000);
if (bytes != size) {
return IRECV_E_USB_UPLOAD;
}
-
+
debug("Sent %d bytes\n", bytes);
error = irecv_get_status(client, &status);
@@ -308,7 +364,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
return error;
}
- if(status != 5) {
+ if (status != 5) {
return IRECV_E_USB_UPLOAD;
}
@@ -317,7 +373,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
libusb_control_transfer(client->handle, 0x21, 1, 0, 0, buffer, 0, 1000);
for (i = 0; i < 3; i++) {
error = irecv_get_status(client, &status);
- if(error != IRECV_E_SUCCESS) {
+ if (error != IRECV_E_SUCCESS) {
return error;
}
}
@@ -328,26 +384,27 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
irecv_error_t irecv_receive(irecv_client_t client) {
unsigned char buffer[BUFFER_SIZE];
memset(buffer, '\0', BUFFER_SIZE);
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
-
- irecv_error_t error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
- }
-
+ /*
+ irecv_error_t error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
int bytes = 0;
- while(libusb_bulk_transfer(client->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) {
- if(bytes > 0) {
- if(client->receive_callback != NULL) {
- if(client->receive_callback(client, buffer, bytes) != bytes) {
+ while (libusb_bulk_transfer(client->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) {
+ if (bytes > 0) {
+ if (client->receive_callback != NULL) {
+ if (client->receive_callback(client, buffer, bytes) != bytes) {
return IRECV_E_UNKNOWN_ERROR;
}
}
- } else break;
+ } else
+ break;
}
-
+
return IRECV_E_SUCCESS;
}
@@ -357,47 +414,47 @@ int irecv_default_sender(irecv_client_t client, unsigned char* data, int size) {
int irecv_default_receiver(irecv_client_t client, unsigned char* data, int size) {
int i = 0;
- for(i = 0; i < size; i++) {
+ for (i = 0; i < size; i++) {
printf("%c", data[i]);
}
return size;
}
irecv_error_t irecv_set_receiver(irecv_client_t client, irecv_receive_callback callback) {
- if(client == NULL) {
+ if (client == NULL) {
return IRECV_E_NO_DEVICE;
}
-
+
client->receive_callback = callback;
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_set_sender(irecv_client_t client, irecv_send_callback callback) {
- if(client == NULL) {
+ if (client == NULL) {
return IRECV_E_NO_DEVICE;
}
-
+
client->send_callback = callback;
return IRECV_E_SUCCESS;
}
irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
-
- irecv_error_t error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
- }
-
+ /*
+ irecv_error_t error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
unsigned char* value = (unsigned char*) malloc(256);
- if(value == NULL) {
+ if (value == NULL) {
return IRECV_E_OUT_OF_MEMORY;
}
- int ret = libusb_control_transfer(client->handle, 0xC0, 0, 0, 0, value, 256, 500);
- if(ret < 0) {
+ int ret = libusb_control_transfer(client->handle, 0xC0, 0, 0, 0, value, 256, 500);
+ if (ret < 0) {
return IRECV_E_UNKNOWN_ERROR;
}
@@ -405,12 +462,11 @@ irecv_error_t irecv_getenv(irecv_client_t client, unsigned char** var) {
return IRECV_E_SUCCESS;
}
-
irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
char info[256];
memset(info, '\0', 256);
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
@@ -418,7 +474,7 @@ irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
printf("%d: %s\n", strlen(info), info);
unsigned char* ecid_string = strstr(info, "ECID:");
- if(ecid_string == NULL) {
+ if (ecid_string == NULL) {
*ecid = 0;
return IRECV_E_UNKNOWN_ERROR;
}
@@ -428,56 +484,55 @@ irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
return IRECV_E_SUCCESS;
}
-
irecv_error_t irecv_send_exploit(irecv_client_t client) {
- if(client == NULL || client->handle == NULL) {
+ if (client == NULL || client->handle == NULL) {
return IRECV_E_NO_DEVICE;
}
-
- irecv_error_t error = irecv_set_interface(client, 1, 1);
- if(error != IRECV_E_SUCCESS) {
- return error;
- }
-
+ /*
+ irecv_error_t error = irecv_set_interface(client, 1, 1);
+ if(error != IRECV_E_SUCCESS) {
+ return error;
+ }
+ */
libusb_control_transfer(client->handle, 0x21, 2, 0, 0, NULL, 0, 100);
return IRECV_E_SUCCESS;
}
const char* irecv_strerror(irecv_error_t error) {
- switch(error) {
+ switch (error) {
case IRECV_E_SUCCESS:
return "Command completed successfully";
-
+
case IRECV_E_NO_DEVICE:
return "Unable to find device";
-
+
case IRECV_E_OUT_OF_MEMORY:
return "Out of memory";
-
+
case IRECV_E_UNABLE_TO_CONNECT:
return "Unable to connect to device";
-
+
case IRECV_E_INVALID_INPUT:
return "Invalid input";
-
+
case IRECV_E_FILE_NOT_FOUND:
return "File not found";
-
+
case IRECV_E_USB_UPLOAD:
return "Unable to upload data to device";
-
+
case IRECV_E_USB_STATUS:
return "Unable to get device status";
-
+
case IRECV_E_USB_INTERFACE:
return "Unable to set device interface";
-
+
case IRECV_E_USB_CONFIGURATION:
return "Unable to set device configuration";
-
+
default:
return "Unknown error";
}
-
+
return NULL;
}