diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/irecovery.c | 118 | ||||
-rw-r--r-- | src/libirecovery.c | 277 |
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, ¤t); - 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; } |