summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/irecovery.c42
-rw-r--r--src/libirecovery.c142
2 files changed, 149 insertions, 35 deletions
diff --git a/src/irecovery.c b/src/irecovery.c
index baae17e..c282cda 100644
--- a/src/irecovery.c
+++ b/src/irecovery.c
@@ -27,13 +27,13 @@
27#define debug(...) if(verbose) fprintf(stderr, __VA_ARGS__) 27#define debug(...) if(verbose) fprintf(stderr, __VA_ARGS__)
28 28
29enum { 29enum {
30 kResetDevice, kStartShell, kSendCommand, kSendFile, kSendExploit 30 kResetDevice, kStartShell, kSendCommand, kSendFile, kSendExploit, kSendScript
31}; 31};
32 32
33static unsigned int quit = 0; 33static unsigned int quit = 0;
34static unsigned int verbose = 0; 34static unsigned int verbose = 0;
35 35
36void print_progress_bar(const char* operation, double progress); 36void print_progress_bar(double progress);
37int received_cb(irecv_client_t client, const irecv_event_t* event); 37int received_cb(irecv_client_t client, const irecv_event_t* event);
38int progress_cb(irecv_client_t client, const irecv_event_t* event); 38int progress_cb(irecv_client_t client, const irecv_event_t* event);
39int precommand_cb(irecv_client_t client, const irecv_event_t* event); 39int precommand_cb(irecv_client_t client, const irecv_event_t* event);
@@ -61,7 +61,7 @@ void parse_command(irecv_client_t client, unsigned char* command, unsigned int s
61 61
62 if (!strcmp(cmd, "/upload")) { 62 if (!strcmp(cmd, "/upload")) {
63 char* filename = strtok(NULL, " "); 63 char* filename = strtok(NULL, " ");
64 debug("Sending %s\n", filename); 64 debug("Uploading files %s\n", filename);
65 if (filename != NULL) { 65 if (filename != NULL) {
66 irecv_send_file(client, filename); 66 irecv_send_file(client, filename);
67 } 67 }
@@ -69,12 +69,21 @@ void parse_command(irecv_client_t client, unsigned char* command, unsigned int s
69 69
70 if (!strcmp(cmd, "/exploit")) { 70 if (!strcmp(cmd, "/exploit")) {
71 char* filename = strtok(NULL, " "); 71 char* filename = strtok(NULL, " ");
72 debug("Sending %s\n", filename); 72 debug("Sending exploit %s\n", filename);
73 if (filename != NULL) { 73 if (filename != NULL) {
74 irecv_send_file(client, filename); 74 irecv_send_file(client, filename);
75 } 75 }
76 irecv_send_exploit(client); 76 irecv_send_exploit(client);
77 } 77 } else
78
79 if (!strcmp(cmd, "/execute")) {
80 char* filename = strtok(NULL, " ");
81 debug("Executing script %s\n", filename);
82 if (filename != NULL) {
83 irecv_execute_script(client, filename);
84 }
85 }
86
78 87
79 free(action); 88 free(action);
80} 89}
@@ -171,12 +180,12 @@ int postcommand_cb(irecv_client_t client, const irecv_event_t* event) {
171 180
172int progress_cb(irecv_client_t client, const irecv_event_t* event) { 181int progress_cb(irecv_client_t client, const irecv_event_t* event) {
173 if (event->type == IRECV_PROGRESS) { 182 if (event->type == IRECV_PROGRESS) {
174 print_progress_bar(event->data, event->progress); 183 print_progress_bar(event->progress);
175 } 184 }
176 return 0; 185 return 0;
177} 186}
178 187
179void print_progress_bar(const char* operation, double progress) { 188void print_progress_bar(double progress) {
180 int i = 0; 189 int i = 0;
181 if(progress < 0) { 190 if(progress < 0) {
182 return; 191 return;
@@ -186,7 +195,7 @@ void print_progress_bar(const char* operation, double progress) {
186 progress = 100; 195 progress = 100;
187 } 196 }
188 197
189 printf("\r%s [", operation); 198 printf("\r[");
190 for(i = 0; i < 50; i++) { 199 for(i = 0; i < 50; i++) {
191 if(i < progress / 2) { 200 if(i < progress / 2) {
192 printf("="); 201 printf("=");
@@ -212,6 +221,7 @@ void print_usage() {
212 printf("\t-h\t\tShow this help.\n"); 221 printf("\t-h\t\tShow this help.\n");
213 printf("\t-r\t\tReset client.\n"); 222 printf("\t-r\t\tReset client.\n");
214 printf("\t-s\t\tStart interactive shell.\n"); 223 printf("\t-s\t\tStart interactive shell.\n");
224 printf("\t-e <script>\tExecutes recovery shell script.");
215 exit(1); 225 exit(1);
216} 226}
217 227
@@ -222,7 +232,7 @@ int main(int argc, char** argv) {
222 char* argument = NULL; 232 char* argument = NULL;
223 irecv_error_t error = 0; 233 irecv_error_t error = 0;
224 if (argc == 1) print_usage(); 234 if (argc == 1) print_usage();
225 while ((opt = getopt(argc, argv, "vhrsc:f:k::")) > 0) { 235 while ((opt = getopt(argc, argv, "vhrsc:f:e:k::")) > 0) {
226 switch (opt) { 236 switch (opt) {
227 case 'v': 237 case 'v':
228 verbose += 1; 238 verbose += 1;
@@ -255,6 +265,11 @@ int main(int argc, char** argv) {
255 argument = optarg; 265 argument = optarg;
256 break; 266 break;
257 267
268 case 'e':
269 action = kSendScript;
270 argument = optarg;
271 break;
272
258 default: 273 default:
259 fprintf(stderr, "Unknown argument\n"); 274 fprintf(stderr, "Unknown argument\n");
260 return -1; 275 return -1;
@@ -275,7 +290,7 @@ int main(int argc, char** argv) {
275 } 290 }
276 } 291 }
277 292
278 if (verbose) irecv_set_debug(client, verbose); 293 if (verbose) irecv_set_debug_level(verbose);
279 294
280 switch (action) { 295 switch (action) {
281 case kResetDevice: 296 case kResetDevice:
@@ -310,6 +325,13 @@ int main(int argc, char** argv) {
310 init_shell(client); 325 init_shell(client);
311 break; 326 break;
312 327
328 case kSendScript:
329 error = irecv_execute_script(client, argument);
330 if(error != IRECV_E_SUCCESS) {
331 debug("%s\n", irecv_strerror(error));
332 }
333 break;
334
313 default: 335 default:
314 fprintf(stderr, "Unknown action\n"); 336 fprintf(stderr, "Unknown action\n");
315 break; 337 break;
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 05a162f..dd5c734 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -25,23 +25,30 @@
25#include "libirecovery.h" 25#include "libirecovery.h"
26 26
27#define BUFFER_SIZE 0x1000 27#define BUFFER_SIZE 0x1000
28#define debug(...) if(client->debug) fprintf(stderr, __VA_ARGS__) 28#define debug(...) if(libirecovery_debug) fprintf(stderr, __VA_ARGS__)
29 29
30void irecv_print_progress(const char* operation, float progress); 30static int libirecovery_debug = 0;
31static libusb_context* libirecovery_context = NULL;
32
33int irecv_write_file(const char* filename, const void* data, size_t size);
34int irecv_read_file(const char* filename, char** data, uint32_t* size);
31 35
32irecv_error_t irecv_open(irecv_client_t* pclient) { 36irecv_error_t irecv_open(irecv_client_t* pclient) {
33 int i = 0; 37 int i = 0;
34 char serial[256]; 38 char serial[256];
35 struct libusb_device* usb_device = NULL; 39 struct libusb_device* usb_device = NULL;
36 struct libusb_context* usb_context = NULL;
37 struct libusb_device** usb_device_list = NULL; 40 struct libusb_device** usb_device_list = NULL;
38 struct libusb_device_handle* usb_handle = NULL; 41 struct libusb_device_handle* usb_handle = NULL;
39 struct libusb_device_descriptor usb_descriptor; 42 struct libusb_device_descriptor usb_descriptor;
40 43
41 *pclient = NULL; 44 *pclient = NULL;
42 libusb_init(&usb_context); 45 libusb_init(&libirecovery_context);
46 if(libirecovery_debug) {
47 irecv_set_debug_level(libirecovery_debug);
48 }
49
43 irecv_error_t error = IRECV_E_SUCCESS; 50 irecv_error_t error = IRECV_E_SUCCESS;
44 int usb_device_count = libusb_get_device_list(usb_context, &usb_device_list); 51 int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list);
45 for (i = 0; i < usb_device_count; i++) { 52 for (i = 0; i < usb_device_count; i++) {
46 usb_device = usb_device_list[i]; 53 usb_device = usb_device_list[i];
47 libusb_get_device_descriptor(usb_device, &usb_descriptor); 54 libusb_get_device_descriptor(usb_device, &usb_descriptor);
@@ -57,7 +64,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
57 if (usb_handle == NULL) { 64 if (usb_handle == NULL) {
58 libusb_free_device_list(usb_device_list, 1); 65 libusb_free_device_list(usb_device_list, 1);
59 libusb_close(usb_handle); 66 libusb_close(usb_handle);
60 libusb_exit(usb_context); 67 libusb_exit(libirecovery_context);
61 return IRECV_E_UNABLE_TO_CONNECT; 68 return IRECV_E_UNABLE_TO_CONNECT;
62 } 69 }
63 libusb_free_device_list(usb_device_list, 1); 70 libusb_free_device_list(usb_device_list, 1);
@@ -65,14 +72,13 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
65 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client)); 72 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client));
66 if (client == NULL) { 73 if (client == NULL) {
67 libusb_close(usb_handle); 74 libusb_close(usb_handle);
68 libusb_exit(usb_context); 75 libusb_exit(libirecovery_context);
69 return IRECV_E_OUT_OF_MEMORY; 76 return IRECV_E_OUT_OF_MEMORY;
70 } 77 }
71 78
72 memset(client, '\0', sizeof(struct irecv_client)); 79 memset(client, '\0', sizeof(struct irecv_client));
73 client->interface = 0; 80 client->interface = 0;
74 client->handle = usb_handle; 81 client->handle = usb_handle;
75 client->context = usb_context;
76 client->mode = usb_descriptor.idProduct; 82 client->mode = usb_descriptor.idProduct;
77 83
78 error = irecv_set_configuration(client, 1); 84 error = irecv_set_configuration(client, 1);
@@ -223,9 +229,9 @@ irecv_error_t irecv_close(irecv_client_t client) {
223 client->handle = NULL; 229 client->handle = NULL;
224 } 230 }
225 231
226 if (client->context != NULL) { 232 if (libirecovery_context != NULL) {
227 libusb_exit(client->context); 233 libusb_exit(libirecovery_context);
228 client->context = NULL; 234 libirecovery_context = NULL;
229 } 235 }
230 236
231 free(client); 237 free(client);
@@ -235,14 +241,11 @@ irecv_error_t irecv_close(irecv_client_t client) {
235 return IRECV_E_SUCCESS; 241 return IRECV_E_SUCCESS;
236} 242}
237 243
238irecv_error_t irecv_set_debug(irecv_client_t client, int level) { 244void irecv_set_debug_level(int level) {
239 if (client == NULL || client->context == NULL) { 245 libirecovery_debug = level;
240 return IRECV_E_NO_DEVICE; 246 if(libirecovery_context) {
247 libusb_set_debug(libirecovery_context, libirecovery_debug);
241 } 248 }
242
243 libusb_set_debug(client->context, level);
244 client->debug = level;
245 return IRECV_E_SUCCESS;
246} 249}
247 250
248irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) { 251irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) {
@@ -350,14 +353,11 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
350 unsigned int status = 0; 353 unsigned int status = 0;
351 for (i = 0; i < packets; i++) { 354 for (i = 0; i < packets; i++) {
352 int size = i + 1 < packets ? 0x800 : last; 355 int size = i + 1 < packets ? 0x800 : last;
353 int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], 356 int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], size, 1000);
354 size, 1000);
355 if (bytes != size) { 357 if (bytes != size) {
356 return IRECV_E_USB_UPLOAD; 358 return IRECV_E_USB_UPLOAD;
357 } 359 }
358 360
359 debug("Sent %d bytes\n", bytes);
360
361 error = irecv_get_status(client, &status); 361 error = irecv_get_status(client, &status);
362 if (error != IRECV_E_SUCCESS) { 362 if (error != IRECV_E_SUCCESS) {
363 return error; 363 return error;
@@ -375,6 +375,8 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
375 event.data = "Uploading"; 375 event.data = "Uploading";
376 event.size = count; 376 event.size = count;
377 client->progress_callback(client, &event); 377 client->progress_callback(client, &event);
378 } else {
379 debug("Sent: %d bytes - %d of %d\n", bytes, count, length);
378 } 380 }
379 } 381 }
380 382
@@ -457,7 +459,6 @@ irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid) {
457 } 459 }
458 460
459 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 461 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
460 printf("%d: %s\n", strlen(info), info);
461 462
462 unsigned char* cpid_string = strstr(info, "CPID:"); 463 unsigned char* cpid_string = strstr(info, "CPID:");
463 if (cpid_string == NULL) { 464 if (cpid_string == NULL) {
@@ -478,7 +479,6 @@ irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid) {
478 } 479 }
479 480
480 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 481 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
481 printf("%d: %s\n", strlen(info), info);
482 482
483 unsigned char* bdid_string = strstr(info, "BDID:"); 483 unsigned char* bdid_string = strstr(info, "BDID:");
484 if (bdid_string == NULL) { 484 if (bdid_string == NULL) {
@@ -499,7 +499,6 @@ irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
499 } 499 }
500 500
501 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 501 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
502 printf("%d: %s\n", strlen(info), info);
503 502
504 unsigned char* ecid_string = strstr(info, "ECID:"); 503 unsigned char* ecid_string = strstr(info, "ECID:");
505 if (ecid_string == NULL) { 504 if (ecid_string == NULL) {
@@ -520,6 +519,37 @@ irecv_error_t irecv_send_exploit(irecv_client_t client) {
520 return IRECV_E_SUCCESS; 519 return IRECV_E_SUCCESS;
521} 520}
522 521
522irecv_error_t irecv_execute_script(irecv_client_t client, const char* filename) {
523 irecv_error_t error = IRECV_E_SUCCESS;
524 if (client == NULL || client->handle == NULL) {
525 return IRECV_E_NO_DEVICE;
526 }
527
528 int file_size = 0;
529 char* file_data = NULL;
530 if(irecv_read_file(filename, &file_data, &file_size) < 0) {
531 return IRECV_E_FILE_NOT_FOUND;
532 }
533
534 char* line = strtok(file_data, "\n");
535 while(line != NULL) {
536 if(line[0] != '#') {
537 error = irecv_send_command(client, line);
538 if(error != IRECV_E_SUCCESS) {
539 return error;
540 }
541
542 error = irecv_receive(client);
543 if(error != IRECV_E_SUCCESS) {
544 return error;
545 }
546 }
547 line = strtok(NULL, "\n");
548 }
549
550 return IRECV_E_SUCCESS;
551}
552
523irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) { 553irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) {
524 char command[256]; 554 char command[256];
525 if (client == NULL || client->handle == NULL) { 555 if (client == NULL || client->handle == NULL) {
@@ -578,3 +608,65 @@ const char* irecv_strerror(irecv_error_t error) {
578 608
579 return NULL; 609 return NULL;
580} 610}
611
612int irecv_write_file(const char* filename, const void* data, size_t size) {
613 size_t bytes = 0;
614 FILE* file = NULL;
615
616 debug("Writing data to %s\n", filename);
617 file = fopen(filename, "wb");
618 if (file == NULL) {
619 error("read_file: Unable to open file %s\n", filename);
620 return -1;
621 }
622
623 bytes = fwrite(data, 1, size, file);
624 fclose(file);
625
626 if (bytes != size) {
627 error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size);
628 return -1;
629 }
630
631 return size;
632}
633
634int irecv_read_file(const char* filename, char** data, uint32_t* size) {
635 size_t bytes = 0;
636 size_t length = 0;
637 FILE* file = NULL;
638 char* buffer = NULL;
639 debug("Reading data from %s\n", filename);
640
641 *size = 0;
642 *data = NULL;
643
644 file = fopen(filename, "rb");
645 if (file == NULL) {
646 error("read_file: File %s not found\n", filename);
647 return -1;
648 }
649
650 fseek(file, 0, SEEK_END);
651 length = ftell(file);
652 rewind(file);
653
654 buffer = (char*) malloc(length);
655 if(buffer == NULL) {
656 error("ERROR: Out of memory\n");
657 fclose(file);
658 return -1;
659 }
660 bytes = fread(buffer, 1, length, file);
661 fclose(file);
662
663 if(bytes != length) {
664 error("ERROR: Unable to read entire file\n");
665 free(buffer);
666 return -1;
667 }
668
669 *size = length;
670 *data = buffer;
671 return 0;
672}