update atrs list
[RRG-proxmark3.git] / armsrc / Standalone / hf_unisniff.c
blobbe0414a58cf82bbdb3381a937ca21eb3a7d21102
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 // HF_UNISNIFF: Integrated 14a/14b/15/picopass sniffer
17 //-----------------------------------------------------------------------------
20 * 'hf_unisniff' integrates existing sniffer functionality for 14a/14b/15/iclass into
21 * one standalone module. It can sniff to the RAM trace buffer, or if you have
22 * a PM3 with Flash it will (optionally) save traces to SPIFFS.
24 * You can select which protocol will be sniffed with compile-time flags, or at
25 * runtime via button presses or a config file in SPIFFS. You can also choose
26 * whether it will append to the trace file for each sniffing session
27 * or create new ones.
29 * If the protocol to sniff is configured at compile time or in config file:
30 * Once the module is launched, it will begin sniffing immediately.
32 * If configured for runtime selection:
33 * Flashing LED(s) indicate selected sniffer protocol: A=14a, B=14b, A+B=15, C=iclass
34 * Short press cycles through options. Long press begins sniffing.
36 * Short-pressing the button again will stop sniffing, with the sniffed data in
37 * the trace buffer. If you have Flash, and have not set the 'save=none'
38 * option in the config file, trace data will be saved to SPIFFS. The default
39 * is to create a new file for each sniffing session, but you may configure it
40 * to append instead.
42 * Once the data is saved, standalone mode will exit.
44 * LEDs:
45 * - LED1: sniffing
46 * - LED2: sniffed tag command, turns off when finished sniffing reader command
47 * - LED3: sniffed reader command, turns off when finished sniffing tag command
48 * - LED4: unmounting/sync'ing flash (normally < 100ms)
50 * Config file: 'hf_unisniff.conf' is a plain text file, one option per line.
51 * Settings here will override the compile-time options.
53 * Currently available options:
54 * save = [new|append|none]
55 * new = create a new file with a numbered name for each session.
56 * append = append to existing file, create if not existing.
57 * none = do not save to SPIFFS, leave in trace buffer only.
59 * protocol = [14a|14b|15|iclass|user]
60 * which protocol to sniff. If you choose a protocol it will go directly
61 * to work. If you choose 'user' you may select the protocol at the start
62 * of each session.
64 * hf_unisniff.conf sample file:
65 * save=new
66 * protocol=14a
68 * Upload it to the Proxmark3 spiffs.
69 * mem spiffs upload -s hf_unisniff.conf -d hf_unisniff.conf
71 * To use the mode:
72 * Start mode by pressing the Proxmark3 button for 3 seconds. See ledshow as indicator its in standalone mode.
73 * present proxmark3 and card to the reader.
74 * press proxmark3 button to exit the standalone mode.
77 * To retrieve trace data from flash:
79 * 1. mem spiffs dump -s hf_unisniff_[protocol]_[number].trace -d hf_unisniff.trace
80 * Copies trace data file from flash to your PC.
82 * 2. trace load -f hf_unisniff.trace
83 * Loads trace data from a file into PC-side buffers.
85 * 3. For ISO14443a........ trace list -1 -t 14a
86 * For MIFARE Classic... trace list -1 -t mf
88 * Lists trace data from buffer without requesting it from PM3.
90 * This module emits debug strings during normal operation -- so try it out in
91 * the lab connected to PM3 client before taking it into the field.
92 * Use `hw dbg -3` for debug messages.
94 * To delete the trace data from flash:
95 * mem spiffs remove -f [filename]
97 * Caveats / notes:
98 * - Trace buffer will be cleared on starting stand-alone mode. Data in flash
99 * will remain unless explicitly deleted.
100 * - This module will terminate if the trace buffer is full (and save data to flash).
101 * - Like normal sniffing mode, timestamps overflow after 5 min 16 sec.
102 * However, the trace buffer is sequential, so will be in the correct order.
104 * Mostly this is based on existing code, i.e. the hf_1*sniff modules and dankarmulti.
105 * I find it handy to have multiprotocol sniffing on the go, and prefer separate trace
106 * files rather than appends, so here it is.
108 * If you really like navigating menus with one button and some LEDs, it also works
109 * with dankarmulti :)
111 * Enjoy!
114 #include "standalone.h" // standalone definitions
115 #include "proxmark3_arm.h"
116 #include "iso14443a.h"
117 #include "iso14443b.h"
118 #include "iso15693.h"
119 #include "iso15.h"
120 #include "util.h"
121 #include "commonutil.h"
122 #include "spiffs.h"
123 #include "appmain.h"
124 #include "dbprint.h"
125 #include "ticks.h"
126 #include "BigBuf.h"
127 #include "string.h"
129 #define HF_UNISNIFF_PROTOCOL "14a"
130 #define HF_UNISNIFF_LOGFILE "hf_unisniff"
131 #define HF_UNISNIFF_LOGEXT ".trace"
132 #define HF_UNISNIFF_CONFIG "hf_unisniff.conf"
133 #define HF_UNISNIFF_CONFIG_SIZE 128
135 // The logic requires USER be last.
136 #define HF_UNISNIFF_PROTO_14A 0
137 #define HF_UNISNIFF_PROTO_14B 1
138 #define HF_UNISNIFF_PROTO_15 2
139 #define HF_UNISNIFF_PROTO_ICLASS 3
140 #define HF_UNISNIFF_PROTO_USER 4
142 // Default, override in .conf
143 #define HF_UNISNIFF_SAVE_MODE HF_UNISNIFF_SAVE_MODE_NEW
144 #define HF_UNISNIFF_SAVE_MODE_NEW 0
145 #define HF_UNISNIFF_SAVE_MODE_APPEND 1
146 #define HF_UNISNIFF_SAVE_MODE_NONE 2
148 #ifdef WITH_FLASH
149 static void UniSniff_DownloadTraceInstructions(char *fn, const char *proto) {
150 Dbprintf("");
151 Dbprintf("To get the trace from flash and display it:");
152 Dbprintf(" 1. mem spiffs dump -s %s -d hf_unisniff.trace", fn);
153 Dbprintf(" 2. trace load -f hf_unisniff.trace");
154 Dbprintf(" 3. trace list -t %s -1", proto);
156 #endif
158 void ModInfo(void) {
159 DbpString(" HF UNISNIFF - multimode HF sniffer (hazardousvoltage)");
160 Dbprintf(" Compile-time default protocol... %s", HF_UNISNIFF_PROTOCOL);
161 #ifdef WITH_FLASH
162 DbpString(" FLASH support................... yes");
163 #endif
166 void RunMod(void) {
168 StandAloneMode();
170 Dbprintf(_YELLOW_("HF UNISNIFF started"));
172 const char *protocols[] = {"14a", "14b", "15", "iclass", "user"};
174 // some magic to allow for `hw standalone` command to trigger a particular sniff from inside the pm3 client
175 const char *bb = (const char *)BigBuf_get_EM_addr();
176 uint8_t sniff_protocol;
177 if (strlen(bb) > 0) {
178 for (sniff_protocol = 0; sniff_protocol < ARRAYLEN(protocols); sniff_protocol++) {
179 if (strcmp(protocols[sniff_protocol], bb) == 0) {
180 break;
183 } else {
184 for (sniff_protocol = 0; sniff_protocol < ARRAYLEN(protocols); sniff_protocol++) {
185 if (strcmp(protocols[sniff_protocol], HF_UNISNIFF_PROTOCOL) == 0) {
186 break;
191 uint8_t default_sniff_protocol = sniff_protocol;
193 if (g_dbglevel >= DBG_DEBUG) {
194 Dbprintf("Compile-time configured protocol... %s ( %u )", protocols[sniff_protocol], sniff_protocol);
197 #ifdef WITH_FLASH
198 uint8_t save_mode = HF_UNISNIFF_SAVE_MODE;
199 rdv40_spiffs_lazy_mount();
200 // Allocate memory now for buffer for filename to save to. Who knows what'll be
201 // available after filling the trace buffer.
202 char *filename = (char *)BigBuf_calloc(64);
203 if (filename == NULL) {
204 Dbprintf("failed to allocate memory");
205 return;
207 // Read the config file. Size is limited to defined value so as not to consume
208 // stupid amounts of stack
209 if (exists_in_spiffs(HF_UNISNIFF_CONFIG)) {
211 uint32_t fsize = size_in_spiffs(HF_UNISNIFF_CONFIG);
212 if (fsize > HF_UNISNIFF_CONFIG_SIZE) {
213 fsize = HF_UNISNIFF_CONFIG_SIZE;
216 char config_buffer[HF_UNISNIFF_CONFIG_SIZE];
217 char *d = &config_buffer[0];
219 rdv40_spiffs_read_as_filetype(HF_UNISNIFF_CONFIG
220 , (uint8_t *)d
221 , fsize
222 , RDV40_SPIFFS_SAFETY_SAFE
225 // This parser is terrible but I think fairly memory efficient? Maybe better to use JSON?
226 char *x = d;
227 char *y = x;
229 // strip out all the whitespace and Windows line-endings
230 do {
232 while (*y == 0x20 || *y == 0x09 || *y == 0x0D) {
233 ++y;
235 } while ((*x++ = c_tolower(*y++)));
237 char *token = strchr(d, '\n');
239 while (token != NULL) {
240 *token++ = '\0';
241 char *tag = strtok(d, "=");
242 char *value = strtok(NULL, "\n");
244 if (tag != NULL && value != NULL) {
246 if (strcmp(tag, "protocol") == 0) {
247 // If we got a selection here, override compile-time selection
248 for (uint8_t i = 0; i < ARRAYLEN(protocols); i++) {
249 if (strcmp(protocols[i], value) == 0) {
250 sniff_protocol = i;
251 break;
255 } else if (strcmp(tag, "save") == 0) {
257 // Assume NEW
258 save_mode = HF_UNISNIFF_SAVE_MODE_NEW;
260 if (strcmp(value, "append") == 0) {
261 save_mode = HF_UNISNIFF_SAVE_MODE_APPEND;
264 if (strcmp(value, "none") == 0) {
265 save_mode = HF_UNISNIFF_SAVE_MODE_NONE;
269 d = token;
270 token = strchr(d, '\n');
273 if (g_dbglevel >= DBG_DEBUG) {
274 const char *save_modes[] = {"new", "append", "none"};
275 Dbprintf("Run-time configured protocol.... %s ( %u )", protocols[sniff_protocol], sniff_protocol);
276 Dbprintf("Run-time configured save_mode... %s ( %u )", save_modes[save_mode], sniff_protocol);
280 #endif
282 if (sniff_protocol >= HF_UNISNIFF_PROTO_USER) {
284 Dbprintf("Protocol undefined, going to prompt loop");
285 sniff_protocol = default_sniff_protocol; // Default to compile-time setting.
287 for (;;) {
289 WDT_HIT();
290 if (data_available()) {
291 BigBuf_free();
292 return;
295 if (GetTickCount() & 0x80) {
296 LED(sniff_protocol + 1, 0);
297 } else {
298 LEDsoff();
301 // Was our button held down or pressed?
302 int button_pressed = BUTTON_HELD(1000);
304 if (button_pressed == BUTTON_SINGLE_CLICK) {
306 sniff_protocol++;
307 if (sniff_protocol >= HF_UNISNIFF_PROTO_USER) {
308 sniff_protocol = HF_UNISNIFF_PROTO_14A;
311 SpinDelay(100);
312 Dbprintf("Selected protocol.... " _YELLOW_("%s"), protocols[sniff_protocol]);
315 if (button_pressed == BUTTON_HOLD) {
316 Dbprintf("Executing protocol... " _YELLOW_("%s"), protocols[sniff_protocol]);
318 for (uint8_t i = 0; i < 4; i++) {
319 LED(15, 0);
320 SpinDelay(100);
321 LEDsoff();
322 SpinDelay(100);
325 WAIT_BUTTON_RELEASED();
326 SpinDelay(300);
327 LEDsoff();
328 break;
333 switch (sniff_protocol) {
334 case HF_UNISNIFF_PROTO_14A:
335 SniffIso14443a(0);
336 break;
337 case HF_UNISNIFF_PROTO_14B:
338 SniffIso14443b();
339 break;
340 case HF_UNISNIFF_PROTO_15:
341 SniffIso15693(0, NULL, false);
342 break;
343 case HF_UNISNIFF_PROTO_ICLASS:
344 SniffIso15693(0, NULL, true);
345 break;
346 default:
347 Dbprintf("No protocol selected, exiting...");
348 BigBuf_free();
349 LEDsoff();
350 return;
353 Dbprintf("Stopped sniffing");
354 SpinDelay(200);
356 uint32_t trace_len = BigBuf_get_traceLen();
358 #ifndef WITH_FLASH
359 // Keep stuff in BigBuf for USB/BT dumping
360 if (trace_len > 0) {
361 Dbprintf("Trace length... %u bytes", trace_len);
364 #else
365 // Write stuff to spiffs logfile
366 if (trace_len == 0) {
367 Dbprintf("Trace buffer is empty, nothing to write!");
368 } else if (save_mode == HF_UNISNIFF_SAVE_MODE_NONE) {
369 Dbprintf("Trace save to flash disabled in config!");
370 } else {
371 Dbprintf("Trace length... %u bytes", trace_len);
373 uint8_t *trace_buffer = BigBuf_get_addr();
375 sprintf(filename, "%s_%s%s", HF_UNISNIFF_LOGFILE, protocols[sniff_protocol], HF_UNISNIFF_LOGEXT);
377 if (save_mode == HF_UNISNIFF_SAVE_MODE_NEW) {
379 uint16_t file_index = 0;
380 while (exists_in_spiffs(filename)) {
382 if (file_index++ == 1000) {
383 break;
386 sprintf(filename, "%s_%s-%03d%s"
387 , HF_UNISNIFF_LOGFILE
388 , protocols[sniff_protocol]
389 , file_index
390 , HF_UNISNIFF_LOGEXT
394 if (file_index > 999) {
395 Dbprintf("Too many files! Trace not saved. Try clean up your SPIFFS");
396 } else {
397 rdv40_spiffs_write(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
398 Dbprintf("Wrote trace to " _YELLOW_("%s"), filename);
402 if (save_mode == HF_UNISNIFF_SAVE_MODE_APPEND) {
404 if (exists_in_spiffs(filename) == false) {
405 rdv40_spiffs_write(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
406 Dbprintf("Wrote trace to " _YELLOW_("%s"), filename);
407 } else {
408 rdv40_spiffs_append(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
409 Dbprintf("Appended trace to " _YELLOW_("%s"), filename);
412 UniSniff_DownloadTraceInstructions(filename, protocols[sniff_protocol]);
415 LED_D_ON();
416 rdv40_spiffs_lazy_unmount();
417 LED_D_OFF();
419 SpinErr(LED_A, 200, 5);
420 SpinDelay(100);
421 BigBuf_free();
422 #endif
424 Dbprintf("-=[ exit ]=-");
425 LEDsoff();