diff options
| author | 2013-09-27 02:22:56 +0200 | |
|---|---|---|
| committer | 2013-09-27 02:22:56 +0200 | |
| commit | 0e2bfbd3450096ae9e4c22e18fb169429c25d1f4 (patch) | |
| tree | 46e851fc0d1ff93b445ef775796039012491590d /tools | |
| parent | c84fb716cd998118c95fb59a8ba4d3e26a673749 (diff) | |
| download | libirecovery-0e2bfbd3450096ae9e4c22e18fb169429c25d1f4.tar.gz libirecovery-0e2bfbd3450096ae9e4c22e18fb169429c25d1f4.tar.bz2 | |
irecovery: Update code style, add "show mode" and "normal mode reboot" commands
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/irecovery.c | 286 |
1 files changed, 191 insertions, 95 deletions
diff --git a/tools/irecovery.c b/tools/irecovery.c index effd3fb..12f05b7 100644 --- a/tools/irecovery.c +++ b/tools/irecovery.c | |||
| @@ -41,7 +41,9 @@ enum { | |||
| 41 | kSendCommand, | 41 | kSendCommand, |
| 42 | kSendFile, | 42 | kSendFile, |
| 43 | kSendExploit, | 43 | kSendExploit, |
| 44 | kSendScript | 44 | kSendScript, |
| 45 | kShowMode, | ||
| 46 | kRebootToNormalMode | ||
| 45 | }; | 47 | }; |
| 46 | 48 | ||
| 47 | static unsigned int quit = 0; | 49 | static unsigned int quit = 0; |
| @@ -255,19 +257,51 @@ void print_progress_bar(double progress) { | |||
| 255 | } | 257 | } |
| 256 | } | 258 | } |
| 257 | 259 | ||
| 258 | static void print_usage() { | 260 | static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) { |
| 259 | printf("iRecovery - iDevice Recovery Utility\n"); | 261 | FILE *f; |
| 260 | printf("Usage: irecovery [args]\n"); | 262 | uint64_t size; |
| 261 | printf("\t-i <ecid>\tTarget specific device by its hexadecimal ECID\n"); | 263 | |
| 262 | printf("\t-v\t\tStart irecovery in verbose mode.\n"); | 264 | *length = 0; |
| 263 | printf("\t-c <cmd>\tSend command to client.\n"); | 265 | |
| 264 | printf("\t-f <file>\tSend file to client.\n"); | 266 | f = fopen(filename, "rb"); |
| 265 | printf("\t-k [payload]\tSend usb exploit to client.\n"); | 267 | if (!f) { |
| 266 | printf("\t-h\t\tShow this help.\n"); | 268 | return; |
| 267 | printf("\t-r\t\tReset client.\n"); | 269 | } |
| 268 | printf("\t-s\t\tStart interactive shell.\n"); | 270 | |
| 269 | printf("\t-e <script>\tExecutes recovery shell script.\n"); | 271 | fseek(f, 0, SEEK_END); |
| 270 | exit(1); | 272 | size = ftell(f); |
| 273 | rewind(f); | ||
| 274 | |||
| 275 | if (size == 0) { | ||
| 276 | fclose(f); | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | *buffer = (char*)malloc(sizeof(char)*(size+1)); | ||
| 281 | fread(*buffer, sizeof(char), size, f); | ||
| 282 | fclose(f); | ||
| 283 | |||
| 284 | *length = size; | ||
| 285 | } | ||
| 286 | |||
| 287 | static void print_usage(int argc, char **argv) { | ||
| 288 | char *name = NULL; | ||
| 289 | name = strrchr(argv[0], '/'); | ||
| 290 | printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0])); | ||
| 291 | printf("Interact with a iBSS/iBoot iOS device in DFU or recovery mode.\n\n"); | ||
| 292 | printf("options:\n"); | ||
| 293 | printf(" -i ECID\tconnect to specific device by its hexadecimal ECID\n"); | ||
| 294 | printf(" -c CMD\trun CMD on device\n"); | ||
| 295 | printf(" -m\t\tprint current device mode\n"); | ||
| 296 | printf(" -f FILE\tsend file to device\n"); | ||
| 297 | printf(" -k FILE\tsend limera1in usb exploit payload from FILE\n"); | ||
| 298 | printf(" -r\t\treset client\n"); | ||
| 299 | printf(" -n\t\treboot device into normal mode (exit recovery loop)\n"); | ||
| 300 | printf(" -e FILE\texecutes recovery script from FILE\n"); | ||
| 301 | printf(" -s\t\tstart an interactive shell\n"); | ||
| 302 | printf(" -v\t\tenable verbose output, repeat for higher verbosity\n"); | ||
| 303 | printf(" -h\t\tprints this usage information\n"); | ||
| 304 | printf("\n"); | ||
| 271 | } | 305 | } |
| 272 | 306 | ||
| 273 | int main(int argc, char* argv[]) { | 307 | int main(int argc, char* argv[]) { |
| @@ -275,67 +309,81 @@ int main(int argc, char* argv[]) { | |||
| 275 | int opt = 0; | 309 | int opt = 0; |
| 276 | int action = 0; | 310 | int action = 0; |
| 277 | unsigned long long ecid = 0; | 311 | unsigned long long ecid = 0; |
| 312 | int mode = -1; | ||
| 278 | char* argument = NULL; | 313 | char* argument = NULL; |
| 279 | irecv_error_t error = 0; | 314 | irecv_error_t error = 0; |
| 280 | 315 | ||
| 281 | if (argc == 1) | 316 | char* buffer = NULL; |
| 282 | print_usage(); | 317 | uint64_t buffer_length = 0; |
| 283 | 318 | ||
| 284 | while ((opt = getopt(argc, argv, "i:vhrsc:f:e:k::")) > 0) { | 319 | if (argc == 1) { |
| 320 | print_usage(argc, argv); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | while ((opt = getopt(argc, argv, "i:vhrsmnc:f:e:k::")) > 0) { | ||
| 285 | switch (opt) { | 325 | switch (opt) { |
| 286 | case 'i': | 326 | case 'i': |
| 287 | if (optarg) { | 327 | if (optarg) { |
| 288 | char* tail = NULL; | 328 | char* tail = NULL; |
| 289 | ecid = strtoull(optarg, &tail, 16); | 329 | ecid = strtoull(optarg, &tail, 16); |
| 290 | if (tail && (tail[0] != '\0')) { | 330 | if (tail && (tail[0] != '\0')) { |
| 291 | ecid = 0; | 331 | ecid = 0; |
| 292 | } | 332 | } |
| 293 | if (ecid == 0) { | 333 | if (ecid == 0) { |
| 294 | fprintf(stderr, "ERROR: Could not parse ECID from argument '%s'\n", optarg); | 334 | fprintf(stderr, "ERROR: Could not parse ECID from argument '%s'\n", optarg); |
| 295 | return -1; | 335 | return -1; |
| 336 | } | ||
| 296 | } | 337 | } |
| 297 | } | 338 | break; |
| 298 | break; | ||
| 299 | 339 | ||
| 300 | case 'v': | 340 | case 'v': |
| 301 | verbose += 1; | 341 | verbose += 1; |
| 302 | break; | 342 | break; |
| 303 | 343 | ||
| 304 | case 'h': | 344 | case 'h': |
| 305 | print_usage(); | 345 | print_usage(argc, argv); |
| 306 | break; | 346 | return 0; |
| 307 | 347 | ||
| 308 | case 'r': | 348 | case 'm': |
| 309 | action = kResetDevice; | 349 | action = kShowMode; |
| 310 | break; | 350 | break; |
| 311 | 351 | ||
| 312 | case 's': | 352 | case 'n': |
| 313 | action = kStartShell; | 353 | action = kRebootToNormalMode; |
| 314 | break; | 354 | break; |
| 315 | 355 | ||
| 316 | case 'f': | 356 | case 'r': |
| 317 | action = kSendFile; | 357 | action = kResetDevice; |
| 318 | argument = optarg; | 358 | break; |
| 319 | break; | ||
| 320 | 359 | ||
| 321 | case 'c': | 360 | case 's': |
| 322 | action = kSendCommand; | 361 | action = kStartShell; |
| 323 | argument = optarg; | 362 | break; |
| 324 | break; | ||
| 325 | 363 | ||
| 326 | case 'k': | 364 | case 'f': |
| 327 | action = kSendExploit; | 365 | action = kSendFile; |
| 328 | argument = optarg; | 366 | argument = optarg; |
| 329 | break; | 367 | break; |
| 330 | 368 | ||
| 331 | case 'e': | 369 | case 'c': |
| 332 | action = kSendScript; | 370 | action = kSendCommand; |
| 333 | argument = optarg; | 371 | argument = optarg; |
| 334 | break; | 372 | break; |
| 335 | 373 | ||
| 336 | default: | 374 | case 'k': |
| 337 | fprintf(stderr, "Unknown argument\n"); | 375 | action = kSendExploit; |
| 338 | return -1; | 376 | argument = optarg; |
| 377 | break; | ||
| 378 | |||
| 379 | case 'e': | ||
| 380 | action = kSendScript; | ||
| 381 | argument = optarg; | ||
| 382 | break; | ||
| 383 | |||
| 384 | default: | ||
| 385 | fprintf(stderr, "Unknown argument\n"); | ||
| 386 | return -1; | ||
| 339 | } | 387 | } |
| 340 | } | 388 | } |
| 341 | 389 | ||
| @@ -363,48 +411,96 @@ int main(int argc, char* argv[]) { | |||
| 363 | debug("Connected to %s, model %s, cpid 0x%04x, bdid 0x%02x\n", device->product_type, device->hardware_model, device->chip_id, device->board_id); | 411 | debug("Connected to %s, model %s, cpid 0x%04x, bdid 0x%02x\n", device->product_type, device->hardware_model, device->chip_id, device->board_id); |
| 364 | 412 | ||
| 365 | switch (action) { | 413 | switch (action) { |
| 366 | case kResetDevice: | 414 | case kResetDevice: |
| 367 | irecv_reset(client); | 415 | irecv_reset(client); |
| 368 | break; | 416 | break; |
| 369 | 417 | ||
| 370 | case kSendFile: | 418 | case kSendFile: |
| 371 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); | ||
| 372 | error = irecv_send_file(client, argument, 1); | ||
| 373 | debug("%s\n", irecv_strerror(error)); | ||
| 374 | break; | ||
| 375 | |||
| 376 | case kSendCommand: | ||
| 377 | error = irecv_send_command(client, argument); | ||
| 378 | debug("%s\n", irecv_strerror(error)); | ||
| 379 | break; | ||
| 380 | |||
| 381 | case kSendExploit: | ||
| 382 | if (argument != NULL) { | ||
| 383 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); | 419 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); |
| 384 | error = irecv_send_file(client, argument, 0); | 420 | error = irecv_send_file(client, argument, 1); |
| 421 | debug("%s\n", irecv_strerror(error)); | ||
| 422 | break; | ||
| 423 | |||
| 424 | case kSendCommand: | ||
| 425 | error = irecv_send_command(client, argument); | ||
| 426 | debug("%s\n", irecv_strerror(error)); | ||
| 427 | break; | ||
| 428 | |||
| 429 | case kSendExploit: | ||
| 430 | if (argument != NULL) { | ||
| 431 | irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); | ||
| 432 | error = irecv_send_file(client, argument, 0); | ||
| 433 | if (error != IRECV_E_SUCCESS) { | ||
| 434 | debug("%s\n", irecv_strerror(error)); | ||
| 435 | break; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | error = irecv_trigger_limera1n_exploit(client); | ||
| 439 | debug("%s\n", irecv_strerror(error)); | ||
| 440 | break; | ||
| 441 | |||
| 442 | case kStartShell: | ||
| 443 | init_shell(client); | ||
| 444 | break; | ||
| 445 | |||
| 446 | case kSendScript: | ||
| 447 | buffer_read_from_filename(argument, &buffer, &buffer_length); | ||
| 448 | buffer[buffer_length] = '\0'; | ||
| 449 | |||
| 450 | error = irecv_execute_script(client, buffer); | ||
| 451 | if(error != IRECV_E_SUCCESS) { | ||
| 452 | debug("%s\n", irecv_strerror(error)); | ||
| 453 | } | ||
| 454 | |||
| 455 | if (buffer) | ||
| 456 | free(buffer); | ||
| 457 | |||
| 458 | break; | ||
| 459 | |||
| 460 | case kShowMode: | ||
| 461 | irecv_get_mode(client, &mode); | ||
| 462 | switch (mode) { | ||
| 463 | case IRECV_K_RECOVERY_MODE_1: | ||
| 464 | case IRECV_K_RECOVERY_MODE_2: | ||
| 465 | case IRECV_K_RECOVERY_MODE_3: | ||
| 466 | case IRECV_K_RECOVERY_MODE_4: | ||
| 467 | printf("Recovery Mode\n"); | ||
| 468 | break; | ||
| 469 | case IRECV_K_DFU_MODE: | ||
| 470 | printf("DFU Mode\n"); | ||
| 471 | break; | ||
| 472 | case IRECV_K_WTF_MODE: | ||
| 473 | printf("WTF Mode\n"); | ||
| 474 | break; | ||
| 475 | default: | ||
| 476 | printf("Unknown Mode\n"); | ||
| 477 | break; | ||
| 478 | } | ||
| 479 | break; | ||
| 480 | |||
| 481 | case kRebootToNormalMode: | ||
| 482 | error = irecv_setenv(client, "auto-boot", "true"); | ||
| 385 | if (error != IRECV_E_SUCCESS) { | 483 | if (error != IRECV_E_SUCCESS) { |
| 386 | debug("%s\n", irecv_strerror(error)); | 484 | debug("%s\n", irecv_strerror(error)); |
| 387 | break; | 485 | break; |
| 388 | } | 486 | } |
| 389 | } | ||
| 390 | error = irecv_trigger_limera1n_exploit(client); | ||
| 391 | debug("%s\n", irecv_strerror(error)); | ||
| 392 | break; | ||
| 393 | 487 | ||
| 394 | case kStartShell: | 488 | error = irecv_saveenv(client); |
| 395 | init_shell(client); | 489 | if (error != IRECV_E_SUCCESS) { |
| 396 | break; | 490 | debug("%s\n", irecv_strerror(error)); |
| 397 | 491 | break; | |
| 398 | case kSendScript: | 492 | } |
| 399 | error = irecv_execute_script(client, argument); | ||
| 400 | if(error != IRECV_E_SUCCESS) { | ||
| 401 | debug("%s\n", irecv_strerror(error)); | ||
| 402 | } | ||
| 403 | break; | ||
| 404 | 493 | ||
| 405 | default: | 494 | error = irecv_reboot(client); |
| 406 | fprintf(stderr, "Unknown action\n"); | 495 | if (error != IRECV_E_SUCCESS) { |
| 407 | break; | 496 | debug("%s\n", irecv_strerror(error)); |
| 497 | } else { | ||
| 498 | debug("%s\n", irecv_strerror(error)); | ||
| 499 | } | ||
| 500 | break; | ||
| 501 | default: | ||
| 502 | fprintf(stderr, "Unknown action\n"); | ||
| 503 | break; | ||
| 408 | } | 504 | } |
| 409 | 505 | ||
| 410 | irecv_close(client); | 506 | irecv_close(client); |
