1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
4 // Modified 2018 iceman <iceman at iuse.se>
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
8 //-----------------------------------------------------------------------------
9 // Main command parser entry point
10 //-----------------------------------------------------------------------------
12 // ensure gmtime_r is available even with -std=c99; must be included before
14 #define _POSIX_C_SOURCE 200112L
20 #include <time.h> // MingW
21 #include <stdlib.h> // calloc
30 #include "cmdscript.h"
32 #include "cmdanalyse.h"
33 #include "emv/cmdemv.h" // EMV
34 #include "cmdflashmem.h" // rdv40 flashmem commands
35 #include "cmdsmartcard.h" // rdv40 smart card ISO7816 commands
36 #include "cmdusart.h" // rdv40 FPC USART commands
37 #include "cmdwiegand.h" // wiegand commands
39 #include "util_posix.h"
40 #include "commonutil.h" // ARRAYLEN
41 #include "preferences.h"
42 #include "cliparser.h"
44 static int CmdHelp(const char *Cmd
);
46 static void AppendDate(char *s
, size_t slen
, const char *fmt
) {
47 struct tm
*ct
, tm_buf
;
48 time_t now
= time(NULL
);
50 ct
= gmtime_s(&tm_buf
, &now
) == 0 ? &tm_buf
: NULL
;
52 ct
= gmtime_r(&now
, &tm_buf
);
55 strftime(s
, slen
, "%Y-%m-%dT%H:%M:%SZ", ct
); // ISO8601
57 strftime(s
, slen
, fmt
, ct
);
60 static int lf_search_plus(const char *Cmd
) {
62 sample_config oldconfig
;
63 memset(&oldconfig
, 0, sizeof(sample_config
));
65 int retval
= lf_getconfig(&oldconfig
);
67 if (retval
!= PM3_SUCCESS
) {
68 PrintAndLogEx(ERR
, "failed to get current device config");
72 // Divisor : frequency(khz)
74 // 125.00 134.83 250.00 375.00 500.00
76 int16_t default_divisor
[] = {95, 88, 47, 31, 23};
79 default LF config is set to:
88 sample_config config
= {
92 .trigger_threshold
= 0,
98 for (int i
= 0; i
< ARRAYLEN(default_divisor
); ++i
) {
100 if (kbd_enter_pressed()) {
101 PrintAndLogEx(INFO
, "Keyboard pressed. Done.");
104 // Try to change config!
106 d
= config
.divisor
= default_divisor
[i
];
107 PrintAndLogEx(INFO
, "--> trying (" _GREEN_("%d.%02d kHz")")", 12000 / (d
+ 1), ((1200000 + (d
+ 1) / 2) / (d
+ 1)) - ((12000 / (d
+ 1)) * 100));
109 retval
= lf_config(&config
);
110 if (retval
!= PM3_SUCCESS
)
113 // The config for pm3 is changed, we can trying search!
114 retval
= CmdLFfind(Cmd
);
115 if (retval
== PM3_SUCCESS
)
120 lf_config(&oldconfig
);
124 static int CmdAuto(const char *Cmd
) {
125 CLIParserContext
*ctx
;
126 CLIParserInit(&ctx
, "auto",
127 "Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
133 arg_lit0("c", NULL
, "Continue searching even after a first hit"),
136 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
137 bool exit_first
= (arg_get_lit(ctx
, 1) == false);
140 PrintAndLogEx(INFO
, "lf search");
141 int ret
= CmdLFfind("");
142 if (ret
== PM3_SUCCESS
&& exit_first
)
145 PrintAndLogEx(INFO
, "hf search");
146 ret
= CmdHFSearch("");
147 if (ret
== PM3_SUCCESS
&& exit_first
)
150 PrintAndLogEx(INFO
, "lf search - unknown");
151 ret
= lf_search_plus("");
152 if (ret
== PM3_SUCCESS
&& exit_first
)
155 if (ret
!= PM3_SUCCESS
)
156 PrintAndLogEx(INFO
, "Failed both LF / HF SEARCH,");
158 PrintAndLogEx(INFO
, "Trying " _YELLOW_("`lf read`") " and save a trace for you");
161 lf_read(false, 40000);
162 char *fname
= calloc(100, sizeof(uint8_t));
163 AppendDate(fname
, 100, "-f lf_unknown_%Y-%m-%d_%H:%M");
169 int CmdRem(const char *Cmd
) {
170 CLIParserContext
*ctx
;
171 CLIParserInit(&ctx
, "rem",
172 "Add a text line in log file",
173 "rem my message -> adds a timestamp with `my message`"
178 arg_strx1(NULL
, NULL
, NULL
, "message line you want inserted"),
181 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
183 struct arg_str
*foo
= arg_get_str(ctx
, 1);
187 count
+= strlen(foo
->sval
[len
]);
188 } while (len
++ < (foo
->count
- 1));
190 char s
[count
+ foo
->count
];
191 memset(s
, 0, sizeof(s
));
195 snprintf(s
+ strlen(s
), sizeof(s
) - strlen(s
), "%s ", foo
->sval
[len
]);
196 } while (len
++ < (foo
->count
- 1));
200 AppendDate(buf
, sizeof(buf
), NULL
);
201 PrintAndLogEx(SUCCESS
, "%s remark: %s", buf
, s
);
205 static int CmdHints(const char *Cmd
) {
207 CLIParserContext
*ctx
;
208 CLIParserInit(&ctx
, "hints",
216 arg_lit0("1", "on", "turn on hints"),
217 arg_lit0("0", "off", "turn off hints"),
220 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
222 bool turn_on
= arg_get_lit(ctx
, 1);
223 bool turn_off
= arg_get_lit(ctx
, 2);
226 if (turn_on
&& turn_off
) {
227 PrintAndLogEx(ERR
, "you can't turn off and on at the same time");
232 session
.show_hints
= false;
233 } else if (turn_on
) {
234 session
.show_hints
= true;
237 PrintAndLogEx(INFO
, "Hints are %s", (session
.show_hints
) ? "ON" : "OFF");
241 static int CmdMsleep(const char *Cmd
) {
242 CLIParserContext
*ctx
;
243 CLIParserInit(&ctx
, "msleep",
244 "Sleep for given amount of milliseconds",
250 arg_int0("t", "ms", "<ms>", "time in milliseconds"),
253 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
254 uint32_t ms
= arg_get_u32_def(ctx
, 1, 0);
258 PrintAndLogEx(ERR
, "Specified invalid input. Can't be zero");
266 static int CmdQuit(const char *Cmd
) {
267 CLIParserContext
*ctx
;
268 CLIParserInit(&ctx
, "quit",
269 "Quit the Proxmark3 client terminal",
276 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
281 static int CmdRev(const char *Cmd
) {
286 static int CmdPref(const char *Cmd
) {
291 static int CmdClear(const char *Cmd
) {
292 CLIParserContext
*ctx
;
293 CLIParserInit(&ctx
, "clear",
294 "Clear the Proxmark3 client terminal screen",
301 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
303 PrintAndLogEx(NORMAL
, _CLEAR_ _TOP_
"");
307 static command_t CommandTable
[] = {
309 {"help", CmdHelp
, AlwaysAvailable
, "Use `" _YELLOW_("<command> help") "` for details of a command"},
310 {"prefs", CmdPref
, AlwaysAvailable
, "{ Edit client/device preferences... }"},
311 {"--------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("Technology") " -----------------------"},
312 {"analyse", CmdAnalyse
, AlwaysAvailable
, "{ Analyse utils... }"},
313 {"data", CmdData
, AlwaysAvailable
, "{ Plot window / data buffer manipulation... }"},
314 {"emv", CmdEMV
, AlwaysAvailable
, "{ EMV ISO-14443 / ISO-7816... }"},
315 {"hf", CmdHF
, AlwaysAvailable
, "{ High frequency commands... }"},
316 {"hw", CmdHW
, AlwaysAvailable
, "{ Hardware commands... }"},
317 {"lf", CmdLF
, AlwaysAvailable
, "{ Low frequency commands... }"},
318 {"mem", CmdFlashMem
, IfPm3Flash
, "{ Flash memory manipulation... }"},
319 {"nfc", CmdNFC
, AlwaysAvailable
, "{ NFC commands... }"},
320 {"reveng", CmdRev
, AlwaysAvailable
, "{ CRC calculations from RevEng software... }"},
321 {"smart", CmdSmartcard
, AlwaysAvailable
, "{ Smart card ISO-7816 commands... }"},
322 {"script", CmdScript
, AlwaysAvailable
, "{ Scripting commands... }"},
323 {"trace", CmdTrace
, AlwaysAvailable
, "{ Trace manipulation... }"},
324 {"usart", CmdUsart
, IfPm3FpcUsartFromUsb
, "{ USART commands... }"},
325 {"wiegand", CmdWiegand
, AlwaysAvailable
, "{ Wiegand format manipulation... }"},
326 {"--------", CmdHelp
, AlwaysAvailable
, "----------------------- " _CYAN_("General") " -----------------------"},
327 {"auto", CmdAuto
, IfPm3Present
, "Automated detection process for unknown tags"},
328 {"clear", CmdClear
, AlwaysAvailable
, "Clear screen"},
329 {"hints", CmdHints
, AlwaysAvailable
, "Turn hints on / off"},
330 {"msleep", CmdMsleep
, AlwaysAvailable
, "Add a pause in milliseconds"},
331 {"rem", CmdRem
, AlwaysAvailable
, "Add a text line in log file"},
332 {"quit", CmdQuit
, AlwaysAvailable
, ""},
333 {"exit", CmdQuit
, AlwaysAvailable
, "Exit program"},
334 {NULL
, NULL
, NULL
, NULL
}
337 static int CmdHelp(const char *Cmd
) {
338 (void)Cmd
; // Cmd is not used so far
339 CmdsHelp(CommandTable
);
343 //-----------------------------------------------------------------------------
344 // Entry point into our code: called whenever the user types a command and
345 // then presses Enter, which the full command line that they typed.
346 //-----------------------------------------------------------------------------
347 int CommandReceived(char *Cmd
) {
348 return CmdsParse(CommandTable
, Cmd
);
351 command_t
*getTopLevelCommandTable(void) {