Merge pull request #2741 from Donny-Guo/hidbrute
[RRG-proxmark3.git] / armsrc / Standalone / lf_tharexde.c
blobb46ea69d8c818d0306df73ed471aefdb6566c6b8
1 //-----------------------------------------------------------------------------
2 // Copyright (C) tharexde, 2021
3 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // See LICENSE.txt for the text of the license.
16 //-----------------------------------------------------------------------------
17 // main code for EM4x50 simulator and collector aka THAREXDE
18 //-----------------------------------------------------------------------------
19 #include <inttypes.h>
20 #include "ticks.h"
21 #include "standalone.h"
22 #include "proxmark3_arm.h"
23 #include "appmain.h"
24 #include "BigBuf.h"
25 #include "commonutil.h"
26 #include "fpgaloader.h"
27 #include "util.h"
28 #include "dbprint.h"
29 #include "spiffs.h"
30 #include "../em4x50.h"
33 * `lf_tharexde` simulates EM4x50 dumps uploaded to flash, reads words
34 * transmitted by EM4x50 tags in standard read mode and stores them in
35 * internal flash.
36 * It requires RDV4 hardware (for flash and battery).
38 * On entering stand-alone mode, this module will start simulating EM4x50 data.
39 * Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml).
40 * If reader sends password different from dump file password, it is saved in
41 * file lf_em4x50_passwords.log in flash memory.
43 * On switching to read/record mode by pressing pm3 button, module will start
44 * reading EM4x50 data. Each collected data set will be written/appended to the
45 * logfile in flash (lf_em4x50_collect.log) as a text string.
47 * LEDs:
48 * - LED A: simulating
49 * - LED A blinking: no simulation data or read error
50 * - LED B: reading/recording
51 * - LED D: unmounting/sync'ing flash (normally < 100ms)
53 * To upload input file (eml format) to flash:
54 * - mem spiffs upload -s <filename> -d lf_em4x50_simulate.eml
56 * To retrieve password file from flash:
57 * - mem spiffs dump -s lf_em4x50_passwords.log
59 * To retrieve log file from flash:
60 * - mem spiffs dump -s lf_em4x50_collect.log
62 * This module emits debug strings during normal operation -- so try it out in
63 * the lab connected to PM3 client before taking it into the field.
65 * To delete the input file from flash:
66 * - mem spiffs remove -f lf_em4x50_simulate.eml
68 * To delete the log file from flash:
69 * - mem spiffs remove -f lf_em4x50_passwords.log
71 * To delete the log file from flash:
72 * - mem spiffs remove -f lf_em4x50_collect.log
75 #define STATE_SIM 0
76 #define STATE_READ 1
77 #define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml"
78 #define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log"
79 #define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log"
80 #define MAX_NO_PWDS_TO_SAVE 50
82 static void LoadDataInstructions(const char *inputfile) {
83 Dbprintf("");
84 Dbprintf("To load datafile to flash and display it:");
85 Dbprintf("1. edit input file %s", inputfile);
86 Dbprintf("2. start proxmark3 client");
87 Dbprintf("3. mem spiffs upload -s <filename> -d %s", inputfile);
88 Dbprintf("4. start standalone mode");
91 static void DownloadLogInstructions(const char *logfile) {
92 Dbprintf("");
93 Dbprintf("To get the logfile from flash and display it:");
94 Dbprintf("1. mem spiffs dump -s %s", logfile);
95 Dbprintf("2. exit proxmark3 client");
96 Dbprintf("3. cat <filename>");
99 static bool get_input_data_from_file(uint32_t *tag, char *inputfile) {
101 size_t now = 0;
103 if (exists_in_spiffs(inputfile)) {
105 uint32_t size = size_in_spiffs(inputfile);
106 uint8_t *mem = BigBuf_malloc(size);
108 Dbprintf(_YELLOW_("found input file %s"), inputfile);
110 rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE);
112 now = (size + 1) / 9;
113 for (int i = 0; i < now; i++) {
114 for (int j = 0; j < 4; j++) {
115 tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
119 Dbprintf(_YELLOW_("read tag data from input file"));
120 } else {
121 Dbprintf(_RED_("no input file %s"), inputfile);
124 BigBuf_free();
126 return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]));
129 static void append(const char *filename, uint8_t *entry, size_t entry_len) {
130 if (exists_in_spiffs(filename)) {
131 rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
132 } else {
133 rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
137 static void save_pwds(uint32_t *pwdlist, size_t no_pwd) {
138 if (no_pwd > 0) {
139 Dbprintf("");
140 for (int i = 0; i < no_pwd; i++) {
141 uint8_t entry[10] = {0};
142 sprintf((char *)entry, "%08"PRIx32"\n", pwdlist[i]);
143 append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry));
144 Dbprintf("received password: %08"PRIx32"", pwdlist[i]);
149 void ModInfo(void) {
150 DbpString(_YELLOW_(" LF EM4x50 sim/collector mode") " - a.k.a tharexde");
153 void RunMod(void) {
155 bool state_change = true, read_ok = false;
156 int no_words = 0, command = 0, no_pwd = 0;
157 uint8_t entry[400], state = STATE_SIM;
158 uint32_t tag[EM4X50_NO_WORDS] = {0x0}, pwdlist[MAX_NO_PWDS_TO_SAVE];
160 rdv40_spiffs_lazy_mount();
161 StandAloneMode();
162 Dbprintf(_YELLOW_("Standalone mode THAREXDE started"));
164 for (;;) {
166 WDT_HIT();
167 if (data_available()) {
168 break;
171 // press button - toggle between SIM and READ
172 // hold button - exit
173 int button_pressed = BUTTON_CLICKED(1000);
174 if (button_pressed == BUTTON_SINGLE_CLICK) {
176 switch (state) {
177 case STATE_SIM:
178 // save and display passwords
179 save_pwds(pwdlist, no_pwd);
180 state = STATE_READ;
181 break;
182 case STATE_READ:
183 state = STATE_SIM;
184 break;
185 default:
186 break;
189 state_change = true;
191 } else if (button_pressed == BUTTON_HOLD) {
192 break;
195 if (state == STATE_SIM) {
197 if (state_change) {
199 // initialize simulation mode
200 LEDsoff();
201 LED_A_ON();
202 Dbprintf("");
203 Dbprintf(_YELLOW_("switched to EM4x50 simulating mode"));
205 read_ok = get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM);
206 if (read_ok) {
207 Dbprintf(_YELLOW_("tag data ok"));
208 } else {
209 Dbprintf(_RED_("error in tag data"));
210 LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM);
213 LED_D_OFF();
214 g_Login = false;
215 g_Password = reflect32(tag[0]);
216 g_WritePasswordProcess = false;
217 command = EM4X50_COMMAND_STANDARD_READ;
218 no_pwd = 0;
219 memset(pwdlist, 0, sizeof(pwdlist));
221 em4x50_setup_sim();
222 state_change = false;
225 // if no data or read error -> blink
226 if (read_ok == false) {
227 LED(LED_A, 200);
228 SpinDelay(200);
231 em4x50_handle_commands(&command, tag, true);
233 // check if new password was found
234 if (g_Password != reflect32(tag[EM4X50_DEVICE_PASSWORD])) {
235 if (no_pwd < MAX_NO_PWDS_TO_SAVE) {
236 pwdlist[no_pwd] = g_Password;
237 no_pwd++;
239 g_Password = reflect32(tag[EM4X50_DEVICE_PASSWORD]);
242 // if timeout (e.g. no reader field) continue with standard read
243 // mode and reset former authentication
244 if (command == PM3_ETIMEOUT) {
245 command = EM4X50_COMMAND_STANDARD_READ;
246 g_Login = false;
247 LED_D_OFF();
250 } else if (state == STATE_READ) {
252 if (state_change) {
254 // initialize read mode
255 LEDsoff();
256 LED_B_ON();
257 Dbprintf("");
258 Dbprintf(_YELLOW_("switched to EM4x50 reading mode"));
260 em4x50_setup_read();
261 state_change = false;
264 no_words = 0;
265 memset(tag, 0, sizeof(tag));
266 standard_read(&no_words, tag);
268 if (no_words > 0) {
270 memset(entry, 0, sizeof(entry));
272 sprintf((char *)entry, "found EM4x50 tag:\n");
273 for (int i = 0; i < no_words; i++) {
274 sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]);
276 Dbprintf("%s", entry);
277 sprintf((char *)entry + strlen((char *)entry), "\n");
278 append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry));
282 // reset timer
283 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
284 AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
285 AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
286 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
289 if (state == STATE_READ) {
290 DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT);
291 } else {
292 // save and display passwords
293 save_pwds(pwdlist, no_pwd);
294 DownloadLogInstructions(LF_EM4X50_LOGFILE_SIM);
297 LED_D_ON();
298 rdv40_spiffs_lazy_unmount();
299 LED_D_OFF();
301 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
303 LEDsoff();
304 Dbprintf("");
305 Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped"));