예제 #1
0
int main(int argc, char *argv[]) {
	printf("iRecovery - Recovery Utility\n");
	printf("by westbaer\nThanks to pod2g, tom3q, planetbeing, geohot and posixninja.\n\n");
	if(argc < 2) {
		irecv_usage();
		return -1;
	}

	struct usb_dev_handle* handle = irecv_init(RECV_MODE);
	if (handle == NULL) {
		handle = irecv_init(WTF_MODE);
		if (handle == NULL) {
		    printf("No iPhone/iPod found.\n");
		    return -1;
		    
		} else {
		    printf("Found iPhone/iPod in DFU/WTF mode\n");
		}
	} else {
	    printf("Found iPhone/iPod in Recovery mode\n");
	}
	
	if(!strcmp(argv[1], "-f")) {
	    if(argc == 3) {
            irecv_upload(handle, argv[2]);
        }
            
	} else if(!strcmp(argv[1], "-c")) {
	   	if(argc >= 3) {
	        irecv_command(handle, argc-2, &argv[2]);
	    }

	} else if(!strcmp(argv[1], "-k")) {
	   	if(argc >= 3) {
	        irecv_exploit(handle, argv[2]);
	    } else {
	        irecv_exploit(handle, NULL);
	    }

	} else if(!strcmp(argv[1], "-s")) {
	   	if(argc >= 3) {
            irecv_console(handle, argv[2]);
	    } else {
	        irecv_console(handle, NULL);
	    }
	    
	} else if(!strcmp(argv[1], "-r")) {
        irecv_reset(handle);
	} else if (!strcmp(argv[1], "-l")) {
	    irecv_list(handle, argv[2]);
	}
	  else if (!strcmp(argv[1], "-x")) {
	    if(argc == 3) {
	    irecv_upload(handle, argv[2]);
	    irecv_reset(handle);
		}
	}
	irecv_close(handle);
	return 0;
}
예제 #2
0
int main(int argc, char *argv[]) {
	printf("iRecovery - Recovery Utility\n");
	printf("by westbaer\nThanks to pod2g, tom3q, planetbeing and geohot.\n\n");
	if(argc < 2) {
		irecv_usage();
		exit(EXIT_FAILURE);
	}

	if(argv[1][0] != '-') {
		irecv_usage();
		exit(EXIT_FAILURE);
	}
	
	signal(SIGINT, irecv_quit); // Close USB on ^C
	
	if(strcmp(argv[1], "-f") == 0) {
		if(argc < 3) {
			printf("No valid file set.\n");
			exit(EXIT_FAILURE);
		} 

		irecv_sendfile(argv[2]);
	} else if(strcmp(argv[1], "-c") == 0) {
		irecv_sendcmd(argv[2]);
	} else if(strcmp(argv[1], "-s") == 0) {
		irecv_console();
	} else if(strcmp(argv[1], "-r") == 0) {
		irecv_reset();
	}
	
	return 0;
}
예제 #3
0
irecv_error_t irecv_finish_transfer(irecv_client_t client) {
	int i = 0;
	unsigned int status = 0;

	if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;

	irecv_control_transfer(client, 0x21, 1, 0, 0, 0, 0, 1000);

	for(i = 0; i < 3; i++){
		irecv_get_status(client, &status);
	}
	irecv_reset(client);
	return IRECV_E_SUCCESS;
}
예제 #4
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;
}
예제 #5
0
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) {
	irecv_client_t dfu = NULL;
	const char* component = "iBSS";
	irecv_error_t dfu_error = IRECV_E_SUCCESS;

	if (recovery_open_with_timeout(client) < 0 || dfu->mode != kDfuMode) {
		error("ERROR: Unable to connect to DFU device\n");
		if (dfu)
			irecv_close(dfu);
		return -1;
	}

	if (recovery_send_component(client, build_identity, component) < 0) {
		error("ERROR: Unable to send %s to device\n", component);
		irecv_close(dfu);
		return -1;
	}

	dfu_error = irecv_reset(client->dfu->client);
	if (dfu_error != IRECV_E_SUCCESS) {
		error("ERROR: Unable to reset device\n");
		irecv_close(dfu);
		return -1;
	}
	irecv_close(client->dfu->client);
	client->dfu->client = NULL;

	// Reconnect to device, but this time make sure we're not still in DFU mode
	if (recovery_open_with_timeout(client) < 0 || client->mode->index != kDfuMode) {
		error("ERROR: Unable to connect to recovery device\n");
		if (client->dfu->client)
			irecv_close(client->dfu->client);
		return -1;
	}

	client->mode = &idevicerestore_modes[MODE_RECOVERY];
	irecv_close(client->dfu->client);
	client->dfu->client = NULL;
	return 0;
}
예제 #6
0
int irecv_parse(struct usb_dev_handle* handle, char* command) {
    	unsigned int status = 0;
    	char* action = strtok(strdup(command), " ");
	
    	if(!strcmp(action, "help")) {
		printf("Commands:\n");
		printf("\t/exit\t\t\texit from recovery console.\n");
		printf("\t/upload <file>\t\tupload file to device.\n");
		printf("\t/exploit [payload]\tsend usb exploit packet.\n");
		printf("\t/reset\t\t\tsend usb reset.\n");
	    
    	} else if(!strcmp(action, "exit")) {
		free(action);
		return -1;
	    
    	} else if (!strcmp(action, "reset")) {
		irecv_reset(handle);
        	return 0;

    	} else if(strcmp(action, "upload") == 0) {
		char* filename = strtok(NULL, " ");
	
		if(filename != NULL) {
            		irecv_upload(handle, filename);
			
		} else if(strcmp(action, "exploit") == 0) {
	    		char* payload = strtok(NULL, " ");
	    
            		if (payload != NULL) {
				irecv_exploit(handle, payload);
	   		} else {
				irecv_exploit(handle, NULL);
	   		}
		} 
	
	free(action);
	return 0;
    }
}
예제 #7
0
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);
	if (check_context(client) != IRECV_E_SUCCESS) return IRECV_E_NO_DEVICE;

	int packet_size = 0x800;
	int last = length % packet_size;
	int packets = length / packet_size;
	if (last != 0) {
		packets++;
	} else {
		last = packet_size;
	}

	/* initiate transfer */
	if (recovery_mode) {
		error = irecv_control_transfer(client, 0x41, 0, 0, 0, NULL, 0, 1000);
	} else {
		error = irecv_control_transfer(client, 0x21, 4, 0, 0, NULL, 0, 1000);
	}
	if (error != IRECV_E_SUCCESS) {
		return error;
	}

	int i = 0;
	double progress = 0;
	unsigned long count = 0;
	unsigned int status = 0;
	int bytes = 0;
	for (i = 0; i < packets; i++) {
		int size = (i + 1) < packets ? packet_size : last;

		/* Use bulk transfer for recovery mode and control transfer for DFU and WTF mode */
		if (recovery_mode) {
			error = irecv_bulk_transfer(client, 0x04, &buffer[i * packet_size], size, &bytes, 1000);
		} else {
			bytes = irecv_control_transfer(client, 0x21, 1, 0, 0, &buffer[i * packet_size], size, 1000);
		}

		if (bytes != size) {
			return IRECV_E_USB_UPLOAD;
		}

		if (!recovery_mode) {
			error = irecv_get_status(client, &status);
		}

		if (error != IRECV_E_SUCCESS) {
			return error;
		}

		if (!recovery_mode && status != 5) {
			return IRECV_E_USB_UPLOAD;
		}

		count += size;
		if(client->progress_callback != NULL) {
			irecv_event_t event;
			event.progress = ((double) count/ (double) length) * 100.0;
			event.type = IRECV_PROGRESS;
			event.data = "Uploading";
			event.size = count;
			client->progress_callback(client, &event);
		} else {
			debug("Sent: %d bytes - %lu of %lu\n", bytes, count, length);
		}
	}

	if (dfuNotifyFinished && !recovery_mode) {
		irecv_control_transfer(client, 0x21, 1, 0, 0, (unsigned char*) buffer, 0, 1000);

		for (i = 0; i < 3; i++) {
			error = irecv_get_status(client, &status);
			if (error != IRECV_E_SUCCESS) {
				return error;
			}
		}
		irecv_reset(client);
	}

	return IRECV_E_SUCCESS;
}
예제 #8
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();
	while ((opt = getopt(argc, argv, "vhrsc:f:e:k::")) > 0) {
		switch (opt) {
		case 'v':
			verbose += 1;
			break;

		case 'h':
			print_usage();
			break;

		case 'r':
			action = kResetDevice;
			break;

		case 's':
			action = kStartShell;
			break;

		case 'f':
			action = kSendFile;
			argument = optarg;
			break;

		case 'c':
			action = kSendCommand;
			argument = optarg;
			break;

		case 'k':
			action = kSendExploit;
			argument = optarg;
			break;

		case 'e':
			action = kSendScript;
			argument = optarg;
			break;

		default:
			fprintf(stderr, "Unknown argument\n");
			return -1;
		}
	}

	if (verbose) irecv_set_debug_level(verbose);

	irecv_init();
	irecv_client_t client = NULL;
	for (i = 0; i <= 5; i++) {
		debug("Attempting to connect... \n");

		if (irecv_open(&client) != IRECV_E_SUCCESS)
			sleep(1);
		else
			break;

		if (i == 5) {
			return -1;
		}
	}

	switch (action) {
	case kResetDevice:
		irecv_reset(client);
		break;

	case kSendFile:
		irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
		error = irecv_send_file(client, argument, 1);
		debug("%s\n", irecv_strerror(error));
		break;

	case kSendCommand:
		error = irecv_send_command(client, argument);
		debug("%s\n", irecv_strerror(error));
		break;

	case kSendExploit:
		if (argument != NULL) {
			irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
			error = irecv_send_file(client, argument, 0);
			if (error != IRECV_E_SUCCESS) {
				debug("%s\n", irecv_strerror(error));
				break;
			}
		}
		error = irecv_send_exploit(client);
		debug("%s\n", irecv_strerror(error));
		break;

	case kStartShell:
		init_shell(client);
		break;

	case kSendScript:
		error = irecv_execute_script(client, argument);
		if(error != IRECV_E_SUCCESS) {
			debug("%s\n", irecv_strerror(error));
		}
		break;

	default:
		fprintf(stderr, "Unknown action\n");
		break;
	}

	irecv_close(client);
	return 0;
}
예제 #9
0
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) {
	irecv_error_t dfu_error = IRECV_E_SUCCESS;

	if (dfu_client_new(client) < 0) {
		error("ERROR: Unable to connect to DFU device\n");
		return -1;
	}

	if (client->dfu->client->mode != kDfuMode) {
		info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
		client->mode = &idevicerestore_modes[MODE_RECOVERY];
		return 0;
	}

	if (dfu_send_component(client, build_identity, "iBSS") < 0) {
		error("ERROR: Unable to send iBSS to device\n");
		irecv_close(client->dfu->client);
		return -1;
	}

	dfu_error = irecv_reset(client->dfu->client);
	if (dfu_error != IRECV_E_SUCCESS) {
		error("ERROR: Unable to reset device\n");
		irecv_close(client->dfu->client);
		return -1;
	}

	if (client->build[0] > '8') {
		/* reconnect */
		dfu_client_free(client);
		sleep(1);
		dfu_client_new(client);

		/* get nonce */
		unsigned char* nonce = NULL;
		int nonce_size = 0;
		int nonce_changed = 0;
		if (dfu_get_nonce(client, &nonce, &nonce_size) < 0) {
			error("ERROR: Unable to get nonce from device!\n");
			return -1;
		}

		if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) {
			nonce_changed = 1;
			if (client->nonce) {
				free(client->nonce);
			}
			client->nonce = nonce;
			client->nonce_size = nonce_size;
		} else {
			free(nonce);
		}

		info("Nonce: ");
		int i;
		for (i = 0; i < client->nonce_size; i++) {
			info("%02x ", client->nonce[i]);
		}
		info("\n");

		if (nonce_changed && !(client->flags & FLAG_CUSTOM)) {
			// Welcome iOS5. We have to re-request the TSS with our nonce.
			plist_free(client->tss);
			if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) {
				error("ERROR: Unable to get SHSH blobs for this device\n");
				return -1;
			}
			if (!client->tss) {
				error("ERROR: can't continue without TSS\n");
				return -1;
			}
			fixup_tss(client->tss);
		}

		if (irecv_set_configuration(client->dfu->client, 1) < 0) {
			error("ERROR: set configuration failed\n");
		}

		/* send iBEC */
		if (dfu_send_component(client, build_identity, "iBEC") < 0) {
			error("ERROR: Unable to send iBEC to device\n");
			irecv_close(client->dfu->client);
			return -1;
		}

		dfu_error = irecv_reset(client->dfu->client);
		if (dfu_error != IRECV_E_SUCCESS) {
			error("ERROR: Unable to reset device\n");
			irecv_close(client->dfu->client);
			return -1;
		}
	}

	dfu_client_free(client);

	sleep(7);

	// Reconnect to device, but this time make sure we're not still in DFU mode
	if (recovery_client_new(client) < 0 || client->recovery->client->mode == kDfuMode) {
		error("ERROR: Unable to connect to recovery device\n");
		if (client->recovery->client)
			irecv_close(client->recovery->client);
		return -1;
	}
	return 0;
}
예제 #10
0
int limera1n_exploit(struct idevicerestore_device_t *device, irecv_client_t client)
{
    irecv_error_t error = IRECV_E_SUCCESS;
    unsigned int i = 0;
    unsigned char buf[0x800];
    unsigned char shellcode[0x800];
    unsigned int max_size = 0x24000;
    //unsigned int load_address = 0x84000000;
    unsigned int stack_address = 0x84033F98;
    unsigned int shellcode_address = 0x84023001;
    unsigned int shellcode_length = 0;


    if (device->chip_id == 8930) {
        max_size = 0x2C000;
        stack_address = 0x8403BF9C;
        shellcode_address = 0x8402B001;
    }
    if (device->chip_id == 8920) {
        max_size = 0x24000;
        stack_address = 0x84033FA4;
        shellcode_address = 0x84023001;
    }

    memset(shellcode, 0x0, 0x800);
    shellcode_length = sizeof(limera1n_payload);
    memcpy(shellcode, limera1n_payload, sizeof(limera1n_payload));

    debug("Resetting device counters\n");
    error = irecv_reset_counters(client);
    if (error != IRECV_E_SUCCESS) {
        error("%s\n", irecv_strerror(error));
        return -1;
    }

    memset(buf, 0xCC, 0x800);
    for(i = 0; i < 0x800; i += 0x40) {
        unsigned int* heap = (unsigned int*)(buf+i);
        heap[0] = 0x405;
        heap[1] = 0x101;
        heap[2] = shellcode_address;
        heap[3] = stack_address;
    }

    debug("Sending chunk headers\n");
    irecv_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000);

    memset(buf, 0xCC, 0x800);
    for(i = 0; i < (max_size - (0x800 * 3)); i += 0x800) {
        irecv_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000);
    }

    debug("Sending exploit payload\n");
    irecv_control_transfer(client, 0x21, 1, 0, 0, shellcode, 0x800, 1000);

    debug("Sending fake data\n");
    memset(buf, 0xBB, 0x800);
    irecv_control_transfer(client, 0xA1, 1, 0, 0, buf, 0x800, 1000);
    irecv_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 10);

    //debug("Executing exploit\n");
    irecv_control_transfer(client, 0x21, 2, 0, 0, buf, 0, 1000);

    irecv_reset(client);
    irecv_finish_transfer(client);
    debug("Exploit sent\n");

    debug("Reconnecting to device\n");
    client = irecv_reconnect(client, 7);
    if (client == NULL) {
        debug("%s\n", irecv_strerror(error));
        error("Unable to reconnect\n");
        return -1;
    }

    return 0;
}
예제 #11
0
int main(int argc, char* argv[]) {
	int i = 0;
	int opt = 0;
	int action = 0;
	unsigned long long ecid = 0;
	int mode = -1;
	char* argument = NULL;
	irecv_error_t error = 0;

	char* buffer = NULL;
	uint64_t buffer_length = 0;

	if (argc == 1) {
		print_usage(argc, argv);
		return 0;
	}

	while ((opt = getopt(argc, argv, "i:vhrsmnc:f:e:k::")) > 0) {
		switch (opt) {
			case 'i':
				if (optarg) {
					char* tail = NULL;
					ecid = strtoull(optarg, &tail, 16);
					if (tail && (tail[0] != '\0')) {
						ecid = 0;
					}
					if (ecid == 0) {
						fprintf(stderr, "ERROR: Could not parse ECID from argument '%s'\n", optarg);
						return -1;
					}
				}
				break;

			case 'v':
				verbose += 1;
				break;

			case 'h':
				print_usage(argc, argv);
				return 0;

			case 'm':
				action = kShowMode;
				break;

			case 'n':
				action = kRebootToNormalMode;
				break;

			case 'r':
				action = kResetDevice;
				break;

			case 's':
				action = kStartShell;
				break;

			case 'f':
				action = kSendFile;
				argument = optarg;
				break;

			case 'c':
				action = kSendCommand;
				argument = optarg;
				break;

			case 'k':
				action = kSendExploit;
				argument = optarg;
				break;

			case 'e':
				action = kSendScript;
				argument = optarg;
				break;

			default:
				fprintf(stderr, "Unknown argument\n");
				return -1;
		}
	}

	if (verbose)
		irecv_set_debug_level(verbose);

	irecv_init();
	irecv_client_t client = NULL;
	for (i = 0; i <= 5; i++) {
		debug("Attempting to connect... \n");

		if (irecv_open_with_ecid(&client, ecid) != IRECV_E_SUCCESS)
			sleep(1);
		else
			break;

		if (i == 5) {
			return -1;
		}
	}

	irecv_device_t device = NULL;
	irecv_devices_get_device_by_client(client, &device);
	if (device)
		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);

	switch (action) {
		case kResetDevice:
			irecv_reset(client);
			break;

		case kSendFile:
			irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
			error = irecv_send_file(client, argument, 1);
			debug("%s\n", irecv_strerror(error));
			break;

		case kSendCommand:
			error = irecv_send_command(client, argument);
			debug("%s\n", irecv_strerror(error));
			break;

		case kSendExploit:
			if (argument != NULL) {
				irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
				error = irecv_send_file(client, argument, 0);
				if (error != IRECV_E_SUCCESS) {
					debug("%s\n", irecv_strerror(error));
					break;
				}
			}
			error = irecv_trigger_limera1n_exploit(client);
			debug("%s\n", irecv_strerror(error));
			break;

		case kStartShell:
			init_shell(client);
			break;

		case kSendScript:
			buffer_read_from_filename(argument, &buffer, &buffer_length);
			if (buffer) {
				buffer[buffer_length] = '\0';

				error = irecv_execute_script(client, buffer);
				if(error != IRECV_E_SUCCESS) {
					debug("%s\n", irecv_strerror(error));
				}

				free(buffer);
			} else {
				fprintf(stderr, "Could not read file '%s'\n", argument);
			}
			break;

		case kShowMode:
			irecv_get_mode(client, &mode);
			printf("%s Mode\n", mode_to_str(mode));
			break;

		case kRebootToNormalMode:
			error = irecv_setenv(client, "auto-boot", "true");
			if (error != IRECV_E_SUCCESS) {
				debug("%s\n", irecv_strerror(error));
				break;
			}

			error = irecv_saveenv(client);
			if (error != IRECV_E_SUCCESS) {
				debug("%s\n", irecv_strerror(error));
				break;
			}

			error = irecv_reboot(client);
			if (error != IRECV_E_SUCCESS) {
				debug("%s\n", irecv_strerror(error));
			} else {
				debug("%s\n", irecv_strerror(error));
			}
			break;
		default:
			fprintf(stderr, "Unknown action\n");
			break;
	}

	irecv_close(client);

	return 0;
}
예제 #12
0
int main(int argc, char *argv[]) {
	printf("iRecovery - Recovery Utility\n");
	printf("by westbaer\nThanks to pod2g, tom3q, planetbeing, geohot and posixninja.\n\n");

	if(argc < 2) {
		irecv_usage();
		return -1;
	}

        if(!strcmp(argv[1], "-q")) {
                enter_recovery();

        } 

	struct usb_dev_handle* handle = irecv_init(RECV_MODE);

	if (handle == NULL) {
		handle = irecv_init(WTF_MODE);
		if (handle == NULL) {
			printf("No iPhone/iPod found.\n");
		    	return -1;
		    
		} else {
		   	printf("Found iPhone/iPod in DFU/WTF mode\n");

		}

	} else {
	    	printf("Found iPhone/iPod in Recovery mode\n");

	}

	if (((irecv_command(handle, 1, "setenv auto-boot true")) == -1) ||
            ((irecv_command(handle, 1, "saveenv")) == -1))
                printf("Failed to set auto-boot");

	if(!strcmp(argv[1], "-f")) {
	    	if(argc == 3) {
                	irecv_upload(handle, argv[2]);

            	}
            
	} else if(!strcmp(argv[1], "-c")) {
	   	if(argc >= 3) {
	            	irecv_command(handle, argc-2, &argv[2]);

	        } 

	} else if(!strcmp(argv[1], "-k")) {
	   	if(argc >= 3) {
	            	irecv_exploit(handle, argv[2]);
	        } else {
	            	irecv_exploit(handle, NULL);
	        }
	    
	} else if(!strcmp(argv[1], "-k")) {
	   	if(argc >= 3) {
	            	irecv_exploit(handle, argv[2]);
	        }

	} else if(!strcmp(argv[1], "-x40")) {
	   	if(argc >= 3) {
	            	irecv_sendrawusb0x40(handle, argv[2]);
	        }
	    
	} else if(!strcmp(argv[1], "-x21")) {
	   	if(argc >= 3) {
	            	irecv_sendrawusb0x21(handle, argv[2]);
	        }
	    
	} else if(!strcmp(argv[1], "-xA1")) {
	   	if(argc >= 3) {
	            	irecv_sendrawusb0xA1(handle, argv[2]);
	        }

	} else if(!strcmp(argv[1], "-s")) {
	   	if(argc >= 3) {
                    	irecv_console(handle, argv[2]);
	        } else {
	            	irecv_console(handle, NULL);
	        }
	    
	} else if(!strcmp(argv[1], "-r")) {
                irecv_reset(handle);

	} else if (!strcmp(argv[1], "-l")) {
	        irecv_list(handle, argv[2]);

	} else if (!strcmp(argv[1], "-x")) {
		if (argc == 3) {
		    	irecv_upload(handle, argv[2]);
		    	irecv_reset(handle);
		}

	}
	
	irecv_close(handle);
	return 0;
}