Release v4.18994 - Backdoor
[RRG-proxmark3.git] / client / src / proxmark3.c
blob7d93473a3bd9d5794e57fa1db0cfce41c2c97d02
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Main binary
17 //-----------------------------------------------------------------------------
19 #include "proxmark3.h"
21 #include <stdlib.h>
22 #include <limits.h>
23 #include <unistd.h>
24 #include <ctype.h>
25 #include <libgen.h> // basename
26 #include <time.h>
28 #include "pm3line.h"
29 #include "usart_defs.h"
30 #include "util_posix.h"
31 #include "proxgui.h"
32 #include "cmdmain.h"
33 #include "ui.h"
34 #include "cmdhw.h"
35 #include "whereami.h"
36 #include "comms.h"
37 #include "fileutils.h"
38 #include "flash.h"
39 #include "preferences.h"
40 #include "commonutil.h"
42 #ifndef _WIN32
43 #include <locale.h>
44 #endif
47 static int mainret = PM3_SUCCESS;
49 #ifndef LIBPM3
50 #define BANNERMSG1 ""
51 #define BANNERMSG2 " [ :coffee: ]"
52 #define BANNERMSG3 "Release v4.18994 - Backdoor"
54 typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode;
56 static void showBanner_logo(LogoMode mode) {
57 switch (mode) {
58 case UTF8: {
59 const char *sq = "\xE2\x96\x88"; // square block
60 const char *tr = "\xE2\x95\x97"; // top right corner
61 const char *tl = "\xE2\x95\x94"; // top left corner
62 const char *br = "\xE2\x95\x9D"; // bottom right corner
63 const char *bl = "\xE2\x95\x9A"; // bottom left corner
64 const char *hl = "\xE2\x95\x90"; // horiz line
65 const char *vl = "\xE2\x95\x91"; // vert line
66 const char *__ = " ";
68 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
69 sq, sq, sq, sq, sq, sq, tr, __, sq, sq, sq, tr, __, __, __, sq, sq, sq, tr, sq, sq, sq, sq, sq, tr, __);
70 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
71 sq, sq, tl, hl, hl, sq, sq, tr, sq, sq, sq, sq, tr, __, sq, sq, sq, sq, vl, bl, hl, hl, hl, sq, sq, tr);
72 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
73 sq, sq, sq, sq, sq, sq, tl, br, sq, sq, tl, sq, sq, sq, sq, tl, sq, sq, vl, __, sq, sq, sq, sq, tl, br);
74 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"),
75 sq, sq, tl, hl, hl, hl, br, __, sq, sq, vl, bl, sq, sq, tl, br, sq, sq, vl, __, bl, hl, hl, sq, sq, tr);
76 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG1,
77 sq, sq, vl, __, __, __, __, __, sq, sq, vl, __, bl, hl, br, __, sq, sq, vl, sq, sq, sq, sq, sq, tl, br);
78 PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG2,
79 bl, hl, br, __, __, __, __, __, bl, hl, br, __, __, __, __, __, bl, hl, br, bl, hl, hl, hl, hl, br, __);
80 break;
82 case ANSI: {
83 PrintAndLogEx(NORMAL, " " _CYAN_("8888888b. 888b d888 .d8888b. "));
84 PrintAndLogEx(NORMAL, " " _CYAN_("888 Y88b 8888b d8888 d88P Y88b "));
85 PrintAndLogEx(NORMAL, " " _CYAN_("888 888 88888b.d88888 .d88P "));
86 PrintAndLogEx(NORMAL, " " _CYAN_("888 d88P 888Y88888P888 8888\" "));
87 PrintAndLogEx(NORMAL, " " _CYAN_("8888888P\" 888 Y888P 888 \"Y8b. "));
88 PrintAndLogEx(NORMAL, " " _CYAN_("888 888 Y8P 888 888 888 "));
89 PrintAndLogEx(NORMAL, " " _CYAN_("888 888 \" 888 Y88b d88P") " " BANNERMSG1);
90 PrintAndLogEx(NORMAL, " " _CYAN_("888 888 888 \"Y8888P\"") " " BANNERMSG2);
91 break;
93 case ASCII: {
94 PrintAndLogEx(NORMAL, " 8888888b. 888b d888 .d8888b. ");
95 PrintAndLogEx(NORMAL, " 888 Y88b 8888b d8888 d88P Y88b ");
96 PrintAndLogEx(NORMAL, " 888 888 88888b.d88888 .d88P ");
97 PrintAndLogEx(NORMAL, " 888 d88P 888Y88888P888 8888\" ");
98 PrintAndLogEx(NORMAL, " 8888888P\" 888 Y888P 888 \"Y8b. ");
99 PrintAndLogEx(NORMAL, " 888 888 Y8P 888 888 888 ");
100 PrintAndLogEx(NORMAL, " 888 888 \" 888 Y88b d88P " BANNERMSG1);
101 PrintAndLogEx(NORMAL, " 888 888 888 \"Y8888P\" " BANNERMSG2);
102 break;
105 PrintAndLogEx(NORMAL, "");
106 PrintAndLogEx(NORMAL, BANNERMSG3);
109 static uint8_t detect_current_lang(void) {
110 #ifndef _WIN32
111 const char *lang = setlocale(LC_ALL, "");
112 if (lang == NULL) {
113 return 1;
115 if (memcmp(lang, "fr", 2) == 0) {
116 return 2;
118 if (memcmp(lang, "es", 2) == 0) {
119 return 3;
121 #endif
122 return 1;
125 static const char *get_quote(void) {
127 const char *quotes_en[] = {
128 "Fund creativity, empower dreams",
129 "Invest in open innovation",
130 "Donate, empower, grow, sustain",
131 "Back global innovation today",
132 "Fuel open source revolution",
133 "Contribute funds, drive progress",
134 "Sponsor innovation, build tomorrow",
135 "Consider supporting: fund innovation",
136 "Your donation fuels progress",
137 "Empower dreams with your support",
138 "Join us: finance creative freedom",
139 "Make an impact: donate today",
140 "Help us drive open innovation",
141 "Your support, our future",
142 "Invest in a better tomorrow",
143 "Every contribution powers change",
144 "Support us, shape the future",
145 "Ignite change: support open-source creativity",
146 "Together, we can innovate without limits",
149 const char *quotes_fr[] = {
150 "Financez la créativité, donnez pouvoir aux rêves",
151 "Investissez dans l'innovation ouverte",
152 "Donnez, habilitez, croissez, soutenez",
153 "Soutenez l'innovation mondiale aujourd'hui",
154 "Alimentez la révolution open source",
155 "Contribuez financièrement, poussez le progrès",
156 "Parrainez l'innovation, construisez demain",
157 "Envisagez de soutenir : financez l'innovation",
158 "Votre don alimente le progrès",
159 "Donnez pouvoir aux rêves avec votre soutien",
160 "Rejoignez-nous : financez la liberté créative",
161 "Faites une différence : donnez aujourd'hui",
162 "Aidez-nous à stimuler l'innovation ouverte",
163 "Votre soutien, notre avenir",
164 "Investissez dans un meilleur demain",
165 "Chaque contribution favorise le changement",
166 "Soutenez-nous, façonnez l'avenir",
167 "Allumez le changement : soutenez la créativité open-source",
168 "Ensemble, nous pouvons innover sans limites",
171 const char *quotes_es[] = {
172 "Financia la creatividad, empodera sueños",
173 "Invierte en innovación abierta",
174 "Dona, empodera, crece, sostén",
175 "Apoya la innovación global hoy",
176 "Impulsa la revolución de código abierto",
177 "Contribuye fondos, impulsa el progreso",
178 "Patrocina la innovación, construye el mañana",
179 "Considera apoyar: financia la innovación",
180 "Tu donación impulsa el progreso",
181 "Empodera sueños con tu apoyo",
182 "Únete a nosotros: financia la libertad creativa",
183 "Haz un impacto: dona hoy",
184 "Ayúdanos a impulsar la innovación abierta",
185 "Tu apoyo, nuestro futuro",
186 "Invierte en un mejor mañana",
187 "Cada contribución impulsa el cambio",
188 "Apóyanos, forma el futuro",
189 "Enciende el cambio: apoya la creatividad de código abierto",
190 "Juntos, podemos innovar sin límites",
193 srand((uint32_t)time(NULL));
194 int r = rand() % ARRAYLEN(quotes_en);
196 uint8_t lang = detect_current_lang();
197 switch (lang) {
198 case 2:
199 return quotes_fr[r];
200 case 3:
201 return quotes_es[r];
202 case 1:
203 default:
204 return quotes_en[r];
208 static void showBanner(void) {
209 uint8_t old_printAndLog = g_printAndLog;
210 g_printAndLog &= PRINTANDLOG_PRINT;
211 PrintAndLogEx(NORMAL, "\n");
213 #if defined(_WIN32)
214 if (GetConsoleCP() == 65001) {
215 // If on Windows and using UTF-8 then we need utf-8 ascii art for banner.
216 showBanner_logo(UTF8);
217 } else {
218 showBanner_logo(ANSI);
220 #elif defined(__linux__) || defined(__APPLE__)
221 showBanner_logo(ANSI);
222 #else
223 showBanner_logo(ASCII);
224 #endif
226 PrintAndLogEx(NORMAL, "");
227 PrintAndLogEx(NORMAL, " [ " _YELLOW_("%s!")" ]", get_quote());
228 PrintAndLogEx(NORMAL, " Patreon - https://www.patreon.com/iceman1001/");
229 PrintAndLogEx(NORMAL, " Paypal - https://www.paypal.me/iceman1001/");
230 PrintAndLogEx(NORMAL, "");
231 // PrintAndLogEx(NORMAL, " Monero");
232 // PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
233 PrintAndLogEx(NORMAL, "");
234 fflush(stdout);
235 g_printAndLog = old_printAndLog;
237 #endif //LIBPM3
239 static const char *prompt_dev = "";
240 static const char *prompt_ctx = "";
241 static const char *prompt_net = "";
244 static void prompt_set(void) {
245 if (g_session.pm3_present) {
247 switch (g_conn.send_via_ip) {
248 case PM3_TCPv4:
249 prompt_net = PROXPROMPT_NET_TCPV4;
250 break;
251 case PM3_TCPv6:
252 prompt_net = PROXPROMPT_NET_TCPV6;
253 break;
254 case PM3_UDPv4:
255 prompt_net = PROXPROMPT_NET_UDPV4;
256 break;
257 case PM3_UDPv6:
258 prompt_net = PROXPROMPT_NET_UDPV6;
259 break;
260 case PM3_NONE:
261 prompt_net = PROXPROMPT_NET_NONE;
262 break;
263 default:
264 break;
267 if (g_conn.send_via_fpc_usart)
268 prompt_dev = PROXPROMPT_DEV_FPC;
269 else
270 prompt_dev = PROXPROMPT_DEV_USB;
272 } else {
273 prompt_dev = PROXPROMPT_DEV_OFFLINE;
277 static void prompt_compose(char *buf, size_t buflen, const char *promptctx, const char *promptdev, const char *promptnet, bool no_newline) {
278 if (no_newline) {
279 snprintf(buf, buflen - 1, PROXPROMPT_COMPOSE, promptdev, promptnet, promptctx);
280 } else {
281 snprintf(buf, buflen - 1, "\r \r" PROXPROMPT_COMPOSE, promptdev, promptnet, promptctx);
285 static bool c_update_reconnect_prompt = false;
287 // This function is hooked via RL_EVENT_HOOK.
288 static int check_comm(void) {
289 // If communications thread goes down. Device disconnected then this should hook up PM3 again.
290 if (IsCommunicationThreadDead() && g_session.pm3_present) {
292 #ifndef HAVE_READLINE
293 PrintAndLogEx(INFO, _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n");
294 #endif
295 prompt_dev = PROXPROMPT_DEV_OFFLINE;
296 char prompt[PROXPROMPT_MAX_SIZE] = {0};
297 prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev, prompt_net, false);
298 char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
299 memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !g_session.supports_colors);
300 pm3line_update_prompt(prompt_filtered);
301 CloseProxmark(g_session.current_device);
302 StartReconnectProxmark();
303 c_update_reconnect_prompt = true;
305 // its alive again
306 if (c_update_reconnect_prompt && IsReconnectedOk() && g_session.pm3_present) {
308 prompt_set();
310 char prompt[PROXPROMPT_MAX_SIZE] = {0};
311 prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev, prompt_net, false);
312 char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
313 memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !g_session.supports_colors);
314 pm3line_update_prompt(prompt_filtered);
315 c_update_reconnect_prompt = false;
318 msleep(50);
319 return 0;
322 #if defined(_WIN32)
323 static bool DetectWindowsAnsiSupport(void) {
324 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
325 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
326 #endif
328 // disable colors if stdin or stdout are redirected
329 if ((! g_session.stdinOnTTY) || (! g_session.stdoutOnTTY))
330 return false;
332 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
333 DWORD dwMode = 0;
334 GetConsoleMode(hOut, &dwMode);
336 //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set
337 if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
338 return true;
340 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
342 return SetConsoleMode(hOut, dwMode) ? true : false;
344 #endif //_WIN32
346 // first slot is always NULL, indicating absence of script when idx=0
347 static FILE *cmdscriptfile[MAX_NESTED_CMDSCRIPT + 1] = {0};
348 static uint8_t cmdscriptfile_idx = 0;
349 static bool cmdscriptfile_stayafter = false;
351 int push_cmdscriptfile(char *path, bool stayafter) {
352 if (cmdscriptfile_idx == MAX_NESTED_CMDSCRIPT) {
353 PrintAndLogEx(ERR, "Too many nested scripts, skipping %s\n", path);
354 return PM3_EMALLOC;
357 FILE *f = fopen(path, "r");
358 if (f == NULL)
359 return PM3_EFILE;
361 if (cmdscriptfile_idx == 0)
362 cmdscriptfile_stayafter = stayafter;
364 cmdscriptfile[++cmdscriptfile_idx] = f;
365 return PM3_SUCCESS;
368 static FILE *current_cmdscriptfile(void) {
369 return cmdscriptfile[cmdscriptfile_idx];
372 static bool pop_cmdscriptfile(void) {
373 fclose(cmdscriptfile[cmdscriptfile_idx]);
374 cmdscriptfile[cmdscriptfile_idx--] = NULL;
375 if (cmdscriptfile_idx == 0)
376 return cmdscriptfile_stayafter;
377 else
378 return true;
381 // Main thread of PM3 Client
382 void
383 #ifdef __has_attribute
384 #if __has_attribute(force_align_arg_pointer)
385 __attribute__((force_align_arg_pointer))
386 #endif
387 #endif
388 main_loop(const char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
390 char *cmd = NULL;
391 bool execCommand = (script_cmd != NULL);
392 bool fromInteractive = false;
393 uint16_t script_cmd_len = 0;
394 if (execCommand) {
395 script_cmd_len = strlen(script_cmd);
396 str_creplace(script_cmd, script_cmd_len, ';', '\0');
398 bool stdinOnPipe = !isatty(STDIN_FILENO);
399 char script_cmd_buf[256] = {0x00}; // iceman, needs lua script the same file_path_buffer as the rest
401 // cache Version information now:
402 if (execCommand || script_cmds_file || stdinOnPipe)
403 pm3_version(false, false);
404 else
405 pm3_version_short();
407 if (script_cmds_file) {
409 char *path;
410 int res = searchFile(&path, CMD_SCRIPTS_SUBDIR, script_cmds_file, ".cmd", false);
411 if (res == PM3_SUCCESS) {
412 if (push_cmdscriptfile(path, stayInCommandLoop) == PM3_SUCCESS)
413 PrintAndLogEx(SUCCESS, "executing commands from file: %s\n", path);
414 else
415 PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", path);
416 free(path);
420 g_session.history_path = NULL;
421 if (g_session.incognito) {
422 PrintAndLogEx(INFO, "No history will be recorded");
423 } else {
424 if (searchHomeFilePath(&g_session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
425 g_session.history_path = NULL;
426 PrintAndLogEx(ERR, "No history will be recorded");
427 } else {
428 if (pm3line_load_history(g_session.history_path) != PM3_SUCCESS) {
429 PrintAndLogEx(INFO, "No previous history could be loaded");
434 // loops every time enter is pressed...
435 while (1) {
437 bool printprompt = false;
439 prompt_set();
441 check_script:
442 // If there is a script file
443 if (current_cmdscriptfile()) {
445 // clear array
446 memset(script_cmd_buf, 0, sizeof(script_cmd_buf));
448 // read script file
449 if (fgets(script_cmd_buf, sizeof(script_cmd_buf), current_cmdscriptfile()) == NULL) {
450 if (pop_cmdscriptfile() == false) {
451 break;
453 goto check_script;
456 prompt_ctx = PROXPROMPT_CTX_SCRIPTFILE;
458 // remove linebreaks
459 str_cleanrn(script_cmd_buf, sizeof(script_cmd_buf));
461 cmd = str_dup(script_cmd_buf);
462 if (cmd != NULL) {
463 printprompt = true;
466 } else {
467 // If there is a script command
468 if (execCommand) {
469 prompt_ctx = stdinOnPipe ? PROXPROMPT_CTX_STDIN : PROXPROMPT_CTX_SCRIPTCMD;
471 cmd = str_dup(script_cmd);
472 if ((cmd != NULL) && (! fromInteractive))
473 printprompt = true;
475 uint16_t len = strlen(script_cmd) + 1;
476 script_cmd += len;
478 if (script_cmd_len == len - 1)
479 execCommand = false;
481 script_cmd_len -= len;
482 } else {
483 // exit after exec command
484 if (script_cmd && !stayInCommandLoop)
485 break;
487 // if there is a pipe from stdin
488 if (stdinOnPipe) {
489 // clear array
490 memset(script_cmd_buf, 0, sizeof(script_cmd_buf));
491 // get
492 if (fgets(script_cmd_buf, sizeof(script_cmd_buf), stdin) == NULL) {
493 PrintAndLogEx(ERR, "STDIN unexpected end, exit...");
494 break;
496 execCommand = true;
497 stayInCommandLoop = true;
498 fromInteractive = false;
499 script_cmd = script_cmd_buf;
500 script_cmd_len = strlen(script_cmd);
501 str_creplace(script_cmd, script_cmd_len, ';', '\0');
502 // remove linebreaks
503 str_cleanrn(script_cmd, script_cmd_len);
504 goto check_script;
505 } else {
506 pm3line_check(check_comm);
507 prompt_ctx = PROXPROMPT_CTX_INTERACTIVE;
508 char prompt[PROXPROMPT_MAX_SIZE] = {0};
509 prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev, prompt_net, true);
510 char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
511 memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !g_session.supports_colors);
512 g_pendingPrompt = true;
513 script_cmd = pm3line_read(prompt_filtered);
514 #if defined(_WIN32)
515 //Check if color support needs to be enabled again in case the window buffer did change
516 g_session.supports_colors = DetectWindowsAnsiSupport();
517 #endif
518 if (script_cmd != NULL) {
519 execCommand = true;
520 stayInCommandLoop = true;
521 fromInteractive = true;
522 script_cmd_len = strlen(script_cmd);
523 str_creplace(script_cmd, script_cmd_len, ';', '\0');
524 // remove linebreaks
525 str_cleanrn(script_cmd, script_cmd_len);
526 goto check_script;
528 fflush(NULL);
533 // execute command
534 if (cmd) {
536 // rtrim
537 size_t l = strlen(cmd);
538 while (l > 0 && isspace(cmd[l - 1])) {
539 cmd[--l] = '\0';
541 // ltrim
542 size_t off = 0;
543 while ((cmd[off] != '\0') && isspace(cmd[off])) {
544 off++;
547 for (size_t i = 0; i < strlen(cmd) - off; i++) {
548 cmd[i] = cmd[i + off];
551 cmd[strlen(cmd) - off] = '\0';
553 if (cmd[0] != '\0') {
554 uint8_t old_printAndLog = g_printAndLog;
555 if (!printprompt) {
556 g_printAndLog &= ~PRINTANDLOG_PRINT;
558 char prompt[PROXPROMPT_MAX_SIZE] = {0};
559 prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev, prompt_net, true);
560 // always filter RL magic separators if not using readline
561 char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
562 memcpy_filter_rlmarkers(prompt_filtered, prompt, sizeof(prompt_filtered));
563 PrintAndLogEx(NORMAL, "%s%s", prompt_filtered, cmd);
564 g_printAndLog = old_printAndLog;
566 // add to history if not from a script
567 if (!current_cmdscriptfile()) {
568 pm3line_add_history(cmd);
570 // process cmd
571 g_pendingPrompt = false;
572 mainret = CommandReceived(cmd);
574 // exit or quit
575 if (mainret == PM3_EFATAL)
576 break;
577 if (mainret == PM3_SQUIT) {
578 // Normal quit, map to 0
579 mainret = PM3_SUCCESS;
580 break;
583 free(cmd);
584 cmd = NULL;
585 } else {
586 PrintAndLogEx(NORMAL, "\n");
587 if (script_cmds_file && stayInCommandLoop)
588 stayInCommandLoop = false;
589 else
590 break;
592 } // end while
594 if (g_session.pm3_present) {
595 clearCommandBuffer();
596 SendCommandNG(CMD_QUIT_SESSION, NULL, 0);
597 msleep(100); // Make sure command is sent before killing client
600 while (current_cmdscriptfile()) {
601 pop_cmdscriptfile();
604 pm3line_flush_history();
606 if (cmd) {
607 free(cmd);
608 cmd = NULL;
612 #ifndef LIBPM3
613 static void dumpAllHelp(int markdown, bool full_help) {
614 g_session.help_dump_mode = true;
615 PrintAndLogEx(NORMAL, "\n%sProxmark3 command dump%s\n\n", markdown ? "# " : "", markdown ? "" : "\n======================");
616 PrintAndLogEx(NORMAL, "Some commands are available only if a Proxmark3 is actually connected.%s\n", markdown ? " " : "");
617 PrintAndLogEx(NORMAL, "Check column \"offline\" for their availability.\n");
618 PrintAndLogEx(NORMAL, "\n");
619 command_t *cmds = getTopLevelCommandTable();
620 dumpCommandsRecursive(cmds, markdown, full_help);
621 g_session.help_dump_mode = false;
622 PrintAndLogEx(NORMAL, "Full help dump done.");
624 #endif //LIBPM3
626 static char *my_executable_path = NULL;
627 static char *my_executable_directory = NULL;
629 const char *get_my_executable_path(void) {
630 return my_executable_path;
633 const char *get_my_executable_directory(void) {
634 return my_executable_directory;
637 static void set_my_executable_path(void) {
638 int path_length = wai_getExecutablePath(NULL, 0, NULL);
639 if (path_length == -1)
640 return;
642 my_executable_path = (char *)calloc(path_length + 1, sizeof(uint8_t));
643 int dirname_length = 0;
644 if (wai_getExecutablePath(my_executable_path, path_length, &dirname_length) != -1) {
645 my_executable_path[path_length] = '\0';
646 my_executable_directory = (char *)calloc(dirname_length + 2, sizeof(uint8_t));
647 strncpy(my_executable_directory, my_executable_path, dirname_length + 1);
648 my_executable_directory[dirname_length + 1] = '\0';
652 static const char *my_user_directory = NULL;
653 // static char _cwd_Buffer [FILENAME_MAX] = {0};
655 const char *get_my_user_directory(void) {
656 return my_user_directory;
659 static void set_my_user_directory(void) {
660 /* my_user_directory = getenv("HOME");
662 // if not found, default to current directory
663 if (my_user_directory == NULL) {
664 my_user_directory = GetCurrentDir(_cwd_Buffer, sizeof(_cwd_Buffer));
665 // change all slashes to / (windows should not care...
666 for (int i = 0; i < strlen(_cwd_Buffer); i++)
667 if (_cwd_Buffer[i] == '\\') _cwd_Buffer[i] = '/';
668 // my_user_directory = ".";
671 my_user_directory = getenv("HOME");
673 // if not found, default to current directory
674 if (my_user_directory == NULL) {
676 uint16_t pathLen = FILENAME_MAX; // should be a good starting point
677 char *cwd_buffer = (char *)calloc(pathLen, sizeof(uint8_t));
678 if (cwd_buffer == NULL) {
679 PrintAndLogEx(WARNING, "failed to allocate memory");
680 return;
683 while (GetCurrentDir(cwd_buffer, pathLen) == NULL) {
684 if (errno == ERANGE) { // Need bigger buffer
685 pathLen += 10; // if buffer was too small add 10 characters and try again
686 char *tmp = realloc(cwd_buffer, pathLen);
687 if (tmp == NULL) {
688 PrintAndLogEx(WARNING, "failed to allocate memory");
689 free(cwd_buffer);
690 return;
692 cwd_buffer = tmp;
693 } else {
694 free(cwd_buffer);
695 return;
699 for (int i = 0; i < strlen(cwd_buffer); i++) {
700 if (cwd_buffer[i] == '\\') {
701 cwd_buffer[i] = '/';
705 my_user_directory = cwd_buffer;
709 #ifndef LIBPM3
710 static void show_help(bool showFullHelp, char *exec_name) {
712 PrintAndLogEx(NORMAL, "\nsyntax: %s [-h|-t|-m|--fulltext]", exec_name);
713 #ifdef HAVE_PYTHON
714 PrintAndLogEx(NORMAL, " %s [[-p] <port>] [-b] [-w] [-f] [-c <command>]|[-l <lua_script_file>]|[-y <python_script_file>]|[-s <cmd_script_file>] [-i] [-d <0|1|2>]", exec_name);
715 #else // HAVE_PYTHON
716 PrintAndLogEx(NORMAL, " %s [[-p] <port>] [-b] [-w] [-f] [-c <command>]|[-l <lua_script_file>]|[-s <cmd_script_file>] [-i] [-d <0|1|2>]", exec_name);
717 #endif // HAVE_PYTHON
718 PrintAndLogEx(NORMAL, " %s [-p] <port> --flash [--unlock-bootloader] [--image <imagefile>]+ [-w] [-f] [-d <0|1|2>]", exec_name);
720 if (showFullHelp) {
722 PrintAndLogEx(NORMAL, "\nCommon options:");
723 PrintAndLogEx(NORMAL, " -h/--help this help");
724 PrintAndLogEx(NORMAL, " -v/--version print client version");
725 PrintAndLogEx(NORMAL, " -p/--port serial port to connect to");
726 PrintAndLogEx(NORMAL, " -w/--wait 20sec waiting the serial port to appear in the OS");
727 PrintAndLogEx(NORMAL, " -f/--flush output will be flushed after every print");
728 PrintAndLogEx(NORMAL, " -d/--debug <0|1|2> set debugmode");
729 PrintAndLogEx(NORMAL, "\nOptions in client mode:");
730 PrintAndLogEx(NORMAL, " -t/--text dump all interactive command list at once");
731 PrintAndLogEx(NORMAL, " --fulltext dump all interactive command's help at once");
732 PrintAndLogEx(NORMAL, " -m/--markdown dump all interactive command list at once in markdown syntax");
733 PrintAndLogEx(NORMAL, " -b/--baud serial port speed (only needed for physical UART, not for USB-CDC or BT)");
734 PrintAndLogEx(NORMAL, " -c/--command <command> execute one Proxmark3 command (or several separated by ';').");
735 PrintAndLogEx(NORMAL, " -l/--lua <lua_script_file> execute Lua script.");
736 #ifdef HAVE_PYTHON
737 // Technically, --lua and --py are identical and interexchangeable
738 PrintAndLogEx(NORMAL, " -y/--py <python_script_file> execute Python script.");
739 #endif // HAVE_PYTHON
740 PrintAndLogEx(NORMAL, " -s/--script-file <cmd_script_file> script file with one Proxmark3 command per line");
741 PrintAndLogEx(NORMAL, " -i/--interactive enter interactive mode after executing the script or the command");
742 PrintAndLogEx(NORMAL, " --incognito do not use history, prefs file nor log files");
743 PrintAndLogEx(NORMAL, " --ncpu <num_cores> override number of CPU cores");
744 PrintAndLogEx(NORMAL, "\nOptions in flasher mode:");
745 PrintAndLogEx(NORMAL, " --flash flash Proxmark3, requires at least one --image");
746 PrintAndLogEx(NORMAL, " --reboot-to-bootloader reboot Proxmark3 into bootloader mode");
747 PrintAndLogEx(NORMAL, " --unlock-bootloader Enable flashing of bootloader area *DANGEROUS* (need --flash)");
748 PrintAndLogEx(NORMAL, " --force Enable flashing even if firmware seems to not match client version");
749 PrintAndLogEx(NORMAL, " --image <imagefile> image to flash. Can be specified several times.");
750 PrintAndLogEx(NORMAL, "\nOptions in memory dump mode:");
751 PrintAndLogEx(NORMAL, " --dumpmem <dumpfile> dumps Proxmark3 flash memory to file");
752 PrintAndLogEx(NORMAL, " --dumpaddr <address> starting address for dump, default 0");
753 PrintAndLogEx(NORMAL, " --dumplen <length> number of bytes to dump, default 512KB");
754 PrintAndLogEx(NORMAL, " --dumpraw raw address mode: dump from anywhere, not just flash");
755 PrintAndLogEx(NORMAL, "\nExamples:");
756 PrintAndLogEx(NORMAL, "\n to run Proxmark3 client:\n");
757 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -- runs the pm3 client", exec_name);
758 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -f -- flush output every time", exec_name);
759 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -w -- wait for serial port", exec_name);
760 PrintAndLogEx(NORMAL, " %s -- runs the pm3 client in OFFLINE mode", exec_name);
761 PrintAndLogEx(NORMAL, "\n to execute different commands from terminal:\n");
762 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -c \"hf mf chk --1k\" -- execute cmd and quit client", exec_name);
763 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -l hf_read -- execute Lua script `hf_read` and quit client", exec_name);
764 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -s mycmds.txt -- execute each pm3 cmd in file and quit client", exec_name);
765 PrintAndLogEx(NORMAL, "\n to flash fullimage and bootloader:\n");
766 PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" --flash --unlock-bootloader --image bootrom.elf --image fullimage.elf", exec_name);
767 #ifdef __linux__
768 PrintAndLogEx(NORMAL, "\nNote (Linux):\nif the flasher gets stuck in 'Waiting for Proxmark3 to reappear on <DEVICE>',");
769 PrintAndLogEx(NORMAL, "you need to blacklist Proxmark3 for modem-manager - see documentation for more details:");
770 PrintAndLogEx(NORMAL, "* https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md");
771 PrintAndLogEx(NORMAL, "\nMore info on flashing procedure from the official Proxmark3 wiki:");
772 PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/Gentoo%%20Linux");
773 PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/Ubuntu%%20Linux");
774 PrintAndLogEx(NORMAL, "* https://github.com/Proxmark/proxmark3/wiki/OSX\n");
775 #endif
779 static int dumpmem_to_file(const char *filename, uint32_t addr, uint32_t len, bool raw, bool in_bootloader) {
781 uint8_t *buffer = calloc(len, sizeof(uint8_t));
782 if (buffer == NULL) {
783 PrintAndLogEx(ERR, "error, cannot allocate memory ");
784 return PM3_EMALLOC;
787 int res = PM3_EUNDEF;
788 size_t readlen = 0;
789 DeviceMemType_t type = raw ? MCU_MEM : MCU_FLASH;
790 if (GetFromDevice(type, buffer, len, addr, NULL, 0, NULL, 1000, true)) {
791 res = PM3_SUCCESS;
792 readlen = len; // GetFromDevice does not report the actual number of bytes received.
795 if (res == PM3_SUCCESS) {
796 res = saveFile(filename, ".bin", buffer, readlen);
797 if (res != PM3_SUCCESS) {
798 PrintAndLogEx(ERR, "error writing to file "_YELLOW_("%s"), filename);
802 free(buffer);
803 return res;
806 static int dumpmem_pm3(char *serial_port_name, const char *filename, uint32_t addr, uint32_t len, bool raw) {
807 int ret = PM3_EUNDEF;
808 bool in_bootloader = false;
810 if (serial_port_name == NULL) {
811 PrintAndLogEx(ERR, "You must specify a port.\n");
812 return PM3_EINVARG;
815 if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED)) {
816 PrintAndLogEx(NORMAL, _GREEN_(" found"));
817 msleep(200);
818 } else {
819 PrintAndLogEx(ERR, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name);
820 ret = PM3_ETIMEOUT;
821 goto finish;
824 // Determine if we're talking to a bootloader or main firmware.
825 SendCommandBL(CMD_DEVICE_INFO, 0, 0, 0, NULL, 0);
826 PacketResponseNG resp;
827 if (WaitForResponseTimeout(CMD_UNKNOWN, &resp, 1000) == false) {
828 PrintAndLogEx(ERR, "Could not get device info.");
829 goto finish2;
831 uint32_t dev_info = resp.oldarg[0];
832 in_bootloader = (dev_info & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) != 0;
833 if (in_bootloader) {
834 if ((dev_info & DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM) != 0) {
835 PrintAndLogEx(INFO, "Device is running the bootloader.");
836 } else {
837 PrintAndLogEx(ERR, "Device is running the bootloader, but the bootloader"
838 " doesn't understand the READ MEM command.");
839 goto finish2;
843 PrintAndLogEx(SUCCESS, "Dump requested from address "_YELLOW_("%u")", length "_YELLOW_("%u")"%s.",
844 addr, len, raw ? ", in raw address mode" : "");
846 PrintAndLogEx(SUCCESS, _CYAN_("Memory dumping to file..."));
847 ret = dumpmem_to_file(filename, addr, len, raw, in_bootloader);
848 if (ret != PM3_SUCCESS) {
849 goto finish2;
851 PrintAndLogEx(NORMAL, "");
853 finish2:
854 clearCommandBuffer();
855 if (in_bootloader) {
856 g_session.current_device->g_conn->run = false;
857 SendCommandOLD(CMD_PING, 0, 0, 0, NULL, 0);
858 } else {
859 SendCommandNG(CMD_QUIT_SESSION, NULL, 0);
860 msleep(100);
862 CloseProxmark(g_session.current_device);
864 finish:
865 if (ret == PM3_SUCCESS)
866 PrintAndLogEx(SUCCESS, _CYAN_("All done"));
867 else if (ret == PM3_EOPABORTED)
868 PrintAndLogEx(FAILED, "Aborted by user");
869 else
870 PrintAndLogEx(ERR, "Aborted on error %u", ret);
871 return ret;
874 static int flash_pm3(char *serial_port_name, uint8_t num_files, const char *filenames[FLASH_MAX_FILES], bool can_write_bl, bool force) {
876 int ret = PM3_EUNDEF;
877 flash_file_t files[FLASH_MAX_FILES];
878 memset(files, 0, sizeof(files));
880 if (serial_port_name == NULL) {
881 PrintAndLogEx(ERR, "You must specify a port.\n");
882 return PM3_EINVARG;
885 for (int i = 0 ; i < num_files; ++i) {
886 char *path;
887 ret = searchFile(&path, FIRMWARES_SUBDIR, filenames[i], ".elf", true);
888 if (ret != PM3_SUCCESS) {
889 ret = searchFile(&path, BOOTROM_SUBDIR, filenames[i], ".elf", true);
891 if (ret != PM3_SUCCESS) {
892 // Last try, let the error msg be displayed if not found
893 ret = searchFile(&path, FULLIMAGE_SUBDIR, filenames[i], ".elf", false);
895 if (ret != PM3_SUCCESS) {
896 goto finish2;
898 files[i].filename = path;
901 PrintAndLogEx(SUCCESS, "About to use the following file%s:", num_files > 1 ? "s" : "");
902 for (int i = 0 ; i < num_files; ++i) {
903 PrintAndLogEx(SUCCESS, " "_YELLOW_("%s"), files[i].filename);
906 for (int i = 0 ; i < num_files; ++i) {
907 ret = flash_load(&files[i], force);
908 if (ret != PM3_SUCCESS) {
909 goto finish2;
911 PrintAndLogEx(NORMAL, "");
914 if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED)) {
915 PrintAndLogEx(NORMAL, _GREEN_(" found"));
916 msleep(200);
917 } else {
918 PrintAndLogEx(ERR, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name);
919 ret = PM3_ETIMEOUT;
920 goto finish2;
923 uint32_t max_allowed = 0;
924 ret = flash_start_flashing(can_write_bl, serial_port_name, &max_allowed);
925 if (ret != PM3_SUCCESS) {
926 goto finish;
929 if (num_files == 0)
930 goto finish;
932 for (int i = 0 ; i < num_files; ++i) {
933 ret = flash_prepare(&files[i], can_write_bl, max_allowed * ONE_KB);
934 if (ret != PM3_SUCCESS) {
935 goto finish;
937 PrintAndLogEx(NORMAL, "");
940 PrintAndLogEx(SUCCESS, _CYAN_("Flashing..."));
942 for (int i = 0; i < num_files; i++) {
943 ret = flash_write(&files[i]);
944 if (ret != PM3_SUCCESS) {
945 goto finish;
947 PrintAndLogEx(NORMAL, "");
950 finish:
951 if (ret != PM3_SUCCESS)
952 PrintAndLogEx(WARNING, "The flashing procedure failed, follow the suggested steps!");
953 ret = flash_stop_flashing();
954 CloseProxmark(g_session.current_device);
955 finish2:
956 for (int i = 0 ; i < num_files; ++i) {
957 flash_free(&files[i]);
959 if (ret == PM3_SUCCESS)
960 PrintAndLogEx(SUCCESS, _CYAN_("All done"));
961 else if (ret == PM3_EOPABORTED)
962 PrintAndLogEx(FAILED, "Aborted by user");
963 else
964 PrintAndLogEx(ERR, "Aborted on error");
965 PrintAndLogEx(INFO, "\nHave a nice day!");
966 return ret;
969 static int reboot_bootloader_pm3(char *serial_port_name) {
970 if (serial_port_name == NULL) {
971 PrintAndLogEx(ERR, "You must specify a port.\n");
972 return PM3_EINVARG;
975 if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED) == false) {
976 PrintAndLogEx(ERR, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name);
977 return PM3_ETIMEOUT;
980 PrintAndLogEx(NORMAL, _GREEN_(" found"));
981 return flash_reboot_bootloader(serial_port_name, true);
984 #endif //LIBPM3
986 void pm3_init(void) {
987 srand(time(0));
989 g_session.pm3_present = false;
990 g_session.help_dump_mode = false;
991 g_session.incognito = false;
992 g_session.supports_colors = false;
993 g_session.emoji_mode = EMO_ALTTEXT;
994 g_session.stdinOnTTY = false;
995 g_session.stdoutOnTTY = false;
997 // set global variables soon enough to get the log path
998 set_my_executable_path();
999 set_my_user_directory();
1003 #ifndef LIBPM3
1004 int main(int argc, char *argv[]) {
1005 pm3_init();
1006 bool waitCOMPort = false;
1007 bool addScriptExec = false;
1008 bool stayInCommandLoop = false;
1009 char *script_cmds_file = NULL;
1010 char *script_cmd = NULL;
1011 char *port = NULL;
1012 uint32_t speed = 0;
1014 pm3line_init();
1016 char exec_name[100] = {0};
1017 strncpy(exec_name, basename(argv[0]), sizeof(exec_name) - 1);
1019 bool flash_mode = false;
1020 bool reboot_bootloader_mode = false;
1021 bool flash_can_write_bl = false;
1022 bool flash_force = false;
1023 bool debug_mode_forced = false;
1024 int flash_num_files = 0;
1025 const char *flash_filenames[FLASH_MAX_FILES];
1026 bool dumpmem_mode = false;
1027 const char *dumpmem_filename = NULL;
1028 uint32_t dumpmem_addr = 0;
1029 uint32_t dumpmem_len = 512 * 1024;
1030 bool dumpmem_raw = false;
1032 // color management:
1033 // 1. default = no color
1034 // 2. enable colors if OS seems to support colors and if stdin/stdout aren't redirected
1035 // 3. load prefs if available, overwrite colors choice if needed
1036 // 4. disable colors anyway if stdin/stdout are redirected
1038 // For info, grep --color=auto is doing sth like this, plus test getenv("TERM") != "dumb":
1039 // struct stat tmp_stat;
1040 // if ((fstat (STDOUT_FILENO, &tmp_stat) == 0) && (S_ISCHR (tmp_stat.st_mode)) && isatty(STDIN_FILENO))
1041 g_session.stdinOnTTY = isatty(STDIN_FILENO);
1042 g_session.stdoutOnTTY = isatty(STDOUT_FILENO);
1043 g_session.supports_colors = false;
1044 g_session.emoji_mode = EMO_ALTTEXT;
1045 if (g_session.stdinOnTTY && g_session.stdoutOnTTY) {
1046 #if defined(__linux__) || defined(__APPLE__)
1047 g_session.supports_colors = true;
1048 g_session.emoji_mode = EMO_EMOJI;
1049 #elif defined(_WIN32)
1050 g_session.supports_colors = DetectWindowsAnsiSupport();
1051 g_session.emoji_mode = EMO_ALTTEXT;
1052 #endif
1054 for (int i = 1; i < argc; i++) {
1056 if (argv[i][0] != '-') {
1057 // For backward compatibility we accept direct port
1058 if (port != NULL) {
1059 // We got already one
1060 PrintAndLogEx(ERR, _RED_("ERROR:") " cannot parse command line. We got " _YELLOW_("%s") " as port and now we got also: " _YELLOW_("%s") "\n", port, argv[i]);
1061 show_help(false, exec_name);
1062 return 1;
1064 port = argv[i];
1065 continue;
1068 // port
1069 if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) {
1070 if (i + 1 == argc) {
1071 PrintAndLogEx(ERR, _RED_("ERROR:") " missing port specification after -p\n");
1072 show_help(false, exec_name);
1073 return 1;
1075 if (port != NULL) {
1076 // We got already one
1077 PrintAndLogEx(ERR, _RED_("ERROR:") " cannot parse command line. We got " _YELLOW_("%s") " as port and now we got also: " _YELLOW_("%s") "\n", port, argv[i + 1]);
1078 show_help(false, exec_name);
1079 return 1;
1081 port = argv[++i];
1082 continue;
1085 // short help
1086 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
1087 g_printAndLog = PRINTANDLOG_PRINT;
1088 show_help(true, exec_name);
1089 return 0;
1092 // dump help
1093 if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--text") == 0) {
1094 g_printAndLog = PRINTANDLOG_PRINT;
1095 show_help(false, exec_name);
1096 dumpAllHelp(0, false);
1097 return 0;
1100 // dump help
1101 if (strcmp(argv[i], "--fulltext") == 0) {
1102 g_printAndLog = PRINTANDLOG_PRINT;
1103 show_help(false, exec_name);
1104 dumpAllHelp(0, true);
1105 return 0;
1108 // dump markup
1109 if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--markdown") == 0) {
1110 g_printAndLog = PRINTANDLOG_PRINT;
1111 dumpAllHelp(1, false);
1112 return 0;
1114 // print client version
1115 if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
1116 pm3_version(true, true);
1117 return 0;
1120 // set debugmode
1121 if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0) {
1122 if (i + 1 == argc) {
1123 PrintAndLogEx(ERR, _RED_("ERROR:") " missing debugmode specification after -d\n");
1124 show_help(false, exec_name);
1125 return 1;
1127 int demod = atoi(argv[i + 1]);
1128 if (demod < 0 || demod > 2) {
1129 PrintAndLogEx(ERR, _RED_("ERROR:") " invalid debugmode: -d " _YELLOW_("%s") "\n", argv[i + 1]);
1130 return 1;
1132 g_debugMode = demod;
1133 debug_mode_forced = true;
1134 i++;
1135 continue;
1138 // flush output
1139 if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--flush") == 0) {
1140 SetFlushAfterWrite(true);
1141 PrintAndLogEx(INFO, "Output will be flushed after every print.\n");
1142 continue;
1145 // set baudrate
1146 if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--baud") == 0) {
1147 if (i + 1 == argc) {
1148 PrintAndLogEx(ERR, _RED_("ERROR:") " missing baud specification after -b\n");
1149 show_help(false, exec_name);
1150 return 1;
1152 uint64_t tmpspeed = strtoul(argv[i + 1], NULL, 10);
1153 if ((tmpspeed == ULONG_MAX) || (tmpspeed == 0)) {
1154 PrintAndLogEx(ERR, _RED_("ERROR:") " invalid baudrate: -b " _YELLOW_("%s") "\n", argv[i + 1]);
1155 return 1;
1157 speed = tmpspeed;
1158 i++;
1159 continue;
1162 // wait for comport
1163 if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--wait") == 0) {
1164 waitCOMPort = true;
1165 continue;
1168 // execute pm3 command
1169 if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--command") == 0) {
1170 if (i + 1 == argc) {
1171 PrintAndLogEx(ERR, _RED_("ERROR:") " missing command specification after -c\n");
1172 show_help(false, exec_name);
1173 return 1;
1175 script_cmd = argv[++i];
1176 continue;
1179 // execute pm3 command file
1180 if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--script-file") == 0) {
1181 if (i + 1 == argc || strlen(argv[i + 1]) == 0) {
1182 PrintAndLogEx(ERR, _RED_("ERROR:") " missing script file specification after -s\n");
1183 show_help(false, exec_name);
1184 return 1;
1186 script_cmds_file = argv[++i];
1187 continue;
1190 // execute Lua script
1191 if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--lua") == 0) {
1192 if (i + 1 == argc || strlen(argv[i + 1]) == 0) {
1193 PrintAndLogEx(ERR, _RED_("ERROR:") " missing Lua script specification after --lua\n");
1194 show_help(false, exec_name);
1195 return 1;
1197 script_cmd = argv[++i];
1198 if (script_cmd == NULL || strlen(script_cmd) == 0) {
1199 return 1;
1201 addScriptExec = true;
1202 continue;
1204 #ifdef HAVE_PYTHON
1205 // execute Python script
1206 if (strcmp(argv[i], "-y") == 0 || strcmp(argv[i], "--py") == 0) {
1207 if (i + 1 == argc || strlen(argv[i + 1]) == 0) {
1208 PrintAndLogEx(ERR, _RED_("ERROR:") " missing Python script specification after --py\n");
1209 show_help(false, exec_name);
1210 return 1;
1212 script_cmd = argv[++i];
1213 if (script_cmd == NULL || strlen(script_cmd) == 0) {
1214 return 1;
1216 addScriptExec = true;
1217 continue;
1219 #endif // HAVE_PYTHON
1220 // go to interactive instead of quitting after a script/command
1221 if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--interactive") == 0) {
1222 stayInCommandLoop = true;
1223 continue;
1226 // do not use history nor log files
1227 if (strcmp(argv[i], "--incognito") == 0) {
1228 g_session.incognito = true;
1229 continue;
1232 // go to dump mode
1233 if (strcmp(argv[i], "--dumpmem") == 0) {
1234 dumpmem_mode = true;
1235 if (i + 1 == argc) {
1236 PrintAndLogEx(ERR, _RED_("ERROR:") " missing file specification after --dumpmem\n");
1237 show_help(false, exec_name);
1238 return 1;
1240 dumpmem_filename = argv[++i];
1241 continue;
1243 if (strcmp(argv[i], "--dumpaddr") == 0) {
1244 if (i + 1 == argc) {
1245 PrintAndLogEx(ERR, _RED_("ERROR:") " missing address specification after -dumpaddr\n");
1246 show_help(false, exec_name);
1247 return 1;
1249 uint32_t tmpaddr = strtoul(argv[i + 1], NULL, 0);
1250 dumpmem_addr = tmpaddr;
1251 i++;
1252 continue;
1254 if (strcmp(argv[i], "--dumplen") == 0) {
1255 if (i + 1 == argc) {
1256 PrintAndLogEx(ERR, _RED_("ERROR:") " missing address specification after -dumplen\n");
1257 show_help(false, exec_name);
1258 return 1;
1260 uint32_t tmplen = strtoul(argv[i + 1], NULL, 0);
1261 dumpmem_len = tmplen;
1262 i++;
1263 continue;
1265 if (strcmp(argv[i], "--dumpraw") == 0) {
1266 dumpmem_raw = true;
1267 continue;
1270 // go to flash mode
1271 if (strcmp(argv[i], "--flash") == 0) {
1272 flash_mode = true;
1273 continue;
1276 // go to flash mode
1277 if (strcmp(argv[i], "--reboot-to-bootloader") == 0) {
1278 reboot_bootloader_mode = true;
1279 continue;
1282 // unlock bootloader area
1283 if (strcmp(argv[i], "--unlock-bootloader") == 0) {
1284 flash_can_write_bl = true;
1285 continue;
1288 // force flash even if firmware seems to not match client version
1289 if (strcmp(argv[i], "--force") == 0) {
1290 flash_force = true;
1291 continue;
1294 // flash file
1295 if (strcmp(argv[i], "--image") == 0) {
1296 if (flash_num_files == FLASH_MAX_FILES) {
1297 PrintAndLogEx(ERR, _RED_("ERROR:") " too many --image, please use it max %i times\n", FLASH_MAX_FILES);
1298 return 1;
1300 if (i + 1 == argc) {
1301 PrintAndLogEx(ERR, _RED_("ERROR:") " missing image specification after --image\n");
1302 show_help(false, exec_name);
1303 return 1;
1305 flash_filenames[flash_num_files++] = argv[++i];
1306 continue;
1309 if (strcmp(argv[i], "--ncpu") == 0) {
1310 if (i + 1 == argc) {
1311 PrintAndLogEx(ERR, _RED_("ERROR:") " missing CPU number specification after --ncpu\n");
1312 show_help(false, exec_name);
1313 return 1;
1315 long int ncpus = strtol(argv[i + 1], NULL, 10);
1316 const int detected_cpus = detect_num_CPUs();
1317 if (ncpus < 0 || ncpus >= detected_cpus) {
1318 PrintAndLogEx(ERR, _RED_("ERROR:") " invalid number of CPU cores: --ncpu " _YELLOW_("%s") " (available: %d)\n", argv[i + 1], detected_cpus);
1319 return 1;
1321 g_numCPUs = ncpus;
1322 i++;
1323 continue;
1326 // We got an unknown parameter
1327 PrintAndLogEx(ERR, _RED_("ERROR:") " invalid parameter: " _YELLOW_("%s") "\n", argv[i]);
1328 show_help(false, exec_name);
1329 return 1;
1332 // Load Settings and assign
1333 // This will allow the command line to override the settings.json values
1334 preferences_load();
1335 // quick patch for debug level
1336 if (! debug_mode_forced)
1337 g_debugMode = g_session.client_debug_level;
1338 // settings_save ();
1339 // End Settings
1341 // even if prefs, we disable colors if stdin or stdout is not a TTY
1342 if ((! g_session.stdinOnTTY) || (! g_session.stdoutOnTTY)) {
1343 g_session.supports_colors = false;
1344 g_session.emoji_mode = EMO_ALTTEXT;
1347 // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway
1348 if (speed == 0)
1349 speed = USART_BAUD_RATE;
1351 if (dumpmem_mode) {
1352 dumpmem_pm3(port, dumpmem_filename, dumpmem_addr, dumpmem_len, dumpmem_raw);
1353 exit(EXIT_SUCCESS);
1356 if (flash_mode) {
1357 flash_pm3(port, flash_num_files, flash_filenames, flash_can_write_bl, flash_force);
1358 exit(EXIT_SUCCESS);
1361 if (reboot_bootloader_mode) {
1362 reboot_bootloader_pm3(port);
1363 exit(EXIT_SUCCESS);
1366 if (script_cmd) {
1367 while (script_cmd[strlen(script_cmd) - 1] == ' ')
1368 script_cmd[strlen(script_cmd) - 1] = 0x00;
1370 if (strlen(script_cmd) == 0) {
1371 script_cmd = NULL;
1372 PrintAndLogEx(ERR, _RED_("ERROR:") " execute command: " _YELLOW_("command not found") ".\n");
1373 return 2;
1374 } else {
1375 if (addScriptExec) {
1376 // add "script run " to command
1377 int len = strlen(script_cmd) + 11 + 1;
1378 char *ctmp = (char *) calloc(len, sizeof(uint8_t));
1379 if (ctmp != NULL) {
1380 memset(ctmp, 0, len);
1381 strcpy(ctmp, "script run ");
1382 strcpy(&ctmp[11], script_cmd);
1383 script_cmd = ctmp;
1387 PrintAndLogEx(SUCCESS, "execute command from commandline: " _YELLOW_("%s") "\n", script_cmd);
1391 // try to open USB connection to Proxmark
1392 if (port != NULL) {
1393 OpenProxmark(&g_session.current_device, port, waitCOMPort, 20, false, speed);
1396 if (g_session.pm3_present && (TestProxmark(g_session.current_device) != PM3_SUCCESS)) {
1397 PrintAndLogEx(ERR, _RED_("ERROR:") " cannot communicate with the Proxmark3\n");
1398 CloseProxmark(g_session.current_device);
1401 if ((port != NULL) && (!g_session.pm3_present)) {
1402 exit(EXIT_FAILURE);
1405 if (!g_session.pm3_present) {
1406 PrintAndLogEx(INFO, _YELLOW_("OFFLINE") " mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name);
1409 // ascii art only in interactive client
1410 if (!script_cmds_file && !script_cmd && g_session.stdinOnTTY && g_session.stdoutOnTTY && !dumpmem_mode && !flash_mode && !reboot_bootloader_mode) {
1411 showBanner();
1414 // Save settings if not loaded from settings json file.
1415 // Doing this here will ensure other checks and updates are saved to over rule default
1416 // e.g. Linux color use check
1417 if ((!g_session.preferences_loaded) && (!g_session.incognito)) {
1418 PrintAndLogEx(INFO, "Creating initial preferences file"); // json save reports file name, so just info msg here
1419 preferences_save(); // Save defaults
1420 g_session.preferences_loaded = true;
1421 } /* else {
1422 // Set device debug level
1423 PrintAndLogEx(INFO,"setting device debug loglevel");
1424 if (g_session.pm3_present) {
1425 SendCommandNG(CMD_SET_DBGMODE, &g_session.device_debug_level, 1);
1426 PacketResponseNG resp;
1427 if (WaitForResponseTimeout(CMD_SET_DBGMODE, &resp, 2000) == false)
1428 PrintAndLogEx (INFO,"failed to set device debug loglevel");
1430 else
1431 PrintAndLogEx(WARNING,"Proxmark3 not ready to set debug level");
1435 #ifdef HAVE_GUI
1437 # if defined(_WIN32)
1438 InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
1439 MainGraphics();
1440 # else
1441 // for *nix distro's, check environment variable to verify a display
1442 const char *display = getenv("DISPLAY");
1443 if (display && strlen(display) > 1) {
1444 InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
1445 MainGraphics();
1446 } else {
1447 main_loop(script_cmds_file, script_cmd, stayInCommandLoop);
1449 # endif
1451 #else
1452 main_loop(script_cmds_file, script_cmd, stayInCommandLoop);
1453 #endif
1455 // Clean up the port
1456 if (g_session.pm3_present) {
1457 CloseProxmark(g_session.current_device);
1460 // Plot/Overlay moved or resized
1461 if (g_session.window_changed) {
1462 preferences_save();
1465 free_grabber();
1467 return mainret;
1469 #endif //LIBPM3