1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
19 #include "proxmark3.h"
25 #include <libgen.h> // basename
29 #include "usart_defs.h"
30 #include "util_posix.h"
37 #include "fileutils.h"
39 #include "preferences.h"
40 #include "commonutil.h"
47 static int mainret
= PM3_SUCCESS
;
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
) {
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
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
, __
);
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
);
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
);
105 PrintAndLogEx(NORMAL
, "");
106 PrintAndLogEx(NORMAL
, BANNERMSG3
);
109 static uint8_t detect_current_lang(void) {
111 const char *lang
= setlocale(LC_ALL
, "");
115 if (memcmp(lang
, "fr", 2) == 0) {
118 if (memcmp(lang
, "es", 2) == 0) {
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();
208 static void showBanner(void) {
209 uint8_t old_printAndLog
= g_printAndLog
;
210 g_printAndLog
&= PRINTANDLOG_PRINT
;
211 PrintAndLogEx(NORMAL
, "\n");
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
);
218 showBanner_logo(ANSI
);
220 #elif defined(__linux__) || defined(__APPLE__)
221 showBanner_logo(ANSI
);
223 showBanner_logo(ASCII
);
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
, "");
235 g_printAndLog
= old_printAndLog
;
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
) {
249 prompt_net
= PROXPROMPT_NET_TCPV4
;
252 prompt_net
= PROXPROMPT_NET_TCPV6
;
255 prompt_net
= PROXPROMPT_NET_UDPV4
;
258 prompt_net
= PROXPROMPT_NET_UDPV6
;
261 prompt_net
= PROXPROMPT_NET_NONE
;
267 if (g_conn
.send_via_fpc_usart
)
268 prompt_dev
= PROXPROMPT_DEV_FPC
;
270 prompt_dev
= PROXPROMPT_DEV_USB
;
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
) {
279 snprintf(buf
, buflen
- 1, PROXPROMPT_COMPOSE
, promptdev
, promptnet
, promptctx
);
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");
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;
306 if (c_update_reconnect_prompt
&& IsReconnectedOk() && g_session
.pm3_present
) {
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;
323 static bool DetectWindowsAnsiSupport(void) {
324 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
325 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
328 // disable colors if stdin or stdout are redirected
329 if ((! g_session
.stdinOnTTY
) || (! g_session
.stdoutOnTTY
))
332 HANDLE hOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
334 GetConsoleMode(hOut
, &dwMode
);
336 //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set
337 if ((dwMode
& ENABLE_VIRTUAL_TERMINAL_PROCESSING
))
340 dwMode
|= ENABLE_VIRTUAL_TERMINAL_PROCESSING
;
342 return SetConsoleMode(hOut
, dwMode
) ? true : false;
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
);
357 FILE *f
= fopen(path
, "r");
361 if (cmdscriptfile_idx
== 0)
362 cmdscriptfile_stayafter
= stayafter
;
364 cmdscriptfile
[++cmdscriptfile_idx
] = f
;
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
;
381 // Main thread of PM3 Client
383 #ifdef __has_attribute
384 #if __has_attribute(force_align_arg_pointer)
385 __attribute__((force_align_arg_pointer
))
388 main_loop(const char *script_cmds_file
, char *script_cmd
, bool stayInCommandLoop
) {
391 bool execCommand
= (script_cmd
!= NULL
);
392 bool fromInteractive
= false;
393 uint16_t script_cmd_len
= 0;
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);
407 if (script_cmds_file
) {
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
);
415 PrintAndLogEx(ERR
, "could not open " _YELLOW_("%s") "...", path
);
420 g_session
.history_path
= NULL
;
421 if (g_session
.incognito
) {
422 PrintAndLogEx(INFO
, "No history will be recorded");
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");
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...
437 bool printprompt
= false;
442 // If there is a script file
443 if (current_cmdscriptfile()) {
446 memset(script_cmd_buf
, 0, sizeof(script_cmd_buf
));
449 if (fgets(script_cmd_buf
, sizeof(script_cmd_buf
), current_cmdscriptfile()) == NULL
) {
450 if (pop_cmdscriptfile() == false) {
456 prompt_ctx
= PROXPROMPT_CTX_SCRIPTFILE
;
459 str_cleanrn(script_cmd_buf
, sizeof(script_cmd_buf
));
461 cmd
= str_dup(script_cmd_buf
);
467 // If there is a script command
469 prompt_ctx
= stdinOnPipe
? PROXPROMPT_CTX_STDIN
: PROXPROMPT_CTX_SCRIPTCMD
;
471 cmd
= str_dup(script_cmd
);
472 if ((cmd
!= NULL
) && (! fromInteractive
))
475 uint16_t len
= strlen(script_cmd
) + 1;
478 if (script_cmd_len
== len
- 1)
481 script_cmd_len
-= len
;
483 // exit after exec command
484 if (script_cmd
&& !stayInCommandLoop
)
487 // if there is a pipe from stdin
490 memset(script_cmd_buf
, 0, sizeof(script_cmd_buf
));
492 if (fgets(script_cmd_buf
, sizeof(script_cmd_buf
), stdin
) == NULL
) {
493 PrintAndLogEx(ERR
, "STDIN unexpected end, exit...");
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');
503 str_cleanrn(script_cmd
, script_cmd_len
);
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
);
515 //Check if color support needs to be enabled again in case the window buffer did change
516 g_session
.supports_colors
= DetectWindowsAnsiSupport();
518 if (script_cmd
!= NULL
) {
520 stayInCommandLoop
= true;
521 fromInteractive
= true;
522 script_cmd_len
= strlen(script_cmd
);
523 str_creplace(script_cmd
, script_cmd_len
, ';', '\0');
525 str_cleanrn(script_cmd
, script_cmd_len
);
537 size_t l
= strlen(cmd
);
538 while (l
> 0 && isspace(cmd
[l
- 1])) {
543 while ((cmd
[off
] != '\0') && isspace(cmd
[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
;
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
);
571 g_pendingPrompt
= false;
572 mainret
= CommandReceived(cmd
);
575 if (mainret
== PM3_EFATAL
)
577 if (mainret
== PM3_SQUIT
) {
578 // Normal quit, map to 0
579 mainret
= PM3_SUCCESS
;
586 PrintAndLogEx(NORMAL
, "\n");
587 if (script_cmds_file
&& stayInCommandLoop
)
588 stayInCommandLoop
= false;
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()) {
604 pm3line_flush_history();
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.");
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)
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");
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
);
688 PrintAndLogEx(WARNING
, "failed to allocate memory");
699 for (int i
= 0; i
< strlen(cwd_buffer
); i
++) {
700 if (cwd_buffer
[i
] == '\\') {
705 my_user_directory
= cwd_buffer
;
710 static void show_help(bool showFullHelp
, char *exec_name
) {
712 PrintAndLogEx(NORMAL
, "\nsyntax: %s [-h|-t|-m|--fulltext]", exec_name
);
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
);
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
);
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.");
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
);
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");
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 ");
787 int res
= PM3_EUNDEF
;
789 DeviceMemType_t type
= raw
? MCU_MEM
: MCU_FLASH
;
790 if (GetFromDevice(type
, buffer
, len
, addr
, NULL
, 0, NULL
, 1000, true)) {
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
);
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");
815 if (OpenProxmark(&g_session
.current_device
, serial_port_name
, true, 60, true, FLASHMODE_SPEED
)) {
816 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
819 PrintAndLogEx(ERR
, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name
);
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.");
831 uint32_t dev_info
= resp
.oldarg
[0];
832 in_bootloader
= (dev_info
& DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM
) != 0;
834 if ((dev_info
& DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM
) != 0) {
835 PrintAndLogEx(INFO
, "Device is running the bootloader.");
837 PrintAndLogEx(ERR
, "Device is running the bootloader, but the bootloader"
838 " doesn't understand the READ MEM command.");
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
) {
851 PrintAndLogEx(NORMAL
, "");
854 clearCommandBuffer();
856 g_session
.current_device
->g_conn
->run
= false;
857 SendCommandOLD(CMD_PING
, 0, 0, 0, NULL
, 0);
859 SendCommandNG(CMD_QUIT_SESSION
, NULL
, 0);
862 CloseProxmark(g_session
.current_device
);
865 if (ret
== PM3_SUCCESS
)
866 PrintAndLogEx(SUCCESS
, _CYAN_("All done"));
867 else if (ret
== PM3_EOPABORTED
)
868 PrintAndLogEx(FAILED
, "Aborted by user");
870 PrintAndLogEx(ERR
, "Aborted on error %u", 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");
885 for (int i
= 0 ; i
< num_files
; ++i
) {
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
) {
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
) {
911 PrintAndLogEx(NORMAL
, "");
914 if (OpenProxmark(&g_session
.current_device
, serial_port_name
, true, 60, true, FLASHMODE_SPEED
)) {
915 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
918 PrintAndLogEx(ERR
, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name
);
923 uint32_t max_allowed
= 0;
924 ret
= flash_start_flashing(can_write_bl
, serial_port_name
, &max_allowed
);
925 if (ret
!= PM3_SUCCESS
) {
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
) {
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
) {
947 PrintAndLogEx(NORMAL
, "");
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
);
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");
964 PrintAndLogEx(ERR
, "Aborted on error");
965 PrintAndLogEx(INFO
, "\nHave a nice day!");
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");
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
);
980 PrintAndLogEx(NORMAL
, _GREEN_(" found"));
981 return flash_reboot_bootloader(serial_port_name
, true);
986 void pm3_init(void) {
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();
1004 int main(int argc
, char *argv
[]) {
1006 bool waitCOMPort
= false;
1007 bool addScriptExec
= false;
1008 bool stayInCommandLoop
= false;
1009 char *script_cmds_file
= NULL
;
1010 char *script_cmd
= NULL
;
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
;
1054 for (int i
= 1; i
< argc
; i
++) {
1056 if (argv
[i
][0] != '-') {
1057 // For backward compatibility we accept direct port
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
);
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
);
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
);
1086 if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
1087 g_printAndLog
= PRINTANDLOG_PRINT
;
1088 show_help(true, exec_name
);
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);
1101 if (strcmp(argv
[i
], "--fulltext") == 0) {
1102 g_printAndLog
= PRINTANDLOG_PRINT
;
1103 show_help(false, exec_name
);
1104 dumpAllHelp(0, true);
1109 if (strcmp(argv
[i
], "-m") == 0 || strcmp(argv
[i
], "--markdown") == 0) {
1110 g_printAndLog
= PRINTANDLOG_PRINT
;
1111 dumpAllHelp(1, false);
1114 // print client version
1115 if (strcmp(argv
[i
], "-v") == 0 || strcmp(argv
[i
], "--version") == 0) {
1116 pm3_version(true, true);
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
);
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]);
1132 g_debugMode
= demod
;
1133 debug_mode_forced
= true;
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");
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
);
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]);
1163 if (strcmp(argv
[i
], "-w") == 0 || strcmp(argv
[i
], "--wait") == 0) {
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
);
1175 script_cmd
= argv
[++i
];
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
);
1186 script_cmds_file
= argv
[++i
];
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
);
1197 script_cmd
= argv
[++i
];
1198 if (script_cmd
== NULL
|| strlen(script_cmd
) == 0) {
1201 addScriptExec
= true;
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
);
1212 script_cmd
= argv
[++i
];
1213 if (script_cmd
== NULL
|| strlen(script_cmd
) == 0) {
1216 addScriptExec
= true;
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;
1226 // do not use history nor log files
1227 if (strcmp(argv
[i
], "--incognito") == 0) {
1228 g_session
.incognito
= true;
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
);
1240 dumpmem_filename
= argv
[++i
];
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
);
1249 uint32_t tmpaddr
= strtoul(argv
[i
+ 1], NULL
, 0);
1250 dumpmem_addr
= tmpaddr
;
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
);
1260 uint32_t tmplen
= strtoul(argv
[i
+ 1], NULL
, 0);
1261 dumpmem_len
= tmplen
;
1265 if (strcmp(argv
[i
], "--dumpraw") == 0) {
1271 if (strcmp(argv
[i
], "--flash") == 0) {
1277 if (strcmp(argv
[i
], "--reboot-to-bootloader") == 0) {
1278 reboot_bootloader_mode
= true;
1282 // unlock bootloader area
1283 if (strcmp(argv
[i
], "--unlock-bootloader") == 0) {
1284 flash_can_write_bl
= true;
1288 // force flash even if firmware seems to not match client version
1289 if (strcmp(argv
[i
], "--force") == 0) {
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
);
1300 if (i
+ 1 == argc
) {
1301 PrintAndLogEx(ERR
, _RED_("ERROR:") " missing image specification after --image\n");
1302 show_help(false, exec_name
);
1305 flash_filenames
[flash_num_files
++] = argv
[++i
];
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
);
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
);
1326 // We got an unknown parameter
1327 PrintAndLogEx(ERR
, _RED_("ERROR:") " invalid parameter: " _YELLOW_("%s") "\n", argv
[i
]);
1328 show_help(false, exec_name
);
1332 // Load Settings and assign
1333 // This will allow the command line to override the settings.json values
1335 // quick patch for debug level
1336 if (! debug_mode_forced
)
1337 g_debugMode
= g_session
.client_debug_level
;
1338 // settings_save ();
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
1349 speed
= USART_BAUD_RATE
;
1352 dumpmem_pm3(port
, dumpmem_filename
, dumpmem_addr
, dumpmem_len
, dumpmem_raw
);
1357 flash_pm3(port
, flash_num_files
, flash_filenames
, flash_can_write_bl
, flash_force
);
1361 if (reboot_bootloader_mode
) {
1362 reboot_bootloader_pm3(port
);
1367 while (script_cmd
[strlen(script_cmd
) - 1] == ' ')
1368 script_cmd
[strlen(script_cmd
) - 1] = 0x00;
1370 if (strlen(script_cmd
) == 0) {
1372 PrintAndLogEx(ERR
, _RED_("ERROR:") " execute command: " _YELLOW_("command not found") ".\n");
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));
1380 memset(ctmp
, 0, len
);
1381 strcpy(ctmp
, "script run ");
1382 strcpy(&ctmp
[11], script_cmd
);
1387 PrintAndLogEx(SUCCESS
, "execute command from commandline: " _YELLOW_("%s") "\n", script_cmd
);
1391 // try to open USB connection to Proxmark
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
)) {
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
) {
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;
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");
1431 PrintAndLogEx(WARNING,"Proxmark3 not ready to set debug level");
1437 # if defined(_WIN32)
1438 InitGraphics(argc
, argv
, script_cmds_file
, script_cmd
, stayInCommandLoop
);
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
);
1447 main_loop(script_cmds_file
, script_cmd
, stayInCommandLoop
);
1452 main_loop(script_cmds_file
, script_cmd
, stayInCommandLoop
);
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
) {