summaryrefslogtreecommitdiffstats
path: root/tools/irecovery.c
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2013-09-26 09:45:58 +0200
committerGravatar Martin Szulecki2013-09-26 09:45:58 +0200
commit9099c5d9e28ca6348fc1b0431f47e2592649ae84 (patch)
tree3793c93f6f81061f78c3a78921d9c47c950c41c1 /tools/irecovery.c
parente8aef4a02bb11d38dafd20108e86ab543f0987f6 (diff)
downloadlibirecovery-9099c5d9e28ca6348fc1b0431f47e2592649ae84.tar.gz
libirecovery-9099c5d9e28ca6348fc1b0431f47e2592649ae84.tar.bz2
Move irecovery to new tools directory
Diffstat (limited to 'tools/irecovery.c')
-rw-r--r--tools/irecovery.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/tools/irecovery.c b/tools/irecovery.c
new file mode 100644
index 0000000..075ee79
--- /dev/null
+++ b/tools/irecovery.c
@@ -0,0 +1,400 @@
1/*
2 * irecovery.c - software frontend for iBoot/iBSS communication for iOS devices
3 *
4 * Copyright (c) 2012-2013 Martin Szulecki <m.szulecki@libimobiledevice.org>
5 * Copyright (c) 2010-2011 Chronic-Dev Team
6 * Copyright (c) 2010-2011 Joshua Hill
7 * Copyright (c) 2008-2011 Nicolas Haunold
8 *
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the GNU Lesser General Public License
11 * (LGPL) version 2.1 which accompanies this distribution, and is available at
12 * http://www.gnu.org/licenses/lgpl-2.1.html
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <string.h>
24#include <libirecovery.h>
25#include <readline/readline.h>
26#include <readline/history.h>
27
28#define FILE_HISTORY_PATH ".irecovery"
29#define debug(...) if(verbose) fprintf(stderr, __VA_ARGS__)
30
31enum {
32 kResetDevice, kStartShell, kSendCommand, kSendFile, kSendExploit, kSendScript
33};
34
35static unsigned int quit = 0;
36static unsigned int verbose = 0;
37
38void print_progress_bar(double progress);
39int received_cb(irecv_client_t client, const irecv_event_t* event);
40int progress_cb(irecv_client_t client, const irecv_event_t* event);
41int precommand_cb(irecv_client_t client, const irecv_event_t* event);
42int postcommand_cb(irecv_client_t client, const irecv_event_t* event);
43
44static void shell_usage() {
45 printf("Usage:\n");
46 printf("\t/upload <file>\tSend file to client.\n");
47 printf("\t/exploit [file]\tSend usb exploit with optional payload\n");
48 printf("\t/deviceinfo\tShow device information (ECID, IMEI, etc.)\n");
49 printf("\t/help\t\tShow this help.\n");
50 printf("\t/exit\t\tExit interactive shell.\n");
51}
52
53static void parse_command(irecv_client_t client, unsigned char* command, unsigned int size) {
54 char* cmd = strdup((char*)command);
55 char* action = strtok(cmd, " ");
56 debug("Executing %s\n", action);
57 if (!strcmp(cmd, "/exit")) {
58 quit = 1;
59 } else
60
61 if (!strcmp(cmd, "/help")) {
62 shell_usage();
63 } else
64
65 if (!strcmp(cmd, "/upload")) {
66 char* filename = strtok(NULL, " ");
67 debug("Uploading files %s\n", filename);
68 if (filename != NULL) {
69 irecv_send_file(client, filename, 0);
70 }
71 } else
72
73 if (!strcmp(cmd, "/deviceinfo")) {
74 int ret;
75 unsigned int cpid, bdid;
76 unsigned long long ecid;
77 char srnm[12], imei[15];
78
79 ret = irecv_get_cpid(client, &cpid);
80 if(ret == IRECV_E_SUCCESS) {
81 printf("CPID: %d\n", cpid);
82 }
83
84 ret = irecv_get_bdid(client, &bdid);
85 if(ret == IRECV_E_SUCCESS) {
86 printf("BDID: %d\n", bdid);
87 }
88
89 ret = irecv_get_ecid(client, &ecid);
90 if(ret == IRECV_E_SUCCESS) {
91 printf("ECID: %lld\n", ecid);
92 }
93
94 ret = irecv_get_srnm(client, srnm);
95 if(ret == IRECV_E_SUCCESS) {
96 printf("SRNM: %s\n", srnm);
97 }
98
99 ret = irecv_get_imei(client, imei);
100 if(ret == IRECV_E_SUCCESS) {
101 printf("IMEI: %s\n", imei);
102 }
103 } else
104
105 if (!strcmp(cmd, "/exploit")) {
106 char* filename = strtok(NULL, " ");
107 debug("Sending exploit %s\n", filename);
108 if (filename != NULL) {
109 irecv_send_file(client, filename, 0);
110 }
111 irecv_send_exploit(client);
112 } else
113
114 if (!strcmp(cmd, "/execute")) {
115 char* filename = strtok(NULL, " ");
116 debug("Executing script %s\n", filename);
117 if (filename != NULL) {
118 irecv_execute_script(client, filename);
119 }
120 }
121
122
123 free(action);
124}
125
126static void load_command_history() {
127 read_history(FILE_HISTORY_PATH);
128}
129
130static void append_command_to_history(char* cmd) {
131 add_history(cmd);
132 write_history(FILE_HISTORY_PATH);
133}
134
135static void init_shell(irecv_client_t client) {
136 irecv_error_t error = 0;
137 load_command_history();
138 irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
139 irecv_event_subscribe(client, IRECV_RECEIVED, &received_cb, NULL);
140 irecv_event_subscribe(client, IRECV_PRECOMMAND, &precommand_cb, NULL);
141 irecv_event_subscribe(client, IRECV_POSTCOMMAND, &postcommand_cb, NULL);
142 while (!quit) {
143 error = irecv_receive(client);
144
145 if (error != IRECV_E_SUCCESS) {
146 debug("%s\n", irecv_strerror(error));
147 break;
148 }
149
150 char* cmd = readline("> ");
151 if (cmd && *cmd) {
152 error = irecv_send_command(client, cmd);
153 if (error != IRECV_E_SUCCESS) {
154 quit = 1;
155 }
156
157 append_command_to_history(cmd);
158 free(cmd);
159 }
160 }
161}
162
163int received_cb(irecv_client_t client, const irecv_event_t* event) {
164 if (event->type == IRECV_RECEIVED) {
165 int i = 0;
166 int size = event->size;
167 const char* data = event->data;
168 for (i = 0; i < size; i++) {
169 printf("%c", data[i]);
170 }
171 }
172 return 0;
173}
174
175int precommand_cb(irecv_client_t client, const irecv_event_t* event) {
176 if (event->type == IRECV_PRECOMMAND) {
177 if (event->data[0] == '/') {
178 parse_command(client, (unsigned char*)event->data, event->size);
179 return -1;
180 }
181 }
182 return 0;
183}
184
185int postcommand_cb(irecv_client_t client, const irecv_event_t* event) {
186 char* value = NULL;
187 char* action = NULL;
188 char* command = NULL;
189 char* argument = NULL;
190 irecv_error_t error = IRECV_E_SUCCESS;
191
192 if (event->type == IRECV_POSTCOMMAND) {
193 command = strdup(event->data);
194 action = strtok(command, " ");
195 if (!strcmp(action, "getenv")) {
196 argument = strtok(NULL, " ");
197 error = irecv_getenv(client, argument, &value);
198 if (error != IRECV_E_SUCCESS) {
199 debug("%s\n", irecv_strerror(error));
200 free(command);
201 return error;
202 }
203 printf("%s\n", value);
204 free(value);
205 }
206
207 if (!strcmp(action, "reboot")) {
208 quit = 1;
209 }
210 }
211
212 if (command) free(command);
213 return 0;
214}
215
216int progress_cb(irecv_client_t client, const irecv_event_t* event) {
217 if (event->type == IRECV_PROGRESS) {
218 print_progress_bar(event->progress);
219 }
220 return 0;
221}
222
223void print_progress_bar(double progress) {
224 int i = 0;
225 if(progress < 0) {
226 return;
227 }
228
229 if(progress > 100) {
230 progress = 100;
231 }
232
233 printf("\r[");
234 for(i = 0; i < 50; i++) {
235 if(i < progress / 2) {
236 printf("=");
237 } else {
238 printf(" ");
239 }
240 }
241
242 printf("] %3.1f%%", progress);
243 fflush(stdout);
244 if(progress == 100) {
245 printf("\n");
246 }
247}
248
249static void print_usage() {
250 printf("iRecovery - iDevice Recovery Utility\n");
251 printf("Usage: irecovery [args]\n");
252 printf("\t-i <ecid>\tTarget specific device by its hexadecimal ECID\n");
253 printf("\t-v\t\tStart irecovery in verbose mode.\n");
254 printf("\t-c <cmd>\tSend command to client.\n");
255 printf("\t-f <file>\tSend file to client.\n");
256 printf("\t-k [payload]\tSend usb exploit to client.\n");
257 printf("\t-h\t\tShow this help.\n");
258 printf("\t-r\t\tReset client.\n");
259 printf("\t-s\t\tStart interactive shell.\n");
260 printf("\t-e <script>\tExecutes recovery shell script.\n");
261 exit(1);
262}
263
264int main(int argc, char* argv[]) {
265 int i = 0;
266 int opt = 0;
267 int action = 0;
268 unsigned long long ecid = 0;
269 char* argument = NULL;
270 irecv_error_t error = 0;
271 if (argc == 1) print_usage();
272 while ((opt = getopt(argc, argv, "i:vhrsc:f:e:k::")) > 0) {
273 switch (opt) {
274 case 'i':
275 if (optarg) {
276 char* tail = NULL;
277 ecid = strtoull(optarg, &tail, 16);
278 if (tail && (tail[0] != '\0')) {
279 ecid = 0;
280 }
281 if (ecid == 0) {
282 fprintf(stderr, "ERROR: Could not parse ECID from argument '%s'\n", optarg);
283 return -1;
284 }
285 }
286 break;
287
288 case 'v':
289 verbose += 1;
290 break;
291
292 case 'h':
293 print_usage();
294 break;
295
296 case 'r':
297 action = kResetDevice;
298 break;
299
300 case 's':
301 action = kStartShell;
302 break;
303
304 case 'f':
305 action = kSendFile;
306 argument = optarg;
307 break;
308
309 case 'c':
310 action = kSendCommand;
311 argument = optarg;
312 break;
313
314 case 'k':
315 action = kSendExploit;
316 argument = optarg;
317 break;
318
319 case 'e':
320 action = kSendScript;
321 argument = optarg;
322 break;
323
324 default:
325 fprintf(stderr, "Unknown argument\n");
326 return -1;
327 }
328 }
329
330 if (verbose) irecv_set_debug_level(verbose);
331
332 irecv_init();
333 irecv_client_t client = NULL;
334 for (i = 0; i <= 5; i++) {
335 debug("Attempting to connect... \n");
336
337 if (irecv_open(&client, ecid) != IRECV_E_SUCCESS)
338 sleep(1);
339 else
340 break;
341
342 if (i == 5) {
343 return -1;
344 }
345 }
346
347 irecv_device_t device = NULL;
348 irecv_get_device(client, &device);
349 if (device)
350 debug("Connected to %s, model %s, cpid 0x%04x, bdid 0x%02x\n", device->product, device->model, device->chip_id, device->board_id);
351
352 switch (action) {
353 case kResetDevice:
354 irecv_reset(client);
355 break;
356
357 case kSendFile:
358 irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
359 error = irecv_send_file(client, argument, 1);
360 debug("%s\n", irecv_strerror(error));
361 break;
362
363 case kSendCommand:
364 error = irecv_send_command(client, argument);
365 debug("%s\n", irecv_strerror(error));
366 break;
367
368 case kSendExploit:
369 if (argument != NULL) {
370 irecv_event_subscribe(client, IRECV_PROGRESS, &progress_cb, NULL);
371 error = irecv_send_file(client, argument, 0);
372 if (error != IRECV_E_SUCCESS) {
373 debug("%s\n", irecv_strerror(error));
374 break;
375 }
376 }
377 error = irecv_send_exploit(client);
378 debug("%s\n", irecv_strerror(error));
379 break;
380
381 case kStartShell:
382 init_shell(client);
383 break;
384
385 case kSendScript:
386 error = irecv_execute_script(client, argument);
387 if(error != IRECV_E_SUCCESS) {
388 debug("%s\n", irecv_strerror(error));
389 }
390 break;
391
392 default:
393 fprintf(stderr, "Unknown action\n");
394 break;
395 }
396
397 irecv_close(client);
398 return 0;
399}
400