diff options
| -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 {  	kSendCommand,  	kSendFile,  	kSendExploit, -	kSendScript +	kSendScript, +	kShowMode, +	kRebootToNormalMode  };  static unsigned int quit = 0; @@ -255,19 +257,51 @@ void print_progress_bar(double progress) {  	}  } -static void print_usage() { -	printf("iRecovery - iDevice Recovery Utility\n"); -	printf("Usage: irecovery [args]\n"); -	printf("\t-i <ecid>\tTarget specific device by its hexadecimal ECID\n"); -	printf("\t-v\t\tStart irecovery in verbose mode.\n"); -	printf("\t-c <cmd>\tSend command to client.\n"); -	printf("\t-f <file>\tSend file to client.\n"); -	printf("\t-k [payload]\tSend usb exploit to client.\n"); -	printf("\t-h\t\tShow this help.\n"); -	printf("\t-r\t\tReset client.\n"); -	printf("\t-s\t\tStart interactive shell.\n"); -	printf("\t-e <script>\tExecutes recovery shell script.\n"); -	exit(1); +static void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length) { +	FILE *f; +	uint64_t size; + +	*length = 0; + +	f = fopen(filename, "rb"); +	if (!f) { +		return; +	} + +	fseek(f, 0, SEEK_END); +	size = ftell(f); +	rewind(f); + +	if (size == 0) { +		fclose(f); +		return; +	} + +	*buffer = (char*)malloc(sizeof(char)*(size+1)); +	fread(*buffer, sizeof(char), size, f); +	fclose(f); + +	*length = size; +} + +static void print_usage(int argc, char **argv) { +	char *name = NULL; +	name = strrchr(argv[0], '/'); +	printf("Usage: %s [OPTIONS]\n", (name ? name + 1: argv[0])); +	printf("Interact with a iBSS/iBoot iOS device in DFU or recovery mode.\n\n"); +	printf("options:\n"); +	printf("  -i ECID\tconnect to specific device by its hexadecimal ECID\n"); +	printf("  -c CMD\trun CMD on device\n"); +	printf("  -m\t\tprint current device mode\n"); +	printf("  -f FILE\tsend file to device\n"); +	printf("  -k FILE\tsend limera1in usb exploit payload from FILE\n"); +	printf("  -r\t\treset client\n"); +	printf("  -n\t\treboot device into normal mode (exit recovery loop)\n"); +	printf("  -e FILE\texecutes recovery script from FILE\n"); +	printf("  -s\t\tstart an interactive shell\n"); +	printf("  -v\t\tenable verbose output, repeat for higher verbosity\n"); +	printf("  -h\t\tprints this usage information\n"); +	printf("\n");  }  int main(int argc, char* argv[]) { @@ -275,67 +309,81 @@ int main(int argc, char* argv[]) {  	int opt = 0;  	int action = 0;  	unsigned long long ecid = 0; +	int mode = -1;  	char* argument = NULL;  	irecv_error_t error = 0; -	if (argc == 1) -		print_usage(); +	char* buffer = NULL; +	uint64_t buffer_length = 0; -	while ((opt = getopt(argc, argv, "i:vhrsc:f:e:k::")) > 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; +			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; +				break; -		case 'v': -			verbose += 1; -			break; +			case 'v': +				verbose += 1; +				break; -		case 'h': -			print_usage(); -			break; +			case 'h': +				print_usage(argc, argv); +				return 0; -		case 'r': -			action = kResetDevice; -			break; +			case 'm': +				action = kShowMode; +				break; -		case 's': -			action = kStartShell; -			break; +			case 'n': +				action = kRebootToNormalMode; +				break; -		case 'f': -			action = kSendFile; -			argument = optarg; -			break; +			case 'r': +				action = kResetDevice; +				break; -		case 'c': -			action = kSendCommand; -			argument = optarg; -			break; +			case 's': +				action = kStartShell; +				break; -		case 'k': -			action = kSendExploit; -			argument = optarg; -			break; +			case 'f': +				action = kSendFile; +				argument = optarg; +				break; -		case 'e': -			action = kSendScript; -			argument = optarg; -			break; +			case 'c': +				action = kSendCommand; +				argument = optarg; +				break; -		default: -			fprintf(stderr, "Unknown argument\n"); -			return -1; +			case 'k': +				action = kSendExploit; +				argument = optarg; +				break; + +			case 'e': +				action = kSendScript; +				argument = optarg; +				break; + +			default: +				fprintf(stderr, "Unknown argument\n"); +				return -1;  		}  	} @@ -363,48 +411,96 @@ int main(int argc, char* argv[]) {  		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) { +		case kResetDevice: +			irecv_reset(client); +			break; + +		case kSendFile:  			irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL); -			error = irecv_send_file(client, argument, 0); +			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); +			buffer[buffer_length] = '\0'; + +			error = irecv_execute_script(client, buffer); +			if(error != IRECV_E_SUCCESS) { +				debug("%s\n", irecv_strerror(error)); +			} + +			if (buffer) +				free(buffer); + +			break; + +		case kShowMode: +			irecv_get_mode(client, &mode); +			switch (mode) { +				case IRECV_K_RECOVERY_MODE_1: +				case IRECV_K_RECOVERY_MODE_2: +				case IRECV_K_RECOVERY_MODE_3: +				case IRECV_K_RECOVERY_MODE_4: +					printf("Recovery Mode\n"); +					break; +				case IRECV_K_DFU_MODE: +					printf("DFU Mode\n"); +					break; +				case IRECV_K_WTF_MODE: +					printf("WTF Mode\n"); +					break; +				default: +					printf("Unknown Mode\n"); +					break; +			} +			break; + +		case kRebootToNormalMode: +			error = irecv_setenv(client, "auto-boot", "true");  			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: -		error = irecv_execute_script(client, argument); -		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; +			} -	default: -		fprintf(stderr, "Unknown action\n"); -		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); | 
