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