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 //-----------------------------------------------------------------------------
16 // Main command parser entry point
17 //-----------------------------------------------------------------------------
19 // ensure gmtime_r is available even with -std=c99; must be included before
21 #define _POSIX_C_SOURCE 200112L
27 #include <time.h> // MingW
28 #include <stdlib.h> // calloc
37 #include "cmdscript.h"
39 #include "cmdanalyse.h"
40 #include "emv/cmdemv.h" // EMV
41 #include "cmdflashmem.h" // rdv40 flashmem commands
43 #include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
44 #include "cmdusart.h" // rdv40 FPC USART commands
45 #include "cmdwiegand.h" // wiegand commands
47 #include "util_posix.h"
48 #include "commonutil.h" // ARRAYLEN
49 #include "preferences.h"
50 #include "cliparser.h"
52 static int CmdHelp(const char *Cmd
);
54 static void AppendDate(char *s
, size_t slen
, const char *fmt
) {
55 struct tm
*ct
, tm_buf
;
56 time_t now
= time(NULL
);
58 ct
= gmtime_s(&tm_buf
, &now
) == 0 ? &tm_buf
: NULL
;
60 ct
= gmtime_r(&now
, &tm_buf
);
63 strftime(s
, slen
, "%Y-%m-%dT%H:%M:%SZ", ct
); // ISO8601
65 strftime(s
, slen
, fmt
, ct
);
68 static int lf_search_plus(const char *Cmd
) {
70 sample_config oldconfig
;
71 memset(&oldconfig
, 0, sizeof(sample_config
));
73 int retval
= lf_getconfig(&oldconfig
);
75 if (retval
!= PM3_SUCCESS
) {
76 PrintAndLogEx(ERR
, "failed to get current device config");
80 // Divisor : frequency(khz)
82 // 125.00 134.83 250.00 375.00 500.00
84 int16_t default_divisor
[] = {95, 88, 47, 31, 23};
87 default LF config is set to:
96 sample_config config
= {
100 .trigger_threshold
= 0,
101 .samples_to_skip
= 0,
105 // Iteration defaults
106 for (int i
= 0; i
< ARRAYLEN(default_divisor
); ++i
) {
108 if (kbd_enter_pressed()) {
109 PrintAndLogEx(INFO
, "Keyboard pressed. Done.");
112 // Try to change config!
114 d
= config
.divisor
= default_divisor
[i
];
115 PrintAndLogEx(INFO
, "--> trying ( " _GREEN_("%d.%02d kHz")" )", 12000 / (d
+ 1), ((1200000 + (d
+ 1) / 2) / (d
+ 1)) - ((12000 / (d
+ 1)) * 100));
117 retval
= lf_setconfig(&config
);
118 if (retval
!= PM3_SUCCESS
)
121 // The config for pm3 is changed, we can trying search!
122 retval
= CmdLFfind(Cmd
);
123 if (retval
== PM3_SUCCESS
)
128 lf_setconfig(&oldconfig
);
132 static int CmdAuto(const char *Cmd
) {
133 CLIParserContext
*ctx
;
134 CLIParserInit(&ctx
, "auto",
135 "Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
141 arg_lit0("c", NULL
, "Continue searching even after a first hit"),
144 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
145 bool exit_first
= (arg_get_lit(ctx
, 1) == false);
148 PrintAndLogEx(INFO
, "lf search");
149 int ret
= CmdLFfind("");
150 if (ret
== PM3_SUCCESS
&& exit_first
)
153 PrintAndLogEx(INFO
, "hf search");
154 ret
= CmdHFSearch("");
155 if (ret
== PM3_SUCCESS
&& exit_first
)
158 PrintAndLogEx(INFO
, "lf search - unknown");
159 ret
= lf_search_plus("");
160 if (ret
== PM3_SUCCESS
&& exit_first
)
163 if (ret
!= PM3_SUCCESS
)
164 PrintAndLogEx(INFO
, "Failed both LF / HF SEARCH,");
166 PrintAndLogEx(INFO
, "Trying " _YELLOW_("`lf read`") " and save a trace for you");
169 lf_read(false, 40000);
170 char *fname
= calloc(100, sizeof(uint8_t));
171 AppendDate(fname
, 100, "-f lf_unknown_%Y-%m-%d_%H:%M");
177 int CmdRem(const char *Cmd
) {
178 CLIParserContext
*ctx
;
179 CLIParserInit(&ctx
, "rem",
180 "Add a text line in log file",
181 "rem my message -> adds a timestamp with `my message`"
186 arg_strx1(NULL
, NULL
, NULL
, "message line you want inserted"),
189 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
191 struct arg_str
*foo
= arg_get_str(ctx
, 1);
195 count
+= strlen(foo
->sval
[len
]);
196 } while (len
++ < (foo
->count
- 1));
198 char s
[count
+ foo
->count
];
199 memset(s
, 0, sizeof(s
));
203 snprintf(s
+ strlen(s
), sizeof(s
) - strlen(s
), "%s ", foo
->sval
[len
]);
204 } while (len
++ < (foo
->count
- 1));
208 AppendDate(buf
, sizeof(buf
), NULL
);
209 PrintAndLogEx(SUCCESS
, "%s remark: %s", buf
, s
);
213 static int CmdHints(const char *Cmd
) {
215 CLIParserContext
*ctx
;
216 CLIParserInit(&ctx
, "hints",
224 arg_lit0("1", "on", "turn on hints"),
225 arg_lit0("0", "off", "turn off hints"),
228 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
230 bool turn_on
= arg_get_lit(ctx
, 1);
231 bool turn_off
= arg_get_lit(ctx
, 2);
234 if (turn_on
&& turn_off
) {
235 PrintAndLogEx(ERR
, "you can't turn off and on at the same time");
240 g_session
.show_hints
= false;
241 } else if (turn_on
) {
242 g_session
.show_hints
= true;
245 PrintAndLogEx(INFO
, "Hints are %s", (g_session
.show_hints
) ? "ON" : "OFF");
249 static int CmdMsleep(const char *Cmd
) {
250 CLIParserContext
*ctx
;
251 CLIParserInit(&ctx
, "msleep",
252 "Sleep for given amount of milliseconds",
258 arg_int0("t", "ms", "<ms>", "time in milliseconds"),
261 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
262 uint32_t ms
= arg_get_u32_def(ctx
, 1, 0);
266 PrintAndLogEx(ERR
, "Specified invalid input. Can't be zero");
274 static int CmdQuit(const char *Cmd
) {
275 CLIParserContext
*ctx
;
276 CLIParserInit(&ctx
, "quit",
277 "Quit the Proxmark3 client terminal",
284 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
289 static int CmdRev(const char *Cmd
) {
294 static int CmdPref(const char *Cmd
) {
299 static int CmdClear(const char *Cmd
) {
300 CLIParserContext
*ctx
;
301 CLIParserInit(&ctx
, "clear",
302 "Clear the Proxmark3 client terminal screen",
303 "clear -> clear the terminal screen\n"
304 "clear -b -> clear the terminal screen and the scrollback buffer"
308 arg_lit0("b", "back", "also clear the scrollback buffer"),
311 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
312 bool scrollback
= arg_get_lit(ctx
, 1);
316 PrintAndLogEx(NORMAL
, _CLEAR_ _TOP_
"");
318 PrintAndLogEx(NORMAL
, _CLEAR_ _TOP_ _CLEAR_SCROLLBACK_
"");
323 static command_t CommandTable
[] = {
325 {"help", CmdHelp
, AlwaysAvailable
, "Use `" _YELLOW_("<command> help") "` for details of a command"},
326 {"prefs", CmdPref
, AlwaysAvailable
, "{ Edit client/device preferences... }"},
327 {"--------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("Technology") " -----------------------"},
328 {"analyse", CmdAnalyse
, AlwaysAvailable
, "{ Analyse utils... }"},
329 {"data", CmdData
, AlwaysAvailable
, "{ Plot window / data buffer manipulation... }"},
330 {"emv", CmdEMV
, AlwaysAvailable
, "{ EMV ISO-14443 / ISO-7816... }"},
331 {"hf", CmdHF
, AlwaysAvailable
, "{ High frequency commands... }"},
332 {"hw", CmdHW
, AlwaysAvailable
, "{ Hardware commands... }"},
333 {"lf", CmdLF
, AlwaysAvailable
, "{ Low frequency commands... }"},
334 {"mem", CmdFlashMem
, IfPm3Flash
, "{ Flash memory manipulation... }"},
335 {"nfc", CmdNFC
, AlwaysAvailable
, "{ NFC commands... }"},
336 {"piv", CmdPIV
, AlwaysAvailable
, "{ PIV commands... }"},
337 {"reveng", CmdRev
, AlwaysAvailable
, "{ CRC calculations from RevEng software... }"},
338 {"smart", CmdSmartcard
, AlwaysAvailable
, "{ Smart card ISO-7816 commands... }"},
339 {"script", CmdScript
, AlwaysAvailable
, "{ Scripting commands... }"},
340 {"trace", CmdTrace
, AlwaysAvailable
, "{ Trace manipulation... }"},
341 {"usart", CmdUsart
, IfPm3FpcUsartFromUsb
, "{ USART commands... }"},
342 {"wiegand", CmdWiegand
, AlwaysAvailable
, "{ Wiegand format manipulation... }"},
343 {"--------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("General") " -----------------------"},
344 {"auto", CmdAuto
, IfPm3Present
, "Automated detection process for unknown tags"},
345 {"clear", CmdClear
, AlwaysAvailable
, "Clear screen"},
346 {"hints", CmdHints
, AlwaysAvailable
, "Turn hints on / off"},
347 {"msleep", CmdMsleep
, AlwaysAvailable
, "Add a pause in milliseconds"},
348 {"rem", CmdRem
, AlwaysAvailable
, "Add a text line in log file"},
349 {"quit", CmdQuit
, AlwaysAvailable
, ""},
350 {"exit", CmdQuit
, AlwaysAvailable
, "Exit program"},
351 {NULL
, NULL
, NULL
, NULL
}
354 static int CmdHelp(const char *Cmd
) {
355 (void)Cmd
; // Cmd is not used so far
356 CmdsHelp(CommandTable
);
360 //-----------------------------------------------------------------------------
361 // Entry point into our code: called whenever the user types a command and
362 // then presses Enter, which the full command line that they typed.
363 //-----------------------------------------------------------------------------
364 int CommandReceived(const char *Cmd
) {
365 return CmdsParse(CommandTable
, Cmd
);
368 command_t
*getTopLevelCommandTable(void) {