From 1ca5d3c53c02c8d2700ac88e4ce950df7499b6bf Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 25 Jan 2021 23:52:14 +0100 Subject: [PATCH 01/15] 4x50 standalone mode --- armsrc/Standalone/Makefile.hal | 7 +- armsrc/Standalone/Makefile.inc | 4 + armsrc/Standalone/lf_tharexde.c | 271 ++++++++++++++++++++++++++++++++ armsrc/em4x50.c | 249 +++++++++++++++++------------ armsrc/em4x50.h | 8 + include/em4x50.h | 11 ++ 6 files changed, 450 insertions(+), 100 deletions(-) create mode 100644 armsrc/Standalone/lf_tharexde.c diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index d5414f661..552267611 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -35,6 +35,9 @@ define KNOWN_STANDALONE_DEFINITIONS | LF_SAMYRUN | HID26 read/clone/sim | | | - Samy Kamkar | +----------------------------------------------------------+ +| LF_THAREXDE | Simulate/read EM4x50 tags | +| (RDV4 only) | storing in flashmem | ++----------------------------------------------------------+ | HF_14ASNIFF | 14a sniff to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ @@ -67,10 +70,10 @@ define KNOWN_STANDALONE_DEFINITIONS +----------------------------------------------------------+ endef -STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN +STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_TCPRST HF_YOUNG STANDALONE_MODES_REQ_SMARTCARD := -STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS +STANDALONE_MODES_REQ_FLASH := LF_ICEHID LF_THAREXDE HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 087a4d927..519dc2087 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -73,3 +73,7 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS))) SRC_STANDALONE = hf_iceclass.c endif +# WITH_STANDALONE_LF_THAREXDE +ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS))) + SRC_STANDALONE = lf_tharexde.c +endif diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c new file mode 100644 index 000000000..41fd96d34 --- /dev/null +++ b/armsrc/Standalone/lf_tharexde.c @@ -0,0 +1,271 @@ +//----------------------------------------------------------------------------- +// tharexde, 2021 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// main code for EM4x50 simulator and collector aka THAREXDE +//----------------------------------------------------------------------------- +#include +#include "ticks.h" +#include "standalone.h" +#include "proxmark3_arm.h" +#include "appmain.h" +#include "BigBuf.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" +#include "spiffs.h" +#include "../em4x50.h" + +/* + * `lf_tharexde` simulates EM4x50 dumps uploaded words/blocks, reads words of standard read + * mode of EM4x50 tags and stores them in internal flash. + * It requires RDV4 hardware (for flash and battery). + * + * On entering stand-alone mode, this module will start simulating EM4x50 data. + * Data is read from eml dump file uploaded to flash memory. + * + * On switching to read/record mode by pressing pm3 button, module will start + * reading/recording EM4x50 data. Every found / collected data will be + * written/appended to the logfile in flash as a text string. + * + * LEDs: + * - LED A: simulating + * - LED B: reading / record + * - LED C: writing to flash + * - LED D: unmounting/sync'ing flash (normally < 100ms) + * + * To upload input file (eml format) to flash: + * - mem spiffs load f o lf_em4x50_simulate.eml + * + * To retrieve log file from flash: + * - mem spiffs dump o lf_em4x50_collect.log f + * + * This module emits debug strings during normal operation -- so try it out in + * the lab connected to PM3 client before taking it into the field. + * + * To delete the input file from flash: + * - mem spiffs remove lf_em4x50_simulate.eml + * + * To delete the log file from flash: + * - mem spiffs remove lf_em4x50_collect.log + */ + +#define STATE_SIM 0 +#define STATE_READ 1 +#define EM4X50_TAG_WORD 45 +#define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" +#define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" + +bool input_exists; +bool log_exists; + +static void LoadDataInstructions(const char *inputfile) { + Dbprintf(""); + Dbprintf("To load datafile to flash and display it:"); + Dbprintf(_YELLOW_("1.") " edit input file %s", inputfile); + Dbprintf(_YELLOW_("2.") " start proxmark3 client"); + Dbprintf(_YELLOW_("3.") " mem spiffs load f o %s", inputfile); + Dbprintf(_YELLOW_("4.") " start standalone mode"); +} + +static void DownloadLogInstructions(const char *logfile) { + Dbprintf(""); + Dbprintf("To get the logfile from flash and display it:"); + Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f ", logfile); + Dbprintf(_YELLOW_("2.") " exit proxmark3 client"); + Dbprintf(_YELLOW_("3.") " cat "); +} + +static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { + + size_t now = 0; + if (exists_in_spiffs(inputfile)) { + + uint32_t size = size_in_spiffs(inputfile); + uint8_t *mem = BigBuf_malloc(size); + + Dbprintf(_YELLOW_("found input file %s"), inputfile); + + rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE); + + now = size / 9; + for (int i = 0; i < now; i++) + for (int j = 0; j < 4; j++) + tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); + + Dbprintf(_YELLOW_("read tag data from input file")); + } + + BigBuf_free(); + + return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID])); +} + +static void append(const char *filename, uint8_t *entry, size_t entry_len) { + + LED_D_ON(); + if (log_exists == false) { + rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + log_exists = true; + } else { + rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + } + LED_D_OFF(); +} + +void ModInfo(void) { + DbpString(_YELLOW_(" LF EM4x50 sim/collector mode") " - a.k.a tharexde"); +} + +void RunMod(void) { + + bool state_change = true; + int no_words = 0, command = 0; + uint8_t entry[81], state = STATE_SIM; + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + rdv40_spiffs_lazy_mount(); + + StandAloneMode(); + Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); + + for (;;) { + + WDT_HIT(); + if (data_available()) { + break; + } + + // press button - toggle between SIM and READ + // hold button - exit + int button_pressed = BUTTON_CLICKED(1000); + if (button_pressed == BUTTON_SINGLE_CLICK) { + + SpinUp(100); + + switch (state) { + + case STATE_SIM: + state = STATE_READ; + break; + case STATE_READ: + state = STATE_SIM; + break; + default: + break; + } + + state_change = true; + + } else if (button_pressed == BUTTON_HOLD) { + SpinDown(100); + break; + } + + if (state == STATE_SIM) { + + if (state_change) { + + LEDsoff(); + LED_A_ON(); + Dbprintf(""); + Dbprintf(_YELLOW_("switched to EM4x50 simulating mode")); + + if (get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM)) { + Dbprintf(_YELLOW_("tag data ok")); + } else { + Dbprintf(_RED_("error in tag data")); + } + + // init; start with command = standard read mode + em4x50_setup_sim(); + gLogin = false; + gWritePasswordProcess = false; + command = EM4X50_COMMAND_STANDARD_READ; + + state_change = false; + } + + em4x50_handle_commands(&command, tag); + + // stop if key (pm3 button or enter key) has been pressed + if (command == PM3_EOPABORTED) { + break; + } + + // if timeout (e.g. no reader field) continue with standard read + // mode and reset former authentication + if (command == PM3_ETIMEOUT) { + command = EM4X50_COMMAND_STANDARD_READ; + gLogin = false; + } + + } else if (state == STATE_READ) { + + if (state_change) { + + LEDsoff(); + LED_B_ON(); + Dbprintf(""); + Dbprintf(_YELLOW_("switched to EM4x50 reading mode")); + + memset(entry, 0, sizeof(entry)); + memset(tag, 0, sizeof(tag)); + + log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_COLLECT); + + em4x50_setup_read(); + + state_change = false; + } + + standard_read(&no_words, tag); + + // reset timers + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 + AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero + AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer + + if (no_words > 0) { + + memset(entry, 0, sizeof(entry)); + + Dbprintf(""); + sprintf((char *)entry, "found new EM4x50 tag:"); + Dbprintf("%s", entry); + strcat((char *)entry, "\n"); + append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); + + for (int i = 0; i < no_words; i++) { + + sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, tag[i]); + Dbprintf("%s", entry); + strcat((char *)entry, "\n"); + append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); + } + } + + memset(tag, 0, sizeof(tag)); + no_words = 0; + } + } + + if (state == STATE_READ) { + DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT); + } else { + LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM); + } + + LED_D_ON(); + rdv40_spiffs_lazy_unmount(); + LED_D_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + Dbprintf(""); + Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped")); +} diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index f27a21367..49fa0221e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -24,11 +24,17 @@ // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz // EM4x50 units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) // T0 = TIMER_CLOCK1 / 125000 = 192 - #ifndef T0 #define T0 192 #endif +// the following terms are used (for carrier frequency of 125 kHz): +// 1 us = 1.5 ticks +// 1 cycle = 1 period = 8 us = 12 ticks +// 1 bit = 64 cycles = 768 ticks = 512 us +#define CYCLES2TICKS 12 + +// given in cycles/periods #define EM4X50_T_TAG_QUARTER_PERIOD 16 #define EM4X50_T_TAG_HALF_PERIOD 32 #define EM4X50_T_TAG_THREE_QUARTER_PERIOD 48 @@ -40,27 +46,21 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 +#define EM4X50_TAG_TOLERANCE 8 +#define EM4X50_ZERO_DETECTION 3 -// timeout values for simulation mode (may vary with regard to reader) +// timeout values (empirical) for simulation mode (may vary with regard to reader) #define EM4X50_T_SIMULATION_TIMEOUT_READ 600 #define EM4X50_T_SIMULATION_TIMEOUT_WAIT 50 -// the following value seems to be critical; if it's too low (e.g. < 120) -// some cards are no longer readable although they're ok +// the following value (pulses) seems to be critical; if it's too low +//(e.g. < 120) some cards are no longer readable although they're ok #define EM4X50_T_WAITING_FOR_SNGLLIW 140 -#define EM4X50_TAG_TOLERANCE 8 -#define EM4X50_ZERO_DETECTION 3 +// div #define EM4X50_TAG_WORD 45 #define EM4X50_TAG_MAX_NO_BYTES 136 -#define EM4X50_COMMAND_LOGIN 0x01 -#define EM4X50_COMMAND_RESET 0x80 -#define EM4X50_COMMAND_WRITE 0x12 -#define EM4X50_COMMAND_WRITE_PASSWORD 0x11 -#define EM4X50_COMMAND_SELECTIVE_READ 0x0A -#define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command - int gHigh = 190; int gLow = 60; @@ -74,11 +74,15 @@ bool gWritePasswordProcess = false; // do nothing for using timer0 static void wait_timer(uint32_t period) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < period); + + int timeout = period; + uint32_t tval = GetTicks(); + + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //while (AT91C_BASE_TC0->TC_CV < period); + while ((timeout--) && (GetTicks() - tval < period)); } - // extract and check parities // return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { @@ -130,13 +134,16 @@ static bool extract_parities(uint64_t word, uint32_t *data) { return false; } -static void em4x50_setup_read(void) { +void em4x50_setup_read(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + StartTicks(); + // 50ms for the resonant antenna to settle. - SpinDelay(50); + //SpinDelay(50); + WaitMS(50); // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); @@ -154,6 +161,7 @@ static void em4x50_setup_read(void) { // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); + /* // Enable Peripheral Clock for // TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);// | (1 << AT91C_ID_TC1); @@ -172,12 +180,13 @@ static void em4x50_setup_read(void) { // synchronized startup procedure while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero - + */ + // Watchdog hit WDT_HIT(); } -static void em4x50_setup_sim(void) { +void em4x50_setup_sim(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); @@ -186,12 +195,15 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + StartTicks(); + /* AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + */ + // Watchdog hit WDT_HIT(); @@ -200,7 +212,7 @@ static void em4x50_setup_sim(void) { // calculate signal properties (mean amplitudes) from measured data: // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow -static bool get_signalproperties(void) { +bool get_signalproperties(void) { bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; @@ -208,6 +220,7 @@ static bool get_signalproperties(void) { uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; uint32_t sample_max_sum = 0; + uint32_t tval = 0; memset(sample_max, 0x00, sizeof(sample_max)); LED_A_ON(); @@ -218,7 +231,8 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); + wait_timer(12 * EM4X50_T_TAG_HALF_PERIOD); // ignore first samples if ((i > SIGNAL_IGNORE_FIRST_SAMPLES) && (AT91C_BASE_SSC->SSC_RHR > noise)) { @@ -236,8 +250,10 @@ static bool get_signalproperties(void) { // 3 single "full periods" to eliminate the influence of a listen window for (int i = 0; i < no_periods; i++) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) { + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) { + tval = GetTicks(); + while (GetTicks() - tval < 12 * 3 * EM4X50_T_TAG_FULL_PERIOD) { if (BUTTON_PRESS()) return false; @@ -268,12 +284,14 @@ static bool get_signalproperties(void) { static bool invalid_bit(void) { // get sample at 3/4 of bit period - wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + wait_timer(12 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); + wait_timer(12 * EM4X50_T_TAG_QUARTER_PERIOD); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -284,7 +302,7 @@ static bool invalid_bit(void) { static uint32_t get_pulse_length(void) { - int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD), tval = 0; // iterates pulse length (low -> high -> low) @@ -296,7 +314,8 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + tval = GetTicks(); timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); while (sample < gHigh && (timeout--)) @@ -312,41 +331,59 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - return (uint32_t)AT91C_BASE_TC0->TC_CV; + //return (uint32_t)AT91C_BASE_TC0->TC_CV; + return GetTicks() - tval; } // check if pulse length corresponds to given length static bool check_pulse_length(uint32_t pl, int length) { - return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); + //return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); + return ((pl >= 12 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= 12 * (length + EM4X50_TAG_TOLERANCE))); } // send single bit according to EM4x50 application note and datasheet static void em4x50_reader_send_bit(int bit) { + int timeout = 500; + // reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + uint32_t tval = GetTicks(); if (bit == 0) { // disable modulation (activate the field) for 7 cycles of carrier // period (Opt64) LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 7); - + //while (AT91C_BASE_TC0->TC_CV < T0 * 7); + while ((timeout--) && (GetTicks() - tval < 12 * 7)); + if (timeout <= 0) + return; + timeout = 500; + // enable modulation (drop the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); + //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); + while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_HALF_PERIOD)); + if (timeout <= 0) + return; + timeout = 500; // disable modulation for second half of bit period LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD)); + if (timeout <= 0) + return; + timeout = 500; } else { // bit = "1" means disable modulation for full bit period LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD)); } } @@ -446,7 +483,8 @@ static int find_double_listen_window(bool bcommand) { // second window follows - sync on this to issue a command // skip the next bit... - wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -484,7 +522,7 @@ static int find_double_listen_window(bool bcommand) { // function is used to check wether a tag on the proxmark is an // EM4x50 tag or not -> speed up "lf search" process -static bool find_em4x50_tag(void) { +bool find_em4x50_tag(void) { return find_single_listen_window(); } @@ -524,7 +562,8 @@ static bool check_ack(bool bliw) { // wait for 2 bits (remaining "bit" of ACK signal + first // "bit" of listen window) - wait_timer(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); + //wait_timer(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer(12 * 2 * EM4X50_T_TAG_FULL_PERIOD); // check for listen window (if first bit cannot be interpreted // as a valid bit it must belong to a listen window) @@ -655,7 +694,8 @@ static bool login(uint32_t password) { // send password em4x50_reader_send_word(password); - wait_timer(T0 * EM4X50_T_TAG_TPP); + //wait_timer(T0 * EM4X50_T_TAG_TPP); + wait_timer(12 * EM4X50_T_TAG_TPP); // check if ACK is returned if (check_ack(false)) @@ -815,7 +855,7 @@ static int reset(void) { // reads data that tag transmits when exposed to reader field // (standard read mode); number of read words is saved in -static int standard_read(int *now, uint32_t *words) { +int standard_read(int *now, uint32_t *words) { int fwr = *now, res = PM3_EFAILED; @@ -823,8 +863,11 @@ static int standard_read(int *now, uint32_t *words) { if ((res = find_double_listen_window(false)) == PM3_SUCCESS) { // read and save words until following double listen window is detected - while ((res = get_word_from_bitstream(&words[*now])) == EM4X50_TAG_WORD) + res = get_word_from_bitstream(&words[*now]); + while (res == EM4X50_TAG_WORD) { (*now)++; + res = get_word_from_bitstream(&words[*now]); + } // number of detected words *now -= fwr; @@ -957,7 +1000,8 @@ static int write(uint32_t word, uint32_t addresses) { } else { // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(T0 * EM4X50_T_TAG_TWA); + //wait_timer(T0 * EM4X50_T_TAG_TWA); + wait_timer(12 * EM4X50_T_TAG_TWA); // look for ACK sequence if (check_ack(false)) { @@ -965,7 +1009,8 @@ static int write(uint32_t word, uint32_t addresses) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { - wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); } if (check_ack(false)) @@ -996,7 +1041,8 @@ static int write_password(uint32_t password, uint32_t new_password) { } else { // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer(T0 * EM4X50_T_TAG_TPP); + //wait_timer(T0 * EM4X50_T_TAG_TPP); + wait_timer(12 * EM4X50_T_TAG_TPP); // look for ACK sequence and send rm request // during following listen window @@ -1006,14 +1052,16 @@ static int write_password(uint32_t password, uint32_t new_password) { em4x50_reader_send_word(new_password); // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(T0 * EM4X50_T_TAG_TWA); + //wait_timer(T0 * EM4X50_T_TAG_TWA); + wait_timer(12 * EM4X50_T_TAG_TWA); if (check_ack(false)) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { - wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); } if (check_ack(false)) @@ -1216,23 +1264,23 @@ static int em4x50_sim_read_bit(void) { int cycles = 0; int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; + uint32_t tval = 0; while (cycles < EM4X50_T_TAG_FULL_PERIOD) { // wait until reader field disappears while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - // now check until reader switches on carrier field + tval = GetTicks(); while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - // check if cycle (i.e. off -> on -> off) takes longer than T0 - if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) { + // check if current cycle takes longer than "usual"" + if (GetTicks() - tval > EM4X50_ZERO_DETECTION * CYCLES2TICKS) { // gap detected; wait until reader field is switched on again while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - + if (timeout <= 0) { return PM3_ETIMEOUT; } @@ -1727,13 +1775,61 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { return EM4X50_COMMAND_WRITE_PASSWORD; } +void em4x50_handle_commands(int *command, uint32_t *tag) { + + switch (*command) { + + case EM4X50_COMMAND_LOGIN: + LED_B_OFF(); + LED_C_OFF(); + *command = em4x50_sim_handle_login_command(tag); + break; + + case EM4X50_COMMAND_RESET: + LED_B_OFF(); + LED_C_OFF(); + *command = em4x50_sim_handle_reset_command(tag); + break; + + case EM4X50_COMMAND_WRITE: + LED_B_OFF(); + LED_C_OFF(); + *command = em4x50_sim_handle_write_command(tag); + break; + + case EM4X50_COMMAND_WRITE_PASSWORD: + LED_B_OFF(); + LED_C_OFF(); + *command = em4x50_sim_handle_writepwd_command(tag); + break; + + case EM4X50_COMMAND_SELECTIVE_READ: + LED_B_OFF(); + LED_C_ON(); + *command = em4x50_sim_handle_selective_read_command(tag); + break; + + case EM4X50_COMMAND_STANDARD_READ: + LED_B_ON(); + LED_C_OFF(); + *command = em4x50_sim_handle_standard_read_command(tag); + break; + + // bit errors during reading may lead to unknown commands + // -> continue with standard read mode + default: + *command = EM4X50_COMMAND_STANDARD_READ; + break; + } +} + // simulate uploaded data in emulator memory // LED A -> operations that require authentication are possible // LED B -> standard read mode is active // LED C -> command has been transmitted by reader void em4x50_sim(uint32_t *password) { - int command = PM3_ENODATA; + int command = 0; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; @@ -1759,50 +1855,7 @@ void em4x50_sim(uint32_t *password) { for (;;) { - switch (command) { - - case EM4X50_COMMAND_LOGIN: - LED_B_OFF(); - LED_C_OFF(); - command = em4x50_sim_handle_login_command(tag); - break; - - case EM4X50_COMMAND_RESET: - LED_B_OFF(); - LED_C_OFF(); - command = em4x50_sim_handle_reset_command(tag); - break; - - case EM4X50_COMMAND_WRITE: - LED_B_OFF(); - LED_C_OFF(); - command = em4x50_sim_handle_write_command(tag); - break; - - case EM4X50_COMMAND_WRITE_PASSWORD: - LED_B_OFF(); - LED_C_OFF(); - command = em4x50_sim_handle_writepwd_command(tag); - break; - - case EM4X50_COMMAND_SELECTIVE_READ: - LED_B_OFF(); - LED_C_ON(); - command = em4x50_sim_handle_selective_read_command(tag); - break; - - case EM4X50_COMMAND_STANDARD_READ: - LED_B_ON(); - LED_C_OFF(); - command = em4x50_sim_handle_standard_read_command(tag); - break; - - // bit errors during reading may lead to unknown commands - // -> continue with standard read mode - default: - command = EM4X50_COMMAND_STANDARD_READ; - break; - } + em4x50_handle_commands(&command, tag); // stop if key (pm3 button or enter key) has been pressed if (command == PM3_EOPABORTED) { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 72304192b..cf35cc6a4 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -13,6 +13,14 @@ #include "../include/em4x50.h" +void em4x50_setup_read(void); +bool get_signalproperties(void); +bool find_em4x50_tag(void); +int standard_read(int *now, uint32_t *words); + +void em4x50_setup_sim(void); +void em4x50_handle_commands(int *command, uint32_t *tag); + void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_writepwd(em4x50_data_t *etd); diff --git a/include/em4x50.h b/include/em4x50.h index ff0090547..80210cfc2 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -33,6 +33,14 @@ #define FIRST_WORD_WRITE_INHIBITED 2 // third byte #define LAST_WORD_WRITE_INHIBITED 3 // fourth byte +// commands +#define EM4X50_COMMAND_LOGIN 0x01 +#define EM4X50_COMMAND_RESET 0x80 +#define EM4X50_COMMAND_WRITE 0x12 +#define EM4X50_COMMAND_WRITE_PASSWORD 0x11 +#define EM4X50_COMMAND_SELECTIVE_READ 0x0A +#define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command + // misc #define TIMEOUT 2000 #define DUMP_FILESIZE 136 @@ -52,4 +60,7 @@ typedef struct { uint8_t byte[4]; } PACKED em4x50_word_t; +extern bool gLogin; +extern bool gWritePasswordProcess; + #endif /* EM4X50_H__ */ From d53fda3d3d7cb20fbed67df3b7a50ea33f927cf8 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 27 Jan 2021 01:03:10 +0100 Subject: [PATCH 02/15] first working version (complete) --- armsrc/Standalone/lf_tharexde.c | 58 ++++++++++++--------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 41fd96d34..8304edb2a 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -20,20 +20,21 @@ #include "../em4x50.h" /* - * `lf_tharexde` simulates EM4x50 dumps uploaded words/blocks, reads words of standard read - * mode of EM4x50 tags and stores them in internal flash. + * `lf_tharexde` simulates EM4x50 dumps uploaded to flash, reads words + * transmitted by EM4x50 tags in standard read mode and stores them in + * internal flash. * It requires RDV4 hardware (for flash and battery). * * On entering stand-alone mode, this module will start simulating EM4x50 data. * Data is read from eml dump file uploaded to flash memory. * * On switching to read/record mode by pressing pm3 button, module will start - * reading/recording EM4x50 data. Every found / collected data will be - * written/appended to the logfile in flash as a text string. + * reading EM4x50 data. Each collected data set will be written/appended to the + * logfile in flash as a text string. * * LEDs: * - LED A: simulating - * - LED B: reading / record + * - LED B: reading/recording * - LED C: writing to flash * - LED D: unmounting/sync'ing flash (normally < 100ms) * @@ -124,11 +125,10 @@ void RunMod(void) { bool state_change = true; int no_words = 0, command = 0; - uint8_t entry[81], state = STATE_SIM; + uint8_t entry[400], state = STATE_SIM; uint32_t tag[EM4X50_NO_WORDS] = {0x0}; rdv40_spiffs_lazy_mount(); - StandAloneMode(); Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); @@ -144,10 +144,7 @@ void RunMod(void) { int button_pressed = BUTTON_CLICKED(1000); if (button_pressed == BUTTON_SINGLE_CLICK) { - SpinUp(100); - switch (state) { - case STATE_SIM: state = STATE_READ; break; @@ -161,7 +158,6 @@ void RunMod(void) { state_change = true; } else if (button_pressed == BUTTON_HOLD) { - SpinDown(100); break; } @@ -210,47 +206,35 @@ void RunMod(void) { LEDsoff(); LED_B_ON(); Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 reading mode")); - - memset(entry, 0, sizeof(entry)); - memset(tag, 0, sizeof(tag)); + Dbprintf(_YELLOW_("switched to EM4x50 reading mode\n")); log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_COLLECT); - em4x50_setup_read(); - state_change = false; } + no_words = 0; + memset(tag, 0, sizeof(tag)); standard_read(&no_words, tag); - // reset timers - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 - AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero - AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer - if (no_words > 0) { memset(entry, 0, sizeof(entry)); - Dbprintf(""); - sprintf((char *)entry, "found new EM4x50 tag:"); - Dbprintf("%s", entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); - + sprintf((char *)entry, "found EM4x50 tag:\n"); for (int i = 0; i < no_words; i++) { - - sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, tag[i]); - Dbprintf("%s", entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); + sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]); } + Dbprintf("%s", entry); + sprintf((char *)entry + strlen((char *)entry), "\n"); + append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); } - - memset(tag, 0, sizeof(tag)); - no_words = 0; + + // reset timer + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 + AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero + AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer } } From 1c3d3b350a709bd95142aecae6d289a8a2828341 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 27 Jan 2021 01:10:57 +0100 Subject: [PATCH 03/15] - used WaitUS() instead of own function for reading operations - used GetTicks() instead of using direct timer TC0 => standalone mode functions can be simplified significantly --- armsrc/em4x50.c | 114 ++++++++++-------------------------------------- 1 file changed, 23 insertions(+), 91 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 49fa0221e..b2107298c 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -28,11 +28,12 @@ #define T0 192 #endif -// the following terms are used (for carrier frequency of 125 kHz): +// conversions (carrier frequency 125 kHz): // 1 us = 1.5 ticks // 1 cycle = 1 period = 8 us = 12 ticks -// 1 bit = 64 cycles = 768 ticks = 512 us +// 1 bit = 64 cycles = 768 ticks = 512 us (for Opt64) #define CYCLES2TICKS 12 +#define CYCLES2MUSEC 8 // given in cycles/periods #define EM4X50_T_TAG_QUARTER_PERIOD 16 @@ -46,8 +47,8 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_ACK 4 -#define EM4X50_TAG_TOLERANCE 8 -#define EM4X50_ZERO_DETECTION 3 +#define EM4X50_T_TOLERANCE 8 +#define EM4X50_T_ZERO_DETECTION 3 // timeout values (empirical) for simulation mode (may vary with regard to reader) #define EM4X50_T_SIMULATION_TIMEOUT_READ 600 @@ -72,17 +73,6 @@ bool gLogin = false; // to be able to identfiy it bool gWritePasswordProcess = false; -// do nothing for using timer0 -static void wait_timer(uint32_t period) { - - int timeout = period; - uint32_t tval = GetTicks(); - - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - //while (AT91C_BASE_TC0->TC_CV < period); - while ((timeout--) && (GetTicks() - tval < period)); -} - // extract and check parities // return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { @@ -142,7 +132,6 @@ void em4x50_setup_read(void) { StartTicks(); // 50ms for the resonant antenna to settle. - //SpinDelay(50); WaitMS(50); // Now set up the SSC to get the ADC samples that are now streaming at us. @@ -161,27 +150,6 @@ void em4x50_setup_read(void) { // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); - /* - // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);// | (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero - */ - // Watchdog hit WDT_HIT(); } @@ -196,13 +164,6 @@ void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; StartTicks(); - /* - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - */ // Watchdog hit WDT_HIT(); @@ -231,8 +192,7 @@ bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); - wait_timer(12 * EM4X50_T_TAG_HALF_PERIOD); + WaitUS(EM4X50_T_TAG_HALF_PERIOD * CYCLES2MUSEC); // ignore first samples if ((i > SIGNAL_IGNORE_FIRST_SAMPLES) && (AT91C_BASE_SSC->SSC_RHR > noise)) { @@ -250,8 +210,6 @@ bool get_signalproperties(void) { // 3 single "full periods" to eliminate the influence of a listen window for (int i = 0; i < no_periods; i++) { - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - //while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) { tval = GetTicks(); while (GetTicks() - tval < 12 * 3 * EM4X50_T_TAG_FULL_PERIOD) { @@ -284,14 +242,12 @@ bool get_signalproperties(void) { static bool invalid_bit(void) { // get sample at 3/4 of bit period - //wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); - wait_timer(12 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + WaitUS(EM4X50_T_TAG_THREE_QUARTER_PERIOD * CYCLES2MUSEC); uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - //wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); - wait_timer(12 * EM4X50_T_TAG_QUARTER_PERIOD); + WaitUS(EM4X50_T_TAG_QUARTER_PERIOD * CYCLES2MUSEC); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -314,7 +270,6 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; tval = GetTicks(); timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); @@ -331,23 +286,20 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - //return (uint32_t)AT91C_BASE_TC0->TC_CV; return GetTicks() - tval; } // check if pulse length corresponds to given length static bool check_pulse_length(uint32_t pl, int length) { - //return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); - return ((pl >= 12 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= 12 * (length + EM4X50_TAG_TOLERANCE))); + return ((pl >= (length - EM4X50_T_TOLERANCE) * CYCLES2TICKS) && + (pl <= (length + EM4X50_T_TOLERANCE) * CYCLES2TICKS)); } // send single bit according to EM4x50 application note and datasheet static void em4x50_reader_send_bit(int bit) { - int timeout = 500; // reset clock for the next bit - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; uint32_t tval = GetTicks(); if (bit == 0) { @@ -356,34 +308,22 @@ static void em4x50_reader_send_bit(int bit) { // period (Opt64) LOW(GPIO_SSC_DOUT); //while (AT91C_BASE_TC0->TC_CV < T0 * 7); - while ((timeout--) && (GetTicks() - tval < 12 * 7)); - if (timeout <= 0) - return; - timeout = 500; + while (GetTicks() - tval < 7 * CYCLES2TICKS); // enable modulation (drop the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); - //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); - while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_HALF_PERIOD)); - if (timeout <= 0) - return; - timeout = 500; + while (GetTicks() - tval < EM4X50_T_TAG_HALF_PERIOD * CYCLES2TICKS); // disable modulation for second half of bit period LOW(GPIO_SSC_DOUT); - //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); - while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD)); - if (timeout <= 0) - return; - timeout = 500; + while (GetTicks() - tval < EM4X50_T_TAG_FULL_PERIOD * CYCLES2TICKS); } else { // bit = "1" means disable modulation for full bit period LOW(GPIO_SSC_DOUT); - //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); - while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD)); + while (GetTicks() - tval < EM4X50_T_TAG_FULL_PERIOD * CYCLES2TICKS); } } @@ -483,8 +423,7 @@ static int find_double_listen_window(bool bcommand) { // second window follows - sync on this to issue a command // skip the next bit... - //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); - wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); + WaitUS(EM4X50_T_TAG_FULL_PERIOD * CYCLES2MUSEC); // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -562,8 +501,7 @@ static bool check_ack(bool bliw) { // wait for 2 bits (remaining "bit" of ACK signal + first // "bit" of listen window) - //wait_timer(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); - wait_timer(12 * 2 * EM4X50_T_TAG_FULL_PERIOD); + WaitUS(2 * EM4X50_T_TAG_FULL_PERIOD * CYCLES2MUSEC); // check for listen window (if first bit cannot be interpreted // as a valid bit it must belong to a listen window) @@ -694,8 +632,7 @@ static bool login(uint32_t password) { // send password em4x50_reader_send_word(password); - //wait_timer(T0 * EM4X50_T_TAG_TPP); - wait_timer(12 * EM4X50_T_TAG_TPP); + WaitUS(EM4X50_T_TAG_TPP * CYCLES2MUSEC); // check if ACK is returned if (check_ack(false)) @@ -1000,8 +937,7 @@ static int write(uint32_t word, uint32_t addresses) { } else { // wait for T0 * EM4X50_T_TAG_TWA (write access time) - //wait_timer(T0 * EM4X50_T_TAG_TWA); - wait_timer(12 * EM4X50_T_TAG_TWA); + WaitUS(EM4X50_T_TAG_TWA * CYCLES2MUSEC); // look for ACK sequence if (check_ack(false)) { @@ -1009,8 +945,7 @@ static int write(uint32_t word, uint32_t addresses) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { - //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); - wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); + WaitUS(EM4X50_T_TAG_FULL_PERIOD * CYCLES2MUSEC); } if (check_ack(false)) @@ -1041,8 +976,7 @@ static int write_password(uint32_t password, uint32_t new_password) { } else { // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - //wait_timer(T0 * EM4X50_T_TAG_TPP); - wait_timer(12 * EM4X50_T_TAG_TPP); + WaitUS(EM4X50_T_TAG_TPP * CYCLES2MUSEC); // look for ACK sequence and send rm request // during following listen window @@ -1052,16 +986,14 @@ static int write_password(uint32_t password, uint32_t new_password) { em4x50_reader_send_word(new_password); // wait for T0 * EM4X50_T_TAG_TWA (write access time) - //wait_timer(T0 * EM4X50_T_TAG_TWA); - wait_timer(12 * EM4X50_T_TAG_TWA); + WaitUS(EM4X50_T_TAG_TWA * CYCLES2MUSEC); if (check_ack(false)) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods) // for saving data and should return with ACK for (int i = 0; i < 50; i++) { - //wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); - wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD); + WaitUS(EM4X50_T_TAG_FULL_PERIOD * CYCLES2MUSEC); } if (check_ack(false)) @@ -1276,7 +1208,7 @@ static int em4x50_sim_read_bit(void) { while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { // check if current cycle takes longer than "usual"" - if (GetTicks() - tval > EM4X50_ZERO_DETECTION * CYCLES2TICKS) { + if (GetTicks() - tval > EM4X50_T_ZERO_DETECTION * CYCLES2TICKS) { // gap detected; wait until reader field is switched on again while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); From 82de4c134c3048c11e6491bd9b87c1cdd35f6cfa Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 28 Jan 2021 23:32:47 +0100 Subject: [PATCH 04/15] changed LED behavior --- armsrc/Standalone/lf_tharexde.c | 10 +-- armsrc/em4x50.c | 106 +++++++++++++++++--------------- 2 files changed, 63 insertions(+), 53 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 8304edb2a..96e8fb48d 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -93,9 +93,11 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE); now = size / 9; - for (int i = 0; i < now; i++) - for (int j = 0; j < 4; j++) + for (int i = 0; i < now; i++) { + for (int j = 0; j < 4; j++) { tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); + } + } Dbprintf(_YELLOW_("read tag data from input file")); } @@ -107,14 +109,12 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { static void append(const char *filename, uint8_t *entry, size_t entry_len) { - LED_D_ON(); if (log_exists == false) { rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); log_exists = true; } else { rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } - LED_D_OFF(); } void ModInfo(void) { @@ -179,6 +179,7 @@ void RunMod(void) { // init; start with command = standard read mode em4x50_setup_sim(); gLogin = false; + LED_D_OFF(); gWritePasswordProcess = false; command = EM4X50_COMMAND_STANDARD_READ; @@ -197,6 +198,7 @@ void RunMod(void) { if (command == PM3_ETIMEOUT) { command = EM4X50_COMMAND_STANDARD_READ; gLogin = false; + LED_D_OFF(); } } else if (state == STATE_READ) { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b2107298c..14097c485 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -167,8 +167,6 @@ void em4x50_setup_sim(void) { // Watchdog hit WDT_HIT(); - - LEDsoff(); } // calculate signal properties (mean amplitudes) from measured data: @@ -184,8 +182,6 @@ bool get_signalproperties(void) { uint32_t tval = 0; memset(sample_max, 0x00, sizeof(sample_max)); - LED_A_ON(); - // wait until signal/noise > 1 (max. 32 periods) for (int i = 0; i < EM4X50_T_TAG_WAITING_FOR_SIGNAL; i++) { @@ -202,7 +198,6 @@ bool get_signalproperties(void) { } if (signal_found == false) { - LED_A_OFF(); return false; } @@ -230,8 +225,6 @@ bool get_signalproperties(void) { gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; - LED_A_OFF(); - return true; } @@ -368,8 +361,6 @@ static void em4x50_reader_send_word(const uint32_t word) { static bool find_single_listen_window(void) { int cnt_pulses = 0; - LED_B_ON(); - while (cnt_pulses < EM4X50_T_WAITING_FOR_SNGLLIW) { // identification of listen window is done via evaluation of @@ -379,14 +370,12 @@ static bool find_single_listen_window(void) { if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // found listen window - LED_B_OFF(); return true; } } cnt_pulses++; } - LED_B_OFF(); return false; } @@ -398,12 +387,11 @@ static bool find_single_listen_window(void) { static int find_double_listen_window(bool bcommand) { int cnt_pulses = 0; - LED_B_ON(); - while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) { - if (BUTTON_PRESS()) + if (BUTTON_PRESS()) { return PM3_EOPABORTED; + } // identification of listen window is done via evaluation of // pulse lengths @@ -434,8 +422,6 @@ static int find_double_listen_window(bool bcommand) { em4x50_reader_send_bit(0); em4x50_reader_send_bit(0); - LED_B_OFF(); - return PM3_SUCCESS; } @@ -443,8 +429,6 @@ static int find_double_listen_window(bool bcommand) { if (check_pulse_length(get_pulse_length(), 3 * EM4X50_T_TAG_FULL_PERIOD)) { - LED_B_OFF(); - // return although second listen window consists of one // more bit period but this period is necessary for // evaluating further pulse lengths @@ -455,7 +439,6 @@ static int find_double_listen_window(bool bcommand) { cnt_pulses++; } - LED_B_OFF(); return PM3_EFAILED; } @@ -535,8 +518,6 @@ static int get_word_from_bitstream(uint32_t *data) { uint32_t pl = 0; uint64_t word = 0x0; - LED_C_ON(); - *data = 0x0; // initial bit value depends on last pulse length of listen window @@ -607,8 +588,6 @@ static int get_word_from_bitstream(uint32_t *data) { } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_FULL_PERIOD)) { - LED_C_OFF(); - // pulse length of 3 indicates listen window -> clear last // bit (= 0) and return (without parities) word >>= 2; @@ -616,8 +595,6 @@ static int get_word_from_bitstream(uint32_t *data) { } } - LED_C_OFF(); - return PM3_EOPABORTED; } @@ -700,9 +677,14 @@ void em4x50_login(uint32_t *password) { em4x50_setup_read(); uint8_t status = PM3_EFAILED; - if (get_signalproperties() && find_em4x50_tag()) + LED_C_ON(); + if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); status = login(*password); + } + LEDsoff(); lf_finalize(); reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0); } @@ -713,9 +695,14 @@ void em4x50_brute(em4x50_data_t *etd) { bool bsuccess = false; uint32_t pwd = 0x0; - if (get_signalproperties() && find_em4x50_tag()) + LED_C_ON(); + if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); bsuccess = brute(etd->password1, etd->password2, &pwd); + } + LEDsoff(); lf_finalize(); reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess ? PM3_SUCCESS : PM3_EFAILED, (uint8_t *)(&pwd), sizeof(pwd)); } @@ -743,8 +730,12 @@ void em4x50_chk(uint8_t *filename) { em4x50_setup_read(); // set gHigh and gLow + LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); + // try to login with current password for (int i = 0; i < pwd_count; i++) { @@ -759,8 +750,11 @@ void em4x50_chk(uint8_t *filename) { for (int j = 0; j < 4; j++) pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); - if ((status = login(pwd)) == PM3_SUCCESS) + if ((status = login(pwd)) == PM3_SUCCESS) { + SpinUp(50); + SpinDown(50); break; + } } } @@ -768,6 +762,7 @@ void em4x50_chk(uint8_t *filename) { #endif + LEDsoff(); lf_finalize(); reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, sizeof(pwd)); } @@ -859,8 +854,12 @@ void em4x50_read(em4x50_data_t *etd) { em4x50_setup_read(); // set gHigh and gLow + LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); + // try to login with given password if (etd->pwd_given) blogin = (login(etd->password1) == PM3_SUCCESS); @@ -870,9 +869,9 @@ void em4x50_read(em4x50_data_t *etd) { status = selective_read(etd->addresses, words); } + LEDsoff(); LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -886,7 +885,10 @@ void em4x50_info(em4x50_data_t *etd) { em4x50_setup_read(); + LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); // login with given password if (etd->pwd_given) @@ -896,8 +898,8 @@ void em4x50_info(em4x50_data_t *etd) { status = selective_read(addresses, words); } + LEDsoff(); lf_finalize(); - reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -909,9 +911,14 @@ void em4x50_reader(void) { em4x50_setup_read(); - if (get_signalproperties() && find_em4x50_tag()) + LED_C_ON(); + if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); standard_read(&now, words); + } + LEDsoff(); LOW(GPIO_SSC_DOUT); lf_finalize(); reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); @@ -1018,8 +1025,12 @@ void em4x50_write(em4x50_data_t *etd) { em4x50_setup_read(); + LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); + // if password is given try to login first status = PM3_SUCCESS; if (etd->pwd_given) @@ -1060,6 +1071,7 @@ void em4x50_write(em4x50_data_t *etd) { } } + LEDsoff(); lf_finalize(); reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -1070,8 +1082,12 @@ void em4x50_writepwd(em4x50_data_t *etd) { em4x50_setup_read(); + LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { + LED_C_OFF(); + LED_D_ON(); + // login and change password if (login(etd->password1) == PM3_SUCCESS) { @@ -1083,6 +1099,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { } } + LEDsoff(); lf_finalize(); reply_ng(CMD_LF_EM4X50_WRITEPWD, status, NULL, 0); } @@ -1308,6 +1325,8 @@ static int check_rm_request(uint32_t *tag) { bit = em4x50_sim_read_bit(); if (bit == 0) { + LED_C_ON(); + // if command before was EM4X50_COMMAND_WRITE_PASSWORD // switch to separate process if (gWritePasswordProcess) { @@ -1508,11 +1527,11 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { if (pwd && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; - LED_A_ON(); + LED_D_ON(); } else { em4x50_sim_send_nak(); gLogin = false; - LED_A_OFF(); + LED_D_OFF(); } // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; @@ -1527,7 +1546,7 @@ static int em4x50_sim_handle_reset_command(uint32_t *tag) { // send ACK em4x50_sim_send_ack(); gLogin = false; - LED_A_OFF(); + LED_D_OFF(); // wait for initialization (tinit) wait_cycles(EM4X50_T_TAG_TINIT); @@ -1712,37 +1731,26 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { switch (*command) { case EM4X50_COMMAND_LOGIN: - LED_B_OFF(); - LED_C_OFF(); *command = em4x50_sim_handle_login_command(tag); break; case EM4X50_COMMAND_RESET: - LED_B_OFF(); - LED_C_OFF(); *command = em4x50_sim_handle_reset_command(tag); break; case EM4X50_COMMAND_WRITE: - LED_B_OFF(); - LED_C_OFF(); *command = em4x50_sim_handle_write_command(tag); break; case EM4X50_COMMAND_WRITE_PASSWORD: - LED_B_OFF(); - LED_C_OFF(); *command = em4x50_sim_handle_writepwd_command(tag); break; case EM4X50_COMMAND_SELECTIVE_READ: - LED_B_OFF(); - LED_C_ON(); *command = em4x50_sim_handle_selective_read_command(tag); break; case EM4X50_COMMAND_STANDARD_READ: - LED_B_ON(); LED_C_OFF(); *command = em4x50_sim_handle_standard_read_command(tag); break; @@ -1756,9 +1764,8 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { } // simulate uploaded data in emulator memory -// LED A -> operations that require authentication are possible -// LED B -> standard read mode is active -// LED C -> command has been transmitted by reader +// LED C -> reader command has been detected +// LED D -> operations that require authentication are possible void em4x50_sim(uint32_t *password) { int command = 0; @@ -1778,6 +1785,7 @@ void em4x50_sim(uint32_t *password) { if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) { // init + LEDsoff(); em4x50_setup_sim(); gLogin = false; gWritePasswordProcess = false; @@ -1799,7 +1807,7 @@ void em4x50_sim(uint32_t *password) { if (command == PM3_ETIMEOUT) { command = EM4X50_COMMAND_STANDARD_READ; gLogin = false; - LED_A_OFF(); + LED_D_OFF(); } } } From a0c92d20bbd905d5999c439d99de6f8987d0e85d Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 29 Jan 2021 00:28:05 +0100 Subject: [PATCH 05/15] make style + cleanup --- armsrc/em4x50.c | 92 ++++++++++++++++++++++++------------------------- armsrc/em4x50.h | 2 -- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 14097c485..5478da58d 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -130,7 +130,7 @@ void em4x50_setup_read(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); StartTicks(); - + // 50ms for the resonant antenna to settle. WaitMS(50); @@ -162,16 +162,16 @@ void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; - + StartTicks(); - + // Watchdog hit WDT_HIT(); } // calculate signal properties (mean amplitudes) from measured data: // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow -bool get_signalproperties(void) { +static bool get_signalproperties(void) { bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; @@ -302,7 +302,7 @@ static void em4x50_reader_send_bit(int bit) { LOW(GPIO_SSC_DOUT); //while (AT91C_BASE_TC0->TC_CV < T0 * 7); while (GetTicks() - tval < 7 * CYCLES2TICKS); - + // enable modulation (drop the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); @@ -444,7 +444,7 @@ static int find_double_listen_window(bool bcommand) { // function is used to check wether a tag on the proxmark is an // EM4x50 tag or not -> speed up "lf search" process -bool find_em4x50_tag(void) { +static bool find_em4x50_tag(void) { return find_single_listen_window(); } @@ -600,7 +600,7 @@ static int get_word_from_bitstream(uint32_t *data) { // simple login to EM4x50, // used in operations that require authentication -static bool login(uint32_t password) { +static int login(uint32_t password) { if (request_receive_mode() == PM3_SUCCESS) { // send login command @@ -1107,7 +1107,6 @@ void em4x50_writepwd(em4x50_data_t *etd) { // send bit in receive mode by counting carrier cycles static void em4x50_sim_send_bit(uint8_t bit) { - //uint16_t timeout = EM4X50_T_TAG_FULL_PERIOD; uint16_t timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { @@ -1115,7 +1114,7 @@ static void em4x50_sim_send_bit(uint8_t bit) { // wait until SSC_CLK goes HIGH // used as a simple detection of a reader field? while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); - + if (timeout <= 0) { return; } @@ -1191,19 +1190,19 @@ static void wait_cycles(int maxperiods) { int period = 0, timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; while (period < maxperiods) { - + while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); if (timeout <= 0) { return; } timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - + while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); if (timeout <= 0) { return; } timeout = EM4X50_T_SIMULATION_TIMEOUT_WAIT; - + period++; } } @@ -1256,12 +1255,12 @@ static int em4x50_sim_read_bit(void) { // read byte in simulation mode either with or without parity check (even) static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { - + for (int i = 0; i < 8; i++) { *byte <<= 1; *byte |= em4x50_sim_read_bit(); } - + if (paritycheck) { int pval = em4x50_sim_read_bit(); @@ -1277,12 +1276,11 @@ static bool em4x50_sim_read_byte(uint8_t *byte, bool paritycheck) { } return true; - } // read complete word in simulation mode static bool em4x50_sim_read_word(uint32_t *word) { - + uint8_t stop_bit = 0; uint8_t parities = 0, parities_calculated = 0; uint8_t bytes[4] = {0}; @@ -1303,20 +1301,20 @@ static bool em4x50_sim_read_word(uint32_t *word) { parities_calculated ^= (bytes[j] >> (7 - i)) & 1; } } - + *word = BYTES2UINT32(bytes); - + // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { return true; } - + return false; } // check if reader requests receive mode (rm) by sending two zeros static int check_rm_request(uint32_t *tag) { - + // look for first zero int bit = em4x50_sim_read_bit(); if (bit == 0) { @@ -1326,7 +1324,7 @@ static int check_rm_request(uint32_t *tag) { if (bit == 0) { LED_C_ON(); - + // if command before was EM4X50_COMMAND_WRITE_PASSWORD // switch to separate process if (gWritePasswordProcess) { @@ -1339,13 +1337,13 @@ static int check_rm_request(uint32_t *tag) { } } } - + return (bit != PM3_ETIMEOUT) ? PM3_SUCCESS : PM3_ETIMEOUT; } // send single listen window in simulation mode static int em4x50_sim_send_listen_window(uint32_t *tag) { - + SHORT_COIL(); wait_cycles(EM4X50_T_TAG_HALF_PERIOD); @@ -1387,7 +1385,7 @@ static void em4x50_sim_send_ack(void) { OPEN_COIL(); wait_cycles(EM4X50_T_TAG_HALF_PERIOD); - + SHORT_COIL(); } @@ -1418,7 +1416,7 @@ static void em4x50_sim_send_nak(void) { // standard read mode process (simulation mode) static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { - + int command = 0; // extract control data @@ -1461,11 +1459,11 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { int command = 0; - + // read password uint32_t address = 0; bool addr = em4x50_sim_read_word(&address); - + // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1485,7 +1483,7 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; // last word read protected int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; - + while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); @@ -1520,7 +1518,7 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { // read password uint32_t password = 0; bool pwd = em4x50_sim_read_word(&password); - + // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -1547,10 +1545,10 @@ static int em4x50_sim_handle_reset_command(uint32_t *tag) { em4x50_sim_send_ack(); gLogin = false; LED_D_OFF(); - + // wait for initialization (tinit) wait_cycles(EM4X50_T_TAG_TINIT); - + // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; } @@ -1564,7 +1562,7 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { // read data uint32_t data = 0; bool word = em4x50_sim_read_word(&data); - + // write access time wait_cycles(EM4X50_T_TAG_TWA); @@ -1633,7 +1631,7 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { } break; } - + // EEPROM write time // strange: need some sort of 'waveform correction', otherwise ack signal // will not be detected; sending a single "1" as last "bit" of Twee @@ -1665,18 +1663,18 @@ static int em4x50_sim_handle_write_command(uint32_t *tag) { static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { bool pwd = false; - + if (gWritePasswordProcess == false) { - + gWritePasswordProcess = true; // read password uint32_t act_password = 0; pwd = em4x50_sim_read_word(&act_password); - + // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); - + if (pwd && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; @@ -1709,7 +1707,7 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { em4x50_sim_send_ack(); return EM4X50_COMMAND_STANDARD_READ; } - + // EEPROM write time // strange: need some sort of 'waveform correction', otherwise ack signal // will not be detected; sending a single "1" as last part of Twee @@ -1721,13 +1719,13 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) { // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; } - + // call writepwd function again for else branch return EM4X50_COMMAND_WRITE_PASSWORD; } void em4x50_handle_commands(int *command, uint32_t *tag) { - + switch (*command) { case EM4X50_COMMAND_LOGIN: @@ -1749,12 +1747,12 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { case EM4X50_COMMAND_SELECTIVE_READ: *command = em4x50_sim_handle_selective_read_command(tag); break; - + case EM4X50_COMMAND_STANDARD_READ: LED_C_OFF(); *command = em4x50_sim_handle_standard_read_command(tag); break; - + // bit errors during reading may lead to unknown commands // -> continue with standard read mode default: @@ -1767,15 +1765,15 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { // LED C -> reader command has been detected // LED D -> operations that require authentication are possible void em4x50_sim(uint32_t *password) { - + int command = 0; - + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; for (int i = 0; i < EM4X50_NO_WORDS; i++) tag[i] = bytes_to_num(em4x50_mem + (i * 4), 4); - + // via eload uploaded dump usually does not contain a password if (tag[EM4X50_DEVICE_PASSWORD] == 0) { tag[EM4X50_DEVICE_PASSWORD] = reflect32(*password); @@ -1796,12 +1794,12 @@ void em4x50_sim(uint32_t *password) { for (;;) { em4x50_handle_commands(&command, tag); - + // stop if key (pm3 button or enter key) has been pressed if (command == PM3_EOPABORTED) { break; } - + // if timeout (e.g. no reader field) continue with standard read // mode and reset former authentication if (command == PM3_ETIMEOUT) { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index cf35cc6a4..d47579dcc 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -14,8 +14,6 @@ #include "../include/em4x50.h" void em4x50_setup_read(void); -bool get_signalproperties(void); -bool find_em4x50_tag(void); int standard_read(int *now, uint32_t *words); void em4x50_setup_sim(void); From 8edbe86b5d20923dd22f671d2f061c35bbc34264 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 30 Jan 2021 00:19:22 +0100 Subject: [PATCH 06/15] added entry for standalone mode lf_tharexde (EM4x50 sim/read) --- CHANGELOG.md | 1 + doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 323774a34..79529f2c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde) - Added support for bidirectional communication for `lf em 4x50 sim` (@tharexde) - Added `tools/hitag2crack/crack5opencl`, an optimized version of `crack5gpu` (@matrix) - Fixed Makefile to account for changes when running on Apple Silicon (@tcprst) diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 6dbe54d49..2ba6aeaba 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -79,6 +79,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo |-----------------|----------------------------------------| | | No standalone mode | LF_SKELETON | standalone mode skeleton - Iceman1001 +| LF_THAREXDE | LF EM4x50 simulator/read standalone mode - tharexde | LF_EM4100EMUL | LF EM4100 simulator standalone mode - temskiy | LF_EM4100RSWB | LF EM4100 read/write/clone/brute mode - Monster1024 | LF_EM4100RWC | LF EM4100 read/write/clone mode - temskiy From ed7f623c6fd9d6bae39a44e52178532b3388f1cb Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 6 Feb 2021 19:59:03 +0100 Subject: [PATCH 07/15] increased timeout -> reliable lf search results --- include/em4x50.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/em4x50.h b/include/em4x50.h index 80210cfc2..45ad04467 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -42,7 +42,7 @@ #define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command // misc -#define TIMEOUT 2000 +#define TIMEOUT_CMD 3000 #define DUMP_FILESIZE 136 #define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) @@ -62,5 +62,6 @@ typedef struct { extern bool gLogin; extern bool gWritePasswordProcess; +extern uint32_t gPassword; #endif /* EM4X50_H__ */ From 94ede77573ea7176abe35fec477929f4426189f7 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 6 Feb 2021 19:59:34 +0100 Subject: [PATCH 08/15] timeout adaption --- client/src/cmdlfem4x50.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ae99bd8a6..ea60c84b9 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -546,7 +546,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -654,7 +654,7 @@ int CmdEM4x50Info(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -767,7 +767,7 @@ int CmdEM4x50Dump(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -862,7 +862,7 @@ int CmdEM4x50Write(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -933,7 +933,7 @@ int CmdEM4x50WritePwd(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -989,7 +989,7 @@ int CmdEM4x50Wipe(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -1015,7 +1015,7 @@ int CmdEM4x50Wipe(const char *Cmd) { etd.addresses = i << 8 | i; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT_CMD)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -1110,7 +1110,7 @@ int CmdEM4x50Restore(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT_CMD)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; From ed642855d89ec1cca0d36602651443801105bf85 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 6 Feb 2021 20:00:58 +0100 Subject: [PATCH 09/15] global parameter for standalone mode (catch pwd sent by reader) --- armsrc/Standalone/lf_tharexde.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 96e8fb48d..d3c8fddc0 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -13,6 +13,7 @@ #include "proxmark3_arm.h" #include "appmain.h" #include "BigBuf.h" +#include "commonutil.h" #include "fpgaloader.h" #include "util.h" #include "dbprint.h" @@ -58,10 +59,12 @@ #define STATE_READ 1 #define EM4X50_TAG_WORD 45 #define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" +#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_tag_data.log" #define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" bool input_exists; bool log_exists; +uint32_t gPassword; static void LoadDataInstructions(const char *inputfile) { Dbprintf(""); @@ -188,6 +191,25 @@ void RunMod(void) { em4x50_handle_commands(&command, tag); + // check if new password was found + if (gPassword != reflect32(tag[0])) { + + // save password to tag + tag[0] = reflect32(gPassword); + Dbprintf("received password: %08"PRIx32"", gPassword); + + // overwrite inputfile in flash memory + memset(entry, 0, sizeof(entry)); + + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]); + } + log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_SIM); + Dbprintf("log_exists = %i", log_exists); + //append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); + + } + // stop if key (pm3 button or enter key) has been pressed if (command == PM3_EOPABORTED) { break; From c5ac3c16f5ebb9771c077519f1186dab2e097f7b Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 6 Feb 2021 20:45:44 +0100 Subject: [PATCH 10/15] - timeout corrections - global parameter for password catch (used in standalone mode) --- armsrc/em4x50.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 0d4df8451..7770a8819 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -61,6 +61,7 @@ // div #define EM4X50_TAG_WORD 45 #define EM4X50_TAG_MAX_NO_BYTES 136 +#define EM4X50_TIMEOUT_PULSE_EVAL 2500 int gHigh = 190; int gLow = 60; @@ -72,6 +73,8 @@ bool gLogin = false; // compared to operations like read, write, login, so it is necessary to // to be able to identfiy it bool gWritePasswordProcess = false; +// if reader sends a different password than "expected" -> save it +uint32_t gPassword = 0; // extract and check parities // return result of parity check and extracted plain data @@ -251,7 +254,8 @@ static bool invalid_bit(void) { static uint32_t get_pulse_length(void) { - int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD), tval = 0; + //int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD), tval = 0; + int32_t timeout = EM4X50_TIMEOUT_PULSE_EVAL, tval = 0; // iterates pulse length (low -> high -> low) @@ -260,23 +264,25 @@ static uint32_t get_pulse_length(void) { while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (timeout == 0) + if (timeout <= 0) return 0; tval = GetTicks(); - timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + //timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + timeout = EM4X50_TIMEOUT_PULSE_EVAL; while (sample < gHigh && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (timeout == 0) + if (timeout <= 0) return 0; - timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + //timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + timeout = EM4X50_TIMEOUT_PULSE_EVAL; while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (timeout == 0) + if (timeout <= 0) return 0; return GetTicks() - tval; @@ -857,16 +863,16 @@ void em4x50_read(em4x50_data_t *etd) { LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { - LED_C_OFF(); - LED_D_ON(); + LED_C_OFF(); + LED_D_ON(); - // try to login with given password - if (etd->pwd_given) - blogin = (login(etd->password1) == PM3_SUCCESS); + // try to login with given password + if (etd->pwd_given) + blogin = (login(etd->password1) == PM3_SUCCESS); - // only one word has to be read -> first word read = last word read - if (blogin) - status = selective_read(etd->addresses, words); + // only one word has to be read -> first word read = last word read + if (blogin) + status = selective_read(etd->addresses, words); } LEDsoff(); @@ -1417,8 +1423,6 @@ static void em4x50_sim_send_nak(void) { // standard read mode process (simulation mode) static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { - int command = 0; - // extract control data int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read @@ -1458,8 +1462,6 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { // selective read mode process (simulation mode) static int em4x50_sim_handle_selective_read_command(uint32_t *tag) { - int command = 0; - // read password uint32_t address = 0; bool addr = em4x50_sim_read_word(&address); @@ -1530,6 +1532,9 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { em4x50_sim_send_nak(); gLogin = false; LED_D_OFF(); + + // save transmitted password for future use (e.g. standalone mode) + gPassword = password; } // continue with standard read mode return EM4X50_COMMAND_STANDARD_READ; From a67c82ff6d526c265498004da5f316d0fcdd8f29 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 6 Feb 2021 20:48:21 +0100 Subject: [PATCH 11/15] clean up --- armsrc/em4x50.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 7770a8819..91bfdef4f 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -254,7 +254,6 @@ static bool invalid_bit(void) { static uint32_t get_pulse_length(void) { - //int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD), tval = 0; int32_t timeout = EM4X50_TIMEOUT_PULSE_EVAL, tval = 0; // iterates pulse length (low -> high -> low) @@ -915,7 +914,7 @@ void em4x50_reader(void) { int now = 0; uint32_t words[EM4X50_NO_WORDS] = {0x0}; - em4x50_setup_read(); + em4x50_setup_read(); LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { From b20f5322820560d1ad1356f60dba6451235813f1 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 9 Feb 2021 23:22:46 +0100 Subject: [PATCH 12/15] - added missing timeout checks - relocated timer resets in standalone mode --- armsrc/Standalone/lf_tharexde.c | 20 +++++++++++--------- armsrc/em4x50.c | 28 ++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index d3c8fddc0..0d7393e01 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -133,6 +133,7 @@ void RunMod(void) { rdv40_spiffs_lazy_mount(); StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); for (;;) { @@ -204,10 +205,11 @@ void RunMod(void) { for (int i = 0; i < EM4X50_NO_WORDS; i++) { sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]); } - log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_SIM); - Dbprintf("log_exists = %i", log_exists); - //append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); + if (exists_in_spiffs(LF_EM4X50_LOGFILE_SIM)) { + rdv40_spiffs_remove(LF_EM4X50_LOGFILE_SIM, RDV40_SPIFFS_SAFETY_SAFE); + } + rdv40_spiffs_write(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry), RDV40_SPIFFS_SAFETY_SAFE); } // stop if key (pm3 button or enter key) has been pressed @@ -253,13 +255,13 @@ void RunMod(void) { sprintf((char *)entry + strlen((char *)entry), "\n"); append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); } - - // reset timer - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 - AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero - AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer } + + // reset timer + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 + AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero + AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer } if (state == STATE_READ) { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 91bfdef4f..17db0cfb1 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1222,11 +1222,19 @@ static int em4x50_sim_read_bit(void) { while (cycles < EM4X50_T_TAG_FULL_PERIOD) { // wait until reader field disappears - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + if (timeout <= 0) { + return PM3_ETIMEOUT; + } + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; // now check until reader switches on carrier field tval = GetTicks(); - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + + if (timeout <= 0) { + return PM3_ETIMEOUT; + } // check if current cycle takes longer than "usual"" if (GetTicks() - tval > EM4X50_T_ZERO_DETECTION * CYCLES2TICKS) { @@ -1237,7 +1245,7 @@ static int em4x50_sim_read_bit(void) { if (timeout <= 0) { return PM3_ETIMEOUT; } - // timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; + //timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; // now we have a reference "position", from here it will take // slightly less than 32 cycles until the end of the bit period @@ -1248,6 +1256,7 @@ static int em4x50_sim_read_bit(void) { return 0; } } + timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; // no gap detected, i.e. reader field is still up; // continue with counting cycles @@ -1431,11 +1440,14 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { // last word read protected int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; + int command = PM3_SUCCESS; + while ((BUTTON_PRESS() == false) && (data_available() == false)) { WDT_HIT(); - int command = em4x50_sim_send_listen_window(tag); + command = em4x50_sim_send_listen_window(tag); + if (command != PM3_SUCCESS) { return command; } @@ -1737,19 +1749,19 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { break; case EM4X50_COMMAND_RESET: - *command = em4x50_sim_handle_reset_command(tag); + *command = em4x50_sim_handle_reset_command(tag); break; case EM4X50_COMMAND_WRITE: - *command = em4x50_sim_handle_write_command(tag); + *command = em4x50_sim_handle_write_command(tag); break; case EM4X50_COMMAND_WRITE_PASSWORD: - *command = em4x50_sim_handle_writepwd_command(tag); + *command = em4x50_sim_handle_writepwd_command(tag); break; case EM4X50_COMMAND_SELECTIVE_READ: - *command = em4x50_sim_handle_selective_read_command(tag); + *command = em4x50_sim_handle_selective_read_command(tag); break; case EM4X50_COMMAND_STANDARD_READ: From a944ff5927479444f73094cff3243aae9c5f7f5e Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 11 Feb 2021 19:29:43 +0100 Subject: [PATCH 13/15] - added flash defines (RDV4) - modified LED signals - cleanup --- armsrc/Standalone/lf_tharexde.c | 73 ++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 0d7393e01..44dbc8a4f 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -27,21 +27,26 @@ * It requires RDV4 hardware (for flash and battery). * * On entering stand-alone mode, this module will start simulating EM4x50 data. - * Data is read from eml dump file uploaded to flash memory. + * Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml). + * If reader sends password different from dump file password, 'new' password + * is saved in file lf_em4x50_passwords.log in flash memory. * * On switching to read/record mode by pressing pm3 button, module will start * reading EM4x50 data. Each collected data set will be written/appended to the - * logfile in flash as a text string. + * logfile in flash (lf_em4x50_collect.log) as a text string. * * LEDs: * - LED A: simulating + * - LED A blinking: no simulation data or read error * - LED B: reading/recording - * - LED C: writing to flash * - LED D: unmounting/sync'ing flash (normally < 100ms) * * To upload input file (eml format) to flash: * - mem spiffs load f o lf_em4x50_simulate.eml * + * To retrieve password file from flash: + * - mem spiffs dump o lf_em4x50_passwords.log f + * * To retrieve log file from flash: * - mem spiffs dump o lf_em4x50_collect.log f * @@ -52,6 +57,9 @@ * - mem spiffs remove lf_em4x50_simulate.eml * * To delete the log file from flash: + * - mem spiffs remove lf_em4x50_passwords.log + * + * To delete the log file from flash: * - mem spiffs remove lf_em4x50_collect.log */ @@ -59,11 +67,9 @@ #define STATE_READ 1 #define EM4X50_TAG_WORD 45 #define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" -#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_tag_data.log" +#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log" #define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" -bool input_exists; -bool log_exists; uint32_t gPassword; static void LoadDataInstructions(const char *inputfile) { @@ -86,6 +92,8 @@ static void DownloadLogInstructions(const char *logfile) { static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { size_t now = 0; + +#ifdef WITH_FLASH if (exists_in_spiffs(inputfile)) { uint32_t size = size_in_spiffs(inputfile); @@ -106,18 +114,20 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { } BigBuf_free(); - +#endif + return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID])); } static void append(const char *filename, uint8_t *entry, size_t entry_len) { - if (log_exists == false) { - rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); - log_exists = true; - } else { +#ifdef WITH_FLASH + if (exists_in_spiffs(filename)) { rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + } else { + rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } +#endif } void ModInfo(void) { @@ -126,14 +136,16 @@ void ModInfo(void) { void RunMod(void) { - bool state_change = true; + bool state_change = true, read_ok = false; int no_words = 0, command = 0; uint8_t entry[400], state = STATE_SIM; uint32_t tag[EM4X50_NO_WORDS] = {0x0}; +#ifdef WITH_FLASH rdv40_spiffs_lazy_mount(); +#endif + StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); for (;;) { @@ -174,7 +186,8 @@ void RunMod(void) { Dbprintf(""); Dbprintf(_YELLOW_("switched to EM4x50 simulating mode")); - if (get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM)) { + read_ok = get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM); + if (read_ok) { Dbprintf(_YELLOW_("tag data ok")); } else { Dbprintf(_RED_("error in tag data")); @@ -184,39 +197,34 @@ void RunMod(void) { em4x50_setup_sim(); gLogin = false; LED_D_OFF(); + gPassword = reflect32(tag[0]); gWritePasswordProcess = false; command = EM4X50_COMMAND_STANDARD_READ; state_change = false; } + // if no data or read error -> blink + if (read_ok == false) { + LED(LED_A, 200); + SpinDelay(200); + } + em4x50_handle_commands(&command, tag); // check if new password was found if (gPassword != reflect32(tag[0])) { - // save password to tag - tag[0] = reflect32(gPassword); Dbprintf("received password: %08"PRIx32"", gPassword); - // overwrite inputfile in flash memory + // append password to logfile in flash memory memset(entry, 0, sizeof(entry)); - - for (int i = 0; i < EM4X50_NO_WORDS; i++) { - sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]); - } - - if (exists_in_spiffs(LF_EM4X50_LOGFILE_SIM)) { - rdv40_spiffs_remove(LF_EM4X50_LOGFILE_SIM, RDV40_SPIFFS_SAFETY_SAFE); - } - rdv40_spiffs_write(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry), RDV40_SPIFFS_SAFETY_SAFE); + sprintf((char *)entry, "%08"PRIx32"\n", gPassword); + append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); + + gPassword = reflect32(tag[0]); } - // stop if key (pm3 button or enter key) has been pressed - if (command == PM3_EOPABORTED) { - break; - } - // if timeout (e.g. no reader field) continue with standard read // mode and reset former authentication if (command == PM3_ETIMEOUT) { @@ -234,7 +242,6 @@ void RunMod(void) { Dbprintf(""); Dbprintf(_YELLOW_("switched to EM4x50 reading mode\n")); - log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_COLLECT); em4x50_setup_read(); state_change = false; } @@ -264,6 +271,7 @@ void RunMod(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer } +#ifdef WITH_FLASH if (state == STATE_READ) { DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT); } else { @@ -273,6 +281,7 @@ void RunMod(void) { LED_D_ON(); rdv40_spiffs_lazy_unmount(); LED_D_OFF(); +#endif FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); From 9a96157e824cb573b3b615b7751dc339ec64eb47 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 14 Feb 2021 12:20:18 +0100 Subject: [PATCH 14/15] initial implementation of em4x50 standalone mode --- armsrc/Standalone/lf_tharexde.c | 57 +++++++++++++++------------------ armsrc/em4x50.c | 30 ++++++++--------- armsrc/iso14443a.c | 4 +-- client/src/cmdhfjooki.c | 13 +++++--- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 44dbc8a4f..c88437f4f 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -28,8 +28,8 @@ * * On entering stand-alone mode, this module will start simulating EM4x50 data. * Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml). - * If reader sends password different from dump file password, 'new' password - * is saved in file lf_em4x50_passwords.log in flash memory. + * If reader sends password different from dump file password, it is saved in + * file lf_em4x50_passwords.log in flash memory. * * On switching to read/record mode by pressing pm3 button, module will start * reading EM4x50 data. Each collected data set will be written/appended to the @@ -65,7 +65,6 @@ #define STATE_SIM 0 #define STATE_READ 1 -#define EM4X50_TAG_WORD 45 #define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" #define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log" #define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" @@ -75,25 +74,24 @@ uint32_t gPassword; static void LoadDataInstructions(const char *inputfile) { Dbprintf(""); Dbprintf("To load datafile to flash and display it:"); - Dbprintf(_YELLOW_("1.") " edit input file %s", inputfile); - Dbprintf(_YELLOW_("2.") " start proxmark3 client"); - Dbprintf(_YELLOW_("3.") " mem spiffs load f o %s", inputfile); - Dbprintf(_YELLOW_("4.") " start standalone mode"); + Dbprintf("1. edit input file %s", inputfile); + Dbprintf("2. start proxmark3 client"); + Dbprintf("3. mem spiffs load f o %s", inputfile); + Dbprintf("4. start standalone mode"); } static void DownloadLogInstructions(const char *logfile) { Dbprintf(""); Dbprintf("To get the logfile from flash and display it:"); - Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f ", logfile); - Dbprintf(_YELLOW_("2.") " exit proxmark3 client"); - Dbprintf(_YELLOW_("3.") " cat "); + Dbprintf("1. mem spiffs dump o %s f ", logfile); + Dbprintf("2. exit proxmark3 client"); + Dbprintf("3. cat "); } static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { size_t now = 0; -#ifdef WITH_FLASH if (exists_in_spiffs(inputfile)) { uint32_t size = size_in_spiffs(inputfile); @@ -111,23 +109,21 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { } Dbprintf(_YELLOW_("read tag data from input file")); + } else { + Dbprintf(_RED_("no input file %s"), inputfile); } BigBuf_free(); -#endif - + return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID])); } static void append(const char *filename, uint8_t *entry, size_t entry_len) { - -#ifdef WITH_FLASH if (exists_in_spiffs(filename)) { rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } else { rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } -#endif } void ModInfo(void) { @@ -141,10 +137,8 @@ void RunMod(void) { uint8_t entry[400], state = STATE_SIM; uint32_t tag[EM4X50_NO_WORDS] = {0x0}; -#ifdef WITH_FLASH rdv40_spiffs_lazy_mount(); -#endif - + StandAloneMode(); Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); @@ -191,8 +185,9 @@ void RunMod(void) { Dbprintf(_YELLOW_("tag data ok")); } else { Dbprintf(_RED_("error in tag data")); + LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM); } - + // init; start with command = standard read mode em4x50_setup_sim(); gLogin = false; @@ -209,22 +204,22 @@ void RunMod(void) { LED(LED_A, 200); SpinDelay(200); } - + em4x50_handle_commands(&command, tag); // check if new password was found - if (gPassword != reflect32(tag[0])) { - + if (gPassword != reflect32(tag[EM4X50_DEVICE_PASSWORD])) { + Dbprintf("received password: %08"PRIx32"", gPassword); - + // append password to logfile in flash memory memset(entry, 0, sizeof(entry)); sprintf((char *)entry, "%08"PRIx32"\n", gPassword); append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); - - gPassword = reflect32(tag[0]); + + gPassword = reflect32(tag[EM4X50_DEVICE_PASSWORD]); } - + // if timeout (e.g. no reader field) continue with standard read // mode and reset former authentication if (command == PM3_ETIMEOUT) { @@ -232,7 +227,7 @@ void RunMod(void) { gLogin = false; LED_D_OFF(); } - + } else if (state == STATE_READ) { if (state_change) { @@ -263,7 +258,7 @@ void RunMod(void) { append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); } } - + // reset timer AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero @@ -271,17 +266,15 @@ void RunMod(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer } -#ifdef WITH_FLASH if (state == STATE_READ) { DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT); } else { - LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM); + DownloadLogInstructions(LF_EM4X50_LOGFILE_SIM); } LED_D_ON(); rdv40_spiffs_lazy_unmount(); LED_D_OFF(); -#endif FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 17db0cfb1..6c5f9c2d2 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -256,7 +256,7 @@ static uint32_t get_pulse_length(void) { int32_t timeout = EM4X50_TIMEOUT_PULSE_EVAL, tval = 0; - // iterates pulse length (low -> high -> low) + // iterates pulse lengths (low -> high -> low) volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -267,7 +267,6 @@ static uint32_t get_pulse_length(void) { return 0; tval = GetTicks(); - //timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); timeout = EM4X50_TIMEOUT_PULSE_EVAL; while (sample < gHigh && (timeout--)) @@ -276,7 +275,6 @@ static uint32_t get_pulse_length(void) { if (timeout <= 0) return 0; - //timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); timeout = EM4X50_TIMEOUT_PULSE_EVAL; while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -305,7 +303,6 @@ static void em4x50_reader_send_bit(int bit) { // disable modulation (activate the field) for 7 cycles of carrier // period (Opt64) LOW(GPIO_SSC_DOUT); - //while (AT91C_BASE_TC0->TC_CV < T0 * 7); while (GetTicks() - tval < 7 * CYCLES2TICKS); // enable modulation (drop the field) for remaining first @@ -862,16 +859,16 @@ void em4x50_read(em4x50_data_t *etd) { LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { - LED_C_OFF(); - LED_D_ON(); + LED_C_OFF(); + LED_D_ON(); - // try to login with given password - if (etd->pwd_given) - blogin = (login(etd->password1) == PM3_SUCCESS); + // try to login with given password + if (etd->pwd_given) + blogin = (login(etd->password1) == PM3_SUCCESS); - // only one word has to be read -> first word read = last word read - if (blogin) - status = selective_read(etd->addresses, words); + // only one word has to be read -> first word read = last word read + if (blogin) + status = selective_read(etd->addresses, words); } LEDsoff(); @@ -914,7 +911,7 @@ void em4x50_reader(void) { int now = 0; uint32_t words[EM4X50_NO_WORDS] = {0x0}; - em4x50_setup_read(); + em4x50_setup_read(); LED_C_ON(); if (get_signalproperties() && find_em4x50_tag()) { @@ -1245,7 +1242,6 @@ static int em4x50_sim_read_bit(void) { if (timeout <= 0) { return PM3_ETIMEOUT; } - //timeout = EM4X50_T_SIMULATION_TIMEOUT_READ; // now we have a reference "position", from here it will take // slightly less than 32 cycles until the end of the bit period @@ -1447,7 +1443,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) { WDT_HIT(); command = em4x50_sim_send_listen_window(tag); - + if (command != PM3_SUCCESS) { return command; } @@ -1543,7 +1539,7 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) { em4x50_sim_send_nak(); gLogin = false; LED_D_OFF(); - + // save transmitted password for future use (e.g. standalone mode) gPassword = password; } @@ -1782,7 +1778,7 @@ void em4x50_handle_commands(int *command, uint32_t *tag) { // LED D -> operations that require authentication are possible void em4x50_sim(uint32_t *password) { - int command = 0; + int command = PM3_ENODATA; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 999c5eded..cd07a4007 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -920,14 +920,14 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) { uint16_t checker = 0; for (;;) { WDT_HIT(); - if (flip == 2) { + if (flip == 3) { if (data_available()) return false; flip = 0; } - if (checker >= 4000) { + if (checker >= 3000) { if (BUTTON_PRESS()) return false; diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index 352c61ae7..9b1a14b8b 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -327,15 +327,19 @@ static int CmdHF14AJookiSim(const char *Cmd) { jooki_print(b64, result, false); + // copy UID from base64 url parameter + uint8_t uid[7] = {0}; + memcpy(uid, result + 5, 7); + // hf mfu sim... uint8_t *data = calloc(144, sizeof(uint8_t)); - // copy UID from base64 url parameter - memcpy(data, result + 5, 3); + memcpy(data, uid, 3); + memcpy(data + (1*4), uid + 3, 4); + // bbc0 data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2]; - memcpy(data + (1*4), result + 8, 4); // bbc1 data[8] = data[4] ^ data[5] ^ data[6] ^ data[7]; @@ -398,8 +402,9 @@ static int CmdHF14AJookiSim(const char *Cmd) { // NTAG, 7 byte UID in eloaded data. payload.tagtype = 7; - payload.flags = FLAG_7B_UID_IN_DATA; + payload.flags = FLAG_UID_IN_EMUL; payload.exitAfter = 0; + memcpy(payload.uid, uid, sizeof(uid)); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); From a78fecad07fbd5b0a9d73f1659eaebc6cfff88ea Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 15 Feb 2021 21:26:16 +0100 Subject: [PATCH 15/15] revert changes (PR follows) --- CHANGELOG.md | 1 - armsrc/Standalone/Makefile.hal | 7 +- armsrc/Standalone/Makefile.inc | 4 - armsrc/Standalone/lf_tharexde.c | 283 ------------------ .../4_Advanced-compilation-parameters.md | 1 - 5 files changed, 2 insertions(+), 294 deletions(-) delete mode 100644 armsrc/Standalone/lf_tharexde.c diff --git a/CHANGELOG.md b/CHANGELOG.md index b730df269..9547aba77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] - - Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde) - Added `hf jooki` commands (@iceman1001) - Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001) - Fix cppchecker warnings (@iceman1001) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index 552267611..d5414f661 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -35,9 +35,6 @@ define KNOWN_STANDALONE_DEFINITIONS | LF_SAMYRUN | HID26 read/clone/sim | | | - Samy Kamkar | +----------------------------------------------------------+ -| LF_THAREXDE | Simulate/read EM4x50 tags | -| (RDV4 only) | storing in flashmem | -+----------------------------------------------------------+ | HF_14ASNIFF | 14a sniff to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ @@ -70,10 +67,10 @@ define KNOWN_STANDALONE_DEFINITIONS +----------------------------------------------------------+ endef -STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE +STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_TCPRST HF_YOUNG STANDALONE_MODES_REQ_SMARTCARD := -STANDALONE_MODES_REQ_FLASH := LF_ICEHID LF_THAREXDE HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS +STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 519dc2087..087a4d927 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -73,7 +73,3 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS))) SRC_STANDALONE = hf_iceclass.c endif -# WITH_STANDALONE_LF_THAREXDE -ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS))) - SRC_STANDALONE = lf_tharexde.c -endif diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c deleted file mode 100644 index c88437f4f..000000000 --- a/armsrc/Standalone/lf_tharexde.c +++ /dev/null @@ -1,283 +0,0 @@ -//----------------------------------------------------------------------------- -// tharexde, 2021 -// -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// main code for EM4x50 simulator and collector aka THAREXDE -//----------------------------------------------------------------------------- -#include -#include "ticks.h" -#include "standalone.h" -#include "proxmark3_arm.h" -#include "appmain.h" -#include "BigBuf.h" -#include "commonutil.h" -#include "fpgaloader.h" -#include "util.h" -#include "dbprint.h" -#include "spiffs.h" -#include "../em4x50.h" - -/* - * `lf_tharexde` simulates EM4x50 dumps uploaded to flash, reads words - * transmitted by EM4x50 tags in standard read mode and stores them in - * internal flash. - * It requires RDV4 hardware (for flash and battery). - * - * On entering stand-alone mode, this module will start simulating EM4x50 data. - * Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml). - * If reader sends password different from dump file password, it is saved in - * file lf_em4x50_passwords.log in flash memory. - * - * On switching to read/record mode by pressing pm3 button, module will start - * reading EM4x50 data. Each collected data set will be written/appended to the - * logfile in flash (lf_em4x50_collect.log) as a text string. - * - * LEDs: - * - LED A: simulating - * - LED A blinking: no simulation data or read error - * - LED B: reading/recording - * - LED D: unmounting/sync'ing flash (normally < 100ms) - * - * To upload input file (eml format) to flash: - * - mem spiffs load f o lf_em4x50_simulate.eml - * - * To retrieve password file from flash: - * - mem spiffs dump o lf_em4x50_passwords.log f - * - * To retrieve log file from flash: - * - mem spiffs dump o lf_em4x50_collect.log f - * - * This module emits debug strings during normal operation -- so try it out in - * the lab connected to PM3 client before taking it into the field. - * - * To delete the input file from flash: - * - mem spiffs remove lf_em4x50_simulate.eml - * - * To delete the log file from flash: - * - mem spiffs remove lf_em4x50_passwords.log - * - * To delete the log file from flash: - * - mem spiffs remove lf_em4x50_collect.log - */ - -#define STATE_SIM 0 -#define STATE_READ 1 -#define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" -#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log" -#define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" - -uint32_t gPassword; - -static void LoadDataInstructions(const char *inputfile) { - Dbprintf(""); - Dbprintf("To load datafile to flash and display it:"); - Dbprintf("1. edit input file %s", inputfile); - Dbprintf("2. start proxmark3 client"); - Dbprintf("3. mem spiffs load f o %s", inputfile); - Dbprintf("4. start standalone mode"); -} - -static void DownloadLogInstructions(const char *logfile) { - Dbprintf(""); - Dbprintf("To get the logfile from flash and display it:"); - Dbprintf("1. mem spiffs dump o %s f ", logfile); - Dbprintf("2. exit proxmark3 client"); - Dbprintf("3. cat "); -} - -static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { - - size_t now = 0; - - if (exists_in_spiffs(inputfile)) { - - uint32_t size = size_in_spiffs(inputfile); - uint8_t *mem = BigBuf_malloc(size); - - Dbprintf(_YELLOW_("found input file %s"), inputfile); - - rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE); - - now = size / 9; - for (int i = 0; i < now; i++) { - for (int j = 0; j < 4; j++) { - tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); - } - } - - Dbprintf(_YELLOW_("read tag data from input file")); - } else { - Dbprintf(_RED_("no input file %s"), inputfile); - } - - BigBuf_free(); - - return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID])); -} - -static void append(const char *filename, uint8_t *entry, size_t entry_len) { - if (exists_in_spiffs(filename)) { - rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); - } else { - rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); - } -} - -void ModInfo(void) { - DbpString(_YELLOW_(" LF EM4x50 sim/collector mode") " - a.k.a tharexde"); -} - -void RunMod(void) { - - bool state_change = true, read_ok = false; - int no_words = 0, command = 0; - uint8_t entry[400], state = STATE_SIM; - uint32_t tag[EM4X50_NO_WORDS] = {0x0}; - - rdv40_spiffs_lazy_mount(); - - StandAloneMode(); - Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); - - for (;;) { - - WDT_HIT(); - if (data_available()) { - break; - } - - // press button - toggle between SIM and READ - // hold button - exit - int button_pressed = BUTTON_CLICKED(1000); - if (button_pressed == BUTTON_SINGLE_CLICK) { - - switch (state) { - case STATE_SIM: - state = STATE_READ; - break; - case STATE_READ: - state = STATE_SIM; - break; - default: - break; - } - - state_change = true; - - } else if (button_pressed == BUTTON_HOLD) { - break; - } - - if (state == STATE_SIM) { - - if (state_change) { - - LEDsoff(); - LED_A_ON(); - Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 simulating mode")); - - read_ok = get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM); - if (read_ok) { - Dbprintf(_YELLOW_("tag data ok")); - } else { - Dbprintf(_RED_("error in tag data")); - LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM); - } - - // init; start with command = standard read mode - em4x50_setup_sim(); - gLogin = false; - LED_D_OFF(); - gPassword = reflect32(tag[0]); - gWritePasswordProcess = false; - command = EM4X50_COMMAND_STANDARD_READ; - - state_change = false; - } - - // if no data or read error -> blink - if (read_ok == false) { - LED(LED_A, 200); - SpinDelay(200); - } - - em4x50_handle_commands(&command, tag); - - // check if new password was found - if (gPassword != reflect32(tag[EM4X50_DEVICE_PASSWORD])) { - - Dbprintf("received password: %08"PRIx32"", gPassword); - - // append password to logfile in flash memory - memset(entry, 0, sizeof(entry)); - sprintf((char *)entry, "%08"PRIx32"\n", gPassword); - append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); - - gPassword = reflect32(tag[EM4X50_DEVICE_PASSWORD]); - } - - // if timeout (e.g. no reader field) continue with standard read - // mode and reset former authentication - if (command == PM3_ETIMEOUT) { - command = EM4X50_COMMAND_STANDARD_READ; - gLogin = false; - LED_D_OFF(); - } - - } else if (state == STATE_READ) { - - if (state_change) { - - LEDsoff(); - LED_B_ON(); - Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 reading mode\n")); - - em4x50_setup_read(); - state_change = false; - } - - no_words = 0; - memset(tag, 0, sizeof(tag)); - standard_read(&no_words, tag); - - if (no_words > 0) { - - memset(entry, 0, sizeof(entry)); - - sprintf((char *)entry, "found EM4x50 tag:\n"); - for (int i = 0; i < no_words; i++) { - sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]); - } - Dbprintf("%s", entry); - sprintf((char *)entry + strlen((char *)entry), "\n"); - append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); - } - } - - // reset timer - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 - AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero - AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer - } - - if (state == STATE_READ) { - DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT); - } else { - DownloadLogInstructions(LF_EM4X50_LOGFILE_SIM); - } - - LED_D_ON(); - rdv40_spiffs_lazy_unmount(); - LED_D_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - Dbprintf(""); - Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped")); -} diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 2ba6aeaba..6dbe54d49 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -79,7 +79,6 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo |-----------------|----------------------------------------| | | No standalone mode | LF_SKELETON | standalone mode skeleton - Iceman1001 -| LF_THAREXDE | LF EM4x50 simulator/read standalone mode - tharexde | LF_EM4100EMUL | LF EM4100 simulator standalone mode - temskiy | LF_EM4100RSWB | LF EM4100 read/write/clone/brute mode - Monster1024 | LF_EM4100RWC | LF EM4100 read/write/clone mode - temskiy