From c49e2d7ba9b3cffa0c05aff77e109542132f5ccf Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 5 Sep 2020 13:25:57 +0200 Subject: [PATCH 001/174] solved --- armsrc/Standalone/Makefile.hal | 9 +- armsrc/Standalone/Makefile.inc | 3 + armsrc/appmain.c | 8 + armsrc/em4x50.c | 890 ++++++++++++++++++++++++++++++--- armsrc/em4x50.h | 6 + armsrc/lfadc.h | 1 + client/src/cmdlfem4x.c | 2 + client/src/cmdlfem4x50.c | 169 ++++++- client/src/cmdlfem4x50.h | 2 + include/em4x50.h | 2 + include/pm3_cmd.h | 2 + 11 files changed, 1026 insertions(+), 68 deletions(-) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index eef4ecf6f..ff01e7c67 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 | read and sim em4x50 tags | +| (RDV4 only) | | ++----------------------------------------------------------+ | HF_14ASNIFF | 14a sniff to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ @@ -64,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 -STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG +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_BOG HF_COLIN HF_LEGIC HF_MATTYRUN HF_MSDSAL 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_THAREXDE LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN 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 c5730965b..9be213368 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -68,4 +68,7 @@ endif # WITH_STANDALONE_HF_ICECLASS ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS))) SRC_STANDALONE = hf_iceclass.c +# WITH_STANDALONE_LF_THAREXDE +ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS))) + SRC_STANDALONE = lf_tharexde.c endif diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 26a62bf9b..10c1f1ac7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1021,6 +1021,14 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_wipe((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_SIM: { + em4x50_sim((em4x50_data_t *)packet->data.asBytes); + break; + } + case CMD_LF_EM4X50_TEST: { + em4x50_test((em4x50_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 45ffc8bbd..b6a44a12c 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -8,10 +8,12 @@ // Low frequency EM4x50 commands //----------------------------------------------------------------------------- +#include "BigBuf.h" #include "fpgaloader.h" #include "ticks.h" #include "dbprint.h" #include "lfadc.h" +#include "lfsampling.h" #include "commonutil.h" #include "em4x50.h" @@ -72,18 +74,21 @@ static em4x50_tag_t tag = { #define EM4X50_T_TAG_HALF_PERIOD 32 #define EM4X50_T_TAG_THREE_QUARTER_PERIOD 48 #define EM4X50_T_TAG_FULL_PERIOD 64 +#define EM4X50_T_TAG_THREE_HALF_PERIOD 96 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 -#define EM4X50_T_WAITING_FOR_SNGLLIW 50 +#define EM4X50_T_WAITING_FOR_SNGLLIW 100 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 +#define EM4X50_SAMPLE_CNT_MAX 3000 #define EM4X50_BIT_0 0 #define EM4X50_BIT_1 1 #define EM4X50_BIT_OTHER 2 +#define EM4X50_COMMAND_REQUEST 2 #define EM4X50_COMMAND_LOGIN 0x01 #define EM4X50_COMMAND_RESET 0x80 #define EM4X50_COMMAND_WRITE 0x12 @@ -170,7 +175,7 @@ static void wait_timer(int timer, uint32_t period) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < period); - + } else { AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; @@ -231,6 +236,62 @@ static void em4x50_setup_read(void) { WDT_HIT(); } +static void em4x50_setup_sim(void) { + + StopTicks(); + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + sample_config *sc = getSamplingConfig(); + sc->decimation = 1; + sc->averaging = 0; + + //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + // FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + LOW(GPIO_SSC_DOUT); + + // Enable peripheral Clock for TIMER_CLOCK 0 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + //AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // Enable peripheral Clock for TIMER_CLOCK 1 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + //AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // Clear all leds + LEDsoff(); + + // Reset and enable timers + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Prepare data trace + uint32_t bufsize = 10000; + + // use malloc + if (g_logging) initSampleBufferEx(&bufsize, true); + + lf_sample_mean(); + +} + // functions for "reader" use case static bool get_signalproperties(void) { @@ -249,6 +310,8 @@ static bool get_signalproperties(void) { // wait until signal/noise > 1 (max. 32 periods) for (int i = 0; i < T0 * no_periods; i++) { + if (BUTTON_PRESS()) return false; + // about 2 samples per bit period wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); @@ -269,8 +332,9 @@ static bool get_signalproperties(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) { - volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (BUTTON_PRESS()) return false; + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; if (sample > sample_max[i]) sample_max[i] = sample; @@ -316,50 +380,54 @@ static uint32_t get_pulse_length(void) { int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); // iterates pulse length (low -> high -> low) - - volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - while (sample > gLow || (timeout--)) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } + // to avoid endless loops - quit after EM4X50_SAMPLE_CNT_MAX samples - if (timeout == 0) - return 0; + int sample_cnt = 0; + uint8_t sample = 0; + + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + while (sample > gLow) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) + return 0; + } AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample < gHigh || (timeout--)) { + + sample_cnt = 0; + while (sample < gHigh) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) + return 0; } - if (timeout == 0) - return 0; - - timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample > gLow || (timeout--)) { + sample_cnt = 0; + while (sample > gLow) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) + return 0; } - if (timeout == 0) - return 0; - return (uint32_t)AT91C_BASE_TC1->TC_CV; } static bool check_pulse_length(uint32_t pl, int length) { // check if pulse length corresponds to given length + + if ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && + (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))) - if ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) & - (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))) return true; else return false; } -static void em4x50_send_bit(int bit) { - +static void em4x50_reader_send_bit(int bit) { + // send single bit according to EM4x50 application note and datasheet // reset clock for the next bit @@ -388,45 +456,200 @@ static void em4x50_send_bit(int bit) { while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); } } +/* +static void em4x50_sim_send_bit(int bit) { + + // send single bit according to EM4x50 application note and datasheet + + // reset clock for the next bit + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; -static void em4x50_send_byte(uint8_t byte) { + if (bit == 0) { + + // disable modulation (activates the field) for first half of bit period + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); + + // enable modulation for second half of bit period + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + + } else { + + // enable modulation (drop the field) for first half of bit period + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); + + // disable modulation for second half of bit period + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); + } +} +*/ +static void em4x50_reader_send_byte(uint8_t byte) { + + // send byte (without parity) + + for (int i = 0; i < 8; i++) + em4x50_reader_send_bit((byte >> (7-i)) & 1); + +} +/* +static void em4x50_sim_send_byte(uint8_t byte) { // send byte (without parity) for (int i = 0; i < 8; i++) - em4x50_send_bit((byte >> (7 - i)) & 1); + em4x50_sim_send_bit((byte >> (7-i)) & 1); } +*/ +static void em4x50_reader_send_byte_with_parity(uint8_t byte) { -static void em4x50_send_byte_with_parity(uint8_t byte) { + // send byte followed by its (equal) parity bit + + int parity = 0, bit = 0; + + for (int i = 0; i < 8; i++) { + bit = (byte >> (7-i)) & 1; + em4x50_reader_send_bit(bit); + parity ^= bit; + } + + em4x50_reader_send_bit(parity); +} +/* +static void em4x50_sim_send_byte_with_parity(uint8_t byte) { // send byte followed by its (equal) parity bit int parity = 0, bit = 0; for (int i = 0; i < 8; i++) { - bit = (byte >> (7 - i)) & 1; - em4x50_send_bit(bit); + bit = (byte >> (7-i)) & 1; + em4x50_sim_send_bit(bit); parity ^= bit; } - em4x50_send_bit(parity); + em4x50_sim_send_bit(parity); } +*/ +static void em4x50_reader_send_word(const uint8_t bytes[4]) { + + // send 32 bit word with parity bits according to EM4x50 datasheet + + for (int i = 0; i < 4; i++) + em4x50_reader_send_byte_with_parity(bytes[i]); + + // send column parities + em4x50_reader_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); -static void em4x50_send_word(const uint8_t bytes[4]) { + // send final stop bit (always "0") + em4x50_reader_send_bit(0); +} +/* +static void em4x50_sim_send_word(const uint8_t bytes[4]) { + // send 32 bit word with parity bits according to EM4x50 datasheet for (int i = 0; i < 4; i++) - em4x50_send_byte_with_parity(bytes[i]); - + em4x50_sim_send_byte_with_parity(bytes[i]); + // send column parities - em4x50_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); + em4x50_sim_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); // send final stop bit (always "0") - em4x50_send_bit(0); + em4x50_sim_send_bit(0); } +static void em4x50_sim_send_ack(void) { + + // send "acknowledge" according to EM4x50 application note and datasheet + + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + +} + +static void em4x50_sim_send_nak(void) { + + // send "not" acknowledge" according to EM4x50 application note and datasheet + + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + +} + +static void em4x50_sim_handle_command(void) { + + em4x50_sim_send_ack(); + em4x50_sim_send_nak(); + Dbprintf(""); + +} +*/ +/* +static bool em4x50_sim_detect_rm(void) { + + if (get_next_bit() == EM4X50_BIT_0) + if (get_next_bit() == EM4X50_BIT_0) + return true; + + //int periods = 0; + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) + // adc_val[periods++] = AT91C_BASE_SSC->SSC_RHR; + + return false; +} +*/ +/* +static void em4x50_sim_send_listen_window(void) { + + // send single listen window according to EM4x50 application note and datasheet + + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + + HIGH(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); + + HIGH(GPIO_SSC_DOUT); + if (em4x50_sim_detect_rm()) + em4x50_sim_handle_command(); + + LOW(GPIO_SSC_DOUT); + wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); + +} +*/ + static bool find_single_listen_window(void) { // find single listen window @@ -491,8 +714,8 @@ static bool find_double_listen_window(bool bcommand) { if (get_next_bit() == EM4X50_BIT_OTHER) { // send RM for request mode - em4x50_send_bit(0); - em4x50_send_bit(0); + em4x50_reader_send_bit(0); + em4x50_reader_send_bit(0); return true; } @@ -571,8 +794,8 @@ static bool check_ack(bool bliw) { if (get_next_bit() == EM4X50_BIT_OTHER) { // send RM for request mode - em4x50_send_bit(0); - em4x50_send_bit(0); + em4x50_reader_send_bit(0); + em4x50_reader_send_bit(0); return true; } @@ -588,7 +811,7 @@ static bool check_ack(bool bliw) { return false; } -static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { +static int get_word_from_bitstream(uintö8_t bits[EM4X50_TAG_WORD]) { // decodes one word by evaluating pulse lengths and previous bit; // word must have 45 bits in total: @@ -621,8 +844,8 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { // identify remaining bits based on pulse lengths // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (true) { - + while (BUTTON_PRESS() == false) { + i++; pl = get_pulse_length(); @@ -670,6 +893,8 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { } } + + return 0; } //============================================================================== @@ -684,10 +909,10 @@ static bool login(uint8_t password[4]) { if (request_receive_mode()) { // send login command - em4x50_send_byte_with_parity(EM4X50_COMMAND_LOGIN); + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_LOGIN); // send password - em4x50_send_word(password); + em4x50_reader_send_word(password); // check if ACK is returned if (check_ack(false)) @@ -706,14 +931,19 @@ static bool login(uint8_t password[4]) { //============================================================================== static bool reset(void) { - + // resets EM4x50 tag (used by write function) if (request_receive_mode()) { // send login command +<<<<<<< Updated upstream em4x50_send_byte_with_parity(EM4X50_COMMAND_RESET); +======= + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); + +>>>>>>> Stashed changes if (check_ack(false)) return true; @@ -770,15 +1000,14 @@ static bool selective_read(uint8_t addresses[4]) { if (request_receive_mode()) { // send selective read command - em4x50_send_byte_with_parity(EM4X50_COMMAND_SELECTIVE_READ); + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_SELECTIVE_READ); // send address data - em4x50_send_word(addresses); + em4x50_reader_send_word(addresses); - // look for ACK sequence + // look for ACK sequence -> save and verify via standard read mode + // (compare number of words) if (check_ack(false)) - - // save and verify via standard read mode (compare number of words) if (standard_read(&now)) if (now == (lwr - fwr + 1)) return true; @@ -807,7 +1036,7 @@ void em4x50_info(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - + if (etd->pwd_given) { // try to login with given password @@ -845,8 +1074,7 @@ void em4x50_read(em4x50_data_t *etd) { em4x50_setup_read(); // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - + if (get_signalproperties()) {//} && find_em4x50_tag()) { if (etd->addr_given) { // selective read mode @@ -863,12 +1091,12 @@ void em4x50_read(em4x50_data_t *etd) { // standard read mode bsuccess = standard_read(&now); - } } status = (now << 2) + (bsuccess << 1) + blogin; + LOW(GPIO_SSC_DOUT); lf_finalize(); reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); } @@ -884,13 +1112,13 @@ static bool write(uint8_t word[4], uint8_t address) { if (request_receive_mode()) { // send write command - em4x50_send_byte_with_parity(EM4X50_COMMAND_WRITE); + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_WRITE); // send address data - em4x50_send_byte_with_parity(address); + em4x50_reader_send_byte_with_parity(address); // send data - em4x50_send_word(word); + em4x50_reader_send_word(word); // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); @@ -920,10 +1148,10 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { if (request_receive_mode()) { // send write password command - em4x50_send_byte_with_parity(EM4X50_COMMAND_WRITE_PASSWORD); + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_WRITE_PASSWORD); // send address data - em4x50_send_word(password); + em4x50_reader_send_word(password); // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); @@ -933,7 +1161,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { if (check_ack(true)) { // send new password - em4x50_send_word(new_password); + em4x50_reader_send_word(new_password); // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); @@ -1090,3 +1318,545 @@ void em4x50_wipe(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } + +static bool em4x50_sim_send_bit2(uint8_t bit) { + + uint16_t check = 0; + + for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { + + // wait until SSC_CLK goes HIGH + // used as a simple detection of a reader field? + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (bit) + OPEN_COIL(); + else + SHORT_COIL(); + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (t == EM4X50_T_TAG_HALF_PERIOD) + bit ^= 1; + + } + + return true; +} + +static bool em4x50_sim_send_byte2(uint8_t byte) { + + // send byte + for (int i = 0; i < 8; i++) + if (!em4x50_sim_send_bit2((byte >> (7 - i)) & 1)) + return false; + + return true; + +} + +static bool em4x50_sim_send_byte_with_parity2(uint8_t byte) { + + uint8_t parity = 0x0; + + // send byte with parity (even) + for (int i = 0; i < 8; i++) + parity ^= (byte >> i) & 1; + + if (!em4x50_sim_send_byte2(byte)) + return false;; + + if (!em4x50_sim_send_bit2(parity)) + return false; + + return true; +} + +static bool em4x50_sim_send_word2(uint8_t *word) { + + uint8_t cparity = 0x00; + + // 4 bytes each with even row parity bit + for (int i = 0; i < 4; i++) + if (!em4x50_sim_send_byte_with_parity2(word[i])) + return false; + + // column parity + for (int i = 0; i < 8; i++) { + cparity <<= 1; + for (int j = 0; j < 4; j++) { + cparity ^= (word[j] >> i) & 1; + } + } + if (!em4x50_sim_send_byte2(cparity)) + return false; + + // stop bit + if (!em4x50_sim_send_bit2(0)) + return false; + + return true; +} + +bool em4x50_sim_send_word3(uint32_t word) { + + uint8_t cparity = 0x00; + + // 4 bytes each with even row parity bit + for (int i = 0; i < 4; i++) + if (!em4x50_sim_send_byte_with_parity2( (word >> ((3 - i) * 8)) & 0xFF)) + return false; + + // column parity + for (int i = 0; i < 8; i++) { + cparity <<= 1; + for (int j = 0; j < 4; j++) { + cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; + } + } + if (!em4x50_sim_send_byte2(cparity)) + return false; + + // stop bit + if (!em4x50_sim_send_bit2(0)) + return false; + + return true; +} + +bool em4x50_sim_send_listen_window2(void) { + + //int i = 0; + uint16_t check = 0; + //uint8_t test[100] = {0}; + + for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + + // wait until SSC_CLK goes HIGH + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { + OPEN_COIL(); + } else if (t >= EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= EM4X50_T_TAG_HALF_PERIOD) { + OPEN_COIL(); + } else { + SHORT_COIL(); + } + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + } + + return true; +} + +static bool em4x50_sim_send_listen_window3(void) { + + int t = 0; + int i = 0; + uint16_t check = 0; + uint8_t test[100] = {0}; + + while (t < 5 * EM4X50_T_TAG_FULL_PERIOD) { + + // wait until SSC_CLK goes HIGH + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { + OPEN_COIL(); + + i = 0; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) { + + if (i == 0) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + FpgaSetupSsc(); + //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + } + + if (i < 100) + test[i++] = AT91C_BASE_SSC->SSC_RHR; + + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + + t = 4 * EM4X50_T_TAG_FULL_PERIOD - 1; + + } else if (t >= EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= EM4X50_T_TAG_HALF_PERIOD) { + OPEN_COIL(); + } else { + SHORT_COIL(); + } + + t++; + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + } + for (i = 0; i < 100; i++) + Dbprintf("value[%i] = %i", i, test[i]); + + return true; +} + +/* +static void em4x50_sim_send_word3(uint8_t *word) { + + uint8_t rparity = 0x00, cparity = 0x00; + uint64_t word_with_parities = { 0x00 }; + + // bytes + row parities + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 8; j++) { + word_with_parities += (word[i] >> j) & 1; + word_with_parities <<= 1; + rparity ^= (word[i] >> j) & 1; + } + word_with_parities += rparity & 1; + word_with_parities <<= 1; + } + + // column parities + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 4; j++) { + cparity ^= (word[j] >> i) & 1; + } + word_with_parities += cparity; + word_with_parities <<= 1; + cparity = 0; + } + + // stop bit + word_with_parities += 0; + + // send total word + for (int i = 0; i < EM4X50_TAG_WORD; i++) + em4x50_sim_send_bit2((word_with_parities >> (EM4X50_TAG_WORD-1 - i)) & 1); + +} +*/ + +/* +static void simlf(uint8_t *buf, int period) { + + int i = 0, count = 0; + int clock1 = 32, clock2 = 64; + uint16_t check = 0; + + for (;;) { + + // wait until SSC_CLK goes HIGH + // used as a simple detection of a reader field? + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return; + check = 0; + } + ++check; + } + + if (buf[i]) + OPEN_COIL(); + else + SHORT_COIL(); + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return; + check = 0; + } + ++check; + } + + if (count == EM4X50_T_TAG_HALF_PERIOD) { + buf[i] ^= 1; + } else if (count == EM4X50_T_TAG_FULL_PERIOD) { + buf[i] ^= 1; + count = 0; + i++; + if (i == period) { + i = 0; + } + } + count++; + } +} +*/ + +void em4x50_sim(em4x50_data_t *etd) { + + bool bsuccess = false; + + //init_tag(); + //em4x50_setup_sim(); + + //FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + //StartTicks(); + + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_MAJOR_MODE_LF_ADC ); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + //WaitMS(20); + + //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + //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; + + // from hitag2 + //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + //FpgaSetupSsc(); + //AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + //AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + //LOW(GPIO_SSC_DOUT); + //AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + // works! + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); + // does not really work + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_MAJOR_MODE_LF_ADC ); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + // does not work! + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + //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; + + 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; + while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero + + uint8_t word1[4] = {0x27, 0xfc, 0x42, 0x40}; + uint8_t word2[4] = {0x12, 0x34, 0x56, 0x78}; + + bsuccess = em4x50_sim_send_listen_window3(); + while (bsuccess) { + + bsuccess = em4x50_sim_send_listen_window3() + & em4x50_sim_send_word2(word1) + & em4x50_sim_send_listen_window3() + & em4x50_sim_send_word2(word2) + & em4x50_sim_send_listen_window3(); + } + + /* + WDT_HIT(); + while (BUTTON_PRESS() == false) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + for (int i = 0; i < 10; i++) { + + HIGH(GPIO_SSC_DOUT); + lf_wait_periods(32); + Dbprintf("High"); + + LOW(GPIO_SSC_DOUT); + lf_wait_periods(32); + Dbprintf("Low"); + } + Dbprintf("geht"); + } else { + Dbprintf("Mist"); + } + } + */ + + /* + volatile uint8_t adc_val[2000] = {0}; + + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + //FpgaSetupSsc(); + + while (BUTTON_PRESS() == false) { + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) + for (int i = 0; i < 2000; i++) + adc_val[i] = AT91C_BASE_SSC->SSC_RHR; + } + + for (int i = 0; i < 2000; i++) + Dbprintf("adc_val = %i", adc_val[i]); +*/ + + lf_finalize(); + reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); +} + +void em4x50_test(em4x50_data_t *etd) { + + DBGLEVEL = DBG_DEBUG; + + bool bsuccess = false; + + em4x50_setup_sim(); + + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + //FpgaSetupSsc(); + //AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + if (etd->carrier == 1) { + + LED_A_ON(); + LOW(GPIO_SSC_DOUT); + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("carrier on"); + + } else if (etd->carrier == 0) { + + LED_A_OFF(); + HIGH(GPIO_SSC_DOUT); + + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("carrier off"); + + } else { + + LED_B_ON(); + + LOW(GPIO_SSC_DOUT); + + while (BUTTON_PRESS() == false) { + + for (int i = 0; i < 10; i++) + wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); + + LED_C_ON(); + + // send selective read command + em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_SELECTIVE_READ); + em4x50_reader_send_bit(0); + em4x50_reader_send_bit(0); + em4x50_reader_send_byte_with_parity(etd->byte); + + LED_C_OFF(); + + } + + LED_B_OFF(); + + lf_finalize(); + } + + bsuccess = true; + + reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); +} + +int em4x50_standalone_read(uint64_t *words) { + + int now = 0; + uint8_t bits[EM4X50_TAG_WORD]; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) { + + if (find_double_listen_window(false)) { + + memset(bits, 0, sizeof(bits)); + + while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { + + words[now] = 0; + + for (int i = 0; i < EM4X50_TAG_WORD; i++) { + words[now] <<= 1; + words[now] += bits[i] & 1; + } + + now++; + } + } + } + + return now; +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index f9f1375f2..c483bf27f 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -17,10 +17,16 @@ typedef struct { uint8_t sectors[34][7]; } em4x50_tag_t; +int em4x50_standalone_read(uint64_t *words); +bool em4x50_sim_send_listen_window2(void); +bool em4x50_sim_send_word3(uint32_t word); + void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_write_password(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(em4x50_data_t *etd); +void em4x50_sim(em4x50_data_t *etd); +void em4x50_test(em4x50_data_t *etd); #endif /* EM4X50_H */ diff --git a/armsrc/lfadc.h b/armsrc/lfadc.h index 1c8a4211f..66c6da534 100644 --- a/armsrc/lfadc.h +++ b/armsrc/lfadc.h @@ -31,6 +31,7 @@ void lf_wait_periods(size_t periods); void lf_init(bool reader, bool simulate); void lf_finalize(void); size_t lf_detect_field_drop(size_t max); + bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len); void lf_modulation(bool modulation); diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index a9d6c9794..c7857c2cb 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1397,6 +1397,8 @@ static command_t CommandTable[] = { {"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change passwword of EM4x50 tag"}, {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, + {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, + {"4x50_test", CmdEM4x50Test, IfPm3EM4x50, "test functionality for EM4x50"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 03ec3f5dc..92dd19510 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -93,7 +93,32 @@ static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " p - password (hex)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wwipe p 11223344")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wipe p 11223344")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} +static int usage_lf_em4x50_sim(void) { + PrintAndLogEx(NORMAL, "Simulate EM4x50 tag. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] w "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " w - word (hex)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim w 12345678")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} +static int usage_lf_em4x50_test(void) { + PrintAndLogEx(NORMAL, "Test functionality for EM4x50 tag. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_test [h] ..."); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " c <0|1> - carrier on|off (optional)"); + PrintAndLogEx(NORMAL, " b - byte (hex) (optional)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_test ...")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -539,10 +564,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { uint8_t *data = resp.data.asBytes; em4x50_word_t words[EM4X50_NO_WORDS]; + int now = (resp.status & STATUS_NO_WORDS) >> 2; if (edata.addr_given) { prepare_result(data, etd->address, etd->address, words); } else { - int now = (resp.status & STATUS_NO_WORDS) >> 2; prepare_result(data, 0, now - 1, words); } @@ -550,7 +575,11 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); } - print_result(words, etd->address, etd->address); + if (edata.addr_given) + print_result(words, etd->address, etd->address); + else + print_result(words, 0, now - 1); + return PM3_SUCCESS; } @@ -598,8 +627,9 @@ int CmdEM4x50Read(const char *Cmd) { } } - if (errors || strlen(Cmd) == 0 || etd.addr_given == false) - return usage_lf_em4x50_read(); + //if (errors || strlen(Cmd) == 0 || etd.addr_given == false) + if (errors) + return usage_lf_em4x50_read(); return em4x50_read(&etd, NULL, true); } @@ -740,3 +770,132 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50Sim(const char *Cmd) { + + // fills EM4x50 tag with zeros including password + + bool errors = false, bword = false; + uint8_t cmdp = 0; + em4x50_data_t etd; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_em4x50_sim(); + + case 'w': { + if (param_gethex(Cmd, cmdp + 1, etd.word, 8)) { + PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); + return PM3_EINVARG; + } + bword = true; + cmdp += 2; + break; + } + + case 'f': { + if (param_gethex(Cmd, cmdp + 1, etd.word, 8)) { + PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); + return PM3_EINVARG; + } + bword = true; + cmdp += 2; + break; + } + + default: + PrintAndLogEx(WARNING, "\nUnknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors || !bword) + return usage_lf_em4x50_sim(); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&etd, sizeof(etd)); + + if (!WaitForResponse(CMD_ACK, &resp)) { + PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n"); + return PM3_ETIMEOUT; + } + + // print response + bool isOK = resp.status; + if (isOK) { + PrintAndLogEx(SUCCESS,"\nsimulation data " _GREEN_("ok") "\n"); + } else { + PrintAndLogEx(FAILED,"\nsimulating data " _RED_("failed") "\n"); + return PM3_ESOFT; + } + + return PM3_SUCCESS; +} + +int CmdEM4x50Test(const char *Cmd) { + + // fills EM4x50 tag with zeros including password + + bool errors = false; + uint8_t cmdp = 0; + em4x50_data_t etd; + PacketResponseNG resp; + + etd.carrier = 2; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_em4x50_test(); + + case 'c': + param_getdec(Cmd, cmdp + 1, &etd.carrier); + if (etd.carrier != 0 && etd.carrier != 1) { + PrintAndLogEx(FAILED, "\ncarrier has to be either 0 or 1\n"); + return PM3_EINVARG; + } + cmdp += 2; + break; + + case 'b': + if (param_gethex(Cmd, cmdp + 1, &etd.byte, 2)) { + PrintAndLogEx(FAILED, "\nbyte has to be 2 hex symbols\n"); + return PM3_EINVARG; + } + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "\nUnknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors) + return usage_lf_em4x50_test(); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_TEST, (uint8_t *)&etd, sizeof(etd)); + + if (!WaitForResponse(CMD_ACK, &resp)) { + PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n"); + return PM3_ETIMEOUT; + } + + // print response + bool isOK = resp.status; + if (isOK) { + PrintAndLogEx(SUCCESS,"\ntest " _GREEN_("ok") "\n"); + } else { + PrintAndLogEx(FAILED,"\ntest " _RED_("failed") "\n"); + return PM3_ESOFT; + } + + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 01417aa1e..8a66fd7b8 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -24,5 +24,7 @@ int CmdEM4x50WritePassword(const char *Cmd); int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); +int CmdEM4x50Sim(const char *Cmd); +int CmdEM4x50Test(const char *Cmd); #endif diff --git a/include/em4x50.h b/include/em4x50.h index b70072c32..ea759ca97 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -44,6 +44,8 @@ typedef struct { bool addr_given; bool pwd_given; bool newpwd_given; + uint8_t carrier; + uint8_t byte; uint8_t password[4]; uint8_t new_password[4]; uint8_t addresses[4]; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index b2eff0ddb..492738bb8 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -484,6 +484,8 @@ typedef struct { #define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 +#define CMD_LF_EM4X50_SIM 0x0245 +#define CMD_LF_EM4X50_TEST 0x0246 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 732d903b52b8e6fe7fe58524858f3997ba9e988d Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 22 Sep 2020 23:31:11 +0200 Subject: [PATCH 002/174] simulate/read --- armsrc/Standalone/lf_tharexde.c | 297 ++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 armsrc/Standalone/lf_tharexde.c diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c new file mode 100644 index 000000000..11e056c8b --- /dev/null +++ b/armsrc/Standalone/lf_tharexde.c @@ -0,0 +1,297 @@ +//----------------------------------------------------------------------------- +// Tharexde, 2020 +// +// 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 "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 hardcoded 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 reading/record 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 retrieve log file from flash: + * + * 1. mem spiffs dump o lf_em4x50collect.log f lf_em4x50collect.log + * Copies log file from flash to your client. + * + * 2. exit the Proxmark3 client + * + * 3. more lf_tharexdecollect.log + * + * 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 log file from flash: + * + * 1. mem spiffs remove lf_tharexdecollect.log + */ + +#define STATE_SIM 0 +#define STATE_READ 1 +#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml" +#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log" +#define EM4X50_TAG_WORD 45 + +bool input_exists; +bool log_exists; + +static void LoadDataInstructions(void) { + Dbprintf(""); + Dbprintf("[=] To load datafile into flash and display it:"); + Dbprintf("[=] " _YELLOW_("1.") " edit inputfile "LF_EM4X50SIMULATE_INPUTFILE); + Dbprintf("[=] " _YELLOW_("2.") " start proxmark3 client"); + Dbprintf("[=] " _YELLOW_("3.") " mem spiffs load f "LF_EM4X50SIMULATE_INPUTFILE" o "LF_EM4X50SIMULATE_INPUTFILE); + Dbprintf("[=] " _YELLOW_("4.") " start standalone mode"); +} + +static void DownloadLogInstructions(void) { + Dbprintf(""); + Dbprintf("[=] To get the logfile from flash and display it:"); + Dbprintf("[=] " _YELLOW_("1.") " mem spiffs dump o "LF_EM4X50COLLECT_LOGFILE" f "LF_EM4X50COLLECT_LOGFILE); + Dbprintf("[=] " _YELLOW_("2.") " exit proxmark3 client"); + Dbprintf("[=] " _YELLOW_("3.") " cat "LF_EM4X50COLLECT_LOGFILE); +} + +static bool strip_check_parities(uint64_t data, uint32_t *word) { + + uint8_t rparity = 0, cparity = 0; + uint8_t rparity_m = 0, cparity_m = 0, stop_bit_m = 0; + + // strip parities + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 8; j++) { + *word <<= 1; + *word += (data >> (EM4X50_TAG_WORD - 1 - 9 * i - j)) & 1; + } + } + + // calculate row parities + for (int i = 0; i < 4; i++) { + rparity <<= 1; + for (int j = 0; j < 8; j++) { + rparity ^= (*word >> (31 - 8 * i - j)) & 1; + } + } + + // calculate column parities + for (int i = 0; i < 8; i++) { + cparity <<= 1; + for (int j = 0; j < 4; j++) { + cparity ^= (*word >> (31 - 8 * j - i)) & 1; + } + } + + // measured row parities + for (int i = 0; i < 4; i++) { + rparity_m <<= 1; + rparity_m += (data >> (EM4X50_TAG_WORD - 9 * (i + 1))) & 1; + } + + // measured column parities + cparity_m = (data >> 1) & 0xFF; + + // measured stop bit + stop_bit_m = data & 1; + + if ((cparity_m == cparity) && (rparity_m == rparity) && (stop_bit_m == 0)) + return true; + + return false; +} + +static int get_input_data_from_file(uint32_t *words) { + + size_t now = 0; + + if (exists_in_spiffs(LF_EM4X50SIMULATE_INPUTFILE)) { + + uint32_t size = size_in_spiffs((char *)LF_EM4X50SIMULATE_INPUTFILE); + uint8_t *mem = BigBuf_malloc(size); + + Dbprintf(_YELLOW_("[=] found input file %s"), LF_EM4X50SIMULATE_INPUTFILE); + + rdv40_spiffs_read_as_filetype((char *)LF_EM4X50SIMULATE_INPUTFILE, mem, size, RDV40_SPIFFS_SAFETY_SAFE); + + now = size / 9; + for (int i = 0; i < now; i++) + for (int j = 0; j < 4; j++) + words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); + + Dbprintf(_YELLOW_("[=] read data from input file")); + } + + BigBuf_free(); + + return (now > 0) ? now : 0; +} + +static void append(uint8_t *entry, size_t entry_len) { + + LED_C_ON(); + if (log_exists == false) { + rdv40_spiffs_write(LF_EM4X50COLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + log_exists = true; + } else { + rdv40_spiffs_append(LF_EM4X50COLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + } + LED_C_OFF(); +} + +void ModInfo(void) { + DbpString(_YELLOW_(" LF EM4x50 collector mode") " - a.k.a tharexde"); +} + +void RunMod(void) { + + bool state_change = true; + uint8_t state = STATE_SIM; + // declarations for simulating + uint32_t words[33] = {0x0}; + size_t now = 0; + // declarations for reading + int no_words = 0; + uint64_t data[EM4X50_TAG_WORD]; + uint32_t word = 0; + uint8_t entry[81]; + + 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); + state = (state == STATE_SIM) ? STATE_READ : STATE_SIM; + state_change = true; + + } else if (button_pressed == BUTTON_HOLD) { + + SpinDown(100); + break; + } + + if (state == STATE_SIM) { + + if (state_change) { + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + 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; + + LED_A_ON(); + LED_B_OFF(); + Dbprintf(_YELLOW_("[=] switched to EM4x50 simulating mode")); + + now = get_input_data_from_file(words); + if (now > 0) { + Dbprintf(_YELLOW_("[=] simulating %i blocks"), now); + for (int i = 0; i < now; i++) + Dbprintf(_YELLOW_("[=] %2i -> %lx"), i + 1, words[i]); + + } else { + Dbprintf(_RED_("[!] error in input data")); + } + + state_change = false; + } + + em4x50_sim_send_listen_window2(); + for (int i = 0; i < now; i++) { + em4x50_sim_send_listen_window2(); + em4x50_sim_send_word3(words[i]); + } + + } else if (state == STATE_READ) { + + if (state_change) { + + LED_B_ON(); + LED_A_OFF(); + Dbprintf(_YELLOW_("[=] switched to EM4x50 reading mode")); + + memset(entry, 0, sizeof(entry)); + memset(data, 0, sizeof(data)); + + log_exists = exists_in_spiffs(LF_EM4X50COLLECT_LOGFILE); + + state_change = false; + } + + no_words = em4x50_standalone_read(data); + + if (no_words > 0) { + + memset(entry, 0, sizeof(entry)); + + sprintf((char *)entry, "found new EM4x50 tag:"); + Dbprintf("%s", entry); + strcat((char *)entry, "\n"); + append(entry, strlen((char *)entry)); + + for (int i = 0; i < no_words; i++) { + + if (strip_check_parities(data[i], &word)) + sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check ok)", i + 1, word); + else + sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check failed)", i + 1, word); + + Dbprintf("%s", entry); + strcat((char *)entry, "\n"); + append(entry, strlen((char *)entry)); + } + } + + } + } + + if (state == STATE_READ) + DownloadLogInstructions(); + else + LoadDataInstructions(); + + LED_D_ON(); + rdv40_spiffs_lazy_unmount(); + LED_D_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped")); + +} From 48495bf272de51eef63e8ddc01d43ba40646c1e6 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 22 Sep 2020 23:34:23 +0200 Subject: [PATCH 003/174] added missing "endif" --- armsrc/Standalone/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 9be213368..6fae43f96 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -68,6 +68,7 @@ endif # WITH_STANDALONE_HF_ICECLASS 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 From b96b92249f52522a9fb67a5ea9a789228c997c24 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 22 Sep 2020 23:55:46 +0200 Subject: [PATCH 004/174] div errors --- armsrc/em4x50.c | 330 +----------------------------------------------- 1 file changed, 3 insertions(+), 327 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b6a44a12c..0d27fba9e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -236,62 +236,6 @@ static void em4x50_setup_read(void) { WDT_HIT(); } -static void em4x50_setup_sim(void) { - - StopTicks(); - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - sample_config *sc = getSamplingConfig(); - sc->decimation = 1; - sc->averaging = 0; - - //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - - // FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(); - - // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - LOW(GPIO_SSC_DOUT); - - // Enable peripheral Clock for TIMER_CLOCK 0 - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - //AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // Enable peripheral Clock for TIMER_CLOCK 1 - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - //AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // Clear all leds - LEDsoff(); - - // Reset and enable timers - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Prepare data trace - uint32_t bufsize = 10000; - - // use malloc - if (g_logging) initSampleBufferEx(&bufsize, true); - - lf_sample_mean(); - -} - // functions for "reader" use case static bool get_signalproperties(void) { @@ -301,6 +245,7 @@ static bool get_signalproperties(void) { bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; + uint8_t sample = 0; uint8_t sample_ref = 127; uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; @@ -377,8 +322,6 @@ static int get_next_bit(void) { static uint32_t get_pulse_length(void) { - int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - // iterates pulse length (low -> high -> low) // to avoid endless loops - quit after EM4X50_SAMPLE_CNT_MAX samples @@ -394,8 +337,6 @@ static uint32_t get_pulse_length(void) { } AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - sample_cnt = 0; while (sample < gHigh) { @@ -811,7 +752,7 @@ static bool check_ack(bool bliw) { return false; } -static int get_word_from_bitstream(uintö8_t bits[EM4X50_TAG_WORD]) { +static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { // decodes one word by evaluating pulse lengths and previous bit; // word must have 45 bits in total: @@ -937,13 +878,8 @@ static bool reset(void) { if (request_receive_mode()) { // send login command -<<<<<<< Updated upstream - em4x50_send_byte_with_parity(EM4X50_COMMAND_RESET); - -======= em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); ->>>>>>> Stashed changes if (check_ack(false)) return true; @@ -1391,32 +1327,6 @@ static bool em4x50_sim_send_byte_with_parity2(uint8_t byte) { return true; } -static bool em4x50_sim_send_word2(uint8_t *word) { - - uint8_t cparity = 0x00; - - // 4 bytes each with even row parity bit - for (int i = 0; i < 4; i++) - if (!em4x50_sim_send_byte_with_parity2(word[i])) - return false; - - // column parity - for (int i = 0; i < 8; i++) { - cparity <<= 1; - for (int j = 0; j < 4; j++) { - cparity ^= (word[j] >> i) & 1; - } - } - if (!em4x50_sim_send_byte2(cparity)) - return false; - - // stop bit - if (!em4x50_sim_send_bit2(0)) - return false; - - return true; -} - bool em4x50_sim_send_word3(uint32_t word) { uint8_t cparity = 0x00; @@ -1491,81 +1401,6 @@ bool em4x50_sim_send_listen_window2(void) { return true; } -static bool em4x50_sim_send_listen_window3(void) { - - int t = 0; - int i = 0; - uint16_t check = 0; - uint8_t test[100] = {0}; - - while (t < 5 * EM4X50_T_TAG_FULL_PERIOD) { - - // wait until SSC_CLK goes HIGH - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; - } - - if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { - SHORT_COIL(); - } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { - OPEN_COIL(); - - i = 0; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) { - - if (i == 0) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - FpgaSetupSsc(); - //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - } - - if (i < 100) - test[i++] = AT91C_BASE_SSC->SSC_RHR; - - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - - t = 4 * EM4X50_T_TAG_FULL_PERIOD - 1; - - } else if (t >= EM4X50_T_TAG_FULL_PERIOD) { - SHORT_COIL(); - } else if (t >= EM4X50_T_TAG_HALF_PERIOD) { - OPEN_COIL(); - } else { - SHORT_COIL(); - } - - t++; - check = 0; - - //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return false; - check = 0; - } - ++check; - } - } - for (i = 0; i < 100; i++) - Dbprintf("value[%i] = %i", i, test[i]); - - return true; -} - /* static void em4x50_sim_send_word3(uint8_t *word) { @@ -1660,112 +1495,6 @@ static void simlf(uint8_t *buf, int period) { void em4x50_sim(em4x50_data_t *etd) { bool bsuccess = false; - - //init_tag(); - //em4x50_setup_sim(); - - //FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - //StartTicks(); - - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_MAJOR_MODE_LF_ADC ); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - //WaitMS(20); - - //FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - - //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; - - // from hitag2 - //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - //FpgaSetupSsc(); - //AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - //AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - //LOW(GPIO_SSC_DOUT); - //AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // works! - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); - // does not really work - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_MAJOR_MODE_LF_ADC ); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // does not work! - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - - //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; - - 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; - while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero - - uint8_t word1[4] = {0x27, 0xfc, 0x42, 0x40}; - uint8_t word2[4] = {0x12, 0x34, 0x56, 0x78}; - - bsuccess = em4x50_sim_send_listen_window3(); - while (bsuccess) { - - bsuccess = em4x50_sim_send_listen_window3() - & em4x50_sim_send_word2(word1) - & em4x50_sim_send_listen_window3() - & em4x50_sim_send_word2(word2) - & em4x50_sim_send_listen_window3(); - } - - /* - WDT_HIT(); - while (BUTTON_PRESS() == false) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - for (int i = 0; i < 10; i++) { - - HIGH(GPIO_SSC_DOUT); - lf_wait_periods(32); - Dbprintf("High"); - - LOW(GPIO_SSC_DOUT); - lf_wait_periods(32); - Dbprintf("Low"); - } - Dbprintf("geht"); - } else { - Dbprintf("Mist"); - } - } - */ - - /* - volatile uint8_t adc_val[2000] = {0}; - - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); - //SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - //FpgaSetupSsc(); - - while (BUTTON_PRESS() == false) { - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) - for (int i = 0; i < 2000; i++) - adc_val[i] = AT91C_BASE_SSC->SSC_RHR; - } - - for (int i = 0; i < 2000; i++) - Dbprintf("adc_val = %i", adc_val[i]); -*/ lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); @@ -1773,60 +1502,7 @@ void em4x50_sim(em4x50_data_t *etd) { void em4x50_test(em4x50_data_t *etd) { - DBGLEVEL = DBG_DEBUG; - - bool bsuccess = false; - - em4x50_setup_sim(); - - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - //FpgaSetupSsc(); - //AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - if (etd->carrier == 1) { - - LED_A_ON(); - LOW(GPIO_SSC_DOUT); - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("carrier on"); - - } else if (etd->carrier == 0) { - - LED_A_OFF(); - HIGH(GPIO_SSC_DOUT); - - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("carrier off"); - - } else { - - LED_B_ON(); - - LOW(GPIO_SSC_DOUT); - - while (BUTTON_PRESS() == false) { - - for (int i = 0; i < 10; i++) - wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); - - LED_C_ON(); - - // send selective read command - em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_SELECTIVE_READ); - em4x50_reader_send_bit(0); - em4x50_reader_send_bit(0); - em4x50_reader_send_byte_with_parity(etd->byte); - - LED_C_OFF(); - - } - - LED_B_OFF(); - - lf_finalize(); - } - - bsuccess = true; + bool bsuccess = true; reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } From 72ab7177ae6ae039e01d2397f70e6ca02349001c Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 00:12:57 +0200 Subject: [PATCH 005/174] removed double declaration of variable "sample" --- armsrc/em4x50.c | 1 - 1 file changed, 1 deletion(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index bb1eb5f10..b2b9c74f3 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -330,7 +330,6 @@ static uint32_t get_pulse_length(void) { // to avoid endless loops - quit after EM4X50_SAMPLE_CNT_MAX samples int sample_cnt = 0; - uint8_t sample = 0; volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; From 252b8236cfebdf09284b06cf8dec66c9a746b4b2 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:06:12 +0200 Subject: [PATCH 006/174] renamed function names --- armsrc/em4x50.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index c483bf27f..7e4c00fba 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -18,8 +18,8 @@ typedef struct { } em4x50_tag_t; int em4x50_standalone_read(uint64_t *words); -bool em4x50_sim_send_listen_window2(void); -bool em4x50_sim_send_word3(uint32_t word); +bool em4x50_sim_send_listen_window(void); +bool em4x50_sim_send_word(uint32_t word); void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); From a7a86edf51e00f69e7f93fde28817831b7df409a Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:08:24 +0200 Subject: [PATCH 007/174] deleted inactive parts, corrected timeout handling --- armsrc/em4x50.c | 291 ++++-------------------------------------------- 1 file changed, 20 insertions(+), 271 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b2b9c74f3..869f99394 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -324,42 +324,38 @@ static uint32_t get_pulse_length(void) { // Dbprintf( _CYAN_("4x50 get_pulse_length A") ); - int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + int timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); // iterates pulse length (low -> high -> low) - // to avoid endless loops - quit after EM4X50_SAMPLE_CNT_MAX samples + // to avoid endless loops - quit if timeout = 0 - int sample_cnt = 0; - volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; while (sample > gLow && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) - return 0; } - + if (timeout == 0) return 0; AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); while (sample < gHigh && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) - return 0; } if (timeout == 0) return 0; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample > gLow && (timeout--)) { + while (sample > gLow && (timeout--) ) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (++sample_cnt > EM4X50_SAMPLE_CNT_MAX) - return 0; } + if (timeout == 0) + return 0; + return (uint32_t)AT91C_BASE_TC1->TC_CV; } @@ -399,36 +395,7 @@ static void em4x50_reader_send_bit(int bit) { while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); } } -/* -static void em4x50_sim_send_bit(int bit) { - - // send single bit according to EM4x50 application note and datasheet - - // reset clock for the next bit - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - if (bit == 0) { - - // disable modulation (activates the field) for first half of bit period - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); - - // enable modulation for second half of bit period - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); - - } else { - - // enable modulation (drop the field) for first half of bit period - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); - - // disable modulation for second half of bit period - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC1->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD); - } -} -*/ static void em4x50_reader_send_byte(uint8_t byte) { // send byte (without parity) @@ -437,16 +404,7 @@ static void em4x50_reader_send_byte(uint8_t byte) { em4x50_reader_send_bit((byte >> (7-i)) & 1); } -/* -static void em4x50_sim_send_byte(uint8_t byte) { - // send byte (without parity) - - for (int i = 0; i < 8; i++) - em4x50_sim_send_bit((byte >> (7-i)) & 1); - -} -*/ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { // send byte followed by its (equal) parity bit @@ -461,22 +419,7 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { em4x50_reader_send_bit(parity); } -/* -static void em4x50_sim_send_byte_with_parity(uint8_t byte) { - // send byte followed by its (equal) parity bit - - int parity = 0, bit = 0; - - for (int i = 0; i < 8; i++) { - bit = (byte >> (7-i)) & 1; - em4x50_sim_send_bit(bit); - parity ^= bit; - } - - em4x50_sim_send_bit(parity); -} -*/ static void em4x50_reader_send_word(const uint8_t bytes[4]) { // send 32 bit word with parity bits according to EM4x50 datasheet @@ -490,108 +433,6 @@ static void em4x50_reader_send_word(const uint8_t bytes[4]) { // send final stop bit (always "0") em4x50_reader_send_bit(0); } -/* - -static void em4x50_sim_send_word(const uint8_t bytes[4]) { - - // send 32 bit word with parity bits according to EM4x50 datasheet - - for (int i = 0; i < 4; i++) - em4x50_sim_send_byte_with_parity(bytes[i]); - - // send column parities - em4x50_sim_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); - - // send final stop bit (always "0") - em4x50_sim_send_bit(0); -} - -static void em4x50_sim_send_ack(void) { - - // send "acknowledge" according to EM4x50 application note and datasheet - - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - -} - -static void em4x50_sim_send_nak(void) { - - // send "not" acknowledge" according to EM4x50 application note and datasheet - - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_THREE_HALF_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - -} - -static void em4x50_sim_handle_command(void) { - - em4x50_sim_send_ack(); - em4x50_sim_send_nak(); - Dbprintf(""); - -} -*/ -/* -static bool em4x50_sim_detect_rm(void) { - - if (get_next_bit() == EM4X50_BIT_0) - if (get_next_bit() == EM4X50_BIT_0) - return true; - - //int periods = 0; - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - //while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) - // adc_val[periods++] = AT91C_BASE_SSC->SSC_RHR; - - return false; -} -*/ -/* -static void em4x50_sim_send_listen_window(void) { - - // send single listen window according to EM4x50 application note and datasheet - - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - - HIGH(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); - - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); - - HIGH(GPIO_SSC_DOUT); - if (em4x50_sim_detect_rm()) - em4x50_sim_handle_command(); - - LOW(GPIO_SSC_DOUT); - wait_timer(0, T0 * EM4X50_T_TAG_FULL_PERIOD); - -} -*/ static bool find_single_listen_window(void) { @@ -829,7 +670,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { } } - + return 0; } @@ -1250,7 +1091,7 @@ void em4x50_wipe(em4x50_data_t *etd) { reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } -static bool em4x50_sim_send_bit2(uint8_t bit) { +static bool em4x50_sim_send_bit(uint8_t bit) { uint16_t check = 0; @@ -1294,18 +1135,18 @@ static bool em4x50_sim_send_bit2(uint8_t bit) { return true; } -static bool em4x50_sim_send_byte2(uint8_t byte) { +static bool em4x50_sim_send_byte(uint8_t byte) { // send byte for (int i = 0; i < 8; i++) - if (!em4x50_sim_send_bit2((byte >> (7 - i)) & 1)) + if (!em4x50_sim_send_bit((byte >> (7 - i)) & 1)) return false; return true; } -static bool em4x50_sim_send_byte_with_parity2(uint8_t byte) { +static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { uint8_t parity = 0x0; @@ -1313,22 +1154,22 @@ static bool em4x50_sim_send_byte_with_parity2(uint8_t byte) { for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - if (!em4x50_sim_send_byte2(byte)) + if (!em4x50_sim_send_byte(byte)) return false;; - if (!em4x50_sim_send_bit2(parity)) + if (!em4x50_sim_send_bit(parity)) return false; return true; } -bool em4x50_sim_send_word3(uint32_t word) { +bool em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) - if (!em4x50_sim_send_byte_with_parity2( (word >> ((3 - i) * 8)) & 0xFF)) + if (!em4x50_sim_send_byte_with_parity( (word >> ((3 - i) * 8)) & 0xFF)) return false; // column parity @@ -1338,17 +1179,17 @@ bool em4x50_sim_send_word3(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - if (!em4x50_sim_send_byte2(cparity)) + if (!em4x50_sim_send_byte(cparity)) return false; // stop bit - if (!em4x50_sim_send_bit2(0)) + if (!em4x50_sim_send_bit(0)) return false; return true; } -bool em4x50_sim_send_listen_window2(void) { +bool em4x50_sim_send_listen_window(void) { //int i = 0; uint16_t check = 0; @@ -1396,97 +1237,6 @@ bool em4x50_sim_send_listen_window2(void) { return true; } -/* -static void em4x50_sim_send_word3(uint8_t *word) { - - uint8_t rparity = 0x00, cparity = 0x00; - uint64_t word_with_parities = { 0x00 }; - - // bytes + row parities - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 8; j++) { - word_with_parities += (word[i] >> j) & 1; - word_with_parities <<= 1; - rparity ^= (word[i] >> j) & 1; - } - word_with_parities += rparity & 1; - word_with_parities <<= 1; - } - - // column parities - for (int i = 0; i < 8; i++) { - for (int j = 0; j < 4; j++) { - cparity ^= (word[j] >> i) & 1; - } - word_with_parities += cparity; - word_with_parities <<= 1; - cparity = 0; - } - - // stop bit - word_with_parities += 0; - - // send total word - for (int i = 0; i < EM4X50_TAG_WORD; i++) - em4x50_sim_send_bit2((word_with_parities >> (EM4X50_TAG_WORD-1 - i)) & 1); - -} -*/ - -/* -static void simlf(uint8_t *buf, int period) { - - int i = 0, count = 0; - int clock1 = 32, clock2 = 64; - uint16_t check = 0; - - for (;;) { - - // wait until SSC_CLK goes HIGH - // used as a simple detection of a reader field? - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return; - check = 0; - } - ++check; - } - - if (buf[i]) - OPEN_COIL(); - else - SHORT_COIL(); - - check = 0; - - //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS()) - return; - check = 0; - } - ++check; - } - - if (count == EM4X50_T_TAG_HALF_PERIOD) { - buf[i] ^= 1; - } else if (count == EM4X50_T_TAG_FULL_PERIOD) { - buf[i] ^= 1; - count = 0; - i++; - if (i == period) { - i = 0; - } - } - count++; - } -} -*/ - void em4x50_sim(em4x50_data_t *etd) { bool bsuccess = false; @@ -1516,7 +1266,6 @@ int em4x50_standalone_read(uint64_t *words) { memset(bits, 0, sizeof(bits)); while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { - words[now] = 0; for (int i = 0; i < EM4X50_TAG_WORD; i++) { From 7b62035bc40aa57753fbac10ea64ec146e1fa6d3 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:09:12 +0200 Subject: [PATCH 008/174] adopted log file name, renamed functions --- armsrc/Standalone/lf_tharexde.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 11e056c8b..5fb8bf49a 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -53,7 +53,7 @@ #define STATE_SIM 0 #define STATE_READ 1 #define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml" -#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log" +#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect" #define EM4X50_TAG_WORD 45 bool input_exists; @@ -232,10 +232,10 @@ void RunMod(void) { state_change = false; } - em4x50_sim_send_listen_window2(); + em4x50_sim_send_listen_window(); for (int i = 0; i < now; i++) { - em4x50_sim_send_listen_window2(); - em4x50_sim_send_word3(words[i]); + em4x50_sim_send_listen_window(); + em4x50_sim_send_word(words[i]); } } else if (state == STATE_READ) { From eaefd78c647766dd0889e2834a02a7b975128318 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:16:39 +0200 Subject: [PATCH 009/174] corrected stupid error (&->&&) --- armsrc/em4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 869f99394..91294479e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -362,7 +362,7 @@ static uint32_t get_pulse_length(void) { static bool check_pulse_length(uint32_t pl, int length) { // check if pulse length corresponds to given 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))); } static void em4x50_reader_send_bit(int bit) { From a27b3af4cbcc634d49b396a23f8f08688a9a49f0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:44:01 +0200 Subject: [PATCH 010/174] make style --- client/src/cmdlfem4x50.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 9103725dc..ecd4f9334 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -629,7 +629,7 @@ int CmdEM4x50Read(const char *Cmd) { //if (errors || strlen(Cmd) == 0 || etd.addr_given == false) if (errors) - return usage_lf_em4x50_read(); + return usage_lf_em4x50_read(); return em4x50_read(&etd, NULL, true); } @@ -788,8 +788,8 @@ int CmdEM4x50Sim(const char *Cmd) { case 'w': { if (param_gethex(Cmd, cmdp + 1, etd.word, 8)) { - PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); - return PM3_EINVARG; + PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); + return PM3_EINVARG; } bword = true; cmdp += 2; @@ -798,8 +798,8 @@ int CmdEM4x50Sim(const char *Cmd) { case 'f': { if (param_gethex(Cmd, cmdp + 1, etd.word, 8)) { - PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); - return PM3_EINVARG; + PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); + return PM3_EINVARG; } bword = true; cmdp += 2; @@ -814,7 +814,7 @@ int CmdEM4x50Sim(const char *Cmd) { } if (errors || !bword) - return usage_lf_em4x50_sim(); + return usage_lf_em4x50_sim(); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&etd, sizeof(etd)); @@ -827,9 +827,9 @@ int CmdEM4x50Sim(const char *Cmd) { // print response bool isOK = resp.status; if (isOK) { - PrintAndLogEx(SUCCESS,"\nsimulation data " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "\nsimulation data " _GREEN_("ok") "\n"); } else { - PrintAndLogEx(FAILED,"\nsimulating data " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "\nsimulating data " _RED_("failed") "\n"); return PM3_ESOFT; } @@ -844,7 +844,7 @@ int CmdEM4x50Test(const char *Cmd) { uint8_t cmdp = 0; em4x50_data_t etd; PacketResponseNG resp; - + etd.carrier = 2; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -878,7 +878,7 @@ int CmdEM4x50Test(const char *Cmd) { } if (errors) - return usage_lf_em4x50_test(); + return usage_lf_em4x50_test(); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_TEST, (uint8_t *)&etd, sizeof(etd)); @@ -891,9 +891,9 @@ int CmdEM4x50Test(const char *Cmd) { // print response bool isOK = resp.status; if (isOK) { - PrintAndLogEx(SUCCESS,"\ntest " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "\ntest " _GREEN_("ok") "\n"); } else { - PrintAndLogEx(FAILED,"\ntest " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "\ntest " _RED_("failed") "\n"); return PM3_ESOFT; } From 45a1a8375242bd7992357f192ed4b478c78f16f0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:44:42 +0200 Subject: [PATCH 011/174] make style --- armsrc/Standalone/lf_tharexde.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 5fb8bf49a..8cad3e736 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -80,7 +80,7 @@ static bool strip_check_parities(uint64_t data, uint32_t *word) { uint8_t rparity = 0, cparity = 0; uint8_t rparity_m = 0, cparity_m = 0, stop_bit_m = 0; - + // strip parities for (int i = 0; i < 4; i++) { for (int j = 0; j < 8; j++) { @@ -96,7 +96,7 @@ static bool strip_check_parities(uint64_t data, uint32_t *word) { rparity ^= (*word >> (31 - 8 * i - j)) & 1; } } - + // calculate column parities for (int i = 0; i < 8; i++) { cparity <<= 1; @@ -104,7 +104,7 @@ static bool strip_check_parities(uint64_t data, uint32_t *word) { cparity ^= (*word >> (31 - 8 * j - i)) & 1; } } - + // measured row parities for (int i = 0; i < 4; i++) { rparity_m <<= 1; @@ -113,10 +113,10 @@ static bool strip_check_parities(uint64_t data, uint32_t *word) { // measured column parities cparity_m = (data >> 1) & 0xFF; - + // measured stop bit stop_bit_m = data & 1; - + if ((cparity_m == cparity) && (rparity_m == rparity) && (stop_bit_m == 0)) return true; @@ -128,24 +128,24 @@ static int get_input_data_from_file(uint32_t *words) { size_t now = 0; if (exists_in_spiffs(LF_EM4X50SIMULATE_INPUTFILE)) { - + uint32_t size = size_in_spiffs((char *)LF_EM4X50SIMULATE_INPUTFILE); uint8_t *mem = BigBuf_malloc(size); - + Dbprintf(_YELLOW_("[=] found input file %s"), LF_EM4X50SIMULATE_INPUTFILE); rdv40_spiffs_read_as_filetype((char *)LF_EM4X50SIMULATE_INPUTFILE, mem, size, RDV40_SPIFFS_SAFETY_SAFE); - + now = size / 9; for (int i = 0; i < now; i++) for (int j = 0; j < 4; j++) words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); - + Dbprintf(_YELLOW_("[=] read data from input file")); } - + BigBuf_free(); - + return (now > 0) ? now : 0; } @@ -160,7 +160,7 @@ static void append(uint8_t *entry, size_t entry_len) { } LED_C_OFF(); } - + void ModInfo(void) { DbpString(_YELLOW_(" LF EM4x50 collector mode") " - a.k.a tharexde"); } @@ -202,11 +202,11 @@ void RunMod(void) { SpinDown(100); break; } - + if (state == STATE_SIM) { if (state_change) { - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); @@ -214,7 +214,7 @@ void RunMod(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; - + LED_A_ON(); LED_B_OFF(); Dbprintf(_YELLOW_("[=] switched to EM4x50 simulating mode")); @@ -224,7 +224,7 @@ void RunMod(void) { Dbprintf(_YELLOW_("[=] simulating %i blocks"), now); for (int i = 0; i < now; i++) Dbprintf(_YELLOW_("[=] %2i -> %lx"), i + 1, words[i]); - + } else { Dbprintf(_RED_("[!] error in input data")); } @@ -237,7 +237,7 @@ void RunMod(void) { em4x50_sim_send_listen_window(); em4x50_sim_send_word(words[i]); } - + } else if (state == STATE_READ) { if (state_change) { @@ -255,7 +255,7 @@ void RunMod(void) { } no_words = em4x50_standalone_read(data); - + if (no_words > 0) { memset(entry, 0, sizeof(entry)); @@ -266,12 +266,12 @@ void RunMod(void) { append(entry, strlen((char *)entry)); for (int i = 0; i < no_words; i++) { - + if (strip_check_parities(data[i], &word)) sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check ok)", i + 1, word); else sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check failed)", i + 1, word); - + Dbprintf("%s", entry); strcat((char *)entry, "\n"); append(entry, strlen((char *)entry)); @@ -280,7 +280,7 @@ void RunMod(void) { } } - + if (state == STATE_READ) DownloadLogInstructions(); else From 5665de56e99bdc45466b70452d0cccb6c42412a4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 23 Sep 2020 23:45:43 +0200 Subject: [PATCH 012/174] styling --- armsrc/em4x50.c | 98 ++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 91294479e..267a28310 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -8,12 +8,10 @@ // Low frequency EM4x50 commands //----------------------------------------------------------------------------- -#include "BigBuf.h" #include "fpgaloader.h" #include "ticks.h" #include "dbprint.h" #include "lfadc.h" -#include "lfsampling.h" #include "commonutil.h" #include "em4x50.h" @@ -74,7 +72,6 @@ static em4x50_tag_t tag = { #define EM4X50_T_TAG_HALF_PERIOD 32 #define EM4X50_T_TAG_THREE_QUARTER_PERIOD 48 #define EM4X50_T_TAG_FULL_PERIOD 64 -#define EM4X50_T_TAG_THREE_HALF_PERIOD 96 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 #define EM4X50_T_WAITING_FOR_SNGLLIW 100 @@ -82,13 +79,11 @@ static em4x50_tag_t tag = { #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 -#define EM4X50_SAMPLE_CNT_MAX 3000 #define EM4X50_BIT_0 0 #define EM4X50_BIT_1 1 #define EM4X50_BIT_OTHER 2 -#define EM4X50_COMMAND_REQUEST 2 #define EM4X50_COMMAND_LOGIN 0x01 #define EM4X50_COMMAND_RESET 0x80 #define EM4X50_COMMAND_WRITE 0x12 @@ -177,7 +172,7 @@ static void wait_timer(int timer, uint32_t period) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < period); - + } else { AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; @@ -246,7 +241,6 @@ static bool get_signalproperties(void) { bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; - uint8_t sample = 0; uint8_t sample_ref = 127; uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; @@ -257,7 +251,7 @@ static bool get_signalproperties(void) { for (int i = 0; i < T0 * no_periods; i++) { if (BUTTON_PRESS()) return false; - + // about 2 samples per bit period wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); @@ -279,7 +273,7 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; if (sample > sample_max[i]) sample_max[i] = sample; @@ -324,23 +318,22 @@ static uint32_t get_pulse_length(void) { // Dbprintf( _CYAN_("4x50 get_pulse_length A") ); - int timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); // iterates pulse length (low -> high -> low) - // to avoid endless loops - quit if timeout = 0 - + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; while (sample > gLow && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } - + if (timeout == 0) return 0; AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + while (sample < gHigh && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } @@ -349,7 +342,7 @@ static uint32_t get_pulse_length(void) { return 0; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample > gLow && (timeout--) ) { + while (sample > gLow && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } @@ -366,7 +359,7 @@ static bool check_pulse_length(uint32_t pl, int length) { } static void em4x50_reader_send_bit(int bit) { - + // send single bit according to EM4x50 application note and datasheet // reset clock for the next bit @@ -399,20 +392,20 @@ static void em4x50_reader_send_bit(int bit) { static void em4x50_reader_send_byte(uint8_t byte) { // send byte (without parity) - + for (int i = 0; i < 8; i++) - em4x50_reader_send_bit((byte >> (7-i)) & 1); + em4x50_reader_send_bit((byte >> (7 - i)) & 1); } static void em4x50_reader_send_byte_with_parity(uint8_t byte) { // send byte followed by its (equal) parity bit - + int parity = 0, bit = 0; - + for (int i = 0; i < 8; i++) { - bit = (byte >> (7-i)) & 1; + bit = (byte >> (7 - i)) & 1; em4x50_reader_send_bit(bit); parity ^= bit; } @@ -421,12 +414,12 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { } static void em4x50_reader_send_word(const uint8_t bytes[4]) { - + // send 32 bit word with parity bits according to EM4x50 datasheet - + for (int i = 0; i < 4; i++) em4x50_reader_send_byte_with_parity(bytes[i]); - + // send column parities em4x50_reader_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); @@ -622,7 +615,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { // identify remaining bits based on pulse lengths // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible while (BUTTON_PRESS() == false) { - + i++; pl = get_pulse_length(); @@ -708,14 +701,14 @@ static bool login(uint8_t password[4]) { //============================================================================== static bool reset(void) { - + // resets EM4x50 tag (used by write function) if (request_receive_mode()) { // send login command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); - + if (check_ack(false)) return true; @@ -777,9 +770,10 @@ static bool selective_read(uint8_t addresses[4]) { // send address data em4x50_reader_send_word(addresses); - // look for ACK sequence -> save and verify via standard read mode - // (compare number of words) + // look for ACK sequence if (check_ack(false)) + + // save and verify via standard read mode (compare number of words) if (standard_read(&now)) if (now == (lwr - fwr + 1)) return true; @@ -808,7 +802,7 @@ void em4x50_info(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - + if (etd->pwd_given) { // try to login with given password @@ -846,7 +840,8 @@ void em4x50_read(em4x50_data_t *etd) { em4x50_setup_read(); // set gHigh and gLow - if (get_signalproperties()) {//} && find_em4x50_tag()) { + if (get_signalproperties() && find_em4x50_tag()) { + if (etd->addr_given) { // selective read mode @@ -863,6 +858,7 @@ void em4x50_read(em4x50_data_t *etd) { // standard read mode bsuccess = standard_read(&now); + } } @@ -1092,7 +1088,7 @@ void em4x50_wipe(em4x50_data_t *etd) { } static bool em4x50_sim_send_bit(uint8_t bit) { - + uint16_t check = 0; for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { @@ -1115,7 +1111,7 @@ static bool em4x50_sim_send_bit(uint8_t bit) { SHORT_COIL(); check = 0; - + //wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); @@ -1131,7 +1127,7 @@ static bool em4x50_sim_send_bit(uint8_t bit) { bit ^= 1; } - + return true; } @@ -1141,7 +1137,7 @@ static bool em4x50_sim_send_byte(uint8_t byte) { for (int i = 0; i < 8; i++) if (!em4x50_sim_send_bit((byte >> (7 - i)) & 1)) return false; - + return true; } @@ -1149,27 +1145,27 @@ static bool em4x50_sim_send_byte(uint8_t byte) { static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { uint8_t parity = 0x0; - + // send byte with parity (even) for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - + if (!em4x50_sim_send_byte(byte)) return false;; - + if (!em4x50_sim_send_bit(parity)) return false; - + return true; } bool em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; - + // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) - if (!em4x50_sim_send_byte_with_parity( (word >> ((3 - i) * 8)) & 0xFF)) + if (!em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF)) return false; // column parity @@ -1181,7 +1177,7 @@ bool em4x50_sim_send_word(uint32_t word) { } if (!em4x50_sim_send_byte(cparity)) return false; - + // stop bit if (!em4x50_sim_send_bit(0)) return false; @@ -1194,7 +1190,7 @@ bool em4x50_sim_send_listen_window(void) { //int i = 0; uint16_t check = 0; //uint8_t test[100] = {0}; - + for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { // wait until SSC_CLK goes HIGH @@ -1207,7 +1203,7 @@ bool em4x50_sim_send_listen_window(void) { } ++check; } - + if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { SHORT_COIL(); } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { @@ -1221,7 +1217,7 @@ bool em4x50_sim_send_listen_window(void) { } check = 0; - + //wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); @@ -1238,25 +1234,25 @@ bool em4x50_sim_send_listen_window(void) { } void em4x50_sim(em4x50_data_t *etd) { - + bool bsuccess = false; - + lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } void em4x50_test(em4x50_data_t *etd) { - + bool bsuccess = true; reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } int em4x50_standalone_read(uint64_t *words) { - + int now = 0; uint8_t bits[EM4X50_TAG_WORD]; - + em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) { @@ -1267,7 +1263,7 @@ int em4x50_standalone_read(uint64_t *words) { while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { words[now] = 0; - + for (int i = 0; i < EM4X50_TAG_WORD; i++) { words[now] <<= 1; words[now] += bits[i] & 1; From 9df747c3e186944cc8d11c19aaead7ff606c8615 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 24 Sep 2020 23:05:11 +0200 Subject: [PATCH 013/174] new files --- client/src/cmdhfst.c | 172 ++++++++++++++++++------------------ client/src/cmdhfwaveshare.c | 122 ++++++++++++------------- 2 files changed, 147 insertions(+), 147 deletions(-) diff --git a/client/src/cmdhfst.c b/client/src/cmdhfst.c index acb6ee361..8308df9b1 100644 --- a/client/src/cmdhfst.c +++ b/client/src/cmdhfst.c @@ -17,7 +17,7 @@ #include "crc16.h" #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "emv/apduinfo.h" // GetAPDUCodeDescription #include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint #define TIMEOUT 2000 @@ -116,7 +116,7 @@ static char *get_st_chip_model(uint8_t pc) { case 0xE3: sprintf(s, "ST25TA02KB"); break; - case 0xE4: + case 0xE4: sprintf(s, "ST25TA512B"); break; case 0xA3: @@ -150,19 +150,19 @@ static void print_st_cc_info(uint8_t *d, uint8_t n) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------"); - PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1],d[1]); + PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1], d[1]); PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]); - uint16_t maxr = (d[3] << 8 | d[4]); + uint16_t maxr = (d[3] << 8 | d[4]); PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr); - uint16_t maxw = (d[5] << 8 | d[6]); + uint16_t maxw = (d[5] << 8 | d[6]); PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " NDEF file control TLV {"); PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]); PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]); PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]); - + uint16_t maxndef = (d[11] << 8 | d[12]); PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef); PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------"); @@ -178,11 +178,11 @@ static void print_st_system_info(uint8_t *d, uint8_t n) { PrintAndLogEx(WARNING, "Not enought bytes read from system file"); return; } - + PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------"); - - uint16_t len = (d[0] << 8 | d[1]); + PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------"); + + uint16_t len = (d[0] << 8 | d[1]); PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len); if (d[2] == 0x80) { @@ -191,29 +191,29 @@ static void print_st_system_info(uint8_t *d, uint8_t n) { PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]); PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked")); uint8_t conf = (d[2] & 0x70) >> 4; - switch(conf) { - case 0: + switch (conf) { + case 0: PrintAndLogEx(SUCCESS, ""); break; - case 1: + case 1: PrintAndLogEx(SUCCESS, "Session opened"); - break; - case 2: + break; + case 2: PrintAndLogEx(SUCCESS, "WIP"); break; - case 3: + case 3: PrintAndLogEx(SUCCESS, "MIP"); break; - case 4: + case 4: PrintAndLogEx(SUCCESS, "Interrupt"); break; - case 5: + case 5: PrintAndLogEx(SUCCESS, "State Control"); break; - case 6: + case 6: PrintAndLogEx(SUCCESS, "RF Busy"); break; - case 7: + case 7: PrintAndLogEx(SUCCESS, "Field Detect"); break; } @@ -224,25 +224,25 @@ static void print_st_system_info(uint8_t *d, uint8_t n) { PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable")); PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read")); - uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]); + uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]); PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF); - + PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]); - + PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7)); PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8])); PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9])); - PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5)); + PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5)); - uint16_t mem = (d[0xF] << 8 | d[0x10]); + uint16_t mem = (d[0xF] << 8 | d[0x10]); PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem); - + PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]); PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); - PrintAndLogEx(NORMAL, ""); - + PrintAndLogEx(NORMAL, ""); + /* 0012 80000000001302E2007D0E8DCC @@ -252,7 +252,7 @@ static void print_st_system_info(uint8_t *d, uint8_t n) { static uint16_t get_sw(uint8_t *d, uint8_t n) { if (n < 2) return 0; - + n -= 2; return d[n] * 0x0100 + d[n + 1]; } @@ -265,10 +265,10 @@ int infoHF_ST(void) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - // --------------- Select NDEF Tag application ---------------- + // --------------- Select NDEF Tag application ---------------- uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -285,10 +285,10 @@ int infoHF_ST(void) { activate_field = false; keep_field_on = true; // --------------- CC file reading ---------------- - + uint8_t aSELECT_FILE_CC[30]; int aSELECT_FILE_CC_n = 0; - param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n); + param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n); res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -298,10 +298,10 @@ int infoHF_ST(void) { PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return PM3_ESOFT; } - + uint8_t aREAD_CC[30]; int aREAD_CC_n = 0; - param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n); + param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n); res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -315,10 +315,10 @@ int infoHF_ST(void) { print_st_cc_info(response, resplen - 2); - // --------------- System file reading ---------------- + // --------------- System file reading ---------------- uint8_t aSELECT_FILE_SYS[30]; int aSELECT_FILE_SYS_n = 0; - param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n); + param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n); res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -330,10 +330,10 @@ int infoHF_ST(void) { } keep_field_on = false; - + uint8_t aREAD_SYS[30]; int aREAD_SYS_n = 0; - param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n); + param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n); res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -359,17 +359,17 @@ static int cmd_hf_st_sim(const char *Cmd) { char c = tolower(param_getchar(Cmd, 0)); if (c == 'h' || c == 0x00) return usage_hf_st_sim(); - int uidlen = 0; + int uidlen = 0; uint8_t cmdp = 0; uint8_t uid[7] = {0}; if (c == 'u') { param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); uidlen >>= 1; if (uidlen != 7) { - return usage_hf_st_sim(); + return usage_hf_st_sim(); } } - + char param[40]; snprintf(param, sizeof(param), "t 10 u %s", sprint_hex_inrow(uid, uidlen)); return CmdHF14ASim(param); @@ -379,14 +379,14 @@ static int cmd_hf_st_ndef(const char *Cmd) { char c = tolower(param_getchar(Cmd, 0)); if (c == 'h' || c == 0x00) return usage_hf_st_ndef(); - int pwdlen = 0; + int pwdlen = 0; uint8_t cmdp = 0; uint8_t pwd[16] = {0}; if (c == 'p') { param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen); pwdlen >>= 1; if (pwdlen != 16) { - return usage_hf_st_ndef(); + return usage_hf_st_ndef(); } } @@ -395,10 +395,10 @@ static int cmd_hf_st_ndef(const char *Cmd) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - // --------------- Select NDEF Tag application ---------------- + // --------------- Select NDEF Tag application ---------------- uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -418,7 +418,7 @@ static int cmd_hf_st_ndef(const char *Cmd) { // --------------- NDEF file reading ---------------- uint8_t aSELECT_FILE_NDEF[30]; int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -429,7 +429,7 @@ static int cmd_hf_st_ndef(const char *Cmd) { return PM3_ESOFT; } - // --------------- VERIFY ---------------- + // --------------- VERIFY ---------------- uint8_t aVERIFY[30]; int aVERIFY_n = 0; param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); @@ -446,17 +446,17 @@ static int cmd_hf_st_ndef(const char *Cmd) { if (res) return res; - sw = get_sw(response, resplen); + sw = get_sw(response, resplen); if (sw != 0x9000) { PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return PM3_ESOFT; } } - + keep_field_on = false; uint8_t aREAD_NDEF[30]; int aREAD_NDEF_n = 0; - param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); + param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -472,23 +472,23 @@ static int cmd_hf_st_ndef(const char *Cmd) { } static int cmd_hf_st_protect(const char *Cmd) { - + uint8_t cmdp = 0; bool errors = false; int pwdlen = 0; uint8_t pwd[16] = {0}; int statelen = 3; uint8_t state[3] = {0x26, 0, 0}; - + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_hf_st_protect(); - case '0': + case '0': state[0] = 0x26; //Disable protection cmdp++; break; - case '1': + case '1': state[0] = 0x28; //Enable protection cmdp++; break; @@ -515,14 +515,14 @@ static int cmd_hf_st_protect(const char *Cmd) { //Validations if (state[2] == 0x00) { - PrintAndLogEx(WARNING, "Missing action (r)ead or (w)rite"); - errors = true; + PrintAndLogEx(WARNING, "Missing action (r)ead or (w)rite"); + errors = true; } if (pwdlen != 16) { - PrintAndLogEx(WARNING, "Missing 16 byte password"); - errors = true; - } - + PrintAndLogEx(WARNING, "Missing 16 byte password"); + errors = true; + } + if (errors || cmdp == 0) return usage_hf_st_protect(); bool activate_field = true; @@ -530,10 +530,10 @@ static int cmd_hf_st_protect(const char *Cmd) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - // --------------- Select NDEF Tag application ---------------- + // --------------- Select NDEF Tag application ---------------- uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -553,7 +553,7 @@ static int cmd_hf_st_protect(const char *Cmd) { // --------------- Select NDEF file ---------------- uint8_t aSELECT_FILE_NDEF[30]; int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -564,7 +564,7 @@ static int cmd_hf_st_protect(const char *Cmd) { return PM3_ESOFT; } - // --------------- VERIFY ---------------- + // --------------- VERIFY ---------------- uint8_t aVERIFY[30]; int aVERIFY_n = 0; // need to provide 16byte password @@ -574,12 +574,12 @@ static int cmd_hf_st_protect(const char *Cmd) { if (res) return res; - sw = get_sw(response, resplen); + sw = get_sw(response, resplen); if (sw != 0x9000) { PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return PM3_ESOFT; } - + // --------------- Change protection ---------------- keep_field_on = false; uint8_t aPROTECT[30]; @@ -595,9 +595,9 @@ static int cmd_hf_st_protect(const char *Cmd) { PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return PM3_ESOFT; } - - PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"), - ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled")); + + PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"), + ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled")); return PM3_SUCCESS; } @@ -608,9 +608,9 @@ static int cmd_hf_st_pwd(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; - int pwdlen = 0; + int pwdlen = 0; uint8_t pwd[16] = {0}; - int newpwdlen = 0; + int newpwdlen = 0; uint8_t newpwd[16] = {0}; int changePwdlen = 4; uint8_t changePwd[4] = {0x24, 0x00, 0x00, 0x10}; @@ -647,17 +647,17 @@ static int cmd_hf_st_pwd(const char *Cmd) { //Validations if (changePwd[2] == 0x00) { - PrintAndLogEx(WARNING, "Missing password specification: (r)ead or (w)rite"); - errors = true; + PrintAndLogEx(WARNING, "Missing password specification: (r)ead or (w)rite"); + errors = true; } if (pwdlen != 16) { - PrintAndLogEx(WARNING, "Missing original 16 byte password"); - errors = true; - } + PrintAndLogEx(WARNING, "Missing original 16 byte password"); + errors = true; + } if (newpwdlen != 16) { - PrintAndLogEx(WARNING, "Missing new 16 byte password"); - errors = true; - } + PrintAndLogEx(WARNING, "Missing new 16 byte password"); + errors = true; + } if (errors || cmdp == 0) return usage_hf_st_pwd(); bool activate_field = true; @@ -665,10 +665,10 @@ static int cmd_hf_st_pwd(const char *Cmd) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - // --------------- Select NDEF Tag application ---------------- + // --------------- Select NDEF Tag application ---------------- uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -688,7 +688,7 @@ static int cmd_hf_st_pwd(const char *Cmd) { // --------------- Select NDEF file ---------------- uint8_t aSELECT_FILE_NDEF[30]; int aSELECT_FILE_NDEF_n = 0; - param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); + param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) return res; @@ -699,7 +699,7 @@ static int cmd_hf_st_pwd(const char *Cmd) { return PM3_ESOFT; } - // --------------- VERIFY ---------------- + // --------------- VERIFY ---------------- uint8_t aVERIFY[30]; int aVERIFY_n = 0; // need to provide 16byte password @@ -709,7 +709,7 @@ static int cmd_hf_st_pwd(const char *Cmd) { if (res) return res; - sw = get_sw(response, resplen); + sw = get_sw(response, resplen); if (sw != 0x9000) { PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return PM3_ESOFT; @@ -720,7 +720,7 @@ static int cmd_hf_st_pwd(const char *Cmd) { keep_field_on = false; uint8_t aCHG_PWD[30]; int aCHG_PWD_n = 0; - param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n); + param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n); memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen); memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen); res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c index b41ecefea..dd34c046b 100644 --- a/client/src/cmdhfwaveshare.c +++ b/client/src/cmdhfwaveshare.c @@ -97,7 +97,7 @@ static int usage_hf_waveshare_loadbmp(void) { PrintAndLogEx(NORMAL, " f : " _YELLOW_("filename[.bmp]") " to upload to tag"); PrintAndLogEx(NORMAL, " m : " _YELLOW_("model number") " of your tag"); PrintAndLogEx(NORMAL, " s : save dithered version in filename-[n].bmp, only for RGB BMP"); - for (uint8_t i=0; i< MEND; i++) { + for (uint8_t i = 0; i < MEND; i++) { PrintAndLogEx(NORMAL, " m %2i : %s", i, models[i].desc); } PrintAndLogEx(NORMAL, ""); @@ -168,8 +168,8 @@ static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t mod } static void rgb_to_gray(int16_t *chanR, int16_t *chanG, int16_t *chanB, uint16_t width, uint16_t height, int16_t *chanGrey) { - for (uint16_t Y=0; Y 127 ? 255 : 0; chan[X + Y * width] = newp; int16_t err = oldp - newp; - float m[] = {7,3,5,1}; - if (X < width - 1){ - chan[X + 1 + Y * width] = chan[X + 1 + Y * width] + m[0]/16 * err; + float m[] = {7, 3, 5, 1}; + if (X < width - 1) { + chan[X + 1 + Y * width] = chan[X + 1 + Y * width] + m[0] / 16 * err; } if (Y < height - 1) { - chan[X - 1 + (Y + 1) * width] = chan[X - 1 + (Y + 1) * width] + m[1]/16 * err; + chan[X - 1 + (Y + 1) * width] = chan[X - 1 + (Y + 1) * width] + m[1] / 16 * err; } - if (Y < height - 1){ - chan[X + (Y + 1) * width] = chan[X + (Y + 1) * width] + m[2]/16 * err; + if (Y < height - 1) { + chan[X + (Y + 1) * width] = chan[X + (Y + 1) * width] + m[2] / 16 * err; } - if ((X < width - 1) && (Y < height - 1)){ - chan[X + 1 + (Y + 1) * width] = chan[X + 1 + (Y + 1) * width] + m[3]/16 * err; + if ((X < width - 1) && (Y < height - 1)) { + chan[X + 1 + (Y + 1) * width] = chan[X + 1 + (Y + 1) * width] + m[3] / 16 * err; } } } @@ -210,16 +210,16 @@ static uint32_t color_compare(int16_t r1, int16_t g1, int16_t b1, int16_t r2, in int16_t inG = g1 - g2; int16_t inB = b1 - b2; // use RGB-to-grey weighting - float dist = 0.2126 *inR*inR + 0.7152 *inG*inG + 0.0722 *inB*inB; + float dist = 0.2126 * inR * inR + 0.7152 * inG * inG + 0.0722 * inB * inB; return dist; } static void nearest_color(int16_t oldR, int16_t oldG, int16_t oldB, uint8_t *palette, uint16_t palettelen, uint8_t *newR, uint8_t *newG, uint8_t *newB) { - uint32_t bestdist=0x7FFFFFFF; - for (uint16_t i=0; i < palettelen; i++) { - uint8_t R = palette[i*3+0]; - uint8_t G = palette[i*3+1]; - uint8_t B = palette[i*3+2]; + uint32_t bestdist = 0x7FFFFFFF; + for (uint16_t i = 0; i < palettelen; i++) { + uint8_t R = palette[i * 3 + 0]; + uint8_t G = palette[i * 3 + 1]; + uint8_t B = palette[i * 3 + 2]; uint32_t dist = color_compare(oldR, oldG, oldB, R, G, B); if (dist < bestdist) { bestdist = dist; @@ -231,8 +231,8 @@ static void nearest_color(int16_t oldR, int16_t oldG, int16_t oldB, uint8_t *pal } static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, uint16_t width, uint16_t height, uint8_t *palette, uint16_t palettelen) { - for (uint16_t Y=0; Y 0) { - chanR[XX - 1 + Y * width] = (chanR[XX - 1 + Y * width] + m[0]/16 * errR); - chanG[XX - 1 + Y * width] = (chanG[XX - 1 + Y * width] + m[0]/16 * errG); - chanB[XX - 1 + Y * width] = (chanB[XX - 1 + Y * width] + m[0]/16 * errB); + chanR[XX - 1 + Y * width] = (chanR[XX - 1 + Y * width] + m[0] / 16 * errR); + chanG[XX - 1 + Y * width] = (chanG[XX - 1 + Y * width] + m[0] / 16 * errG); + chanB[XX - 1 + Y * width] = (chanB[XX - 1 + Y * width] + m[0] / 16 * errB); } if (Y < height - 1) { - chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[3]/16 * errR); - chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[3]/16 * errG); - chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[3]/16 * errB); + chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[3] / 16 * errR); + chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[3] / 16 * errG); + chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[3] / 16 * errB); } if (Y < height - 1) { - chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2]/16 * errR); - chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2]/16 * errG); - chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2]/16 * errB); + chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2] / 16 * errR); + chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2] / 16 * errG); + chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2] / 16 * errB); } if ((XX < width - 1) && (Y < height - 1)) { - chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[1]/16 * errR); - chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[1]/16 * errG); - chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[1]/16 * errB); + chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[1] / 16 * errR); + chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[1] / 16 * errG); + chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[1] / 16 * errB); } } else { if (XX < width - 1) { - chanR[XX + 1 + Y * width] = (chanR[XX + 1 + Y * width] + m[0]/16 * errR); - chanG[XX + 1 + Y * width] = (chanG[XX + 1 + Y * width] + m[0]/16 * errG); - chanB[XX + 1 + Y * width] = (chanB[XX + 1 + Y * width] + m[0]/16 * errB); + chanR[XX + 1 + Y * width] = (chanR[XX + 1 + Y * width] + m[0] / 16 * errR); + chanG[XX + 1 + Y * width] = (chanG[XX + 1 + Y * width] + m[0] / 16 * errG); + chanB[XX + 1 + Y * width] = (chanB[XX + 1 + Y * width] + m[0] / 16 * errB); } if (Y < height - 1) { - chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[1]/16 * errR); - chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[1]/16 * errG); - chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[1]/16 * errB); + chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[1] / 16 * errR); + chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[1] / 16 * errG); + chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[1] / 16 * errB); } if (Y < height - 1) { - chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2]/16 * errR); - chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2]/16 * errG); - chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2]/16 * errB); + chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2] / 16 * errR); + chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2] / 16 * errG); + chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2] / 16 * errB); } if ((XX < width - 1) && (Y < height - 1)) { - chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[3]/16 * errR); - chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[3]/16 * errG); - chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[3]/16 * errB); + chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[3] / 16 * errR); + chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[3] / 16 * errG); + chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[3] / 16 * errB); } } } @@ -298,8 +298,8 @@ static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, u } static void rgb_to_gray_red_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, uint16_t width, uint16_t height) { - for (uint16_t Y=0; Y= 8) || (X == width - 1)) { - colormap8[X / 8 + Y * width8] = (~data)&0xFF; + colormap8[X / 8 + Y * width8] = (~data) & 0xFF; count = 0; data = 0; } - data = (data << 1)&0xFF; + data = (data << 1) & 0xFF; } } } @@ -430,8 +430,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui } rgb_to_gray_red_inplace(chanR, chanG, chanB, width, height); - uint8_t palette[] ={0x00,0x00,0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; // black, white, red - dither_rgb_inplace(chanR, chanG, chanB, width, height, palette, sizeof(palette)/3); + uint8_t palette[] = {0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; // black, white, red + dither_rgb_inplace(chanR, chanG, chanB, width, height, palette, sizeof(palette) / 3); threshold_rgb_black_red(chanR, chanG, chanB, width, height, 128, 128, mapBlack, mapRed); if (save_conversions) { @@ -552,7 +552,7 @@ static void read_red(uint32_t i, uint8_t *l, uint8_t model_nr, uint8_t *red) { } } -static int transceive_blocking( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBuf, uint16_t rxBufLen, uint16_t* actLen, bool retransmit ){ +static int transceive_blocking(uint8_t *txBuf, uint16_t txBufLen, uint8_t *rxBuf, uint16_t rxBufLen, uint16_t *actLen, bool retransmit) { uint8_t fail_num = 0; if (rxBufLen < 2) { return PM3_EINVARG; @@ -863,7 +863,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) { } else if (model_nr == M2in7) { //2.7inch for (i = 0; i < 48; i++) { //read_black(i,step8, model_nr, black); - memset(&step8[3], 0xFF, sizeof(step8)-3); + memset(&step8[3], 0xFF, sizeof(step8) - 3); ret = transceive_blocking(step8, 124, rx, 20, actrxlen, true); // cd 08 if (ret != PM3_SUCCESS) { return ret; From 52cb9007947121d26cb1887d65f85e3bbbcb909e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:52:10 +0200 Subject: [PATCH 014/174] added new function 4x50_bruteforce --- include/pm3_cmd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 6cacc5ef1..f97be2a06 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -493,6 +493,7 @@ typedef struct { #define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 +#define CMD_LF_EM4X50_BRUTEFORCE 0x0245 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From e8abcb9b2313a23c9a7ddb751d5efa41f07eed25 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:53:09 +0200 Subject: [PATCH 015/174] two more entries for new function 4x50_bruteforce --- include/em4x50.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/em4x50.h b/include/em4x50.h index b70072c32..240a4c41c 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -49,6 +49,8 @@ typedef struct { uint8_t addresses[4]; uint8_t address; uint8_t word[4]; + uint32_t start_password; + uint32_t stop_password; } em4x50_data_t; typedef struct { From d0d6317c33d95a22b6c28a815816184920a60b6f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:53:52 +0200 Subject: [PATCH 016/174] added new function reflect32 --- common/commonutil.c | 18 +++++++++++++++++- common/commonutil.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/common/commonutil.c b/common/commonutil.c index 9be805f31..7da41e807 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -97,6 +97,22 @@ uint16_t reflect16(uint16_t b) { return v; } +uint32_t reflect32(uint32_t b) { + // https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable + uint32_t v = b; // 32-bit word to reverse bit order + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = ( v >> 16 ) | ( v << 16); + return v; +} + void num_to_bytes(uint64_t n, size_t len, uint8_t *dest) { while (len--) { dest[len] = (uint8_t) n; @@ -153,4 +169,4 @@ uint32_t rotl(uint32_t a, uint8_t n) { uint32_t rotr(uint32_t a, uint8_t n) { n &= 31; return (a >> n) | (a << (32 - n)); -} \ No newline at end of file +} diff --git a/common/commonutil.h b/common/commonutil.h index 6bf330e7c..4ba65d171 100644 --- a/common/commonutil.h +++ b/common/commonutil.h @@ -47,6 +47,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers uint32_t reflect(uint32_t v, int b); // used in crc.c ... uint8_t reflect8(uint8_t b); // dedicated 8bit reversal uint16_t reflect16(uint16_t b); // dedicated 16bit reversal +uint32_t reflect32(uint32_t b); // dedicated 32bit reversal void num_to_bytes(uint64_t n, size_t len, uint8_t *dest); uint64_t bytes_to_num(uint8_t *src, size_t len); From 1e75ddfff8833941762c6b6c7d840357ac49de59 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:54:54 +0200 Subject: [PATCH 017/174] new entry for function 4x50_bruteforce --- armsrc/em4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index f9f1375f2..71e1371f6 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -22,5 +22,6 @@ void em4x50_write(em4x50_data_t *etd); void em4x50_write_password(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(em4x50_data_t *etd); +void em4x50_bruteforce(em4x50_data_t *etd); #endif /* EM4X50_H */ From 1492d38bd3ca38f34f345981bab726e42650c6eb Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:55:35 +0200 Subject: [PATCH 018/174] new entry for function 4x50_bruteforce --- client/src/cmdlfem4x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 3b00686b1..efc0bb322 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1398,6 +1398,7 @@ static command_t CommandTable[] = { {"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change passwword of EM4x50 tag"}, {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, + {"4x50_bruteforce", CmdEM4x50BruteForce, IfPm3EM4x50, "guess password of EM4x50"}, {NULL, NULL, NULL, NULL} }; From 38f88c1e4fbc0fdea6f3331a96eb2ce4152b38da Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:55:59 +0200 Subject: [PATCH 019/174] new function 4x50_bruteforce --- armsrc/em4x50.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 3f0ad9b6b..dbc05a836 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1003,9 +1003,11 @@ void em4x50_write(em4x50_data_t *etd) { void em4x50_write_password(em4x50_data_t *etd) { - // sinmple change of password + // simple change of password bool bsuccess = false; + uint8_t rpwd[4] = {0x0, 0x0, 0x0, 0x0}; + uint8_t rnewpwd[4] = {0x0, 0x0, 0x0, 0x0}; init_tag(); em4x50_setup_read(); @@ -1013,9 +1015,20 @@ void em4x50_write_password(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { + // lsb -> msb + rpwd[0] = reflect8(etd->password[3]); + rpwd[1] = reflect8(etd->password[2]); + rpwd[2] = reflect8(etd->password[1]); + rpwd[3] = reflect8(etd->password[0]); + + rnewpwd[0] = reflect8(etd->new_password[3]); + rnewpwd[1] = reflect8(etd->new_password[2]); + rnewpwd[2] = reflect8(etd->new_password[1]); + rnewpwd[3] = reflect8(etd->new_password[0]); + // login and change password - if (login(etd->password)) { - bsuccess = write_password(etd->password, etd->new_password); + if (login(rpwd)) { + bsuccess = write_password(rpwd, rnewpwd); } } @@ -1080,3 +1093,58 @@ void em4x50_wipe(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } + +void em4x50_bruteforce(em4x50_data_t *etd) { + + // searching for password in given range + + bool bsuccess = false; + int cnt = 0; + uint8_t bytes[4] ={0x0, 0x0, 0x0, 0x0}; + uint32_t pwd = 0x0, rpwd = 0x0; + + init_tag(); + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + for (pwd = etd->start_password; pwd <= etd->stop_password; pwd++) { + + // lsb -> msb + rpwd = reflect32(pwd); + + for (int i = 0; i < 4; i++) + bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; + + if (login(bytes)) { + bsuccess = true; + break; + } + + // print password every 500 iterations + if ((++cnt % 500) == 0) { + + // print header + if (cnt == 500) { + Dbprintf(""); + Dbprintf("|---------+------------+------------|"); + Dbprintf("| no. | pwd (lsb) | pwd (msb) |"); + Dbprintf("|---------+------------+------------|"); + } + + // print data + Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, pwd, rpwd); + } + + if (BUTTON_PRESS()) + break; + } + + // print footer + Dbprintf("|---------+------------+------------|"); + } + + lf_finalize(); + reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); +} From 688a2e741cda1c9ee7d3135465147057b75764a5 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:56:18 +0200 Subject: [PATCH 020/174] new entry for function 4x50_bruteforce --- client/src/cmdlfem4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 01417aa1e..6e1815c87 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -24,5 +24,6 @@ int CmdEM4x50WritePassword(const char *Cmd); int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); +int CmdEM4x50BruteForce(const char *Cmd); #endif From 55ba7c695d009aba251c7b4dbaae662c0dca24ff Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:58:13 +0200 Subject: [PATCH 021/174] new function CmdEM4x50BruteForce + hint for lsb notation regarding CmdEM450WritePassword --- client/src/cmdlfem4x50.c | 79 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 124ffe8c0..a87ec2927 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -37,8 +37,8 @@ static int usage_lf_em4x50_write(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " a - memory address to write to (dec)"); - PrintAndLogEx(NORMAL, " w - word to write (hex)"); - PrintAndLogEx(NORMAL, " p - password (hex) (optional)"); + PrintAndLogEx(NORMAL, " w - word to write (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb notation) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write a 3 w deadc0de")); PrintAndLogEx(NORMAL, ""); @@ -50,8 +50,8 @@ static int usage_lf_em4x50_write_password(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] [p ] [n ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex)"); - PrintAndLogEx(NORMAL, " n - new password (hex)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " n - new password (hex, lsb notation)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write_password p 11223344 n 01020304")); PrintAndLogEx(NORMAL, ""); @@ -97,6 +97,19 @@ static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_bruteforce(void) { + PrintAndLogEx(NORMAL, "Guess password of EM4x50 tag. Tag must be on antenna. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_bruteforce [h] f l "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " f - start password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " l - stop password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_bruteforce f 11200000 l 11300000")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t *words) { @@ -740,3 +753,61 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50BruteForce(const char *Cmd) { + + bool startpwd = false, stoppwd = false, errors = false; + const int speed = 27; // 27 passwords/second (empirical value) + int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; + uint8_t cmdp = 0; + em4x50_data_t etd; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_em4x50_bruteforce(); + case 'f': + etd.start_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + startpwd = true; + cmdp += 2; + break; + case 'l': + etd.stop_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + stoppwd = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors || !startpwd || !stoppwd) + return usage_lf_em4x50_bruteforce(); + + // print some information + no_iter = etd.stop_password - etd.start_password + 1; + dur_s = no_iter / speed; + dur_h = dur_s / 3600; + dur_m = (dur_s - dur_h * 3600) / 60; + dur_s -= dur_h * 3600 + dur_m * 60; + PrintAndLogEx(NORMAL, "\ntrying %i passwords in range [0x%08x, 0x%08x]", + no_iter, etd.start_password, etd.stop_password); + PrintAndLogEx(NORMAL, "estimated duration: %ih%im%is\n", dur_h, dur_m, dur_s); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_BRUTEFORCE, (uint8_t *)&etd, sizeof(etd)); + WaitForResponse(CMD_ACK, &resp); + + // print response + if ((bool)resp.status) + PrintAndLogEx(NORMAL, "\npassword " _GREEN_("found") ": 0x%08x\n", resp.data.asDwords[0]); + else + PrintAndLogEx(NORMAL, "\npassword: " _RED_("not found") "\n"); + + return PM3_SUCCESS; +} From 2308cc7175c4fd26b464afd6f108c1f00e839a7f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 12:59:04 +0200 Subject: [PATCH 022/174] new entry for function em4x50_bruteforce --- armsrc/appmain.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 42161d738..88523aa6c 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1037,6 +1037,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_wipe((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_BRUTEFORCE: { + em4x50_bruteforce((em4x50_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 From ab5e4405fe9ab10dd5f6350dc5d79fc0d28ac576 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 13:42:13 +0200 Subject: [PATCH 023/174] changed function name + column order (output "lsb"/msb") --- armsrc/em4x50.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index dbc05a836..15f5194d9 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1094,7 +1094,7 @@ void em4x50_wipe(em4x50_data_t *etd) { reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } -void em4x50_bruteforce(em4x50_data_t *etd) { +void em4x50_brute(em4x50_data_t *etd) { // searching for password in given range @@ -1129,12 +1129,12 @@ void em4x50_bruteforce(em4x50_data_t *etd) { if (cnt == 500) { Dbprintf(""); Dbprintf("|---------+------------+------------|"); - Dbprintf("| no. | pwd (lsb) | pwd (msb) |"); + Dbprintf("| no. | pwd (msb) | pwd (lsb) |"); Dbprintf("|---------+------------+------------|"); } // print data - Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, pwd, rpwd); + Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, rpwd, pwd); } if (BUTTON_PRESS()) From fc3638a5f4eee9b6c7f068bdef8e3f088467a041 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 13:42:27 +0200 Subject: [PATCH 024/174] changed function name --- armsrc/appmain.c | 4 ++-- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x.c | 2 +- client/src/cmdlfem4x50.c | 14 +++++++------- client/src/cmdlfem4x50.h | 2 +- include/pm3_cmd.h | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 88523aa6c..5a465c2bd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1037,8 +1037,8 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_wipe((em4x50_data_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_BRUTEFORCE: { - em4x50_bruteforce((em4x50_data_t *)packet->data.asBytes); + case CMD_LF_EM4X50_BRUTE: { + em4x50_brute((em4x50_data_t *)packet->data.asBytes); break; } #endif diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 71e1371f6..db8235bca 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -22,6 +22,6 @@ void em4x50_write(em4x50_data_t *etd); void em4x50_write_password(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(em4x50_data_t *etd); -void em4x50_bruteforce(em4x50_data_t *etd); +void em4x50_brute(em4x50_data_t *etd); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index efc0bb322..b09f2f102 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1398,7 +1398,7 @@ static command_t CommandTable[] = { {"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change passwword of EM4x50 tag"}, {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, - {"4x50_bruteforce", CmdEM4x50BruteForce, IfPm3EM4x50, "guess password of EM4x50"}, + {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a87ec2927..c0fc06e7b 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -97,16 +97,16 @@ static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_lf_em4x50_bruteforce(void) { +static int usage_lf_em4x50_brute(void) { PrintAndLogEx(NORMAL, "Guess password of EM4x50 tag. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_bruteforce [h] f l "); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_brute [h] f l "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " f - start password (hex, lsb notation)"); PrintAndLogEx(NORMAL, " l - stop password (hex, lsb notation)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_bruteforce f 11200000 l 11300000")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_brute f 11200000 l 11300000")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -754,7 +754,7 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_SUCCESS; } -int CmdEM4x50BruteForce(const char *Cmd) { +int CmdEM4x50Brute(const char *Cmd) { bool startpwd = false, stoppwd = false, errors = false; const int speed = 27; // 27 passwords/second (empirical value) @@ -767,7 +767,7 @@ int CmdEM4x50BruteForce(const char *Cmd) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - return usage_lf_em4x50_bruteforce(); + return usage_lf_em4x50_brute(); case 'f': etd.start_password = param_get32ex(Cmd, cmdp + 1, 0, 16); startpwd = true; @@ -786,7 +786,7 @@ int CmdEM4x50BruteForce(const char *Cmd) { } if (errors || !startpwd || !stoppwd) - return usage_lf_em4x50_bruteforce(); + return usage_lf_em4x50_brute(); // print some information no_iter = etd.stop_password - etd.start_password + 1; @@ -800,7 +800,7 @@ int CmdEM4x50BruteForce(const char *Cmd) { // start clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_BRUTEFORCE, (uint8_t *)&etd, sizeof(etd)); + SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); WaitForResponse(CMD_ACK, &resp); // print response diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 6e1815c87..9a86adfed 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -24,6 +24,6 @@ int CmdEM4x50WritePassword(const char *Cmd); int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); -int CmdEM4x50BruteForce(const char *Cmd); +int CmdEM4x50Brute(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f97be2a06..69a75a1ad 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -493,7 +493,7 @@ typedef struct { #define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 -#define CMD_LF_EM4X50_BRUTEFORCE 0x0245 +#define CMD_LF_EM4X50_BRUTE 0x0245 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From c2d3b893259e75fdb92af7c4eaa00fac33c8db50 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 14:59:53 +0200 Subject: [PATCH 025/174] very small corrections --- armsrc/em4x50.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 15f5194d9..3f1305d8a 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1062,7 +1062,7 @@ void em4x50_wipe(em4x50_data_t *etd) { // to verify result reset EM4x50 if (reset()) { - // login not necessary because protectd word has been set to 0 + // login not necessary because protected word has been set to 0 // -> no read protected words // -> selective read can be called immediately if (selective_read(addresses)) { @@ -1142,7 +1142,8 @@ void em4x50_brute(em4x50_data_t *etd) { } // print footer - Dbprintf("|---------+------------+------------|"); + if (cnt >= 500) + Dbprintf("|---------+------------+------------|"); } lf_finalize(); From 2e5cf12d7d41de105a027e6463c39223bc6a579e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 23:22:51 +0200 Subject: [PATCH 026/174] added login function --- armsrc/appmain.c | 4 +++ armsrc/em4x50.c | 27 ++++++++++++++ armsrc/em4x50.h | 1 + client/src/cmdlfem4x.c | 1 + client/src/cmdlfem4x50.c | 78 +++++++++++++++++++++++++++------------- client/src/cmdlfem4x50.h | 1 + include/pm3_cmd.h | 1 + 7 files changed, 88 insertions(+), 25 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5a465c2bd..2ba931a01 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1041,6 +1041,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_brute((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_LOGIN: { + em4x50_login((em4x50_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ebf381a69..95769e98b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1184,3 +1184,30 @@ void em4x50_brute(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); } + +void em4x50_login(em4x50_data_t *etd) { + + // login into EM4x50 + + uint8_t status = 0; + uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; + uint32_t rpwd = 0x0; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + // lsb -> msb + rpwd = reflect32(etd->login_password); + + // convert to "old" data format + for (int i = 0; i < 4; i++) + bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; + + status = login(bytes); + } + + lf_finalize(); + reply_ng(CMD_ACK, status, 0, 0); +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index d1f897b8a..5c3648a39 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -27,5 +27,6 @@ void em4x50_write_password(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); +void em4x50_login(em4x50_data_t *etd); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index b09f2f102..16a408956 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1399,6 +1399,7 @@ static command_t CommandTable[] = { {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, + {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 15ac9fb4b..4c1dbad67 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -97,31 +97,6 @@ static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_lf_em4x50_sim(void) { - PrintAndLogEx(NORMAL, "Simulate EM4x50 tag. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] w "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " w - word (hex)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim w 12345678")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_test(void) { - PrintAndLogEx(NORMAL, "Test functionality for EM4x50 tag. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_test [h] ..."); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " c <0|1> - carrier on|off (optional)"); - PrintAndLogEx(NORMAL, " b - byte (hex) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_test ...")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_lf_em4x50_brute(void) { PrintAndLogEx(NORMAL, "Guess password of EM4x50 tag. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); @@ -135,6 +110,18 @@ static int usage_lf_em4x50_brute(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_login(void) { + PrintAndLogEx(NORMAL, "Login into EM4x50 tag. Tag must be on antenna. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_login [h] p "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_login p 11200000")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t *words) { @@ -841,3 +828,44 @@ int CmdEM4x50Brute(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50Login(const char *Cmd) { + + bool errors = false, pwd_given = false; + uint8_t cmdp = 0; + em4x50_data_t etd; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_em4x50_login(); + case 'p': + etd.login_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + pwd_given = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors || !pwd_given) + return usage_lf_em4x50_login(); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&etd, sizeof(etd)); + WaitForResponse(CMD_ACK, &resp); + + // print response + if ((bool)resp.status) + PrintAndLogEx(NORMAL, "\nlogin " _GREEN_("ok") "\n"); + else + PrintAndLogEx(NORMAL, "\nlogin " _RED_("failed") "\n"); + + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 9a86adfed..dbf94c660 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -25,5 +25,6 @@ int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); int CmdEM4x50Brute(const char *Cmd); +int CmdEM4x50Login(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 69a75a1ad..8060a3998 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -494,6 +494,7 @@ typedef struct { #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 #define CMD_LF_EM4X50_BRUTE 0x0245 +#define CMD_LF_EM4X50_LOGIN 0x0246 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From a308fc692b01987c81da68695c0cd077198ff4b4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 23:23:30 +0200 Subject: [PATCH 027/174] added entry for login function (may be temporary) --- include/em4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/em4x50.h b/include/em4x50.h index 771c360ee..5b2966253 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -53,6 +53,7 @@ typedef struct { uint8_t word[4]; uint32_t start_password; uint32_t stop_password; + uint32_t login_password; } em4x50_data_t; typedef struct { From c20ab4ca206dad9dcc9583865087491aed3168fc Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Sep 2020 23:39:04 +0200 Subject: [PATCH 028/174] added function reset --- armsrc/appmain.c | 4 +++ armsrc/em4x50.c | 76 +++++++++++++++++++++++++--------------- armsrc/em4x50.h | 1 + client/src/cmdlfem4x.c | 1 + client/src/cmdlfem4x50.c | 46 ++++++++++++++++++++++++ client/src/cmdlfem4x50.h | 1 + include/pm3_cmd.h | 1 + 7 files changed, 101 insertions(+), 29 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2ba931a01..bf8b1e782 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1045,6 +1045,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_login((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_RESET: { + em4x50_reset(); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 95769e98b..bba99e92d 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1100,35 +1100,6 @@ void em4x50_wipe(em4x50_data_t *etd) { reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } -int em4x50_standalone_read(uint64_t *words) { - - int now = 0; - uint8_t bits[EM4X50_TAG_WORD]; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) { - - if (find_double_listen_window(false)) { - - memset(bits, 0, sizeof(bits)); - - while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { - words[now] = 0; - - for (int i = 0; i < EM4X50_TAG_WORD; i++) { - words[now] <<= 1; - words[now] += bits[i] & 1; - } - - now++; - } - } - } - - return now; -} - void em4x50_brute(em4x50_data_t *etd) { // searching for password in given range @@ -1211,3 +1182,50 @@ void em4x50_login(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_ACK, status, 0, 0); } + +void em4x50_reset(void) { + + // reset EM4x50 + + uint8_t status = 0; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + status = reset(); + } + + lf_finalize(); + reply_ng(CMD_ACK, status, 0, 0); +} + +int em4x50_standalone_read(uint64_t *words) { + + int now = 0; + uint8_t bits[EM4X50_TAG_WORD]; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) { + + if (find_double_listen_window(false)) { + + memset(bits, 0, sizeof(bits)); + + while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { + words[now] = 0; + + for (int i = 0; i < EM4X50_TAG_WORD; i++) { + words[now] <<= 1; + words[now] += bits[i] & 1; + } + + now++; + } + } + } + + return now; +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 5c3648a39..35452021d 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -28,5 +28,6 @@ void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(em4x50_data_t *etd); +void em4x50_reset(void); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 16a408956..52ce472e5 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1400,6 +1400,7 @@ static command_t CommandTable[] = { {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, + {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 4c1dbad67..2b73aa2a1 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -122,6 +122,17 @@ static int usage_lf_em4x50_login(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_reset(void) { + PrintAndLogEx(NORMAL, "Reset EM4x50 tag. Tag must be on antenna. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_reset [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_reset")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t *words) { @@ -869,3 +880,38 @@ int CmdEM4x50Login(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50Reset(const char *Cmd) { + + bool errors = false; + uint8_t cmdp = 0; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_em4x50_reset(); + default: + PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors) + return usage_lf_em4x50_reset(); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_RESET, 0, 0); + WaitForResponse(CMD_ACK, &resp); + + // print response + if ((bool)resp.status) + PrintAndLogEx(NORMAL, "\nreset " _GREEN_("ok") "\n"); + else + PrintAndLogEx(NORMAL, "\nreset " _RED_("failed") "\n"); + + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index dbf94c660..6462810d0 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -26,5 +26,6 @@ int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); int CmdEM4x50Brute(const char *Cmd); int CmdEM4x50Login(const char *Cmd); +int CmdEM4x50Reset(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 8060a3998..08207306c 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -495,6 +495,7 @@ typedef struct { #define CMD_LF_EM4X50_WIPE 0x0244 #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 +#define CMD_LF_EM4X50_RESET 0x0247 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From a9ec622d9741d91c318183ab65a91b3a6b45bb8a Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 3 Oct 2020 22:59:21 +0200 Subject: [PATCH 029/174] added standalone mode "brute force" --- armsrc/Standalone/lf_tharexde.c | 206 ++++++++++++++++++----- armsrc/em4x50.c | 284 +++++++++++++++++++++++++------- armsrc/em4x50.h | 2 + 3 files changed, 392 insertions(+), 100 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 8cad3e736..84f0253fa 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -52,28 +52,32 @@ #define STATE_SIM 0 #define STATE_READ 1 -#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml" -#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect" +#define STATE_BRUTE 2 #define EM4X50_TAG_WORD 45 +#define EM4X50_PWD_SPEED 27 +#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml" +#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log" +#define LF_EM4X50BRUTE_INPUTFILE "lf_em4x50brute.eml" +#define LF_EM4X50BRUTE_LOGFILE "lf_em4x50brute.log" bool input_exists; bool log_exists; -static void LoadDataInstructions(void) { +static void LoadDataInstructions(const char *inputfile) { Dbprintf(""); - Dbprintf("[=] To load datafile into flash and display it:"); - Dbprintf("[=] " _YELLOW_("1.") " edit inputfile "LF_EM4X50SIMULATE_INPUTFILE); - Dbprintf("[=] " _YELLOW_("2.") " start proxmark3 client"); - Dbprintf("[=] " _YELLOW_("3.") " mem spiffs load f "LF_EM4X50SIMULATE_INPUTFILE" o "LF_EM4X50SIMULATE_INPUTFILE); - Dbprintf("[=] " _YELLOW_("4.") " start standalone mode"); + Dbprintf("To load datafile into flash and display it:"); + Dbprintf(_YELLOW_("1.") " edit inputfile %s", inputfile); + Dbprintf(_YELLOW_("2.") " start proxmark3 client"); + Dbprintf(_YELLOW_("3.") " mem spiffs load f %s o %s", inputfile, inputfile); + Dbprintf(_YELLOW_("4.") " start standalone mode"); } -static void DownloadLogInstructions(void) { +static void DownloadLogInstructions(const char *logfile) { Dbprintf(""); - Dbprintf("[=] To get the logfile from flash and display it:"); - Dbprintf("[=] " _YELLOW_("1.") " mem spiffs dump o "LF_EM4X50COLLECT_LOGFILE" f "LF_EM4X50COLLECT_LOGFILE); - Dbprintf("[=] " _YELLOW_("2.") " exit proxmark3 client"); - Dbprintf("[=] " _YELLOW_("3.") " cat "LF_EM4X50COLLECT_LOGFILE); + Dbprintf("To get the logfile from flash and display it:"); + Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f %s", logfile, logfile); + Dbprintf(_YELLOW_("2.") " exit proxmark3 client"); + Dbprintf(_YELLOW_("3.") " cat %s", logfile); } static bool strip_check_parities(uint64_t data, uint32_t *word) { @@ -123,25 +127,25 @@ static bool strip_check_parities(uint64_t data, uint32_t *word) { return false; } -static int get_input_data_from_file(uint32_t *words) { +static int get_input_data_from_file(uint32_t *words, char *inputfile) { size_t now = 0; - if (exists_in_spiffs(LF_EM4X50SIMULATE_INPUTFILE)) { + if (exists_in_spiffs(inputfile)) { - uint32_t size = size_in_spiffs((char *)LF_EM4X50SIMULATE_INPUTFILE); + uint32_t size = size_in_spiffs(inputfile); uint8_t *mem = BigBuf_malloc(size); + + Dbprintf(_YELLOW_("found input file %s"), inputfile); - Dbprintf(_YELLOW_("[=] found input file %s"), LF_EM4X50SIMULATE_INPUTFILE); - - rdv40_spiffs_read_as_filetype((char *)LF_EM4X50SIMULATE_INPUTFILE, mem, size, RDV40_SPIFFS_SAFETY_SAFE); + 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++) words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); - Dbprintf(_YELLOW_("[=] read data from input file")); + Dbprintf(_YELLOW_("read data from input file")); } BigBuf_free(); @@ -149,52 +153,72 @@ static int get_input_data_from_file(uint32_t *words) { return (now > 0) ? now : 0; } -static void append(uint8_t *entry, size_t entry_len) { +static void append(const char *filename, uint8_t *entry, size_t entry_len) { - LED_C_ON(); + LED_D_ON(); if (log_exists == false) { - rdv40_spiffs_write(LF_EM4X50COLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); log_exists = true; } else { - rdv40_spiffs_append(LF_EM4X50COLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); } - LED_C_OFF(); + LED_D_OFF(); } void ModInfo(void) { - DbpString(_YELLOW_(" LF EM4x50 collector mode") " - a.k.a tharexde"); + DbpString(_YELLOW_(" LF EM4x50 sim/collector/bruteforce mode") " - a.k.a tharexde"); } void RunMod(void) { - bool state_change = true; + bool state_change = true;//, password_found = false; + int pwd_found = false; + //int cnt = 0; + //int iterprint = 0; uint8_t state = STATE_SIM; // declarations for simulating uint32_t words[33] = {0x0}; + uint32_t pwd = 0x0; + uint32_t passwords[2] = {0x0}; size_t now = 0; // declarations for reading int no_words = 0; uint64_t data[EM4X50_TAG_WORD]; - uint32_t word = 0; + uint32_t word = 0;//, pwd = 0x0, rpwd = 0x0; uint8_t entry[81]; rdv40_spiffs_lazy_mount(); StandAloneMode(); - Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE started")); + Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); for (;;) { WDT_HIT(); if (data_available()) break; - // press button - toggle between SIM and READ + // press button - toggle between SIM, READ and BRUTE // hold button - exit int button_pressed = BUTTON_CLICKED(1000); if (button_pressed == BUTTON_SINGLE_CLICK) { SpinUp(100); - state = (state == STATE_SIM) ? STATE_READ : STATE_SIM; + + switch (state) { + + case STATE_SIM: + state = STATE_READ; + break; + case STATE_READ: + state = STATE_BRUTE; + break; + case STATE_BRUTE: + state = STATE_SIM; + break; + default: + break; + } + state_change = true; } else if (button_pressed == BUTTON_HOLD) { @@ -215,18 +239,19 @@ void RunMod(void) { AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + LEDsoff(); LED_A_ON(); - LED_B_OFF(); - Dbprintf(_YELLOW_("[=] switched to EM4x50 simulating mode")); + Dbprintf(""); + Dbprintf(_YELLOW_("switched to EM4x50 simulating mode")); - now = get_input_data_from_file(words); + now = get_input_data_from_file(words, LF_EM4X50SIMULATE_INPUTFILE); if (now > 0) { - Dbprintf(_YELLOW_("[=] simulating %i blocks"), now); + Dbprintf(_YELLOW_("simulating %i blocks"), now); for (int i = 0; i < now; i++) - Dbprintf(_YELLOW_("[=] %2i -> %lx"), i + 1, words[i]); + Dbprintf("%2i -> %lx", i + 1, words[i]); } else { - Dbprintf(_RED_("[!] error in input data")); + Dbprintf(_RED_("error in input data")); } state_change = false; @@ -242,9 +267,10 @@ void RunMod(void) { if (state_change) { + LEDsoff(); LED_B_ON(); - LED_A_OFF(); - Dbprintf(_YELLOW_("[=] switched to EM4x50 reading mode")); + Dbprintf(""); + Dbprintf(_YELLOW_("switched to EM4x50 reading mode")); memset(entry, 0, sizeof(entry)); memset(data, 0, sizeof(data)); @@ -263,7 +289,7 @@ void RunMod(void) { sprintf((char *)entry, "found new EM4x50 tag:"); Dbprintf("%s", entry); strcat((char *)entry, "\n"); - append(entry, strlen((char *)entry)); + append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry)); for (int i = 0; i < no_words; i++) { @@ -274,17 +300,106 @@ void RunMod(void) { Dbprintf("%s", entry); strcat((char *)entry, "\n"); - append(entry, strlen((char *)entry)); + append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry)); } } + } else if (state == STATE_BRUTE) { + + if (state_change) { + + LEDsoff(); + LED_C_ON(); + Dbprintf(""); + Dbprintf(_YELLOW_("switched to EM4x50 brute force mode")); + + log_exists = exists_in_spiffs(LF_EM4X50BRUTE_LOGFILE); + now = get_input_data_from_file(passwords, LF_EM4X50BRUTE_INPUTFILE); + + if (now == 2) { + + // print some information + int no_iter = passwords[1] - passwords[0] + 1; + int dur_s = no_iter / EM4X50_PWD_SPEED; + int dur_h = dur_s / 3600; + int dur_m = (dur_s - dur_h * 3600) / 60; + dur_s -= dur_h * 3600 + dur_m * 60; + + //iterprint = no_iter/10; + + Dbprintf(_YELLOW_("trying %i passwords in range [0x%08x, 0x%08x]"), + no_iter, passwords[0], passwords[1]); + Dbprintf(_YELLOW_("estimated duration: %ih%im%is"), + dur_h, dur_m, dur_s); + + } else { + Dbprintf(_RED_("error in input data")); + break; + } + + state_change = false; + } + + pwd_found = em4x50_standalone_brute(passwords[0], passwords[1], &pwd); + + if (pwd_found == PM3_ETIMEOUT) { + + // timeout -> no EM4x50 tag on reader? + Dbprintf(_YELLOW_("timeout - no EM4x50 tag detected")); + + } else if (pwd_found == true) { + + // password found -> write to logfile + sprintf((char *)entry, "password found: 0x%08"PRIx32, pwd); + Dbprintf(_YELLOW_("%s"), entry); + strcat((char *)entry, "\n"); + append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); + + break; + + } else { + + if (pwd == passwords[1] + 1) { + + // finished without success -> write to logfile + sprintf((char *)entry, "no password found"); + Dbprintf(_YELLOW_("%s"), entry); + strcat((char *)entry, "\n"); + append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); + + + } else { + + // stopped -> write to logfile + sprintf((char *)entry, "stopped search - last password: 0x%08"PRIx32, pwd); + Dbprintf(_YELLOW_("%s"), entry); + strcat((char *)entry, "\n"); + append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); + + // replace start password by last tested password in + // inputfile (spiffs) so that brute forcing process will + // be continued when envoking brute force mode again + sprintf((char *)entry, "%08"PRIx32"\n%08"PRIx32"\n", pwd, passwords[1]); + rdv40_spiffs_write(LF_EM4X50BRUTE_INPUTFILE, + entry, + strlen((char *)entry), + RDV40_SPIFFS_SAFETY_SAFE); + + } + + break; + } } } - if (state == STATE_READ) - DownloadLogInstructions(); - else - LoadDataInstructions(); + if (state == STATE_READ) { + DownloadLogInstructions(LF_EM4X50COLLECT_LOGFILE); + } else if (state == STATE_BRUTE) { + LoadDataInstructions(LF_EM4X50BRUTE_INPUTFILE); + DownloadLogInstructions(LF_EM4X50BRUTE_LOGFILE); + } else { + LoadDataInstructions(LF_EM4X50SIMULATE_INPUTFILE); + } LED_D_ON(); rdv40_spiffs_lazy_unmount(); @@ -292,6 +407,7 @@ void RunMod(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); + Dbprintf(""); Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped")); } diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index bba99e92d..39b971411 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -451,7 +451,7 @@ static bool find_single_listen_window(void) { return false; } -static bool find_double_listen_window(bool bcommand) { +static int find_double_listen_window(bool bcommand) { // find two successive listen windows that indicate the beginning of // data transmission @@ -505,13 +505,160 @@ static bool find_double_listen_window(bool bcommand) { return true; } } - cnt_pulses++; } + cnt_pulses++; } return false; } +static bool em4x50_sim_send_bit(uint8_t bit) { + + uint16_t check = 0; + + for (int t = 0; t < EM4X50_T_TAG_FULL_PERIOD; t++) { + + // wait until SSC_CLK goes HIGH + // used as a simple detection of a reader field? + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (bit) + OPEN_COIL(); + else + SHORT_COIL(); + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (t == EM4X50_T_TAG_HALF_PERIOD) + bit ^= 1; + + } + + return true; +} + +static bool em4x50_sim_send_byte(uint8_t byte) { + + // send byte + for (int i = 0; i < 8; i++) + if (!em4x50_sim_send_bit((byte >> (7 - i)) & 1)) + return false; + + return true; + +} + +static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { + + uint8_t parity = 0x0; + + // send byte with parity (even) + for (int i = 0; i < 8; i++) + parity ^= (byte >> i) & 1; + + if (!em4x50_sim_send_byte(byte)) + return false;; + + if (!em4x50_sim_send_bit(parity)) + return false; + + return true; +} + +bool em4x50_sim_send_word(uint32_t word) { + + uint8_t cparity = 0x00; + + // 4 bytes each with even row parity bit + for (int i = 0; i < 4; i++) + if (!em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF)) + return false; + + // column parity + for (int i = 0; i < 8; i++) { + cparity <<= 1; + for (int j = 0; j < 4; j++) { + cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; + } + } + if (!em4x50_sim_send_byte(cparity)) + return false; + + // stop bit + if (!em4x50_sim_send_bit(0)) + return false; + + return true; +} + +bool em4x50_sim_send_listen_window(void) { + + //int i = 0; + uint16_t check = 0; + //uint8_t test[100] = {0}; + + for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + + // wait until SSC_CLK goes HIGH + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + + if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { + OPEN_COIL(); + } else if (t >= EM4X50_T_TAG_FULL_PERIOD) { + SHORT_COIL(); + } else if (t >= EM4X50_T_TAG_HALF_PERIOD) { + OPEN_COIL(); + } else { + SHORT_COIL(); + } + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (BUTTON_PRESS()) + return false; + check = 0; + } + ++check; + } + } + + return true; +} + + static bool find_em4x50_tag(void) { // function is used to check wether a tag on the proxmark is an @@ -519,7 +666,7 @@ static bool find_em4x50_tag(void) { return find_single_listen_window(); } -static bool request_receive_mode(void) { +static int request_receive_mode(void) { // To issue a command we have to find a listen window first. // Because identification and sychronization at the same time is not @@ -1100,67 +1247,29 @@ void em4x50_wipe(em4x50_data_t *etd) { reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); } -void em4x50_brute(em4x50_data_t *etd) { +void em4x50_reset(void) { - // searching for password in given range + // reset EM4x50 + + uint8_t status = 0; - bool bsuccess = false; - int cnt = 0; - uint8_t bytes[4] ={0x0, 0x0, 0x0, 0x0}; - uint32_t pwd = 0x0, rpwd = 0x0; - - init_tag(); em4x50_setup_read(); // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - for (pwd = etd->start_password; pwd <= etd->stop_password; pwd++) { - - // lsb -> msb - rpwd = reflect32(pwd); - - for (int i = 0; i < 4; i++) - bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; - - if (login(bytes)) { - bsuccess = true; - break; - } - - // print password every 500 iterations - if ((++cnt % 500) == 0) { - - // print header - if (cnt == 500) { - Dbprintf(""); - Dbprintf("|---------+------------+------------|"); - Dbprintf("| no. | pwd (msb) | pwd (lsb) |"); - Dbprintf("|---------+------------+------------|"); - } - - // print data - Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, rpwd, pwd); - } - - if (BUTTON_PRESS()) - break; - } - - // print footer - if (cnt >= 500) - Dbprintf("|---------+------------+------------|"); + status = reset(); } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); + reply_ng(CMD_ACK, status, 0, 0); } void em4x50_login(em4x50_data_t *etd) { // login into EM4x50 - uint8_t status = 0; + uint8_t status = false; uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; uint32_t rpwd = 0x0; @@ -1183,22 +1292,87 @@ void em4x50_login(em4x50_data_t *etd) { reply_ng(CMD_ACK, status, 0, 0); } -void em4x50_reset(void) { +static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - // reset EM4x50 + // searching for password in given range - uint8_t status = 0; + bool pwd_found = false; + int cnt = 0; + uint32_t rpwd = 0x0; + uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; + + for (*pwd = start; *pwd <= stop; (*pwd)++) { + + // lsb -> msb + rpwd = reflect32(*pwd); + + for (int i = 0; i < 4; i++) + bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; + + if (login(bytes)) { + pwd_found = true; + break; + } + + // print password every 500 iterations + if ((++cnt % 500) == 0) { + + // print header + if (cnt == 500) { + Dbprintf("|---------+------------+------------|"); + Dbprintf("| no. | pwd (msb) | pwd (lsb) |"); + Dbprintf("|---------+------------+------------|"); + } + + // print data + Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, rpwd, *pwd); + } + + if (BUTTON_PRESS()) + break; + + } + + // print footer + if (cnt >= 500) + Dbprintf("|---------+------------+------------|"); + + return pwd_found; +} + +void em4x50_brute(em4x50_data_t *etd) { + + // envoke password search + + bool bsuccess = false; + uint32_t pwd = 0x0; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) + bsuccess = brute(etd->start_password, etd->stop_password, &pwd); + + lf_finalize(); + reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); +} + +int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { + + // envoke password search in standalone mode + + int status = false; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - - status = reset(); + status = brute(start, stop, pwd); + } else { + status = PM3_ETIMEOUT; } lf_finalize(); - reply_ng(CMD_ACK, status, 0, 0); + + return status; } int em4x50_standalone_read(uint64_t *words) { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 35452021d..401e846cd 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -18,9 +18,11 @@ typedef struct { } em4x50_tag_t; int em4x50_standalone_read(uint64_t *words); +int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd); bool em4x50_sim_send_listen_window(void); bool em4x50_sim_send_word(uint32_t word); + void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_write_password(em4x50_data_t *etd); From 68db54028cca6d47d09e9d21caada209e54ef6f3 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 5 Oct 2020 22:59:08 +0200 Subject: [PATCH 030/174] added function 4x50_watch --- armsrc/appmain.c | 4 ++++ armsrc/em4x50.c | 45 ++++++++++++++++++++++++++++++++++++++ armsrc/em4x50.h | 1 + client/src/cmdlfem4x.c | 1 + client/src/cmdlfem4x50.c | 47 ++++++++++++++++++++++++++++++++++++++++ client/src/cmdlfem4x50.h | 1 + include/pm3_cmd.h | 1 + 7 files changed, 100 insertions(+) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index ae1d112c1..bcf0a656f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1049,6 +1049,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_reset(); break; } + case CMD_LF_EM4X50_WATCH: { + em4x50_watch(); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 39b971411..158bfa4f6 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1403,3 +1403,48 @@ int em4x50_standalone_read(uint64_t *words) { return now; } + +void em4x50_watch() { + + // reads continuously and displays standard reads of tag + + int now = 0; + + init_tag(); + em4x50_setup_read(); + + while (BUTTON_PRESS() == false) { + + WDT_HIT(); + init_tag(); + now = 0; + + if (get_signalproperties() && find_em4x50_tag()) { + + standard_read(&now); + + if (now > 0) { + + Dbprintf(""); + for (int i = 0; i < now; i++) { + + Dbprintf("EM4x50 TAG ID: " + _GREEN_("%02x%02x%02x%02x") " (msb) - " + _GREEN_("%02x%02x%02x%02x") " (lsb)", + tag.sectors[i][0], + tag.sectors[i][1], + tag.sectors[i][2], + tag.sectors[i][3], + reflect8(tag.sectors[i][3]), + reflect8(tag.sectors[i][2]), + reflect8(tag.sectors[i][1]), + reflect8(tag.sectors[i][0])); + } + } + } + } + + LOW(GPIO_SSC_DOUT); + lf_finalize(); + reply_ng(CMD_ACK, 1, 0, 0); +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 401e846cd..8c86cfb26 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -31,5 +31,6 @@ void em4x50_wipe(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(em4x50_data_t *etd); void em4x50_reset(void); +void em4x50_watch(void); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 291027754..1b0915241 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -1425,6 +1425,7 @@ static command_t CommandTable[] = { {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, + {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index eeb04dc3a..fc6bbb7e6 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -133,6 +133,17 @@ static int usage_lf_em4x50_reset(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_watch(void) { + PrintAndLogEx(NORMAL, "Watch for EM4x50 tag. Tag must be on antenna. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_watch [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_watch")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t *words) { @@ -917,3 +928,39 @@ int CmdEM4x50Reset(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50Watch(const char *Cmd) { + + // continously envoke reading of a EM4x50 tag + + bool errors = false; + uint8_t cmdp = 0; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_watch(); + + default: + PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + // validation + if (errors) + return usage_lf_em4x50_watch(); + + PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); + WaitForResponse(CMD_ACK, &resp); + + PrintAndLogEx(INFO, "Done"); + + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 6462810d0..32685baaf 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -27,5 +27,6 @@ int CmdEM4x50Wipe(const char *Cmd); int CmdEM4x50Brute(const char *Cmd); int CmdEM4x50Login(const char *Cmd); int CmdEM4x50Reset(const char *Cmd); +int CmdEM4x50Watch(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 08207306c..786b3f8bb 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -496,6 +496,7 @@ typedef struct { #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 #define CMD_LF_EM4X50_RESET 0x0247 +#define CMD_LF_EM4X50_WATCH 0x0248 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From b4a8409349bd5a8e70f5ed7388403e2b395c7024 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 11 Oct 2020 20:06:03 +0200 Subject: [PATCH 031/174] clean up --- armsrc/Standalone/lf_tharexde.c | 62 +------ armsrc/em4x50.c | 301 +++++++++++++------------------- armsrc/em4x50.h | 4 +- client/src/cmdlfem4x50.c | 57 +----- include/em4x50.h | 10 -- 5 files changed, 136 insertions(+), 298 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 84f0253fa..887100855 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -80,53 +80,6 @@ static void DownloadLogInstructions(const char *logfile) { Dbprintf(_YELLOW_("3.") " cat %s", logfile); } -static bool strip_check_parities(uint64_t data, uint32_t *word) { - - uint8_t rparity = 0, cparity = 0; - uint8_t rparity_m = 0, cparity_m = 0, stop_bit_m = 0; - - // strip parities - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 8; j++) { - *word <<= 1; - *word += (data >> (EM4X50_TAG_WORD - 1 - 9 * i - j)) & 1; - } - } - - // calculate row parities - for (int i = 0; i < 4; i++) { - rparity <<= 1; - for (int j = 0; j < 8; j++) { - rparity ^= (*word >> (31 - 8 * i - j)) & 1; - } - } - - // calculate column parities - for (int i = 0; i < 8; i++) { - cparity <<= 1; - for (int j = 0; j < 4; j++) { - cparity ^= (*word >> (31 - 8 * j - i)) & 1; - } - } - - // measured row parities - for (int i = 0; i < 4; i++) { - rparity_m <<= 1; - rparity_m += (data >> (EM4X50_TAG_WORD - 9 * (i + 1))) & 1; - } - - // measured column parities - cparity_m = (data >> 1) & 0xFF; - - // measured stop bit - stop_bit_m = data & 1; - - if ((cparity_m == cparity) && (rparity_m == rparity) && (stop_bit_m == 0)) - return true; - - return false; -} - static int get_input_data_from_file(uint32_t *words, char *inputfile) { size_t now = 0; @@ -173,8 +126,6 @@ void RunMod(void) { bool state_change = true;//, password_found = false; int pwd_found = false; - //int cnt = 0; - //int iterprint = 0; uint8_t state = STATE_SIM; // declarations for simulating uint32_t words[33] = {0x0}; @@ -183,8 +134,7 @@ void RunMod(void) { size_t now = 0; // declarations for reading int no_words = 0; - uint64_t data[EM4X50_TAG_WORD]; - uint32_t word = 0;//, pwd = 0x0, rpwd = 0x0; + //uint32_t words[EM4X50_TAG_WORD]; uint8_t entry[81]; rdv40_spiffs_lazy_mount(); @@ -273,14 +223,14 @@ void RunMod(void) { Dbprintf(_YELLOW_("switched to EM4x50 reading mode")); memset(entry, 0, sizeof(entry)); - memset(data, 0, sizeof(data)); + memset(words, 0, sizeof(words)); log_exists = exists_in_spiffs(LF_EM4X50COLLECT_LOGFILE); state_change = false; } - no_words = em4x50_standalone_read(data); + no_words = em4x50_standalone_read(words); if (no_words > 0) { @@ -293,11 +243,7 @@ void RunMod(void) { for (int i = 0; i < no_words; i++) { - if (strip_check_parities(data[i], &word)) - sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check ok)", i + 1, word); - else - sprintf((char *)entry, " %2i -> 0x%08"PRIx32" (parity check failed)", i + 1, word); - + sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, words[i]); Dbprintf("%s", entry); strcat((char *)entry, "\n"); append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry)); diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 158bfa4f6..4c2bf2444 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -15,50 +15,6 @@ #include "commonutil.h" #include "em4x50.h" -// 4 data bytes -// + byte with row parities -// + column parity byte -// + byte with stop bit - -static em4x50_tag_t tag = { - .sectors = { - [0] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // password - [1] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // protection word - [2] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // control word - [3] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [4] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [5] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [11] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [13] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [14] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [15] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [17] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [18] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [19] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [20] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [21] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [22] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [23] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [24] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [25] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [26] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [27] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [28] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [29] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [30] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [31] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // user - [32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // device serial number - [33] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // device identification - }, -}; - // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) // 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) @@ -93,6 +49,7 @@ static em4x50_tag_t tag = { #define EM4X50_COMMAND_TIMEOUT 5000 #define FPGA_TIMER_0 0 +static uint32_t em4x50_tag[34] = {0x0}; int gHigh = 0; int gLow = 0; @@ -100,27 +57,7 @@ int gLow = 0; static void init_tag(void) { - // iceman: memset(tag.sectors, 0x00, sizeof)); - - // initialize global tag structure - for (int i = 0; i < 34; i++) - for (int j = 0; j < 7; j++) - tag.sectors[i][j] = 0x00; -} - -static uint8_t bits2byte(uint8_t *bits, int length) { - - // converts separate bits into a single "byte" - uint8_t byte = 0; - for (int i = 0; i < length; i++) { - - byte |= bits[i]; - - if (i != length - 1) - byte <<= 1; - } - - return byte; + memset(em4x50_tag, 0x00, sizeof(em4x50_tag)); } static void msb2lsb_word(uint8_t *word) { @@ -139,31 +76,6 @@ static void msb2lsb_word(uint8_t *word) { word[3] = buff[3]; } -static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) { - - // split "raw" word into data, row and column parity bits and stop bit and - // save them in global tag structure - uint8_t row_parity[4]; - uint8_t col_parity[8]; - - // data and row parities - for (int i = 0; i < 4; i++) { - tag.sectors[pos][i] = bits2byte(&bits[9 * i], 8); - row_parity[i] = bits[9 * i + 8]; - } - - tag.sectors[pos][4] = bits2byte(row_parity, 4); - - // column parities - for (int i = 0; i < 8; i++) - col_parity[i] = bits[36 + i]; - - tag.sectors[pos][5] = bits2byte(col_parity, 8); - - // stop bit - tag.sectors[pos][6] = bits[44]; -} - static void wait_timer(int timer, uint32_t period) { // do nothing for using timer @@ -316,8 +228,6 @@ static int get_next_bit(void) { static uint32_t get_pulse_length(void) { -// Dbprintf( _CYAN_("4x50 get_pulse_length A") ); - int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); // iterates pulse length (low -> high -> low) @@ -354,6 +264,7 @@ static uint32_t get_pulse_length(void) { } static bool check_pulse_length(uint32_t pl, int length) { + // check if pulse length corresponds to given length return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); } @@ -612,9 +523,7 @@ bool em4x50_sim_send_word(uint32_t word) { bool em4x50_sim_send_listen_window(void) { - //int i = 0; uint16_t check = 0; - //uint8_t test[100] = {0}; for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { @@ -643,7 +552,7 @@ bool em4x50_sim_send_listen_window(void) { check = 0; - //wait until SSC_CLK goes LOW + // wait until SSC_CLK goes LOW while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); if (check == 1000) { @@ -671,8 +580,7 @@ static int request_receive_mode(void) { // To issue a command we have to find a listen window first. // Because identification and sychronization at the same time is not // possible when using pulse lengths a double listen window is used. - bool bcommand = true; - return find_double_listen_window(bcommand); + return find_double_listen_window(true); } static bool check_ack(bool bliw) { @@ -728,90 +636,146 @@ static bool check_ack(bool bliw) { return false; } -static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) { +static bool extract_parities(uint64_t word, uint32_t *data) { + + // extract and check parities + // return result of parity check and extracted plain data + + uint8_t row_parities = 0x0, col_parities = 0x0; + uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; + + *data = 0x0; + + // extract plain data (32 bits) from raw word (45 bits) + for (int i = 0; i < 4; i++) { + *data <<= 8; + *data |= (word >> ((4 - i) * 9 + 1)) & 0xFF; + } + + // extract row parities (4 bits + stop bit) from raw word (45 bits) + for (int i = 0; i < 5; i++) { + row_parities <<= 1; + row_parities |= (word >> ((4 - i) * 9)) & 0x1; + } + + // extract col_parities (8 bits, no stop bit) from raw word (45 bits) + col_parities = (word >> 1) & 0xFF; + + // check extracted parities against extracted data + + // calculate row parities from data + for (int i = 0; i < 4; i++) { + row_parities_calculated <<= 1; + for (int j = 0; j < 8; j++) { + row_parities_calculated ^= (*data >> ((3 - i) * 8 + (7 - j))) & 0x1; + } + } + + // add stop bit (always zero) + row_parities_calculated <<= 1; + + // calculate column parities from data + for (int i = 0; i < 8; i++) { + col_parities_calculated <<= 1; + for (int j = 0; j < 4; j++) { + col_parities_calculated ^= (*data >> ((3 - j) * 8 + (7 - i))) & 0x1; + } + } + + if ((row_parities == row_parities_calculated) && (col_parities == col_parities_calculated)) + return true; + + return false; +} + +static int get_word_from_bitstream(uint32_t *data) { // decodes one word by evaluating pulse lengths and previous bit; // word must have 45 bits in total: // 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit - bool bbitchange = false; - int i = 0; + bool bitchange = false; + int cnt = 0; uint32_t pl = 0; + uint64_t word = 0x0; + + *data = 0x0; // initial bit value depends on last pulse length of listen window pl = get_pulse_length(); if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { // pulse length = 1.5 - bits[0] = 1; + word = 0x1; } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { // pulse length = 2 - bits[0] = 0; - bbitchange = true; + bitchange = true; } else { // pulse length = 2.5 - bits[0] = 0; - bits[1] = 1; - i++; + word = 0x1; + cnt++; } // identify remaining bits based on pulse lengths // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (BUTTON_PRESS() == false) { + while (true) { - i++; + cnt++; + word <<= 1; + pl = get_pulse_length(); if (check_pulse_length(pl, EM4X50_T_TAG_FULL_PERIOD)) { // pulse length = 1 -> keep former bit value - bits[i] = bits[i - 1]; + word |= (word >> 1) & 0x1; } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { // pulse length = 1.5 -> decision on bit change - if (bbitchange) { + if (bitchange) { // if number of pulse lengths with 1.5 periods is even -> add bit - bits[i] = (bits[i - 1] == 1) ? 1 : 0; + word |= (word >> 1) & 0x1; + word <<= 1; // pulse length of 1.5 changes bit value - bits[i + 1] = (bits[i] == 1) ? 0 : 1; - i++; + word |= ((word >> 1) & 0x1) ^ 0x1; + cnt++; // next time add only one bit - bbitchange = false; + bitchange = false; } else { - bits[i] = (bits[i - 1] == 1) ? 0 : 1; + word |= ((word >> 1) & 0x1) ^ 0x1; // next time two bits have to be added - bbitchange = true; + bitchange = true; } } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { // pulse length of 2 means: adding 2 bits "01" - bits[i] = 0; - bits[i + 1] = 1; - i++; + cnt++; + + word <<= 1; + word |= 0x1; } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_FULL_PERIOD)) { // pulse length of 3 indicates listen window -> clear last - // bit (= 0) and return - return --i; + // bit (= 0) and return (without parities) + word >>= 2; + return (extract_parities(word, data)) ? --cnt : 0; } } - - return 0; } //============================================================================== @@ -877,14 +841,14 @@ static bool standard_read(int *now) { // (standard read mode); number of read words is saved in int fwr = *now; - uint8_t bits[EM4X50_TAG_WORD] = {0}; + uint32_t data = 0x0; // start with the identification of two succsessive listening windows if (find_double_listen_window(false)) { // read and save words until following double listen window is detected - while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) - save_word((*now)++, bits); + while (get_word_from_bitstream(&data) == EM4X50_TAG_WORD) + em4x50_tag[(*now)++] = data; // number of detected words *now -= fwr; @@ -942,7 +906,6 @@ void em4x50_info(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; uint8_t addresses[] = {0x00, 0x00, 0x21, 0x00}; // fwr = 0, lwr = 33 - uint8_t password[] = {0x00, 0x00, 0x00, 0x00}; // default password init_tag(); em4x50_setup_read(); @@ -955,11 +918,6 @@ void em4x50_info(em4x50_data_t *etd) { // try to login with given password blogin = login(etd->password); - } else { - - // if no password is given, try to login with "0x00000000" - blogin = login(password); - } bsuccess = selective_read(addresses); @@ -967,8 +925,11 @@ void em4x50_info(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; + for (int i = 0; i < 34; i++) + Dbprintf("em4x5_tag[%i] = %08x", i, em4x50_tag[i]); + lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); } void em4x50_read(em4x50_data_t *etd) { @@ -1013,7 +974,7 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); } //============================================================================== @@ -1102,7 +1063,8 @@ void em4x50_write(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; - uint8_t word[4] = {0x00, 0x00, 0x00, 0x00}; + //uint8_t word[4] = {0x00, 0x00, 0x00, 0x00}; + uint32_t word = 0x0; uint8_t addresses[4] = {0x00, 0x00, 0x00, 0x00}; init_tag(); @@ -1133,15 +1095,27 @@ void em4x50_write(em4x50_data_t *etd) { if (selective_read(addresses)) { // compare with given word + word = em4x50_tag[etd->address]; + /* word[0] = tag.sectors[etd->address][0]; word[1] = tag.sectors[etd->address][1]; word[2] = tag.sectors[etd->address][2]; word[3] = tag.sectors[etd->address][3]; - msb2lsb_word(word); + */ + reflect32(word); - bsuccess = true; - for (int i = 0; i < 4; i++) - bsuccess &= (word[i] == etd->word[i]) ? true : false; + //bsuccess = true; + //for (int i = 0; i < 4; i++) + // bsuccess &= (word[i] == etd->word[i]) ? true : false; + uint32_t tmp = 0x0; + tmp = etd->word[0]; + tmp <<= 8; + tmp |= etd->word[1]; + tmp <<= 8; + tmp |= etd->word[2]; + tmp <<= 8; + tmp |= etd->word[3]; + bsuccess = (word == tmp); } } @@ -1151,7 +1125,7 @@ void em4x50_write(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); } void em4x50_write_password(em4x50_data_t *etd) { @@ -1223,8 +1197,7 @@ void em4x50_wipe(em4x50_data_t *etd) { // check if everything is zero bsuccess = true; for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++) - for (int j = 0; j < 4; j++) - bsuccess &= (tag.sectors[i][j] == 0) ? true : false; + bsuccess &= (em4x50_tag[i] == 0) ? true : false; } @@ -1244,7 +1217,7 @@ void em4x50_wipe(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_ACK, bsuccess, (uint8_t *)em4x50_tag, 136); } void em4x50_reset(void) { @@ -1364,49 +1337,33 @@ int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { em4x50_setup_read(); - if (get_signalproperties() && find_em4x50_tag()) { + if (get_signalproperties() && find_em4x50_tag()) status = brute(start, stop, pwd); - } else { + else status = PM3_ETIMEOUT; - } lf_finalize(); return status; } -int em4x50_standalone_read(uint64_t *words) { +int em4x50_standalone_read(uint32_t *words) { int now = 0; - uint8_t bits[EM4X50_TAG_WORD]; em4x50_setup_read(); - if (get_signalproperties() && find_em4x50_tag()) { - - if (find_double_listen_window(false)) { - - memset(bits, 0, sizeof(bits)); - - while (get_word_from_bitstream(bits) == EM4X50_TAG_WORD) { - words[now] = 0; - - for (int i = 0; i < EM4X50_TAG_WORD; i++) { - words[now] <<= 1; - words[now] += bits[i] & 1; - } - + if (get_signalproperties() && find_em4x50_tag()) + if (find_double_listen_window(false)) + while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) now++; - } - } - } return now; } void em4x50_watch() { - // reads continuously and displays standard reads of tag + // read continuously and display standard reads of tag int now = 0; @@ -1429,16 +1386,8 @@ void em4x50_watch() { for (int i = 0; i < now; i++) { Dbprintf("EM4x50 TAG ID: " - _GREEN_("%02x%02x%02x%02x") " (msb) - " - _GREEN_("%02x%02x%02x%02x") " (lsb)", - tag.sectors[i][0], - tag.sectors[i][1], - tag.sectors[i][2], - tag.sectors[i][3], - reflect8(tag.sectors[i][3]), - reflect8(tag.sectors[i][2]), - reflect8(tag.sectors[i][1]), - reflect8(tag.sectors[i][0])); + _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", + em4x50_tag[i], reflect32(em4x50_tag[i])); } } } diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 8c86cfb26..663559cd5 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -14,10 +14,10 @@ #include "../include/em4x50.h" typedef struct { - uint8_t sectors[34][7]; + uint8_t sectors[34][4]; } em4x50_tag_t; -int em4x50_standalone_read(uint64_t *words); +int em4x50_standalone_read(uint32_t *words); int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd); bool em4x50_sim_send_listen_window(void); bool em4x50_sim_send_word(uint32_t word); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index fc6bbb7e6..d4cf19a09 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -145,60 +145,13 @@ static int usage_lf_em4x50_watch(void) { return PM3_SUCCESS; } -static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t *words) { +static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { - // restructure received result in "em4x50_word_t" structure and check all - // parities including stop bit; result of each check is stored in structure + // restructure received result in "em4x50_word_t" structure - int p = 0, c[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - for (int i = fwr; i <= lwr; i++) { - - words[i].stopparity = true; - words[i].parity = true; - - for (int j = 0; j < 8; j++) - c[j] = 0; - - for (int j = 0; j < 4; j++) { - words[i].byte[j] = byte[i * 7 + j]; - words[i].row_parity[j] = (byte[i * 7 + 4] >> (3 - j)) & 1; - - // collect parities - p = 0; - - for (int k = 0; k < 8; k++) { - - // row parity - p ^= (words[i].byte[j] >> k) & 1; - - // column parity - c[k] ^= (words[i].byte[j] >> (7 - k)) & 1; - } - - // check row parities - words[i].rparity[j] = (words[i].row_parity[j] == p) ? true : false; - - if (!words[i].rparity[j]) - words[i].parity = false; - } - - // check column parities - words[i].col_parity = byte[i * 7 + 5]; - - for (int j = 0; j < 8; j++) { - words[i].cparity[j] = (((words[i].col_parity >> (7 - j)) & 1) == c[j]) ? true : false; - - if (!words[i].cparity[j]) - words[i].parity = false; - } - - // check stop bit - words[i].stopbit = byte[i * 7 + 6] & 1; - - if (words[i].stopbit == 1) - words[i].stopparity = false; - } + for (int i = fwr; i <= lwr; i++) + for (int j = 0; j < 4; j++) + words[i].byte[j] = data[i * 4 + (3 - j)]; } static void print_result(const em4x50_word_t *words, int fwr, int lwr) { diff --git a/include/em4x50.h b/include/em4x50.h index 5b2966253..ae6a53177 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -44,11 +44,8 @@ typedef struct { bool addr_given; bool pwd_given; bool newpwd_given; - uint8_t carrier; - uint8_t byte; uint8_t password[4]; uint8_t new_password[4]; - uint8_t addresses[4]; uint8_t address; uint8_t word[4]; uint32_t start_password; @@ -58,13 +55,6 @@ typedef struct { typedef struct { uint8_t byte[4]; - uint8_t row_parity[4]; - uint8_t col_parity; - uint8_t stopbit; - bool rparity[4]; - bool cparity[8]; - bool stopparity; - bool parity; } em4x50_word_t; #endif /* EM4X50_H__ */ From f8045e04344886916a2dc5e5597e34c10f35711c Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 14 Oct 2020 19:59:55 +0200 Subject: [PATCH 032/174] removed function call with timeout (initial call after starting pm3 client will always cause a timeout) --- client/src/cmdlfem4x50.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index d4cf19a09..50602e9fb 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -730,12 +730,8 @@ int CmdEM4x50Wipe(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd)); - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2 * TIMEOUT)) { - PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n"); - return PM3_ETIMEOUT; - } - + WaitForResponse(CMD_ACK, &resp); + // print response bool isOK = resp.status; if (isOK) { From a84074686b057c35060ddfdd97c1068ab6bdd28c Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 14 Oct 2020 20:01:15 +0200 Subject: [PATCH 033/174] removed global structure/variable for saving tag information --- armsrc/em4x50.c | 94 ++++++++++++++++++------------------------------- armsrc/em4x50.h | 4 --- 2 files changed, 35 insertions(+), 63 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 4c2bf2444..4fe84eb75 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -13,6 +13,7 @@ #include "dbprint.h" #include "lfadc.h" #include "commonutil.h" +#include "BigBuf.h" #include "em4x50.h" // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) @@ -49,17 +50,11 @@ #define EM4X50_COMMAND_TIMEOUT 5000 #define FPGA_TIMER_0 0 -static uint32_t em4x50_tag[34] = {0x0}; int gHigh = 0; int gLow = 0; // auxiliary functions -static void init_tag(void) { - - memset(em4x50_tag, 0x00, sizeof(em4x50_tag)); -} - static void msb2lsb_word(uint8_t *word) { // reorders given according to EM4x50 datasheet (msb -> lsb) @@ -165,7 +160,7 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD); + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_HALF_PERIOD); if (AT91C_BASE_SSC->SSC_RHR > noise) { signal_found = true; @@ -211,11 +206,11 @@ static int get_next_bit(void) { // "find_double_listen_window" and "check_ack" // get sample at 3/4 of bit period - wait_timer(0, T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - wait_timer(0, T0 * EM4X50_T_TAG_QUARTER_PERIOD); + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_QUARTER_PERIOD); // decide wether "0" or "1" if (sample > gHigh) @@ -538,17 +533,16 @@ bool em4x50_sim_send_listen_window(void) { ++check; } - if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) { + if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); - } else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) { + else if (t >= 3 * EM4X50_T_TAG_FULL_PERIOD) OPEN_COIL(); - } else if (t >= EM4X50_T_TAG_FULL_PERIOD) { + else if (t >= EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); - } else if (t >= EM4X50_T_TAG_HALF_PERIOD) { + else if (t >= EM4X50_T_TAG_HALF_PERIOD) OPEN_COIL(); - } else { + else SHORT_COIL(); - } check = 0; @@ -831,24 +825,24 @@ static bool reset(void) { return false; } + //============================================================================== // read functions //============================================================================== -static bool standard_read(int *now) { +static bool standard_read(int *now, uint32_t *words) { // reads data that tag transmits when exposed to reader field // (standard read mode); number of read words is saved in int fwr = *now; - uint32_t data = 0x0; // start with the identification of two succsessive listening windows if (find_double_listen_window(false)) { // read and save words until following double listen window is detected - while (get_word_from_bitstream(&data) == EM4X50_TAG_WORD) - em4x50_tag[(*now)++] = data; + while (get_word_from_bitstream(&words[*now]) == EM4X50_TAG_WORD) + (*now)++; // number of detected words *now -= fwr; @@ -863,7 +857,7 @@ static bool standard_read(int *now) { return false; } -static bool selective_read(uint8_t addresses[4]) { +static bool selective_read(uint8_t addresses[4], uint32_t *words) { // reads from "first word read" (fwr = addresses[3]) to "last word read" // (lwr = addresses[2]) @@ -885,7 +879,7 @@ static bool selective_read(uint8_t addresses[4]) { if (check_ack(false)) // save and verify via standard read mode (compare number of words) - if (standard_read(&now)) + if (standard_read(&now, words)) if (now == (lwr - fwr + 1)) return true; @@ -906,8 +900,8 @@ void em4x50_info(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; uint8_t addresses[] = {0x00, 0x00, 0x21, 0x00}; // fwr = 0, lwr = 33 + uint32_t words[32] = {0x0}; - init_tag(); em4x50_setup_read(); // set gHigh and gLow @@ -920,16 +914,13 @@ void em4x50_info(em4x50_data_t *etd) { } - bsuccess = selective_read(addresses); + bsuccess = selective_read(addresses, words); } status = (bsuccess << 1) + blogin; - for (int i = 0; i < 34; i++) - Dbprintf("em4x5_tag[%i] = %08x", i, em4x50_tag[i]); - lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); + reply_ng(CMD_ACK, status, (uint8_t *)words, 136); } void em4x50_read(em4x50_data_t *etd) { @@ -943,8 +934,8 @@ void em4x50_read(em4x50_data_t *etd) { int now = 0; uint8_t status = 0; uint8_t addresses[] = {0x00, 0x00, 0x00, 0x00}; + uint32_t words[32] = {0x0}; - init_tag(); em4x50_setup_read(); // set gHigh and gLow @@ -960,12 +951,12 @@ void em4x50_read(em4x50_data_t *etd) { // only one word has to be read -> first word read = last word read addresses[2] = addresses[3] = etd->address; - bsuccess = selective_read(addresses); + bsuccess = selective_read(addresses, words); } else { // standard read mode - bsuccess = standard_read(&now); + bsuccess = standard_read(&now, words); } } @@ -974,7 +965,8 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); + reply_ng(CMD_ACK, status, (uint8_t *)words, 136); + //reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); } //============================================================================== @@ -1063,11 +1055,9 @@ void em4x50_write(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; - //uint8_t word[4] = {0x00, 0x00, 0x00, 0x00}; - uint32_t word = 0x0; uint8_t addresses[4] = {0x00, 0x00, 0x00, 0x00}; + uint32_t words[34] = {0x0}; - init_tag(); em4x50_setup_read(); // set gHigh and gLow @@ -1092,21 +1082,9 @@ void em4x50_write(em4x50_data_t *etd) { // call a selective read addresses[2] = addresses[3] = etd->address; - if (selective_read(addresses)) { + if (selective_read(addresses, words)) { // compare with given word - word = em4x50_tag[etd->address]; - /* - word[0] = tag.sectors[etd->address][0]; - word[1] = tag.sectors[etd->address][1]; - word[2] = tag.sectors[etd->address][2]; - word[3] = tag.sectors[etd->address][3]; - */ - reflect32(word); - - //bsuccess = true; - //for (int i = 0; i < 4; i++) - // bsuccess &= (word[i] == etd->word[i]) ? true : false; uint32_t tmp = 0x0; tmp = etd->word[0]; tmp <<= 8; @@ -1115,8 +1093,7 @@ void em4x50_write(em4x50_data_t *etd) { tmp |= etd->word[2]; tmp <<= 8; tmp |= etd->word[3]; - bsuccess = (word == tmp); - + bsuccess = (words[etd->address] == reflect32(tmp)); } } } @@ -1125,7 +1102,7 @@ void em4x50_write(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); + reply_ng(CMD_ACK, status, (uint8_t *)words, 136); } void em4x50_write_password(em4x50_data_t *etd) { @@ -1136,7 +1113,6 @@ void em4x50_write_password(em4x50_data_t *etd) { uint8_t rpwd[4] = {0x0, 0x0, 0x0, 0x0}; uint8_t rnewpwd[4] = {0x0, 0x0, 0x0, 0x0}; - init_tag(); em4x50_setup_read(); // set gHigh and gLow @@ -1170,8 +1146,8 @@ void em4x50_wipe(em4x50_data_t *etd) { bool bsuccess = false; uint8_t zero[4] = {0, 0, 0, 0}; uint8_t addresses[4] = {0, 0, EM4X50_NO_WORDS - 3, 1}; + uint32_t words[34] = {0x0}; - init_tag(); em4x50_setup_read(); // set gHigh and gLow @@ -1192,12 +1168,12 @@ void em4x50_wipe(em4x50_data_t *etd) { // login not necessary because protected word has been set to 0 // -> no read protected words // -> selective read can be called immediately - if (selective_read(addresses)) { + if (selective_read(addresses, words)) { // check if everything is zero bsuccess = true; for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++) - bsuccess &= (em4x50_tag[i] == 0) ? true : false; + bsuccess &= (words[i] == 0); } @@ -1217,7 +1193,7 @@ void em4x50_wipe(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)em4x50_tag, 136); + reply_ng(CMD_ACK, bsuccess, (uint8_t *)words, 136); } void em4x50_reset(void) { @@ -1366,19 +1342,19 @@ void em4x50_watch() { // read continuously and display standard reads of tag int now = 0; + uint32_t words[34] = {0x0}; - init_tag(); em4x50_setup_read(); while (BUTTON_PRESS() == false) { WDT_HIT(); - init_tag(); + memset(words, 0, sizeof(words)); now = 0; if (get_signalproperties() && find_em4x50_tag()) { - standard_read(&now); + standard_read(&now, words); if (now > 0) { @@ -1387,7 +1363,7 @@ void em4x50_watch() { Dbprintf("EM4x50 TAG ID: " _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", - em4x50_tag[i], reflect32(em4x50_tag[i])); + words[i], reflect32(words[i])); } } } diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 663559cd5..9822d604d 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -13,10 +13,6 @@ #include "../include/em4x50.h" -typedef struct { - uint8_t sectors[34][4]; -} em4x50_tag_t; - int em4x50_standalone_read(uint32_t *words); int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd); bool em4x50_sim_send_listen_window(void); From a04002ab1b40ef6392bd22bdeb3585da4a8df145 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 22 Oct 2020 00:42:18 +0200 Subject: [PATCH 034/174] redesign --- armsrc/appmain.c | 4 +- armsrc/em4x50.c | 299 ++++++++++++++------------------------- armsrc/em4x50.h | 4 +- client/src/cmdlfem4x50.c | 243 +++++++++++++++---------------- include/em4x50.h | 12 +- 5 files changed, 228 insertions(+), 334 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index bcf0a656f..9dc2472c8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1034,7 +1034,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_WIPE: { - em4x50_wipe((em4x50_data_t *)packet->data.asBytes); + em4x50_wipe((uint32_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_BRUTE: { @@ -1042,7 +1042,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_LOGIN: { - em4x50_login((em4x50_data_t *)packet->data.asBytes); + em4x50_login((uint32_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_RESET: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 4fe84eb75..17423caef 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -13,7 +13,6 @@ #include "dbprint.h" #include "lfadc.h" #include "commonutil.h" -#include "BigBuf.h" #include "em4x50.h" // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) @@ -47,45 +46,17 @@ #define EM4X50_COMMAND_WRITE_PASSWORD 0x11 #define EM4X50_COMMAND_SELECTIVE_READ 0x0A -#define EM4X50_COMMAND_TIMEOUT 5000 -#define FPGA_TIMER_0 0 - int gHigh = 0; int gLow = 0; // auxiliary functions -static void msb2lsb_word(uint8_t *word) { - - // reorders given according to EM4x50 datasheet (msb -> lsb) - - uint8_t buff[4]; - buff[0] = reflect8(word[3]); - buff[1] = reflect8(word[2]); - buff[2] = reflect8(word[1]); - buff[3] = reflect8(word[0]); - - word[0] = buff[0]; - word[1] = buff[1]; - word[2] = buff[2]; - word[3] = buff[3]; -} - -static void wait_timer(int timer, uint32_t period) { +static void wait_timer0(uint32_t period) { // do nothing for using timer - if (timer == FPGA_TIMER_0) { - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < period); - - } else { - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC1->TC_CV < period); - - } + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < period); } static void em4x50_setup_read(void) { @@ -160,7 +131,7 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_HALF_PERIOD); + wait_timer0(T0 * EM4X50_T_TAG_HALF_PERIOD); if (AT91C_BASE_SSC->SSC_RHR > noise) { signal_found = true; @@ -194,31 +165,31 @@ static bool get_signalproperties(void) { // set global envelope variables gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; + + Dbprintf("gHigh = %i, gLow = %i", gHigh, gLow); + return true; } -static int get_next_bit(void) { +static bool unvalid_bit(void) { - // returns bit value (or EM4X50_BIT_OTHER -> no bit pattern) by evaluating - // a single sample within a bit period (given there is no LIW, ACK or NAK) - // This function is not used for decoding, it is only used for identifying - // a listen window (return value = EM4X50_BIT_OTHER) in functions + // returns true if bit is undefined by evaluating a single sample within + // a bit period (given there is no LIW, ACK or NAK) + // This function is used for identifying a listen window in functions // "find_double_listen_window" and "check_ack" // get sample at 3/4 of bit period - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + wait_timer0(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_QUARTER_PERIOD); + wait_timer0(T0 * EM4X50_T_TAG_QUARTER_PERIOD); - // decide wether "0" or "1" - if (sample > gHigh) - return EM4X50_BIT_0; - else if (sample < gLow) - return EM4X50_BIT_1; + // bit in "undefined" state? + if (sample <= gHigh && sample >= gLow) + return true; - return EM4X50_BIT_OTHER; + return false; } static uint32_t get_pulse_length(void) { @@ -229,9 +200,8 @@ static uint32_t get_pulse_length(void) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - while (sample > gLow && (timeout--)) { + while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } if (timeout == 0) return 0; @@ -239,17 +209,15 @@ static uint32_t get_pulse_length(void) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample < gHigh && (timeout--)) { + while (sample < gHigh && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } if (timeout == 0) return 0; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample > gLow && (timeout--)) { + while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } if (timeout == 0) return 0; @@ -319,13 +287,18 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { em4x50_reader_send_bit(parity); } -static void em4x50_reader_send_word(const uint8_t bytes[4]) { +static void em4x50_reader_send_word(const uint32_t word) { // send 32 bit word with parity bits according to EM4x50 datasheet + // word hast be sent in msb notation - for (int i = 0; i < 4; i++) + uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; + + for (int i = 0; i < 4; i++) { + bytes[i] = (word >> (24 - (8 * i))) & 0xFF; em4x50_reader_send_byte_with_parity(bytes[i]); - + } + // send column parities em4x50_reader_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); @@ -387,12 +360,12 @@ static int find_double_listen_window(bool bcommand) { // second window follows - sync on this to issue a command // skip the next bit... - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer0(T0 * EM4X50_T_TAG_FULL_PERIOD); // ...and check if the following bit does make sense // (if not it is the correct position within the second // listen window) - if (get_next_bit() == EM4X50_BIT_OTHER) { + if (unvalid_bit()) { // send RM for request mode em4x50_reader_send_bit(0); @@ -606,11 +579,11 @@ static bool check_ack(bool bliw) { // wait for 2 bits (remaining "bit" of ACK signal + first // "bit" of listen window) - wait_timer(FPGA_TIMER_0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); + wait_timer0(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); // check for listen window (if first bit cannot be inerpreted // as a valid bit it must belong to a listen window) - if (get_next_bit() == EM4X50_BIT_OTHER) { + if (unvalid_bit()) { // send RM for request mode em4x50_reader_send_bit(0); @@ -776,7 +749,7 @@ static int get_word_from_bitstream(uint32_t *data) { // login function //============================================================================== -static bool login(uint8_t password[4]) { +static bool login(uint32_t password) { // simple login to EM4x50, // used in operations that require authentication @@ -857,15 +830,14 @@ static bool standard_read(int *now, uint32_t *words) { return false; } -static bool selective_read(uint8_t addresses[4], uint32_t *words) { +static bool selective_read(uint32_t addresses, uint32_t *words) { - // reads from "first word read" (fwr = addresses[3]) to "last word read" - // (lwr = addresses[2]) + // reads from "first word read" (fwr) to "last word read" (lwr) // result is verified by "standard read mode" - int fwr = addresses[3]; // first word read - int lwr = addresses[2]; // last word read - int now = fwr; // number of words + uint8_t fwr = addresses & 0xFF; // first word read (first byte) + uint8_t lwr = (addresses >> 8) & 0xFF; // last word read (second byte) + int now = fwr; // number of words if (request_receive_mode()) { @@ -894,12 +866,10 @@ static bool selective_read(uint8_t addresses[4], uint32_t *words) { void em4x50_info(em4x50_data_t *etd) { // collects as much information as possible via selective read mode - // if no password is given -> try with standard password "0x00000000" - // otherwise continue without login bool bsuccess = false, blogin = false; uint8_t status = 0; - uint8_t addresses[] = {0x00, 0x00, 0x21, 0x00}; // fwr = 0, lwr = 33 + uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) uint32_t words[32] = {0x0}; em4x50_setup_read(); @@ -907,12 +877,9 @@ void em4x50_info(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - if (etd->pwd_given) { - - // try to login with given password - blogin = login(etd->password); - - } + // login with given password + if (etd->pwd_given) + blogin = login(etd->password1); bsuccess = selective_read(addresses, words); } @@ -933,7 +900,6 @@ void em4x50_read(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; int now = 0; uint8_t status = 0; - uint8_t addresses[] = {0x00, 0x00, 0x00, 0x00}; uint32_t words[32] = {0x0}; em4x50_setup_read(); @@ -947,11 +913,10 @@ void em4x50_read(em4x50_data_t *etd) { // try to login with given password if (etd->pwd_given) - blogin = login(etd->password); + blogin = login(etd->password1); // only one word has to be read -> first word read = last word read - addresses[2] = addresses[3] = etd->address; - bsuccess = selective_read(addresses, words); + bsuccess = selective_read(etd->addresses, words); } else { @@ -966,14 +931,13 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); reply_ng(CMD_ACK, status, (uint8_t *)words, 136); - //reply_ng(CMD_ACK, status, (uint8_t *)em4x50_tag, 136); } //============================================================================== // write functions //============================================================================== -static bool write(uint8_t word[4], uint8_t address) { +static bool write(uint32_t word, uint32_t addresses) { // writes to specified
@@ -983,13 +947,13 @@ static bool write(uint8_t word[4], uint8_t address) { em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_WRITE); // send address data - em4x50_reader_send_byte_with_parity(address); + em4x50_reader_send_byte_with_parity(addresses & 0xFF); // send data em4x50_reader_send_word(word); // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); + wait_timer0(T0 * EM4X50_T_TAG_TWA); // look for ACK sequence if (check_ack(false)) { @@ -1009,7 +973,7 @@ static bool write(uint8_t word[4], uint8_t address) { return false; } -static bool write_password(uint8_t password[4], uint8_t new_password[4]) { +static bool write_password(uint32_t password, uint32_t new_password) { // changes password from to @@ -1022,7 +986,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { em4x50_reader_send_word(password); // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); + wait_timer0(T0 * EM4X50_T_TAG_TPP); // look for ACK sequence and send rm request // during following listen window @@ -1032,7 +996,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { em4x50_reader_send_word(new_password); // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); + wait_timer0(T0 * EM4X50_T_TAG_TWA); if (check_ack(false)) if (check_ack(false)) @@ -1055,7 +1019,6 @@ void em4x50_write(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; - uint8_t addresses[4] = {0x00, 0x00, 0x00, 0x00}; uint32_t words[34] = {0x0}; em4x50_setup_read(); @@ -1063,37 +1026,25 @@ void em4x50_write(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - // reorder word according to datasheet - msb2lsb_word(etd->word); - // if password is given try to login first if (etd->pwd_given) - blogin = login(etd->password); + blogin = login(etd->password1); // write word to given address - if (write(etd->word, etd->address)) { + if (write(etd->word, etd->addresses)) { // to verify result reset EM4x50 if (reset()) { // if password is given login if (etd->pwd_given) - blogin &= login(etd->password); + blogin &= login(etd->password1); // call a selective read - addresses[2] = addresses[3] = etd->address; - if (selective_read(addresses, words)) { + if (selective_read(etd->addresses, words)) { // compare with given word - uint32_t tmp = 0x0; - tmp = etd->word[0]; - tmp <<= 8; - tmp |= etd->word[1]; - tmp <<= 8; - tmp |= etd->word[2]; - tmp <<= 8; - tmp |= etd->word[3]; - bsuccess = (words[etd->address] == reflect32(tmp)); + bsuccess = (words[etd->addresses & 0xFF] == reflect32(etd->word)); } } } @@ -1110,43 +1061,29 @@ void em4x50_write_password(em4x50_data_t *etd) { // simple change of password bool bsuccess = false; - uint8_t rpwd[4] = {0x0, 0x0, 0x0, 0x0}; - uint8_t rnewpwd[4] = {0x0, 0x0, 0x0, 0x0}; em4x50_setup_read(); // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - // lsb -> msb - rpwd[0] = reflect8(etd->password[3]); - rpwd[1] = reflect8(etd->password[2]); - rpwd[2] = reflect8(etd->password[1]); - rpwd[3] = reflect8(etd->password[0]); - - rnewpwd[0] = reflect8(etd->new_password[3]); - rnewpwd[1] = reflect8(etd->new_password[2]); - rnewpwd[2] = reflect8(etd->new_password[1]); - rnewpwd[3] = reflect8(etd->new_password[0]); - // login and change password - if (login(rpwd)) { - bsuccess = write_password(rpwd, rnewpwd); - } + if (login(etd->password1)) + bsuccess = write_password(etd->password1, etd->password2); } lf_finalize(); reply_ng(CMD_ACK, bsuccess, 0, 0); } -void em4x50_wipe(em4x50_data_t *etd) { +void em4x50_wipe(uint32_t *password) { // set all data of EM4x50 tag to 0x0 including password bool bsuccess = false; - uint8_t zero[4] = {0, 0, 0, 0}; - uint8_t addresses[4] = {0, 0, EM4X50_NO_WORDS - 3, 1}; + uint32_t addresses = 0x00001E01; // from fwr = 1 to lwr = 31 (0x1E) uint32_t words[34] = {0x0}; + uint32_t zero = 0x0; em4x50_setup_read(); @@ -1154,15 +1091,14 @@ void em4x50_wipe(em4x50_data_t *etd) { if (get_signalproperties() && find_em4x50_tag()) { // login first - if (login(etd->password)) { + if (login(*password)) { // write 0x0 to each address but ignore addresses // 0 -> password, 32 -> serial, 33 -> uid - // writing 34 words takes about 3.6 seconds -> high timeout needed - for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++) + for (int i = 1; i <= 33; i++) write(zero, i); - // to verify result reset EM4x50 + // to verify result -> reset EM4x50 if (reset()) { // login not necessary because protected word has been set to 0 @@ -1172,7 +1108,7 @@ void em4x50_wipe(em4x50_data_t *etd) { // check if everything is zero bsuccess = true; - for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++) + for (int i = 1; i <= 33; i++) bsuccess &= (words[i] == 0); } @@ -1181,8 +1117,8 @@ void em4x50_wipe(em4x50_data_t *etd) { // so far everything is fine // last task: reset password - if (login(etd->password)) - bsuccess = write_password(etd->password, zero); + if (login(*password)) + bsuccess = write_password(*password, zero); // verify by login with new password if (bsuccess) @@ -1205,37 +1141,24 @@ void em4x50_reset(void) { em4x50_setup_read(); // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - + if (get_signalproperties() && find_em4x50_tag()) status = reset(); - } lf_finalize(); reply_ng(CMD_ACK, status, 0, 0); } -void em4x50_login(em4x50_data_t *etd) { +void em4x50_login(uint32_t *password) { // login into EM4x50 uint8_t status = false; - uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; - uint32_t rpwd = 0x0; em4x50_setup_read(); // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // lsb -> msb - rpwd = reflect32(etd->login_password); - - // convert to "old" data format - for (int i = 0; i < 4; i++) - bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; - - status = login(bytes); - } + if (get_signalproperties() && find_em4x50_tag()) + status = login(*password); lf_finalize(); reply_ng(CMD_ACK, status, 0, 0); @@ -1247,18 +1170,10 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { bool pwd_found = false; int cnt = 0; - uint32_t rpwd = 0x0; - uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; for (*pwd = start; *pwd <= stop; (*pwd)++) { - // lsb -> msb - rpwd = reflect32(*pwd); - - for (int i = 0; i < 4; i++) - bytes[i] = (rpwd >> ((3 - i) * 8)) & 0xFF; - - if (login(bytes)) { + if (login(*pwd)) { pwd_found = true; break; } @@ -1274,7 +1189,7 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { } // print data - Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, rpwd, *pwd); + Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, reflect32(*pwd), *pwd); } if (BUTTON_PRESS()) @@ -1299,44 +1214,12 @@ void em4x50_brute(em4x50_data_t *etd) { em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) - bsuccess = brute(etd->start_password, etd->stop_password, &pwd); + bsuccess = brute(etd->password1, etd->password2, &pwd); lf_finalize(); reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); } -int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // envoke password search in standalone mode - - int status = false; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - status = brute(start, stop, pwd); - else - status = PM3_ETIMEOUT; - - lf_finalize(); - - return status; -} - -int em4x50_standalone_read(uint32_t *words) { - - int now = 0; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - if (find_double_listen_window(false)) - while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) - now++; - - return now; -} - void em4x50_watch() { // read continuously and display standard reads of tag @@ -1373,3 +1256,39 @@ void em4x50_watch() { lf_finalize(); reply_ng(CMD_ACK, 1, 0, 0); } + +//============================================================================== +// standalone mode functions +//============================================================================== + +int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { + + // envoke password search in standalone mode + + int status = false; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) + status = brute(start, stop, pwd); + else + status = PM3_ETIMEOUT; + + lf_finalize(); + + return status; +} + +int em4x50_standalone_read(uint32_t *words) { + + int now = 0; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) + if (find_double_listen_window(false)) + while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) + now++; + + return now; +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 9822d604d..c851f04e4 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -23,9 +23,9 @@ void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_write_password(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); -void em4x50_wipe(em4x50_data_t *etd); +void em4x50_wipe(uint32_t *password); void em4x50_brute(em4x50_data_t *etd); -void em4x50_login(em4x50_data_t *etd); +void em4x50_login(uint32_t *password); void em4x50_reset(void); void em4x50_watch(void); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 50602e9fb..83027e4be 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -22,7 +22,7 @@ static int usage_lf_em4x50_info(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " v - verbose output"); - PrintAndLogEx(NORMAL, " p - password (hex) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info p fa225de1")); @@ -37,8 +37,8 @@ static int usage_lf_em4x50_write(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " a - memory address to write to (dec)"); - PrintAndLogEx(NORMAL, " w - word to write (hex, lsb notation)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb notation) (optional)"); + PrintAndLogEx(NORMAL, " w - word to write (hex, lsb)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write a 3 w deadc0de")); PrintAndLogEx(NORMAL, ""); @@ -50,8 +50,8 @@ static int usage_lf_em4x50_write_password(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] [p ] [n ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb notation)"); - PrintAndLogEx(NORMAL, " n - new password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); + PrintAndLogEx(NORMAL, " n - new password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write_password p 11223344 n 01020304")); PrintAndLogEx(NORMAL, ""); @@ -64,7 +64,7 @@ static int usage_lf_em4x50_read(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " a - memory address to read (dec) (optional)"); - PrintAndLogEx(NORMAL, " p - password (hex) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read a 2 p 00000000")); @@ -78,7 +78,7 @@ static int usage_lf_em4x50_dump(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " f - overide filename prefix (optional). Default is based on UID"); - PrintAndLogEx(NORMAL, " p - password (hex) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump p 11223344")); @@ -91,7 +91,7 @@ static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_wipe [h] [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wipe p 11223344")); PrintAndLogEx(NORMAL, ""); @@ -103,8 +103,8 @@ static int usage_lf_em4x50_brute(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_brute [h] f l "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - start password (hex, lsb notation)"); - PrintAndLogEx(NORMAL, " l - stop password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " f - start password (hex, lsb)"); + PrintAndLogEx(NORMAL, " l - stop password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_brute f 11200000 l 11300000")); PrintAndLogEx(NORMAL, ""); @@ -116,7 +116,7 @@ static int usage_lf_em4x50_login(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_login [h] p "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb notation)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_login p 11200000")); PrintAndLogEx(NORMAL, ""); @@ -251,7 +251,7 @@ bool detect_4x50_block(void) { em4x50_data_t etd = { .pwd_given = false, .addr_given = true, - .address = EM4X50_DEVICE_ID, + .addresses = EM4X50_DEVICE_ID, }; em4x50_word_t words[EM4X50_NO_WORDS]; return (em4x50_read(&etd, words, false) == PM3_SUCCESS); @@ -261,7 +261,7 @@ int read_em4x50_uid(void) { em4x50_data_t etd = { .pwd_given = false, .addr_given = true, - .address = EM4X50_DEVICE_SERIAL, + .addresses = EM4X50_DEVICE_SERIAL, }; em4x50_word_t words[EM4X50_NO_WORDS]; int res = em4x50_read(&etd, words, false); @@ -279,7 +279,7 @@ int CmdEM4x50Info(const char *Cmd) { uint8_t cmdp = 0; em4x50_data_t etd; etd.pwd_given = false; - + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -287,21 +287,13 @@ int CmdEM4x50Info(const char *Cmd) { return usage_lf_em4x50_info(); case 'p': - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); etd.pwd_given = true; cmdp += 2; break; - case 'v': - verbose = true; - cmdp += 1; - break; - default: - PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -337,48 +329,48 @@ int CmdEM4x50Write(const char *Cmd) { em4x50_data_t etd = { .pwd_given = false }; bool errors = false, bword = false, baddr = false; + uint8_t address = 0x0; uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { + + case 'h': return usage_lf_em4x50_write(); - } - case 'p': { - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + + case 'p': + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); etd.pwd_given = true; cmdp += 2; break; - } - case 'w': { - if (param_gethex(Cmd, cmdp + 1, etd.word, 8)) { - PrintAndLogEx(FAILED, "\n word has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + + case 'w': + etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); bword = true; cmdp += 2; break; - } - case 'a': { - param_getdec(Cmd, cmdp + 1, &etd.address); + + case 'a': + param_getdec(Cmd, cmdp + 1, &address); // validation - if (etd.address < 1 || etd.address > 31) { - PrintAndLogEx(FAILED, "\n error, address has to be in range [1-31]\n"); + if (address < 1 || address > 31) { + PrintAndLogEx(FAILED, "error, address has to be in range [1-31]\n"); return PM3_EINVARG; } + etd.addresses = address; // lwr + etd.addresses <<= 8; + etd.addresses |= address; // fwr baddr = true; cmdp += 2; break; - } - default: { - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; - } + } } @@ -405,32 +397,20 @@ int CmdEM4x50Write(const char *Cmd) { PrintAndLogEx(FAILED, "login failed"); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%s"), sprint_hex_inrow(etd.password, 4)); + PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%08x"), etd.password1); } // display result of writing operation in structured format uint8_t *data = resp.data.asBytes; em4x50_word_t words[EM4X50_NO_WORDS]; - prepare_result(data, etd.address, etd.address, words); - print_result(words, etd.address, etd.address); + prepare_result(data, address, address, words); + print_result(words, address, address); PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", etd.address); + PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", address); return PM3_SUCCESS; } -static void print_write_password_result(PacketResponseNG *resp, const em4x50_data_t *etd) { - - // display result of password changing operation - - char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0}; - - sprintf(pstring, "\n writing new password " _GREEN_("ok")); - strcat(string, pstring); - - PrintAndLogEx(NORMAL, "%s\n", string); -} - int CmdEM4x50WritePassword(const char *Cmd) { // envokes changing the password of EM4x50 tag @@ -442,7 +422,6 @@ int CmdEM4x50WritePassword(const char *Cmd) { // init etd.pwd_given = false; - etd.newpwd_given = false; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -451,27 +430,20 @@ int CmdEM4x50WritePassword(const char *Cmd) { return usage_lf_em4x50_write_password(); case 'p': - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } - bpwd = true; + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); etd.pwd_given = true; + bpwd = true; cmdp += 2; break; case 'n': - if (param_gethex(Cmd, cmdp + 1, etd.new_password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + etd.password2 = param_get32ex(Cmd, cmdp + 1, 0, 16); bnpwd = true; - etd.newpwd_given = true; cmdp += 2; break; default: - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -489,11 +461,11 @@ int CmdEM4x50WritePassword(const char *Cmd) { } success = (bool)resp.status; - // get, prepare and print response + // print response if (success) - print_write_password_result(&resp, &etd); + PrintAndLogEx(SUCCESS, "\nwriting new password " _GREEN_("ok") "\n"); else - PrintAndLogEx(NORMAL, "\nwriting password " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "\nwriting password " _RED_("failed") "\n"); return (success) ? PM3_SUCCESS : PM3_ESOFT; } @@ -534,14 +506,14 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { PrintAndLogEx(FAILED, "login failed"); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%s"), sprint_hex_inrow(etd->password, 4)); + PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%08x"), etd->password1); } uint8_t *data = resp.data.asBytes; em4x50_word_t words[EM4X50_NO_WORDS]; int now = (resp.status & STATUS_NO_WORDS) >> 2; if (edata.addr_given) { - prepare_result(data, etd->address, etd->address, words); + prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); } else { prepare_result(data, 0, now - 1, words); } @@ -551,7 +523,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { } if (edata.addr_given) - print_result(words, etd->address, etd->address); + print_result(words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF); else print_result(words, 0, now - 1); @@ -560,47 +532,48 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { int CmdEM4x50Read(const char *Cmd) { + uint8_t address = 0x0; em4x50_data_t etd; memset(&etd, 0x00, sizeof(em4x50_data_t)); etd.pwd_given = false; etd.addr_given = false; - etd.newpwd_given = false; bool errors = false; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { + + case 'h': return usage_lf_em4x50_read(); - } + case 'a': { - param_getdec(Cmd, cmdp + 1, &etd.address); + param_getdec(Cmd, cmdp + 1, &address); + // lsb: byte 1 = fwr, byte 2 = lwr, byte 3 = 0x0, byte 4 = 0x0 + etd.addresses = address; // lwr + etd.addresses <<= 8; + etd.addresses |= address; // fwr // validation - if (etd.address <= 0 || etd.address >= EM4X50_NO_WORDS) { - PrintAndLogEx(FAILED, "\n error, address has to be in range [1-33]\n"); + if (address <= 0 || address >= EM4X50_NO_WORDS) { + PrintAndLogEx(FAILED, "error, address has to be in range [1-33]\n"); return PM3_EINVARG; } etd.addr_given = true; cmdp += 2; break; } - case 'p': { - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + case 'p': + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); etd.pwd_given = true; cmdp += 2; break; - } - default: { - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; - } } } @@ -616,7 +589,6 @@ int CmdEM4x50Dump(const char *Cmd) { em4x50_data_t etd; etd.pwd_given = false; etd.addr_given = false; - etd.newpwd_given = false; char filename[FILE_PATH_SIZE] = {0x00}; char *fptr = filename; @@ -625,24 +597,24 @@ int CmdEM4x50Dump(const char *Cmd) { uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x50_dump(); break; + case 'f': param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); cmdp += 2; break; - case 'p': { - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n"); - return PM3_EINVARG; - } + + case 'p': + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); etd.pwd_given = true; cmdp += 2; break; - } + default: - PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; }; @@ -698,38 +670,36 @@ int CmdEM4x50Wipe(const char *Cmd) { // fills EM4x50 tag with zeros including password - bool errors = false, bpwd = false; + bool errors = false, pwd_given = false; uint8_t cmdp = 0; - em4x50_data_t etd; + uint32_t password = 0x0; PacketResponseNG resp; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x50_wipe(); case 'p': - if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) { - PrintAndLogEx(FAILED, "\npassword has to be 8 hex symbols\n"); - return PM3_EINVARG; - } - bpwd = true; + password = param_get32ex(Cmd, cmdp + 1, 0, 16); + pwd_given = true; cmdp += 2; break; default: - PrintAndLogEx(WARNING, "\nUnknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } } - if (errors || !bpwd) + if (errors || !pwd_given) return usage_lf_em4x50_wipe(); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd)); + SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_ACK, &resp); // print response @@ -756,20 +726,24 @@ int CmdEM4x50Brute(const char *Cmd) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x50_brute(); + case 'f': - etd.start_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); startpwd = true; cmdp += 2; break; + case 'l': - etd.stop_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + etd.password2 = param_get32ex(Cmd, cmdp + 1, 0, 16); stoppwd = true; cmdp += 2; break; + default: - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -779,14 +753,14 @@ int CmdEM4x50Brute(const char *Cmd) { return usage_lf_em4x50_brute(); // print some information - no_iter = etd.stop_password - etd.start_password + 1; + no_iter = etd.password2 - etd.password1 + 1; dur_s = no_iter / speed; dur_h = dur_s / 3600; dur_m = (dur_s - dur_h * 3600) / 60; dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(NORMAL, "\ntrying %i passwords in range [0x%08x, 0x%08x]", - no_iter, etd.start_password, etd.stop_password); - PrintAndLogEx(NORMAL, "estimated duration: %ih%im%is\n", dur_h, dur_m, dur_s); + PrintAndLogEx(INFO, "trying %i passwords in range [0x%08x, 0x%08x]", + no_iter, etd.password1, etd.password2); + PrintAndLogEx(INFO, "estimated duration: %ih%im%is", dur_h, dur_m, dur_s); // start clearCommandBuffer(); @@ -795,9 +769,9 @@ int CmdEM4x50Brute(const char *Cmd) { // print response if ((bool)resp.status) - PrintAndLogEx(NORMAL, "\npassword " _GREEN_("found") ": 0x%08x\n", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "\npassword " _GREEN_("found") ": 0x%08x\n", resp.data.asDwords[0]); else - PrintAndLogEx(NORMAL, "\npassword: " _RED_("not found") "\n"); + PrintAndLogEx(FAILED, "\npassword: " _RED_("not found") "\n"); return PM3_SUCCESS; } @@ -806,21 +780,24 @@ int CmdEM4x50Login(const char *Cmd) { bool errors = false, pwd_given = false; uint8_t cmdp = 0; - em4x50_data_t etd; + uint32_t password = 0x0; PacketResponseNG resp; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x50_login(); + case 'p': - etd.login_password = param_get32ex(Cmd, cmdp + 1, 0, 16); + password = param_get32ex(Cmd, cmdp + 1, 0, 16); pwd_given = true; cmdp += 2; break; + default: - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -831,14 +808,14 @@ int CmdEM4x50Login(const char *Cmd) { // start clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&etd, sizeof(etd)); + SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_ACK, &resp); // print response if ((bool)resp.status) - PrintAndLogEx(NORMAL, "\nlogin " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "\nlogin " _GREEN_("ok") "\n"); else - PrintAndLogEx(NORMAL, "\nlogin " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "\nlogin " _RED_("failed") "\n"); return PM3_SUCCESS; } @@ -852,10 +829,12 @@ int CmdEM4x50Reset(const char *Cmd) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x50_reset(); + default: - PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -871,9 +850,9 @@ int CmdEM4x50Reset(const char *Cmd) { // print response if ((bool)resp.status) - PrintAndLogEx(NORMAL, "\nreset " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "\nreset " _GREEN_("ok") "\n"); else - PrintAndLogEx(NORMAL, "\nreset " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "\nreset " _RED_("failed") "\n"); return PM3_SUCCESS; } @@ -893,7 +872,7 @@ int CmdEM4x50Watch(const char *Cmd) { return usage_lf_em4x50_watch(); default: - PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } diff --git a/include/em4x50.h b/include/em4x50.h index ae6a53177..2bb490203 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -43,14 +43,10 @@ typedef struct { bool addr_given; bool pwd_given; - bool newpwd_given; - uint8_t password[4]; - uint8_t new_password[4]; - uint8_t address; - uint8_t word[4]; - uint32_t start_password; - uint32_t stop_password; - uint32_t login_password; + uint32_t password1; + uint32_t password2; + uint32_t word; + uint32_t addresses; } em4x50_data_t; typedef struct { From d6b90bbe6b0d40c560d125360585d2f0d8003795 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 22 Oct 2020 00:55:29 +0200 Subject: [PATCH 035/174] deleted debug output --- armsrc/em4x50.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 17423caef..e19a91e4b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -166,12 +166,10 @@ static bool get_signalproperties(void) { gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; - Dbprintf("gHigh = %i, gLow = %i", gHigh, gLow); - return true; } -static bool unvalid_bit(void) { +static bool invalid_bit(void) { // returns true if bit is undefined by evaluating a single sample within // a bit period (given there is no LIW, ACK or NAK) @@ -365,7 +363,7 @@ static int find_double_listen_window(bool bcommand) { // ...and check if the following bit does make sense // (if not it is the correct position within the second // listen window) - if (unvalid_bit()) { + if (invalid_bit()) { // send RM for request mode em4x50_reader_send_bit(0); @@ -583,7 +581,7 @@ static bool check_ack(bool bliw) { // check for listen window (if first bit cannot be inerpreted // as a valid bit it must belong to a listen window) - if (unvalid_bit()) { + if (invalid_bit()) { // send RM for request mode em4x50_reader_send_bit(0); From 243e6934de66a66e508a2ff56d3c96640455c064 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 22 Oct 2020 15:07:05 +0200 Subject: [PATCH 036/174] added "tearoff" --- armsrc/em4x50.c | 64 +++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index fe5c493b2..33e074310 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -888,7 +888,7 @@ void em4x50_info(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); } void em4x50_read(em4x50_data_t *etd) { @@ -931,14 +931,14 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); } //============================================================================== // write functions //============================================================================== -static bool write(uint32_t word, uint32_t addresses) { +static int write(uint32_t word, uint32_t addresses) { // writes to specified
@@ -953,11 +953,13 @@ static bool write(uint32_t word, uint32_t addresses) { // send data em4x50_reader_send_word(word); - // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer0(T0 * EM4X50_T_TAG_TWA); - + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0); + return PM3_ETEAROFF; + } else { + // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); + wait_timer0(T0 * EM4X50_T_TAG_TWA); // look for ACK sequence if (check_ack(false)) { @@ -969,16 +971,15 @@ static bool write(uint32_t word, uint32_t addresses) { } } - } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("error in command request"); } - return PM3_ESOFT; + return false; } -static bool write_password(uint32_t password, uint32_t new_password) { +static int write_password(uint32_t password, uint32_t new_password) { // changes password from to @@ -990,17 +991,23 @@ static bool write_password(uint32_t password, uint32_t new_password) { // send address data em4x50_reader_send_word(password); - // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer0(T0 * EM4X50_T_TAG_TPP); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0); + return PM3_ETEAROFF; + } else { // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); + wait_timer0(T0 * EM4X50_T_TAG_TPP); - // send new password - em4x50_reader_send_word(new_password); + // look for ACK sequence and send rm request + // during following listen window + if (check_ack(true)) { - // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer0(T0 * EM4X50_T_TAG_TWA); + // send new password + em4x50_reader_send_word(new_password); + + // wait for T0 * EM4X50_T_TAG_TWA (write access time) + wait_timer0(T0 * EM4X50_T_TAG_TWA); if (check_ack(false)) if (check_ack(false)) @@ -1008,7 +1015,6 @@ static bool write_password(uint32_t password, uint32_t new_password) { } } - } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("error in command request"); @@ -1036,9 +1042,14 @@ void em4x50_write(em4x50_data_t *etd) { blogin = login(etd->password1); // write word to given address - if (write(etd->word, etd->addresses)) { + int res = write(etd->word, etd->addresses); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } if (res == PM3_SUCCESS) { + // to verify result reset EM4x50 if (reset()) { @@ -1058,7 +1069,7 @@ void em4x50_write(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); } void em4x50_write_password(em4x50_data_t *etd) { @@ -1073,8 +1084,15 @@ void em4x50_write_password(em4x50_data_t *etd) { if (get_signalproperties() && find_em4x50_tag()) { // login and change password - if (login(etd->password1)) - bsuccess = write_password(etd->password1, etd->password2); + if (login(etd->password1)) { + + int res = write_password(etd->password1, etd->password2); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } + bsuccess = (res == PM3_SUCCESS); + } } lf_finalize(); @@ -1134,7 +1152,7 @@ void em4x50_wipe(uint32_t *password) { } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, (uint8_t *)words, 136); } void em4x50_reset(void) { From 6dc4ed3301dd23fd5665ea6667b6eb802c88adeb Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 22 Oct 2020 15:07:36 +0200 Subject: [PATCH 037/174] syntax error --- client/src/cmdlfem4x50.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 3816574c9..1e3d09fa6 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -706,19 +706,9 @@ int CmdEM4x50Wipe(const char *Cmd) { return usage_lf_em4x50_wipe(); clearCommandBuffer(); -<<<<<<< HEAD SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_ACK, &resp); -======= - SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd)); - - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WIPE, &resp, 2 * TIMEOUT)) { - PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n"); - return PM3_ETIMEOUT; - } - ->>>>>>> master // print response bool isOK = resp.status; if (isOK) { From e1b3cbfc9f6c8d11de59d4c820f1ed31c857d4e2 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 22 Oct 2020 15:09:09 +0200 Subject: [PATCH 038/174] will have a closer look at this later... --- client/src/scripting.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/scripting.c b/client/src/scripting.c index c1f457da8..9fe3dd90e 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -1131,6 +1131,7 @@ static int l_em4x05_read(lua_State *L) { } // 4350 +/* static int l_em4x50_read(lua_State *L) { // get addr @@ -1189,7 +1190,7 @@ static int l_em4x50_read(lua_State *L) { lua_pushinteger(L, word); return 1; } - +*/ // static int l_ndefparse(lua_State *L) { @@ -1382,7 +1383,7 @@ int set_pm3_libraries(lua_State *L) { {"ud", l_ud}, {"rem", l_remark}, {"em4x05_read", l_em4x05_read}, - {"em4x50_read", l_em4x50_read}, +// {"em4x50_read", l_em4x50_read}, {NULL, NULL} }; From fcd9d6d1e8f7770ff965a1c579e749463db95414 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:36:46 +0100 Subject: [PATCH 039/174] added new function 4x50_restore --- include/pm3_cmd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index d092d7e8c..245e2b886 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -512,6 +512,7 @@ typedef struct { #define CMD_LF_EM4X50_LOGIN 0x0246 #define CMD_LF_EM4X50_RESET 0x0247 #define CMD_LF_EM4X50_WATCH 0x0248 +#define CMD_LF_EM4X50_RESTORE 0x0249 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From decabbae0c7d2ea4a1c9992494d9145789117042 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:37:35 +0100 Subject: [PATCH 040/174] new parameter in struct due to new function 4x50_restore --- include/em4x50.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/em4x50.h b/include/em4x50.h index 2bb490203..63efb7a13 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -39,6 +39,7 @@ #define STATUS_LOGIN 0x1 #define NO_CHARS_MAX 400 #define TIMEOUT 2000 +#define RESTORE_DEFAULT_FILENAME "lf-4x50restore.bin" typedef struct { bool addr_given; @@ -47,10 +48,11 @@ typedef struct { uint32_t password2; uint32_t word; uint32_t addresses; -} em4x50_data_t; + uint8_t data[136]; +} PACKED em4x50_data_t; typedef struct { uint8_t byte[4]; -} em4x50_word_t; +} PACKED em4x50_word_t; #endif /* EM4X50_H__ */ From 10aabebec5ab4df5e39be83b850be4728a71aa1d Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:37:55 +0100 Subject: [PATCH 041/174] added new function 4x50_restore --- client/src/cmdlfem4x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index d8303321d..6630e13e8 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -659,6 +659,7 @@ static command_t CommandTable[] = { {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, + {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {NULL, NULL, NULL, NULL} }; From 8ca8c307ad3191c5bf754198b21db2324b3f5834 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:39:10 +0100 Subject: [PATCH 042/174] added new function 4x50_restore + unified cosmetic adaptions --- client/src/cmdlfem4x50.c | 180 +++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 34 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 1e3d09fa6..8d7bda871 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -13,6 +13,7 @@ #include "fileutils.h" #include "comms.h" #include "commonutil.h" +#include "cmdparser.h" #include "em4x50.h" static int usage_lf_em4x50_info(void) { @@ -144,6 +145,22 @@ static int usage_lf_em4x50_watch(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_restore(void) { + PrintAndLogEx(NORMAL, "Restore EM4x50 dump to tag. Tag must be on antenna. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_restore [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); + PrintAndLogEx(NORMAL, " f - data filename . (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore h")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump p 12345678")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { @@ -308,7 +325,7 @@ int CmdEM4x50Info(const char *Cmd) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -318,7 +335,7 @@ int CmdEM4x50Info(const char *Cmd) { return PM3_SUCCESS; } - PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); + PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); return PM3_ESOFT; } @@ -356,7 +373,7 @@ int CmdEM4x50Write(const char *Cmd) { // validation if (address < 1 || address > 31) { - PrintAndLogEx(FAILED, "error, address has to be in range [1-31]\n"); + PrintAndLogEx(FAILED, "Error, address has to be in range [1-31]"); return PM3_EINVARG; } etd.addresses = address; // lwr @@ -367,7 +384,7 @@ int CmdEM4x50Write(const char *Cmd) { break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; @@ -381,7 +398,7 @@ int CmdEM4x50Write(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -390,17 +407,17 @@ int CmdEM4x50Write(const char *Cmd) { bool isOK = (resp.status & STATUS_SUCCESS) >> 1; if (isOK == false) { - PrintAndLogEx(FAILED, "writing " _RED_("failed")); + PrintAndLogEx(FAILED, "Writing " _RED_("failed")); return PM3_ESOFT; } if (etd.pwd_given) { bool login = resp.status & STATUS_LOGIN; if (login == false) { - PrintAndLogEx(FAILED, "login failed"); + PrintAndLogEx(FAILED, "Login failed"); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%08x"), etd.password1); + PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); } // display result of writing operation in structured format @@ -446,7 +463,7 @@ int CmdEM4x50WritePassword(const char *Cmd) { break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -459,7 +476,7 @@ int CmdEM4x50WritePassword(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd)); if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE_PASSWORD, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -470,9 +487,9 @@ int CmdEM4x50WritePassword(const char *Cmd) { // print response if (success) - PrintAndLogEx(SUCCESS, "\nwriting new password " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); else - PrintAndLogEx(FAILED, "\nwriting password " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); return (success) ? PM3_SUCCESS : PM3_ESOFT; } @@ -502,7 +519,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { bool isOK = (resp.status & STATUS_SUCCESS) >> 1; if (isOK == false) { if (verbose) - PrintAndLogEx(FAILED, "reading " _RED_("failed")); + PrintAndLogEx(FAILED, "Reading " _RED_("failed")); return PM3_ESOFT; } @@ -510,10 +527,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { if (edata.pwd_given) { bool login = resp.status & STATUS_LOGIN; if (login == false) { - PrintAndLogEx(FAILED, "login failed"); + PrintAndLogEx(FAILED, "Login failed"); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%08x"), etd->password1); + PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd->password1); } uint8_t *data = resp.data.asBytes; @@ -564,7 +581,7 @@ int CmdEM4x50Read(const char *Cmd) { // validation if (address <= 0 || address >= EM4X50_NO_WORDS) { - PrintAndLogEx(FAILED, "error, address has to be in range [1-33]\n"); + PrintAndLogEx(FAILED, "Error, address has to be in range [1-33]"); return PM3_EINVARG; } etd.addr_given = true; @@ -578,7 +595,7 @@ int CmdEM4x50Read(const char *Cmd) { break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -631,18 +648,18 @@ int CmdEM4x50Dump(const char *Cmd) { if (errors) return usage_lf_em4x50_dump(); - PrintAndLogEx(INFO, "reading EM4x50 tag"); + PrintAndLogEx(INFO, "Reading EM4x50 tag"); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } bool success = (resp.status & STATUS_SUCCESS) >> 1; if (success == false) { - PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); + PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); return PM3_ESOFT; } @@ -696,7 +713,7 @@ int CmdEM4x50Wipe(const char *Cmd) { break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -707,14 +724,14 @@ int CmdEM4x50Wipe(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password)); - WaitForResponse(CMD_ACK, &resp); + WaitForResponse(CMD_LF_EM4X50_WIPE, &resp); // print response bool isOK = resp.status; if (isOK) { - PrintAndLogEx(SUCCESS, "\nwiping data " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); } else { - PrintAndLogEx(FAILED, "\nwiping data " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); return PM3_ESOFT; } @@ -750,7 +767,7 @@ int CmdEM4x50Brute(const char *Cmd) { break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -765,9 +782,9 @@ int CmdEM4x50Brute(const char *Cmd) { dur_h = dur_s / 3600; dur_m = (dur_s - dur_h * 3600) / 60; dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(INFO, "trying %i passwords in range [0x%08x, 0x%08x]", + PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]", no_iter, etd.password1, etd.password2); - PrintAndLogEx(INFO, "estimated duration: %ih%im%is", dur_h, dur_m, dur_s); + PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); // start clearCommandBuffer(); @@ -776,9 +793,9 @@ int CmdEM4x50Brute(const char *Cmd) { // print response if ((bool)resp.status) - PrintAndLogEx(SUCCESS, "\npassword " _GREEN_("found") ": 0x%08x\n", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]); else - PrintAndLogEx(FAILED, "\npassword: " _RED_("not found") "\n"); + PrintAndLogEx(FAILED, "Password: " _RED_("not found")); return PM3_SUCCESS; } @@ -820,9 +837,9 @@ int CmdEM4x50Login(const char *Cmd) { // print response if ((bool)resp.status) - PrintAndLogEx(SUCCESS, "\nlogin " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "Login " _GREEN_("ok")); else - PrintAndLogEx(FAILED, "\nlogin " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "Login " _RED_("failed")); return PM3_SUCCESS; } @@ -841,7 +858,7 @@ int CmdEM4x50Reset(const char *Cmd) { return usage_lf_em4x50_reset(); default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -857,9 +874,9 @@ int CmdEM4x50Reset(const char *Cmd) { // print response if ((bool)resp.status) - PrintAndLogEx(SUCCESS, "\nreset " _GREEN_("ok") "\n"); + PrintAndLogEx(SUCCESS, "Reset " _GREEN_("ok")); else - PrintAndLogEx(FAILED, "\nreset " _RED_("failed") "\n"); + PrintAndLogEx(FAILED, "Reset " _RED_("failed")); return PM3_SUCCESS; } @@ -899,3 +916,98 @@ int CmdEM4x50Watch(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50Restore(const char *Cmd) { + + //uint8_t data[136] = {0x0}; + size_t bytes_read = 0; + char filename[FILE_PATH_SIZE] = {0x00}; + char szTemp[FILE_PATH_SIZE - 20] = {0x00}; + FILE *fdump; + + em4x50_data_t etd; + etd.pwd_given = false; + + bool errors = false; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_restore(); + break; + + case 'u': + param_getstr(Cmd, cmdp + 1, szTemp, FILE_PATH_SIZE - 20); + if (filename[0] == 0x00) + snprintf(filename, FILE_PATH_SIZE, "lf-4x50-%s-dump.bin", szTemp); + cmdp += 2; + break; + + case 'f': + param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + cmdp += 2; + break; + + case 'p': + etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); + etd.pwd_given = true; + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + }; + } + + // validation + if (errors) + return usage_lf_em4x50_restore(); + + // open dump file + if ((fdump = fopen(filename, "rb")) == NULL) { + PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename); + return PM3_EFILE; + } + PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); + + // read data from dump file + bytes_read = fread(&etd.data, sizeof(uint8_t), sizeof(etd.data), fdump); + if (bytes_read != sizeof(etd.data)) { + PrintAndLogEx(FAILED, "Read error"); + return PM3_EFILE; + } + fclose(fdump); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_RESTORE, &resp, 2 * TIMEOUT)) { + PrintAndLogEx(FAILED, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_ETEAROFF) + return PM3_SUCCESS; + + bool isOK = (resp.status & STATUS_SUCCESS) >> 1; + if (isOK == false) { + PrintAndLogEx(FAILED, "Restore " _RED_("failed")); + return PM3_ESOFT; + } + + if (etd.pwd_given) { + bool login = resp.status & STATUS_LOGIN; + if (login == false) { + PrintAndLogEx(FAILED, "Login failed"); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); + } + PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); + PrintAndLogEx(INFO, "Finish restore"); + + return PM3_SUCCESS; +} From 881bdbf456dd977c2c2f95504a541e7dc0dc7d9a Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:39:22 +0100 Subject: [PATCH 043/174] added new function 4x50_restore --- client/src/cmdlfem4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 32685baaf..8ffda2933 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -28,5 +28,6 @@ int CmdEM4x50Brute(const char *Cmd); int CmdEM4x50Login(const char *Cmd); int CmdEM4x50Reset(const char *Cmd); int CmdEM4x50Watch(const char *Cmd); +int CmdEM4x50Restore(const char *Cmd); #endif From 4c6651b3c822c8423e98653f02ab27741fdd5667 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:39:40 +0100 Subject: [PATCH 044/174] added new function 4x50_restore --- armsrc/appmain.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 52c9a132b..e4bd5f600 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1117,6 +1117,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_watch(); break; } + case CMD_LF_EM4X50_RESTORE: { + em4x50_restore((em4x50_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 From ea5fc5cc463327ad63b14466e4b2a20411012f9f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:40:02 +0100 Subject: [PATCH 045/174] added new function 4x50_restore --- armsrc/em4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index c851f04e4..7c9cda575 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -28,5 +28,6 @@ void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); void em4x50_reset(void); void em4x50_watch(void); +void em4x50_restore(em4x50_data_t *etd); #endif /* EM4X50_H */ From 0b034321ac48677679a1f22750f7812a72196db5 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 16:40:39 +0100 Subject: [PATCH 046/174] added new function 4x50_restore --- armsrc/em4x50.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 33e074310..6896bb809 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -14,6 +14,7 @@ #include "lfadc.h" #include "commonutil.h" #include "em4x50.h" +#include "BigBuf.h" #include "appmain.h" // tear // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) @@ -1140,9 +1141,15 @@ void em4x50_wipe(uint32_t *password) { // so far everything is fine // last task: reset password - if (login(*password)) - bsuccess = write_password(*password, zero); + if (login(*password)) { + int res = write_password(*password, zero); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } + bsuccess = (res == PM3_SUCCESS); + } // verify by login with new password if (bsuccess) bsuccess = login(zero); @@ -1150,9 +1157,9 @@ void em4x50_wipe(uint32_t *password) { } } } - + lf_finalize(); - reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, 0, 0); } void em4x50_reset(void) { @@ -1315,3 +1322,66 @@ int em4x50_standalone_read(uint32_t *words) { return now; } + +void em4x50_restore(em4x50_data_t *etd) { + + // restore em4x50 dump file to tag + + bool bsuccess = false, blogin = false; + int res = 0; + int start = (etd->pwd_given) ? 2 : 3; // without password word 2 cannot be written + uint8_t status = 0; + uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) + uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; + uint32_t words_read[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + // read data + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + + for (int j = 0; j < 4; j++) + words_client[i] |= (etd->data[4 * i + j]) << ((3 - j) * 8); + + // lsb is needed (dump is msb) + words_client[i] = reflect32(words_client[i]); + } + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + // login first if password is available + if (etd->pwd_given) + blogin = login(etd->password1); + + // write data to each address but ignore addresses + // 0 -> password, 32 -> serial, 33 -> uid + for (int i = start; i < EM4X50_NO_WORDS - 2; i++) { + res = write(words_client[i], i); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } + } + + // to verify result -> reset EM4x50 + if (reset()) { + + // login not necessary because protected word has been set to 0 + // -> no read protected words + // -> selective read can be called immediately + if (selective_read(addresses, words_read)) { + + // check if everything is zero + bsuccess = true; + for (int i = start; i < EM4X50_NO_WORDS - 2; i++) + bsuccess &= (reflect32(words_read[i]) == words_client[i]); + } + } + } + + status = (bsuccess << 1) + blogin; + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); +} From 86007bfdd46cc78f898e0e3e9024fda1da811903 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 25 Oct 2020 22:01:52 +0100 Subject: [PATCH 047/174] replaced command parameter: a -> b and w -> d --- client/src/cmdlfem4x50.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 8d7bda871..6a163eac3 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -22,7 +22,6 @@ static int usage_lf_em4x50_info(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [v] [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " v - verbose output"); PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info")); @@ -37,8 +36,8 @@ static int usage_lf_em4x50_write(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] [a
] [w ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " a - memory address to write to (dec)"); - PrintAndLogEx(NORMAL, " w - word to write (hex, lsb)"); + PrintAndLogEx(NORMAL, " b - memory address to write to (dec)"); + PrintAndLogEx(NORMAL, " d - word to write (hex, lsb)"); PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write a 3 w deadc0de")); @@ -64,7 +63,7 @@ static int usage_lf_em4x50_read(void) { PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] [a
] [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " a - memory address to read (dec) (optional)"); + PrintAndLogEx(NORMAL, " b - memory address to read (dec) (optional)"); PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read")); @@ -362,13 +361,13 @@ int CmdEM4x50Write(const char *Cmd) { cmdp += 2; break; - case 'w': + case 'd': etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); bword = true; cmdp += 2; break; - case 'a': + case 'b': param_getdec(Cmd, cmdp + 1, &address); // validation @@ -572,7 +571,7 @@ int CmdEM4x50Read(const char *Cmd) { case 'h': return usage_lf_em4x50_read(); - case 'a': { + case 'b': { param_getdec(Cmd, cmdp + 1, &address); // lsb: byte 1 = fwr, byte 2 = lwr, byte 3 = 0x0, byte 4 = 0x0 etd.addresses = address; // lwr From 5af9fc15ecb38dae896714ca0e086cb09586ec9f Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 00:11:49 +0100 Subject: [PATCH 048/174] added default file size for dump files (bin/eml) -> 136 bytes --- include/em4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/em4x50.h b/include/em4x50.h index 63efb7a13..d422cf9c1 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -40,6 +40,7 @@ #define NO_CHARS_MAX 400 #define TIMEOUT 2000 #define RESTORE_DEFAULT_FILENAME "lf-4x50restore.bin" +#define DUMP_FILESIZE 136 typedef struct { bool addr_given; From b3b6f827e871d93f07441930b9a58f69671a07a2 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 00:12:52 +0100 Subject: [PATCH 049/174] no comment necessary --- armsrc/em4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 6896bb809..833cc2511 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1342,7 +1342,7 @@ void em4x50_restore(em4x50_data_t *etd) { for (int j = 0; j < 4; j++) words_client[i] |= (etd->data[4 * i + j]) << ((3 - j) * 8); - + // lsb is needed (dump is msb) words_client[i] = reflect32(words_client[i]); } From e834c30f6bc23ea05197bdef211254a3406f5beb Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 00:14:37 +0100 Subject: [PATCH 050/174] added eml file format support for restoring --- client/src/cmdlfem4x50.c | 58 +++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 6a163eac3..f74b04d61 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -149,14 +149,14 @@ static int usage_lf_em4x50_restore(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: lf em 4x50_restore [h]"); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); - PrintAndLogEx(NORMAL, " f - data filename . (optional)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); + PrintAndLogEx(NORMAL, " f - data filename (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore h")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump p 12345678")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.bin")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.eml p 12345678")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -920,7 +920,8 @@ int CmdEM4x50Restore(const char *Cmd) { //uint8_t data[136] = {0x0}; size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0x00}; + char filename[FILE_PATH_SIZE] = {0}; + char ext[FILE_PATH_SIZE] = {0}; char szTemp[FILE_PATH_SIZE - 20] = {0x00}; FILE *fdump; @@ -939,7 +940,7 @@ int CmdEM4x50Restore(const char *Cmd) { case 'u': param_getstr(Cmd, cmdp + 1, szTemp, FILE_PATH_SIZE - 20); if (filename[0] == 0x00) - snprintf(filename, FILE_PATH_SIZE, "lf-4x50-%s-dump.bin", szTemp); + snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%s-dump.bin", szTemp); cmdp += 2; break; @@ -965,21 +966,42 @@ int CmdEM4x50Restore(const char *Cmd) { if (errors) return usage_lf_em4x50_restore(); - // open dump file - if ((fdump = fopen(filename, "rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename); - return PM3_EFILE; - } PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); - // read data from dump file - bytes_read = fread(&etd.data, sizeof(uint8_t), sizeof(etd.data), fdump); - if (bytes_read != sizeof(etd.data)) { + // read data from dump file; file has to be "bin" or "eml" + // (file type is distinguished by file extension) + + memcpy(ext, &filename[strlen(filename) - 4], 4); + ext[5] = 0x00; + if (memcmp(ext, ".eml", 4) == 0) { + + // read from eml file + if (loadFileEML(filename, etd.data, &bytes_read) != PM3_SUCCESS) + return PM3_EFILE; + + } else { + + // open bin file + if ((fdump = fopen(filename, "rb")) == NULL) { + PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename); + return PM3_EFILE; + } + + // read from bin file + bytes_read = fread(&etd.data, sizeof(uint8_t), DUMP_FILESIZE, fdump); + PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%i") " bytes from bin file " _YELLOW_("%s"), + bytes_read, + filename + ); + + fclose(fdump); + } + + if (bytes_read != DUMP_FILESIZE) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } - fclose(fdump); - + clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; From 82c2f79dd062e3e27c53645b5e9499f8bcb6f1fe Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 00:22:11 +0100 Subject: [PATCH 051/174] dump function indicates use of tag UID in filename but takes device serial -> changed to UID --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index f74b04d61..28cea1244 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -673,7 +673,7 @@ int CmdEM4x50Dump(const char *Cmd) { if (strlen(filename) == 0) { PrintAndLogEx(INFO, "Using UID as filename"); fptr += sprintf(fptr, "lf-4x50-"); - FillFileNameByUID(fptr, words[EM4X50_DEVICE_SERIAL].byte, "-dump", 4); + FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); } uint8_t data[EM4X50_NO_WORDS * 4] = {0}; From 9af388c1e1c14b51b005788ae852901fa390fbde Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 13:30:25 +0100 Subject: [PATCH 052/174] added EM4x50 JSON export --- client/src/cmdlfem4x50.c | 4 +++- client/src/fileutils.c | 14 ++++++++++++++ client/src/fileutils.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 28cea1244..a20808d43 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -683,9 +683,11 @@ int CmdEM4x50Dump(const char *Cmd) { // saveFileEML will add .eml extension to filename // saveFile (binary) passes in the .bin extension. + // saveFileJSON adds .json extension saveFileEML(filename, data, sizeof(data), 4); saveFile(filename, ".bin", data, sizeof(data)); - //saveFileJSON... + saveFileJSON(filename, jsfEM4x50, data, sizeof(data), NULL); + return PM3_SUCCESS; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index ab4a7d241..a304a4f42 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -521,6 +521,20 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, } break; } + case jsfEM4x50: { + JsonSaveStr(root, "FileType", "EM4X50"); + JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (1 * 4), 4); + JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (2 * 4), 4); + JsonSaveBufAsHexCompact(root, "$.Card.Serial", data + (32 * 4), 4); + JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4); + + for (size_t i = 0; i < (datalen / 4); i++) { + char path[PATH_MAX_LENGTH] = {0}; + sprintf(path, "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4); + } + break; + } case jsfMfPlusKeys: { JsonSaveStr(root, "FileType", "mfp"); JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7); diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 49992c998..e307a2492 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -66,6 +66,7 @@ typedef enum { jsfMfDesfireKeys, jsfEM4x05, jsfEM4x69, + jsfEM4x50, } JSONFileType; typedef enum { From bc87a6edf261c516b6c710fd4878bf984ea6f342 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 14:04:39 +0100 Subject: [PATCH 053/174] addded JSON import support for 4x50_restore --- client/src/cmdlfem4x50.c | 41 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a20808d43..1e27be89a 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -151,12 +151,13 @@ static int usage_lf_em4x50_restore(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); - PrintAndLogEx(NORMAL, " f - data filename (optional)"); + PrintAndLogEx(NORMAL, " f - data filename (optional)"); PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore h")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.bin")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.eml p 12345678")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.json p 00000001")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -920,12 +921,11 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { - //uint8_t data[136] = {0x0}; size_t bytes_read = 0; + int res = 0; char filename[FILE_PATH_SIZE] = {0}; char ext[FILE_PATH_SIZE] = {0}; char szTemp[FILE_PATH_SIZE - 20] = {0x00}; - FILE *fdump; em4x50_data_t etd; etd.pwd_given = false; @@ -970,36 +970,17 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); - // read data from dump file; file has to be "bin" or "eml" - // (file type is distinguished by file extension) - + // read data from dump file; file type has to be "bin", "eml" or "json" memcpy(ext, &filename[strlen(filename) - 4], 4); ext[5] = 0x00; - if (memcmp(ext, ".eml", 4) == 0) { + if (memcmp(ext, ".eml", 4) == 0) + res = loadFileEML(filename, etd.data, &bytes_read) != PM3_SUCCESS; + else if (memcmp(ext, ".json", 5) == 0) + res = loadFileJSON(filename, etd.data, sizeof(etd.data), &bytes_read, NULL); + else + res = loadFile(filename, ".bin", etd.data, sizeof(etd.data), &bytes_read); - // read from eml file - if (loadFileEML(filename, etd.data, &bytes_read) != PM3_SUCCESS) - return PM3_EFILE; - - } else { - - // open bin file - if ((fdump = fopen(filename, "rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename); - return PM3_EFILE; - } - - // read from bin file - bytes_read = fread(&etd.data, sizeof(uint8_t), DUMP_FILESIZE, fdump); - PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%i") " bytes from bin file " _YELLOW_("%s"), - bytes_read, - filename - ); - - fclose(fdump); - } - - if (bytes_read != DUMP_FILESIZE) { + if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } From 3a698dfc0cc1e117dcae60b894b6da5479c03998 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 14:34:40 +0100 Subject: [PATCH 054/174] reorder of file types (if extension is neither bin nor eml -> json is assumed) --- client/src/cmdlfem4x50.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 1e27be89a..d26831c26 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -975,10 +975,10 @@ int CmdEM4x50Restore(const char *Cmd) { ext[5] = 0x00; if (memcmp(ext, ".eml", 4) == 0) res = loadFileEML(filename, etd.data, &bytes_read) != PM3_SUCCESS; - else if (memcmp(ext, ".json", 5) == 0) - res = loadFileJSON(filename, etd.data, sizeof(etd.data), &bytes_read, NULL); - else + else if (memcmp(ext, ".bin", 4) == 0) res = loadFile(filename, ".bin", etd.data, sizeof(etd.data), &bytes_read); + else + res = loadFileJSON(filename, etd.data, sizeof(etd.data), &bytes_read, NULL); if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) { PrintAndLogEx(FAILED, "Read error"); From c1f5fc546d12c27d6dc371a36263bd428e568111 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 14:35:09 +0100 Subject: [PATCH 055/174] added import for em4x50 --- client/src/fileutils.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/client/src/fileutils.c b/client/src/fileutils.c index a304a4f42..328d720ec 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -1152,6 +1152,27 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz *datalen = sptr; } + if (!strcmp(ctype, "EM4X50")) { + size_t sptr = 0; + for (size_t i = 0; i < (maxdatalen / 4); i++) { + if (sptr + 4 > maxdatalen) { + retval = PM3_EMALLOC; + goto out; + } + + char blocks[30] = {0}; + sprintf(blocks, "$.blocks.%zu", i); + + size_t len = 0; + JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len); + if (!len) + break; + + sptr += len; + } + *datalen = sptr; + } + out: if (callback != NULL) { From 96e05d49dfa58ac34687197a3298404e49859561 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 22:10:48 +0100 Subject: [PATCH 056/174] added simple sim function for em4x50 --- armsrc/appmain.c | 4 ++++ armsrc/em4x50.h | 1 + client/src/cmdlfem4x.c | 1 + client/src/cmdlfem4x50.h | 1 + include/pm3_cmd.h | 1 + 5 files changed, 8 insertions(+) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e4bd5f600..c5dda3f75 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1121,6 +1121,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_restore((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_SIM: { + em4x50_sim((uint32_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 7c9cda575..e71a2fd89 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -29,5 +29,6 @@ void em4x50_login(uint32_t *password); void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); +void em4x50_sim(uint32_t *word); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 318df61ec..fdf593fc5 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -662,6 +662,7 @@ static command_t CommandTable[] = { {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, + {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate single EM4x50 word (uid)"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 8ffda2933..acadd2084 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -29,5 +29,6 @@ int CmdEM4x50Login(const char *Cmd); int CmdEM4x50Reset(const char *Cmd); int CmdEM4x50Watch(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); +int CmdEM4x50Sim(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 245e2b886..8124cd82b 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -513,6 +513,7 @@ typedef struct { #define CMD_LF_EM4X50_RESET 0x0247 #define CMD_LF_EM4X50_WATCH 0x0248 #define CMD_LF_EM4X50_RESTORE 0x0249 +#define CMD_LF_EM4X50_SIM 0x0250 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 2b5e8f358ea8f7f195028ff859dbfc6a4cde5ce3 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 22:11:57 +0100 Subject: [PATCH 057/174] added simple sim function for em4x50 ( + some minor corrections) --- client/src/cmdlfem4x50.c | 68 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index d26831c26..bdf336455 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -161,6 +161,19 @@ static int usage_lf_em4x50_restore(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_sim(void) { + PrintAndLogEx(NORMAL, "Simulate single EM4x50 word. "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " u - single word to simulate (hex, lsb"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim h")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim u 12345678")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { @@ -791,7 +804,7 @@ int CmdEM4x50Brute(const char *Cmd) { // start clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); - WaitForResponse(CMD_ACK, &resp); + WaitForResponse(CMD_LF_EM4X50_BRUTE, &resp); // print response if ((bool)resp.status) @@ -835,7 +848,7 @@ int CmdEM4x50Login(const char *Cmd) { // start clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); - WaitForResponse(CMD_ACK, &resp); + WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); // print response if ((bool)resp.status) @@ -872,7 +885,7 @@ int CmdEM4x50Reset(const char *Cmd) { // start clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESET, 0, 0); - WaitForResponse(CMD_ACK, &resp); + WaitForResponse(CMD_LF_EM4X50_RESET, &resp); // print response if ((bool)resp.status) @@ -912,7 +925,7 @@ int CmdEM4x50Watch(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); - WaitForResponse(CMD_ACK, &resp); + WaitForResponse(CMD_LF_EM4X50_WATCH, &resp); PrintAndLogEx(INFO, "Done"); @@ -1011,7 +1024,52 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); } PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); - PrintAndLogEx(INFO, "Finish restore"); + PrintAndLogEx(INFO, "Finished restoring"); + + return PM3_SUCCESS; +} + +int CmdEM4x50Sim(const char *Cmd) { + + bool errors = false; + uint8_t cmdp = 0; + uint32_t word = 0x00; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_sim(); + break; + + case 'u': + word = param_get32ex(Cmd, cmdp + 1, 0, 16); + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + }; + } + + // validation + if (errors) + return usage_lf_em4x50_sim(); + + PrintAndLogEx(INFO, "Simulating " _YELLOW_("%08x"), word); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&word, sizeof(word)); + + PacketResponseNG resp; + WaitForResponse(CMD_LF_EM4X50_SIM, &resp); + + if (resp.status == PM3_ETEAROFF) + return PM3_SUCCESS; + + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } From d034d640fced117d14cd2b41dea327581509ea38 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 22:13:07 +0100 Subject: [PATCH 058/174] added simple sim functionality for em4x50 (+ some minor corrections) --- armsrc/em4x50.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 15c017543..03f42f3a5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -112,6 +112,16 @@ static void em4x50_setup_read(void) { WDT_HIT(); } +static void em4x50_setup_sim(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + 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; +} + // functions for "reader" use case static bool get_signalproperties(void) { @@ -1175,7 +1185,7 @@ void em4x50_reset(void) { status = reset(); lf_finalize(); - reply_ng(CMD_ACK, status, 0, 0); + reply_ng(CMD_LF_EM4X50_RESET, status, 0, 0); } void em4x50_login(uint32_t *password) { @@ -1191,7 +1201,7 @@ void em4x50_login(uint32_t *password) { status = login(*password); lf_finalize(); - reply_ng(CMD_ACK, status, 0, 0); + reply_ng(CMD_LF_EM4X50_LOGIN, status, 0, 0); } static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { @@ -1247,7 +1257,7 @@ void em4x50_brute(em4x50_data_t *etd) { bsuccess = brute(etd->password1, etd->password2, &pwd); lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)(&pwd), 32); + reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); } void em4x50_watch() { @@ -1284,7 +1294,7 @@ void em4x50_watch() { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_ACK, 1, 0, 0); + reply_ng(CMD_LF_EM4X50_WATCH, 1, 0, 0); } //============================================================================== @@ -1385,3 +1395,22 @@ void em4x50_restore(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); } + +void em4x50_sim(uint32_t *word) { + + // simulate word (e.g. UID) + + em4x50_setup_sim(); + + while (!BUTTON_PRESS()) { + + WDT_HIT(); + + em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(); + em4x50_sim_send_word(*word); + } + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_SIM, 1, 0, 0); +} From eee2540e8511f0d2bd63c81e7614f62e3278e23f Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 26 Oct 2020 22:14:18 +0100 Subject: [PATCH 059/174] adjustments regarding em4x50 (hopefully it works...) --- client/src/scripting.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/client/src/scripting.c b/client/src/scripting.c index 9fe3dd90e..3ed82591a 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -1131,7 +1131,6 @@ static int l_em4x05_read(lua_State *L) { } // 4350 -/* static int l_em4x50_read(lua_State *L) { // get addr @@ -1147,8 +1146,7 @@ static int l_em4x50_read(lua_State *L) { em4x50_data_t etd; memset(&etd, 0x00, sizeof(em4x50_data_t)); etd.addr_given = true; - etd.address = addr & 0xFF; - etd.newpwd_given = false; + etd.addresses = addr & 0xFF; // get password const char *p_pwd = luaL_checkstring(L, 2); @@ -1163,16 +1161,13 @@ static int l_em4x50_read(lua_State *L) { PrintAndLogEx(DEBUG, " Pwd %08X", pwd); - etd.password[0] = pwd & 0xFF; - etd.password[1] = (pwd >> 8) & 0xFF; - etd.password[2] = (pwd >> 16) & 0xFF; - etd.password[3] = (pwd >> 24) & 0xFF; + etd.password1 = pwd; etd.pwd_given = true; } - PrintAndLogEx(DEBUG, "Addr %u", etd.address); + PrintAndLogEx(DEBUG, "Addr %u", etd.addresses & 0xFF); if (etd.pwd_given) - PrintAndLogEx(DEBUG, " Pwd %s", sprint_hex(etd.password, sizeof(etd.password))); + PrintAndLogEx(DEBUG, " Pwd %08x", etd.password1); em4x50_word_t words[EM4X50_NO_WORDS]; @@ -1182,15 +1177,16 @@ static int l_em4x50_read(lua_State *L) { } uint32_t word = ( - words[etd.address].byte[0] << 24 | - words[etd.address].byte[1] << 16 | - words[etd.address].byte[2] << 8 | - words[etd.address].byte[3] + words[etd.addresses & 0xFF].byte[0] << 24 | + words[etd.addresses & 0xFF].byte[1] << 16 | + words[etd.addresses & 0xFF].byte[2] << 8 | + words[etd.addresses & 0xFF].byte[3] ); lua_pushinteger(L, word); + return 1; } -*/ + // static int l_ndefparse(lua_State *L) { @@ -1383,7 +1379,7 @@ int set_pm3_libraries(lua_State *L) { {"ud", l_ud}, {"rem", l_remark}, {"em4x05_read", l_em4x05_read}, -// {"em4x50_read", l_em4x50_read}, + {"em4x50_read", l_em4x50_read}, {NULL, NULL} }; From e63a40e5b622aa3813f97703dd803b584e3ad6a0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 27 Oct 2020 00:53:50 +0100 Subject: [PATCH 060/174] added file upload for sim function --- armsrc/appmain.c | 2 +- armsrc/em4x50.c | 49 ++++++++++++++++++++++++++------ armsrc/em4x50.h | 2 +- client/src/cmdlfem4x50.c | 60 ++++++++++++++++++++++++++++------------ 4 files changed, 86 insertions(+), 27 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index a9256720d..897b5718d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1123,7 +1123,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_SIM: { - em4x50_sim((uint32_t *)packet->data.asBytes); + em4x50_sim((em4x50_data_t *)packet->data.asBytes); break; } #endif diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 03f42f3a5..9868ce6c2 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -479,6 +479,9 @@ bool em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; + // word has tobe sent in msb, not lsb + word = reflect32(word); + // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) if (!em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF)) @@ -1339,7 +1342,7 @@ void em4x50_restore(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; int res = 0; - int start = (etd->pwd_given) ? 2 : 3; // without password word 2 cannot be written + int start_word = 0; uint8_t status = 0; uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; @@ -1366,7 +1369,11 @@ void em4x50_restore(em4x50_data_t *etd) { // write data to each address but ignore addresses // 0 -> password, 32 -> serial, 33 -> uid - for (int i = start; i < EM4X50_NO_WORDS - 2; i++) { + + // without login words 1 and 2 cannot be written + start_word = (blogin) ? 1 : 3; + + for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) { res = write(words_client[i], i); if (res == PM3_ETEAROFF) { lf_finalize(); @@ -1384,7 +1391,7 @@ void em4x50_restore(em4x50_data_t *etd) { // check if everything is zero bsuccess = true; - for (int i = start; i < EM4X50_NO_WORDS - 2; i++) + for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) bsuccess &= (reflect32(words_read[i]) == words_client[i]); } } @@ -1396,19 +1403,45 @@ void em4x50_restore(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); } -void em4x50_sim(uint32_t *word) { +void em4x50_sim(em4x50_data_t *etd) { - // simulate word (e.g. UID) + // simulate either word (e.g. UID) or complete tag via dump file upload + + uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_sim(); + // read data + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + + for (int j = 0; j < 4; j++) + words[i] |= (etd->data[4 * i + j]) << ((3 - j) * 8); + + // lsb is needed (dump is msb) + words[i] = reflect32(words[i]); + } + + // extract control data + int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read + int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read + + // extract protection data + int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + while (!BUTTON_PRESS()) { WDT_HIT(); + em4x50_sim_send_listen_window(); + for (int i = fwr; i <= lwr; i++) { - em4x50_sim_send_listen_window(); - em4x50_sim_send_listen_window(); - em4x50_sim_send_word(*word); + em4x50_sim_send_listen_window(); + + if ((i >= fwrp) && (i <= lwrp)) + em4x50_sim_send_word(0x00); + else + em4x50_sim_send_word(words[i]); + } } lf_finalize(); diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index e71a2fd89..e286e91f7 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -29,6 +29,6 @@ void em4x50_login(uint32_t *password); void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); -void em4x50_sim(uint32_t *word); +void em4x50_sim(em4x50_data_t *etd); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index bdf336455..1143939cf 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -175,6 +175,31 @@ static int usage_lf_em4x50_sim(void) { return PM3_SUCCESS; } +static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) { + + // read data from dump file; file type is derived from file name extension + + int res = 0; + size_t bytes_read = 0; + char ext[FILE_PATH_SIZE] = {0}; + + + memcpy(ext, &filename[strlen(filename) - 4], 4); + ext[5] = 0x00; + + if (memcmp(ext, ".eml", 4) == 0) + res = loadFileEML(filename, data, &bytes_read) != PM3_SUCCESS; + else if (memcmp(ext, ".bin", 4) == 0) + res = loadFile(filename, ".bin", data, data_len, &bytes_read); + else + res = loadFileJSON(filename, data, data_len, &bytes_read, NULL); + + if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) + return PM3_EFILE; + + return PM3_SUCCESS; +} + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -934,10 +959,7 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { - size_t bytes_read = 0; - int res = 0; char filename[FILE_PATH_SIZE] = {0}; - char ext[FILE_PATH_SIZE] = {0}; char szTemp[FILE_PATH_SIZE - 20] = {0x00}; em4x50_data_t etd; @@ -984,16 +1006,7 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" - memcpy(ext, &filename[strlen(filename) - 4], 4); - ext[5] = 0x00; - if (memcmp(ext, ".eml", 4) == 0) - res = loadFileEML(filename, etd.data, &bytes_read) != PM3_SUCCESS; - else if (memcmp(ext, ".bin", 4) == 0) - res = loadFile(filename, ".bin", etd.data, sizeof(etd.data), &bytes_read); - else - res = loadFileJSON(filename, etd.data, sizeof(etd.data), &bytes_read, NULL); - - if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) { + if (loadFileEM4x50(filename, etd.data, sizeof(etd.data)) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } @@ -1033,7 +1046,9 @@ int CmdEM4x50Sim(const char *Cmd) { bool errors = false; uint8_t cmdp = 0; - uint32_t word = 0x00; + char filename[FILE_PATH_SIZE] = {0}; + + em4x50_data_t etd; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -1043,7 +1058,12 @@ int CmdEM4x50Sim(const char *Cmd) { break; case 'u': - word = param_get32ex(Cmd, cmdp + 1, 0, 16); + etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); + cmdp += 2; + break; + + case 'f': + param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); cmdp += 2; break; @@ -1058,10 +1078,16 @@ int CmdEM4x50Sim(const char *Cmd) { if (errors) return usage_lf_em4x50_sim(); - PrintAndLogEx(INFO, "Simulating " _YELLOW_("%08x"), word); + PrintAndLogEx(INFO, "Start simulating"); + + // read data from dump file; file type has to be "bin", "eml" or "json" + if (loadFileEM4x50(filename, etd.data, sizeof(etd.data)) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Read error"); + return PM3_EFILE; + } clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&word, sizeof(word)); + SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); From 0a41049bf6011cdf5bc6b440ca9ff2fc7c54707d Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 27 Oct 2020 01:09:19 +0100 Subject: [PATCH 061/174] adjusted descriptions --- client/src/cmdlfem4x50.c | 41 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 1143939cf..a86650c2b 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -19,35 +19,34 @@ static int usage_lf_em4x50_info(void) { PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [v] [p ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info p fa225de1")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info v p fa225de1")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } static int usage_lf_em4x50_write(void) { PrintAndLogEx(NORMAL, "Write EM4x50 word. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] [a
] [w ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] b d [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " b - memory address to write to (dec)"); + PrintAndLogEx(NORMAL, " b - block address to write to (dec)"); PrintAndLogEx(NORMAL, " d - word to write (hex, lsb)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write a 3 w deadc0de")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write b 3 d deadc0de")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } static int usage_lf_em4x50_write_password(void) { PrintAndLogEx(NORMAL, "Write EM4x50 password. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] [p ] [n ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] p n ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); @@ -60,14 +59,14 @@ static int usage_lf_em4x50_write_password(void) { static int usage_lf_em4x50_read(void) { PrintAndLogEx(NORMAL, "Read EM4x50 word(s). Tag must be on antenna."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] [a
] [p ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] b [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " b - memory address to read (dec) (optional)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " b - block address to read (dec)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read a 2 p 00000000")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read b 32")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read b 2 p 00000000")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -78,7 +77,7 @@ static int usage_lf_em4x50_dump(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " f - overide filename prefix (optional). Default is based on UID"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump p 11223344")); @@ -88,7 +87,7 @@ static int usage_lf_em4x50_dump(void) { static int usage_lf_em4x50_wipe(void) { PrintAndLogEx(NORMAL, "Wipe data from EM4x50 tag. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_wipe [h] [p ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_wipe [h] p "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); @@ -147,12 +146,12 @@ static int usage_lf_em4x50_watch(void) { static int usage_lf_em4x50_restore(void) { PrintAndLogEx(NORMAL, "Restore EM4x50 dump to tag. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_restore [h]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_restore [h] [u ] [f ] [p ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); - PrintAndLogEx(NORMAL, " f - data filename (optional)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb) (optional)"); + PrintAndLogEx(NORMAL, " f - data filename "); + PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore h")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.bin")); @@ -164,13 +163,15 @@ static int usage_lf_em4x50_restore(void) { static int usage_lf_em4x50_sim(void) { PrintAndLogEx(NORMAL, "Simulate single EM4x50 word. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] [u ] [f ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " u - single word to simulate (hex, lsb"); + PrintAndLogEx(NORMAL, " u - single word (e.g. UID) to simulate (hex, lsb"); + PrintAndLogEx(NORMAL, " f - data filename "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim h")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim u 12345678")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim f em4x50dump.json")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } From ce5181bdc90fcf6f6d0442820b66ba25bea9aaa0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 27 Oct 2020 18:18:02 +0100 Subject: [PATCH 062/174] added std_read command for em4x50 --- armsrc/appmain.c | 4 ++ armsrc/em4x50.c | 28 +++++++++++--- armsrc/em4x50.h | 1 + client/src/cmdlfem4x.c | 1 + client/src/cmdlfem4x50.c | 80 +++++++++++++++++++++++++++++++++++++++- client/src/cmdlfem4x50.h | 1 + include/pm3_cmd.h | 1 + 7 files changed, 110 insertions(+), 6 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 897b5718d..cfbf3f219 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1126,6 +1126,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_sim((em4x50_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_STD_READ: { + em4x50_std_read(); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 9868ce6c2..14029803e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -885,7 +885,7 @@ void em4x50_info(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) - uint32_t words[32] = {0x0}; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -915,7 +915,7 @@ void em4x50_read(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; int now = 0; uint8_t status = 0; - uint32_t words[32] = {0x0}; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -1044,7 +1044,7 @@ void em4x50_write(em4x50_data_t *etd) { bool bsuccess = false, blogin = false; uint8_t status = 0; - uint32_t words[34] = {0x0}; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -1119,7 +1119,7 @@ void em4x50_wipe(uint32_t *password) { bool bsuccess = false; uint32_t addresses = 0x00001E01; // from fwr = 1 to lwr = 31 (0x1E) - uint32_t words[34] = {0x0}; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; uint32_t zero = 0x0; em4x50_setup_read(); @@ -1268,7 +1268,7 @@ void em4x50_watch() { // read continuously and display standard reads of tag int now = 0; - uint32_t words[34] = {0x0}; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -1447,3 +1447,21 @@ void em4x50_sim(em4x50_data_t *etd) { lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, 1, 0, 0); } + +void em4x50_std_read(void) { + + // reads data that tag transmits "voluntarily" -> standard read mode + + int now = 0; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) + standard_read(&now, words); + + LOW(GPIO_SSC_DOUT); + lf_finalize(); + reply_ng(CMD_LF_EM4X50_STD_READ, now, (uint8_t *)words, 4 * now); +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index e286e91f7..75f663db2 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -30,5 +30,6 @@ void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(em4x50_data_t *etd); +void em4x50_std_read(void); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index fdf593fc5..3ae292848 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -663,6 +663,7 @@ static command_t CommandTable[] = { {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate single EM4x50 word (uid)"}, + {"4x50_std_read",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a86650c2b..f1d51efd5 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -175,6 +175,17 @@ static int usage_lf_em4x50_sim(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_std_read(void) { + PrintAndLogEx(NORMAL, "Show standard read mode data of EM4x50 tag. Tag must be on antenna."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_std_read [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_std_read")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) { @@ -426,7 +437,6 @@ int CmdEM4x50Write(const char *Cmd) { PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; - } } @@ -1100,3 +1110,71 @@ int CmdEM4x50Sim(const char *Cmd) { return PM3_SUCCESS; } + +int CmdEM4x50StdRead(const char *Cmd) { + + bool errors = false; + uint8_t cmdp = 0; + int now = 0; + PacketResponseNG resp; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_std_read(); + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors) + return usage_lf_em4x50_std_read(); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_STD_READ, 0, 0); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_STD_READ, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + now = resp.status; + + // print response + if (now > 0) { + + em4x50_word_t words[EM4X50_NO_WORDS]; + + prepare_result(resp.data.asBytes, 0, now - 1, words); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " # | word (msb) | word (lsb) "); + PrintAndLogEx(INFO, "----+-------------+-------------"); + + for (int i = 0; i < now; i++) { + + char r[30] = {0}; + for (int j = 3; j >= 0; j--) + sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + + PrintAndLogEx(INFO, " %2i | " _GREEN_("%s") "| %s", + i, + sprint_hex(words[i].byte, 4), + r + ); + } + + PrintAndLogEx(INFO, "----+-------------+-------------"); + PrintAndLogEx(SUCCESS, "Standard read " _GREEN_("ok")); + + } else { + PrintAndLogEx(FAILED, "Standard read " _RED_("failed")); + } + + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index acadd2084..2eaeb8b86 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -30,5 +30,6 @@ int CmdEM4x50Reset(const char *Cmd); int CmdEM4x50Watch(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); int CmdEM4x50Sim(const char *Cmd); +int CmdEM4x50StdRead(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 8124cd82b..5f4abb85e 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -514,6 +514,7 @@ typedef struct { #define CMD_LF_EM4X50_WATCH 0x0248 #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 +#define CMD_LF_EM4X50_STD_READ 0x0251 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 140037d9f0e5e3a42b9db5721affcd16f505a361 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 27 Oct 2020 19:16:54 +0100 Subject: [PATCH 063/174] Adaptation of the implementation of read function to that currently used in master branch --- armsrc/em4x50.c | 28 +++++++--------------------- client/src/cmdlfem4x50.c | 34 ++++++++++------------------------ client/src/cmdlfem4x50.h | 2 +- client/src/scripting.c | 2 +- 4 files changed, 19 insertions(+), 47 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 14029803e..f3e1ebf06 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -907,13 +907,9 @@ void em4x50_info(em4x50_data_t *etd) { void em4x50_read(em4x50_data_t *etd) { - // reads in two different ways: - // - using "selective read mode" -> bidirectional communication - // - using "standard read mode" -> unidirectional communication (read - // data that tag transmits "voluntarily") + // reads by using "selective read mode" -> bidirectional communication bool bsuccess = false, blogin = false; - int now = 0; uint8_t status = 0; uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -922,26 +918,16 @@ void em4x50_read(em4x50_data_t *etd) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { - if (etd->addr_given) { + // try to login with given password + if (etd->pwd_given) + blogin = login(etd->password1); - // selective read mode + // only one word has to be read -> first word read = last word read + bsuccess = selective_read(etd->addresses, words); - // try to login with given password - if (etd->pwd_given) - blogin = login(etd->password1); - - // only one word has to be read -> first word read = last word read - bsuccess = selective_read(etd->addresses, words); - - } else { - - // standard read mode - bsuccess = standard_read(&now, words); - - } } - status = (now << 2) + (bsuccess << 1) + blogin; + status = (bsuccess << 1) + blogin; LOW(GPIO_SSC_DOUT); lf_finalize(); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index f1d51efd5..7f889a058 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -321,17 +321,17 @@ bool detect_4x50_block(void) { .addresses = EM4X50_DEVICE_ID, }; em4x50_word_t words[EM4X50_NO_WORDS]; - return (em4x50_read(&etd, words, false) == PM3_SUCCESS); + return (em4x50_read(&etd, words) == PM3_SUCCESS); } int read_em4x50_uid(void) { em4x50_data_t etd = { .pwd_given = false, .addr_given = true, - .addresses = EM4X50_DEVICE_SERIAL, + .addresses = (EM4X50_DEVICE_SERIAL << 8) | EM4X50_DEVICE_SERIAL, }; em4x50_word_t words[EM4X50_NO_WORDS]; - int res = em4x50_read(&etd, words, false); + int res = em4x50_read(&etd, words); if (res == PM3_SUCCESS) PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4)); return res; @@ -543,11 +543,10 @@ int CmdEM4x50WritePassword(const char *Cmd) { return (success) ? PM3_SUCCESS : PM3_ESOFT; } -int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { +int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { // envoke reading - // - without option -> standard read mode - // - with given address (option a) (and optional password if address is + // - with given address (option b) (and optional password if address is // read protected) -> selective read mode em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; @@ -566,12 +565,8 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { } bool isOK = (resp.status & STATUS_SUCCESS) >> 1; - if (isOK == false) { - if (verbose) - PrintAndLogEx(FAILED, "Reading " _RED_("failed")); - + if (isOK == false) return PM3_ESOFT; - } if (edata.pwd_given) { bool login = resp.status & STATUS_LOGIN; @@ -584,21 +579,13 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { uint8_t *data = resp.data.asBytes; em4x50_word_t words[EM4X50_NO_WORDS]; - int now = (resp.status & STATUS_NO_WORDS) >> 2; - if (edata.addr_given) { - prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); - } else { - prepare_result(data, 0, now - 1, words); - } + prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); if (out != NULL) { memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); } - if (edata.addr_given) - print_result(words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF); - else - print_result(words, 0, now - 1); + print_result(words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF); return PM3_SUCCESS; } @@ -650,11 +637,10 @@ int CmdEM4x50Read(const char *Cmd) { } } - //if (errors || strlen(Cmd) == 0 || etd.addr_given == false) - if (errors) + if (errors || strlen(Cmd) == 0 || etd.addr_given == false) return usage_lf_em4x50_read(); - return em4x50_read(&etd, NULL, true); + return em4x50_read(&etd, NULL); } int CmdEM4x50Dump(const char *Cmd) { diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 2eaeb8b86..5873e257e 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -16,7 +16,7 @@ int read_em4x50_uid(void); bool detect_4x50_block(void); -int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose); +int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out); int CmdEM4x50Info(const char *Cmd); int CmdEM4x50Write(const char *Cmd); diff --git a/client/src/scripting.c b/client/src/scripting.c index 3ed82591a..f594bd3aa 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -1171,7 +1171,7 @@ static int l_em4x50_read(lua_State *L) { em4x50_word_t words[EM4X50_NO_WORDS]; - int res = em4x50_read(&etd, words, false); + int res = em4x50_read(&etd, words); if (res != PM3_SUCCESS) { return returnToLuaWithError(L, "Failed to read EM4x50 data"); } From 236e3f82d867310f581db16385f820232be64c8c Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 28 Oct 2020 12:41:28 +0100 Subject: [PATCH 064/174] 4x50_sim: options 'u' and 'f' can not be used at the same time --- client/src/cmdlfem4x50.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 7f889a058..987cff499 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1041,7 +1041,7 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - bool errors = false; + bool errors = false, word_given = false;; uint8_t cmdp = 0; char filename[FILE_PATH_SIZE] = {0}; @@ -1056,6 +1056,7 @@ int CmdEM4x50Sim(const char *Cmd) { case 'u': etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); + word_given = true; cmdp += 2; break; @@ -1071,9 +1072,14 @@ int CmdEM4x50Sim(const char *Cmd) { }; } - // validation + // validations if (errors) return usage_lf_em4x50_sim(); + + if (word_given && (strlen(filename) != 0)) { + PrintAndLogEx(INFO, "Plesae use either option 'u' or option 'f'"); + return usage_lf_em4x50_sim(); + } PrintAndLogEx(INFO, "Start simulating"); From eefb8b82b9538459f90ba89216273c14336ad86f Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 29 Oct 2020 00:01:15 +0100 Subject: [PATCH 065/174] use of already existing function in util.c --- client/src/cmdlfem4x50.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 987cff499..9d46fe6b8 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -12,6 +12,7 @@ #include #include "fileutils.h" #include "comms.h" +#include "util.h" #include "commonutil.h" #include "cmdparser.h" #include "em4x50.h" @@ -193,22 +194,17 @@ static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) int res = 0; size_t bytes_read = 0; - char ext[FILE_PATH_SIZE] = {0}; - - - memcpy(ext, &filename[strlen(filename) - 4], 4); - ext[5] = 0x00; - - if (memcmp(ext, ".eml", 4) == 0) + + if (str_endswith(filename, ".eml")) res = loadFileEML(filename, data, &bytes_read) != PM3_SUCCESS; - else if (memcmp(ext, ".bin", 4) == 0) - res = loadFile(filename, ".bin", data, data_len, &bytes_read); - else + else if (str_endswith(filename, ".json")) res = loadFileJSON(filename, data, data_len, &bytes_read, NULL); + else + res = loadFile(filename, ".bin", data, data_len, &bytes_read); if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) return PM3_EFILE; - + return PM3_SUCCESS; } @@ -1081,7 +1077,10 @@ int CmdEM4x50Sim(const char *Cmd) { return usage_lf_em4x50_sim(); } - PrintAndLogEx(INFO, "Start simulating"); + if (word_given) + PrintAndLogEx(INFO, "Simulating " _YELLOW_("%08x"), etd.word); + else + PrintAndLogEx(INFO, "Simulating dump " _YELLOW_("%s"), filename); // read data from dump file; file type has to be "bin", "eml" or "json" if (loadFileEM4x50(filename, etd.data, sizeof(etd.data)) != PM3_SUCCESS) { From 4c95c16e5405b4039d33d4b585a9e5bf00815ecb Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 29 Oct 2020 00:23:14 +0100 Subject: [PATCH 066/174] address has to be inserted twice, otherwise loop from for -> lwr fails, since lwr is 0 --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 9d46fe6b8..879ad0991 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -314,7 +314,7 @@ bool detect_4x50_block(void) { em4x50_data_t etd = { .pwd_given = false, .addr_given = true, - .addresses = EM4X50_DEVICE_ID, + .addresses = (EM4X50_DEVICE_ID << 8) | EM4X50_DEVICE_ID, }; em4x50_word_t words[EM4X50_NO_WORDS]; return (em4x50_read(&etd, words) == PM3_SUCCESS); From 18326934d61a84b96846b38c5de350b4d99e0cc5 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 29 Oct 2020 23:12:46 +0100 Subject: [PATCH 067/174] compact address assignment --- client/src/cmdlfem4x50.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 879ad0991..0cf298292 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -607,9 +607,7 @@ int CmdEM4x50Read(const char *Cmd) { case 'b': { param_getdec(Cmd, cmdp + 1, &address); // lsb: byte 1 = fwr, byte 2 = lwr, byte 3 = 0x0, byte 4 = 0x0 - etd.addresses = address; // lwr - etd.addresses <<= 8; - etd.addresses |= address; // fwr + etd.addresses = (address << 8) | address; // validation if (address <= 0 || address >= EM4X50_NO_WORDS) { From bb04832b9de60d0e52f0c140e60a797537e1a8c1 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 30 Oct 2020 00:41:45 +0100 Subject: [PATCH 068/174] first version of 4x50_eload and 4x50_esave --- client/src/cmdlfem4x.c | 2 + client/src/cmdlfem4x50.c | 178 +++++++++++++++++++++++++++++++++++++-- client/src/cmdlfem4x50.h | 2 + include/pm3_cmd.h | 1 + 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 3ae292848..56681af91 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -664,6 +664,8 @@ static command_t CommandTable[] = { {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate single EM4x50 word (uid)"}, {"4x50_std_read",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, + {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "load a binary dump into emulator memory"}, + {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 0cf298292..7978331da 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -187,6 +187,31 @@ static int usage_lf_em4x50_std_read(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_lf_em4x50_eload(void) { + PrintAndLogEx(NORMAL, "Load dump file into emulator memory."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_eload [h] f "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " f - dump filename "); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_eload f em4x50dump.bin")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} +static int usage_lf_em4x50_esave(void) { + PrintAndLogEx(NORMAL, "Save emulator memory to file."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_esave [h] [f ]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " f - dump filename "); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_esave")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_esave f em4x50dump.bin")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) { @@ -950,6 +975,7 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { + size_t fn_len = 0; char filename[FILE_PATH_SIZE] = {0}; char szTemp[FILE_PATH_SIZE - 20] = {0x00}; @@ -973,7 +999,9 @@ int CmdEM4x50Restore(const char *Cmd) { break; case 'f': - param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (fn_len == 0) + errors = true; cmdp += 2; break; @@ -1035,7 +1063,8 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - bool errors = false, word_given = false;; + bool errors = false, word_given = false, fn_given = false; + size_t fn_len = 0; uint8_t cmdp = 0; char filename[FILE_PATH_SIZE] = {0}; @@ -1055,7 +1084,11 @@ int CmdEM4x50Sim(const char *Cmd) { break; case 'f': - param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (fn_len != 0) + fn_given = true; + else + errors = true; cmdp += 2; break; @@ -1067,10 +1100,10 @@ int CmdEM4x50Sim(const char *Cmd) { } // validations - if (errors) + if (errors || ((word_given == false) && (fn_given == false))) return usage_lf_em4x50_sim(); - if (word_given && (strlen(filename) != 0)) { + if (word_given && fn_given) { PrintAndLogEx(INFO, "Plesae use either option 'u' or option 'f'"); return usage_lf_em4x50_sim(); } @@ -1167,3 +1200,138 @@ int CmdEM4x50StdRead(const char *Cmd) { return PM3_SUCCESS; } + +static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { + + // fast push mode + conn.block_after_ACK = true; + + for (size_t i = offset; i < nobytes; i += PM3_CMD_DATA_SIZE) { + + size_t len = MIN((nobytes - i), PM3_CMD_DATA_SIZE); + if (len == nobytes - i) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + + clearCommandBuffer(); + SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); + } +} + +int CmdEM4x50ELoad(const char *Cmd) { + + bool errors = false, fn_given = false; + size_t nobytes = DUMP_FILESIZE, fn_len = 0; + uint8_t cmdp = 0; + char filename[FILE_PATH_SIZE] = {0}; + uint8_t *data = calloc(nobytes, sizeof(uint8_t)); + + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_eload(); + break; + + case 'f': + fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (fn_len != 0) + fn_given = true; + else + errors = true; + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + }; + } + + // validations + if (errors || (fn_given == false)) + return usage_lf_em4x50_eload(); + + // read data from dump file; file type has to be "bin", "eml" or "json" + if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Read error"); + return PM3_EFILE; + } + + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + em4x50_seteml(data, 0, nobytes); + + free(data); + PrintAndLogEx(SUCCESS, "Done"); + return PM3_SUCCESS; +} + +int CmdEM4x50ESave(const char *Cmd) { + + bool errors = false; + size_t nobytes = DUMP_FILESIZE, fn_len = 0; + uint8_t cmdp = 0; + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + uint8_t *data = calloc(nobytes, sizeof(uint8_t)); + + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x50_esave(); + break; + + case 'f': + fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (fn_len == 0) + errors = true; + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + }; + } + + // validations + if (errors) + return usage_lf_em4x50_esave(); + + // download emulator memory + PrintAndLogEx(SUCCESS, "Reading emulator memory..."); + if (!GetFromDevice(BIG_BUF_EML, data, nobytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(data); + return PM3_ETIMEOUT; + } + + // user supplied filename? + if (fn_len == 0) { + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += snprintf(fptr, sizeof(filename), "lf-4x50-"); + FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); + } + + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + em4x50_seteml(data, 0, nobytes); + + saveFile(filename, ".bin", data, nobytes); + saveFileEML(filename, data, nobytes, 4); + saveFileJSON(filename, jsfEM4x50, data, nobytes, NULL); + return PM3_SUCCESS; +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 5873e257e..2c84d9f15 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -31,5 +31,7 @@ int CmdEM4x50Watch(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); int CmdEM4x50Sim(const char *Cmd); int CmdEM4x50StdRead(const char *Cmd); +int CmdEM4x50ELoad(const char *Cmd); +int CmdEM4x50ESave(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 5f4abb85e..f588f19b3 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -515,6 +515,7 @@ typedef struct { #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 #define CMD_LF_EM4X50_STD_READ 0x0251 +#define CMD_LF_EM4X50_ESET 0x0252 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 902b52ab02579ed03ef0c0ddbb56af9e15a7c61f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 01:49:46 +0100 Subject: [PATCH 069/174] using emulator memory for sim and restore --- armsrc/em4x50.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index f3e1ebf06..38c3c8269 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -122,6 +122,22 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } +static void emlGetMem(uint32_t *words, size_t nowords) { + + // read words from emulator memory + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + + for (int j = 0; j < 4; j++) + words[i] |= (em4x50_mem[4 * i + j]) << ((3 - j) * 8); + + // lsb is needed (given format is msb) + words[i] = reflect32(words[i]); + } +} + // functions for "reader" use case static bool get_signalproperties(void) { @@ -1336,15 +1352,8 @@ void em4x50_restore(em4x50_data_t *etd) { em4x50_setup_read(); - // read data - for (int i = 0; i < EM4X50_NO_WORDS; i++) { - - for (int j = 0; j < 4; j++) - words_client[i] |= (etd->data[4 * i + j]) << ((3 - j) * 8); - - // lsb is needed (dump is msb) - words_client[i] = reflect32(words_client[i]); - } + // read data from emulator memory + emlGetMem(words_client, EM4X50_NO_WORDS); // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { @@ -1389,23 +1398,17 @@ void em4x50_restore(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); } -void em4x50_sim(em4x50_data_t *etd) { +void em4x50_sim(void) { - // simulate either word (e.g. UID) or complete tag via dump file upload + // simulate uploaded data in emulator memory + // (currently only a one-way communication is possible) uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_sim(); - // read data - for (int i = 0; i < EM4X50_NO_WORDS; i++) { - - for (int j = 0; j < 4; j++) - words[i] |= (etd->data[4 * i + j]) << ((3 - j) * 8); - - // lsb is needed (dump is msb) - words[i] = reflect32(words[i]); - } + // read data from emulator memory + emlGetMem(words, EM4X50_NO_WORDS); // extract control data int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read From f412b20fc1b58c7e42659ad49a08bdd664cb6d2a Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 01:50:03 +0100 Subject: [PATCH 070/174] sing emulator memory for sim and restore --- armsrc/em4x50.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 75f663db2..35c519a9e 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -29,7 +29,7 @@ void em4x50_login(uint32_t *password); void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); -void em4x50_sim(em4x50_data_t *etd); +void em4x50_sim(void); void em4x50_std_read(void); #endif /* EM4X50_H */ From 033155e358f6947db8adf9674fb060f1ad0cd8f4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 01:50:24 +0100 Subject: [PATCH 071/174] sing emulator memory for sim and restore --- armsrc/appmain.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index cfbf3f219..70256e80c 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1123,13 +1123,23 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_SIM: { - em4x50_sim((em4x50_data_t *)packet->data.asBytes); + em4x50_sim(); break; } case CMD_LF_EM4X50_STD_READ: { em4x50_std_read(); break; } + case CMD_LF_EM4X50_ESET: { + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it might + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]); + break; + } #endif #ifdef WITH_ISO15693 From 754285d9c714b4b874454a4d18d2e328f8ace917 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 01:51:04 +0100 Subject: [PATCH 072/174] sing emulator memory for sim and restore -> "data" in struct no longer necessary --- include/em4x50.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/em4x50.h b/include/em4x50.h index d422cf9c1..a4c3cacd3 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -49,7 +49,6 @@ typedef struct { uint32_t password2; uint32_t word; uint32_t addresses; - uint8_t data[136]; } PACKED em4x50_data_t; typedef struct { From 35a671d592c26e920c893c5efd0c9db79ca51df0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 01:51:40 +0100 Subject: [PATCH 073/174] sing emulator memory for sim and restore --- client/src/cmdlfem4x50.c | 101 ++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 7978331da..ed311242c 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -162,16 +162,15 @@ static int usage_lf_em4x50_restore(void) { return PM3_SUCCESS; } static int usage_lf_em4x50_sim(void) { - PrintAndLogEx(NORMAL, "Simulate single EM4x50 word. "); + PrintAndLogEx(NORMAL, "Simulate dump of EM4x50 tag in emulatoe memory. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] [u ] [f ]"); + PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] [f ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " u - single word (e.g. UID) to simulate (hex, lsb"); - PrintAndLogEx(NORMAL, " f - data filename "); + PrintAndLogEx(NORMAL, " f - dump filename (bin/eml/json) for emulator memory upload"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim h")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim u 12345678")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim f em4x50dump.json")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -233,6 +232,24 @@ static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) return PM3_SUCCESS; } +static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { + + // fast push mode + conn.block_after_ACK = true; + + for (size_t i = offset; i < nobytes; i += PM3_CMD_DATA_SIZE) { + + size_t len = MIN((nobytes - i), PM3_CMD_DATA_SIZE); + if (len == nobytes - i) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + + clearCommandBuffer(); + SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); + } +} + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -978,8 +995,14 @@ int CmdEM4x50Restore(const char *Cmd) { size_t fn_len = 0; char filename[FILE_PATH_SIZE] = {0}; char szTemp[FILE_PATH_SIZE - 20] = {0x00}; - em4x50_data_t etd; + uint8_t *data = calloc(DUMP_FILESIZE, sizeof(uint8_t)); + + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + etd.pwd_given = false; bool errors = false; @@ -1025,11 +1048,14 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, etd.data, sizeof(etd.data)) != PM3_SUCCESS) { + if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } + em4x50_seteml(data, 0, DUMP_FILESIZE); + free(data); + clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); PacketResponseNG resp; @@ -1063,12 +1089,16 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - bool errors = false, word_given = false, fn_given = false; + bool errors = false, fn_given = false; size_t fn_len = 0; uint8_t cmdp = 0; char filename[FILE_PATH_SIZE] = {0}; + uint8_t *data = calloc(DUMP_FILESIZE, sizeof(uint8_t)); - em4x50_data_t etd; + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -1077,12 +1107,6 @@ int CmdEM4x50Sim(const char *Cmd) { return usage_lf_em4x50_sim(); break; - case 'u': - etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); - word_given = true; - cmdp += 2; - break; - case 'f': fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); if (fn_len != 0) @@ -1100,27 +1124,26 @@ int CmdEM4x50Sim(const char *Cmd) { } // validations - if (errors || ((word_given == false) && (fn_given == false))) + if (errors) return usage_lf_em4x50_sim(); - if (word_given && fn_given) { - PrintAndLogEx(INFO, "Plesae use either option 'u' or option 'f'"); - return usage_lf_em4x50_sim(); - } - - if (word_given) - PrintAndLogEx(INFO, "Simulating " _YELLOW_("%08x"), etd.word); - else - PrintAndLogEx(INFO, "Simulating dump " _YELLOW_("%s"), filename); - // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, etd.data, sizeof(etd.data)) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Read error"); - return PM3_EFILE; + if (fn_given) { + if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Read error"); + return PM3_EFILE; + } + + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + + em4x50_seteml(data, 0, DUMP_FILESIZE); + free(data); } + PrintAndLogEx(INFO, "Simulating data in emulator memory " _YELLOW_("%s"), filename); + clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&etd, sizeof(etd)); + SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); @@ -1201,24 +1224,6 @@ int CmdEM4x50StdRead(const char *Cmd) { return PM3_SUCCESS; } -static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { - - // fast push mode - conn.block_after_ACK = true; - - for (size_t i = offset; i < nobytes; i += PM3_CMD_DATA_SIZE) { - - size_t len = MIN((nobytes - i), PM3_CMD_DATA_SIZE); - if (len == nobytes - i) { - // Disable fast mode on last packet - conn.block_after_ACK = false; - } - - clearCommandBuffer(); - SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); - } -} - int CmdEM4x50ELoad(const char *Cmd) { bool errors = false, fn_given = false; From 098ca87c818b3617946e6047b6b1b1b8ecdc6e22 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 31 Oct 2020 14:53:52 +0100 Subject: [PATCH 074/174] renamed std_read -> stdread --- armsrc/appmain.c | 4 ++-- armsrc/em4x50.c | 30 +++++++++--------------------- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x.c | 2 +- client/src/cmdlfem4x50.c | 10 +++++----- include/pm3_cmd.h | 2 +- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 70256e80c..e11f75a19 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1126,8 +1126,8 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_sim(); break; } - case CMD_LF_EM4X50_STD_READ: { - em4x50_std_read(); + case CMD_LF_EM4X50_STDREAD: { + em4x50_stdread(); break; } case CMD_LF_EM4X50_ESET: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 38c3c8269..f4ed5ba01 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -122,22 +122,6 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } -static void emlGetMem(uint32_t *words, size_t nowords) { - - // read words from emulator memory - - uint8_t *em4x50_mem = BigBuf_get_EM_addr(); - - for (int i = 0; i < EM4X50_NO_WORDS; i++) { - - for (int j = 0; j < 4; j++) - words[i] |= (em4x50_mem[4 * i + j]) << ((3 - j) * 8); - - // lsb is needed (given format is msb) - words[i] = reflect32(words[i]); - } -} - // functions for "reader" use case static bool get_signalproperties(void) { @@ -1346,6 +1330,7 @@ void em4x50_restore(em4x50_data_t *etd) { int res = 0; int start_word = 0; uint8_t status = 0; + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; uint32_t words_read[EM4X50_NO_WORDS] = {0x0}; @@ -1353,8 +1338,9 @@ void em4x50_restore(em4x50_data_t *etd) { em4x50_setup_read(); // read data from emulator memory - emlGetMem(words_client, EM4X50_NO_WORDS); - + for (int i = 0; i < EM4X50_NO_WORDS; i++) + words_client[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { @@ -1403,12 +1389,14 @@ void em4x50_sim(void) { // simulate uploaded data in emulator memory // (currently only a one-way communication is possible) + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_sim(); // read data from emulator memory - emlGetMem(words, EM4X50_NO_WORDS); + for (int i = 0; i < EM4X50_NO_WORDS; i++) + words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); // extract control data int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read @@ -1437,7 +1425,7 @@ void em4x50_sim(void) { reply_ng(CMD_LF_EM4X50_SIM, 1, 0, 0); } -void em4x50_std_read(void) { +void em4x50_stdread(void) { // reads data that tag transmits "voluntarily" -> standard read mode @@ -1452,5 +1440,5 @@ void em4x50_std_read(void) { LOW(GPIO_SSC_DOUT); lf_finalize(); - reply_ng(CMD_LF_EM4X50_STD_READ, now, (uint8_t *)words, 4 * now); + reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); } diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 35c519a9e..57ad94b4d 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -30,6 +30,6 @@ void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); -void em4x50_std_read(void); +void em4x50_stdread(void); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 56681af91..8370edcfb 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -663,7 +663,7 @@ static command_t CommandTable[] = { {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate single EM4x50 word (uid)"}, - {"4x50_std_read",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, + {"4x50_stdread",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "load a binary dump into emulator memory"}, {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ed311242c..ffd4c236c 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -175,7 +175,7 @@ static int usage_lf_em4x50_sim(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_lf_em4x50_std_read(void) { +static int usage_lf_em4x50_stdread(void) { PrintAndLogEx(NORMAL, "Show standard read mode data of EM4x50 tag. Tag must be on antenna."); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: lf em 4x50_std_read [h]"); @@ -1168,7 +1168,7 @@ int CmdEM4x50StdRead(const char *Cmd) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': - return usage_lf_em4x50_std_read(); + return usage_lf_em4x50_stdread(); default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); @@ -1178,12 +1178,12 @@ int CmdEM4x50StdRead(const char *Cmd) { } if (errors) - return usage_lf_em4x50_std_read(); + return usage_lf_em4x50_stdread(); // start clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_STD_READ, 0, 0); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_STD_READ, &resp, TIMEOUT)) { + SendCommandNG(CMD_LF_EM4X50_STDREAD, 0, 0); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_STDREAD, &resp, TIMEOUT)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f588f19b3..9ad61d4a7 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -514,7 +514,7 @@ typedef struct { #define CMD_LF_EM4X50_WATCH 0x0248 #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 -#define CMD_LF_EM4X50_STD_READ 0x0251 +#define CMD_LF_EM4X50_STDREAD 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D From 3ddd9f8a914ef685fc9f43b8e20215c806445a73 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 1 Nov 2020 22:44:16 +0100 Subject: [PATCH 075/174] - added first version of 4x50_chk - renamed 4x50_write_password to 4x50_writepwd --- armsrc/appmain.c | 8 ++++++-- armsrc/em4x50.h | 3 ++- client/src/cmdlfem4x.c | 3 ++- client/src/cmdlfem4x50.h | 3 ++- include/pm3_cmd.h | 3 ++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index dfd4f0751..0fdfa6fd1 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1090,8 +1090,8 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_write((em4x50_data_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_WRITE_PASSWORD: { - em4x50_write_password((em4x50_data_t *)packet->data.asBytes); + case CMD_LF_EM4X50_WRITEPWD: { + em4x50_writepwd((em4x50_data_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_READ: { @@ -1140,6 +1140,10 @@ static void PacketReceived(PacketCommandNG *packet) { emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]); break; } + case CMD_LF_EM4X50_CHK: { + em4x50_chk((uint32_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 57ad94b4d..d1a94d662 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -21,7 +21,7 @@ bool em4x50_sim_send_word(uint32_t word); void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); -void em4x50_write_password(em4x50_data_t *etd); +void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_wipe(uint32_t *password); void em4x50_brute(em4x50_data_t *etd); @@ -31,5 +31,6 @@ void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); void em4x50_stdread(void); +void em4x50_chk(uint32_t *numkeys); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 8370edcfb..0c038a438 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -654,7 +654,7 @@ static command_t CommandTable[] = { {"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, {"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"}, + {"4x50_writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50 tag"}, {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, @@ -666,6 +666,7 @@ static command_t CommandTable[] = { {"4x50_stdread",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "load a binary dump into emulator memory"}, {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, + {"4x50_chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 2c84d9f15..753210f0a 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -20,7 +20,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out); int CmdEM4x50Info(const char *Cmd); int CmdEM4x50Write(const char *Cmd); -int CmdEM4x50WritePassword(const char *Cmd); +int CmdEM4x50WritePwd(const char *Cmd); int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); @@ -33,5 +33,6 @@ int CmdEM4x50Sim(const char *Cmd); int CmdEM4x50StdRead(const char *Cmd); int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); +int CmdEM4x50Chk(const char *Cmd); #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index bf05735da..d90b78f60 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -505,7 +505,7 @@ typedef struct { #define CMD_LF_EM410X_WATCH 0x021C #define CMD_LF_EM4X50_INFO 0x0240 #define CMD_LF_EM4X50_WRITE 0x0241 -#define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242 +#define CMD_LF_EM4X50_WRITEPWD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 #define CMD_LF_EM4X50_BRUTE 0x0245 @@ -516,6 +516,7 @@ typedef struct { #define CMD_LF_EM4X50_SIM 0x0250 #define CMD_LF_EM4X50_STDREAD 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 +#define CMD_LF_EM4X50_CHK 0x0253 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 65a591119b26c5120dcd8106533a1f28ad087a78 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 1 Nov 2020 22:47:00 +0100 Subject: [PATCH 076/174] - added first version of 4x50_chk - renamed 4x50_write_password to 4x50_writepwd - added check regarding valid data in emulation memory for 4x50_sim --- armsrc/em4x50.c | 72 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index f4ed5ba01..3dba0edb1 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1072,7 +1072,7 @@ void em4x50_write(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); } -void em4x50_write_password(em4x50_data_t *etd) { +void em4x50_writepwd(em4x50_data_t *etd) { // simple change of password @@ -1096,7 +1096,7 @@ void em4x50_write_password(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITE_PASSWORD, bsuccess, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITEPWD, bsuccess, 0, 0); } void em4x50_wipe(uint32_t *password) { @@ -1389,6 +1389,7 @@ void em4x50_sim(void) { // simulate uploaded data in emulator memory // (currently only a one-way communication is possible) + int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -1398,31 +1399,36 @@ void em4x50_sim(void) { for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - // extract control data - int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read - int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read + if ((words[EM4X50_DEVICE_SERIAL] != 0x0) && (words[EM4X50_DEVICE_ID] != 0X0)) { - // extract protection data - int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + // extract control data + int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read + int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read - while (!BUTTON_PRESS()) { - - WDT_HIT(); - em4x50_sim_send_listen_window(); - for (int i = fwr; i <= lwr; i++) { + // extract protection data + int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + while (!BUTTON_PRESS()) { + + WDT_HIT(); em4x50_sim_send_listen_window(); + for (int i = fwr; i <= lwr; i++) { - if ((i >= fwrp) && (i <= lwrp)) - em4x50_sim_send_word(0x00); - else - em4x50_sim_send_word(words[i]); + em4x50_sim_send_listen_window(); + + if ((i >= fwrp) && (i <= lwrp)) + em4x50_sim_send_word(0x00); + else + em4x50_sim_send_word(words[i]); + } } + } else { + status = PM3_ENODATA; } lf_finalize(); - reply_ng(CMD_LF_EM4X50_SIM, 1, 0, 0); + reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); } void em4x50_stdread(void) { @@ -1442,3 +1448,33 @@ void em4x50_stdread(void) { lf_finalize(); reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); } + +void em4x50_chk(uint32_t *numkeys) { + + // reads data that tag transmits "voluntarily" -> standard read mode + + bool bsuccess = false; + uint32_t password = 0x0; + uint32_t keys[200] = {0x0}; + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + + em4x50_setup_read(); + + // read data from emulator memory + for (int i = 0; i < *numkeys; i++) + keys[i] = bytes_to_num(em4x50_mem + (i * 4), 4); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + for (int i = 0; i < *numkeys; i++) { + if (login(keys[i])) { + bsuccess = true; + password = keys[i]; + break; + } + } + } + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_CHK, bsuccess, (uint8_t *)&password, 32); +} From 6af4bc1f1b9c46b669488514a3777287a81806cc Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 1 Nov 2020 22:51:32 +0100 Subject: [PATCH 077/174] - added first version of 4x50_chk - renamed 4x50_write_password to 4x50_writepwd - added check regarding valid data in emulation memory for 4x50_esave - minor changes - introduced new cliparser --- client/src/cmdlfem4x50.c | 1146 +++++++++++++++++--------------------- 1 file changed, 504 insertions(+), 642 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ffd4c236c..cef36a5ba 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -8,6 +8,7 @@ // Low frequency EM4x50 commands //----------------------------------------------------------------------------- +#include "cliparser.h" #include "cmdlfem4x50.h" #include #include "fileutils.h" @@ -17,201 +18,6 @@ #include "cmdparser.h" #include "em4x50.h" -static int usage_lf_em4x50_info(void) { - PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info p fa225de1")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_write(void) { - PrintAndLogEx(NORMAL, "Write EM4x50 word. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] b d [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " b - block address to write to (dec)"); - PrintAndLogEx(NORMAL, " d - word to write (hex, lsb)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write b 3 d deadc0de")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_write_password(void) { - PrintAndLogEx(NORMAL, "Write EM4x50 password. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] p n ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, " n - new password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write_password p 11223344 n 01020304")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_read(void) { - PrintAndLogEx(NORMAL, "Read EM4x50 word(s). Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] b [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " b - block address to read (dec)"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read b 32")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read b 2 p 00000000")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_dump(void) { - PrintAndLogEx(NORMAL, "Dump EM4x50 tag. Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_dump [h] [f ] [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - overide filename prefix (optional). Default is based on UID"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump p 11223344")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump f card_nnn p 11223344")); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_wipe(void) { - PrintAndLogEx(NORMAL, "Wipe data from EM4x50 tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_wipe [h] p "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wipe p 11223344")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_brute(void) { - PrintAndLogEx(NORMAL, "Guess password of EM4x50 tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_brute [h] f l "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - start password (hex, lsb)"); - PrintAndLogEx(NORMAL, " l - stop password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_brute f 11200000 l 11300000")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_login(void) { - PrintAndLogEx(NORMAL, "Login into EM4x50 tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_login [h] p "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_login p 11200000")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_reset(void) { - PrintAndLogEx(NORMAL, "Reset EM4x50 tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_reset [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_reset")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_watch(void) { - PrintAndLogEx(NORMAL, "Watch for EM4x50 tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_watch [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_watch")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_restore(void) { - PrintAndLogEx(NORMAL, "Restore EM4x50 dump to tag. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_restore [h] [u ] [f ] [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " u - uid, try to restore from lf-4x50--dump.bin"); - PrintAndLogEx(NORMAL, " f - data filename "); - PrintAndLogEx(NORMAL, " p - password (hex, lsb)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore h")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.bin")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.eml p 12345678")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_restore f em4x50dump.json p 00000001")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_sim(void) { - PrintAndLogEx(NORMAL, "Simulate dump of EM4x50 tag in emulatoe memory. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sim [h] [f ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - dump filename (bin/eml/json) for emulator memory upload"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim h")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_sim f em4x50dump.json")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_stdread(void) { - PrintAndLogEx(NORMAL, "Show standard read mode data of EM4x50 tag. Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_std_read [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_std_read")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_eload(void) { - PrintAndLogEx(NORMAL, "Load dump file into emulator memory."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_eload [h] f "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - dump filename "); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_eload f em4x50dump.bin")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_em4x50_esave(void) { - PrintAndLogEx(NORMAL, "Save emulator memory to file."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x50_esave [h] [f ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " f - dump filename "); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_esave")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_esave f em4x50dump.bin")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) { // read data from dump file; file type is derived from file name extension @@ -307,7 +113,7 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr) { PrintAndLogEx(INFO, "----+-------------+-------------+--------------------"); } -static void print_info_result(uint8_t *data, bool verbose) { +static void print_info_result(uint8_t *data) { // display all information of info result in structured format em4x50_word_t words[EM4X50_NO_WORDS]; @@ -380,33 +186,38 @@ int CmdEM4x50Info(const char *Cmd) { // envoke reading of a EM4x50 tag which has to be on the antenna because // decoding is done by the device (not on client side) - bool errors = false, verbose = false; - uint8_t cmdp = 0; - em4x50_data_t etd; - etd.pwd_given = false; + int pwdLen = 0; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd = {.pwd_given = false}; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_info", + "Read all information of EM4x50 tag. Tag must be on antenna.", + "lf em 4x50_info\n" + "lf em 4x50_info -p 12345678\n" + ); - case 'h': - return usage_lf_em4x50_info(); + void *argtable[] = { + arg_param_begin, + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; } } - // validation - if (errors) - return usage_lf_em4x50_info(); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); @@ -417,9 +228,18 @@ int CmdEM4x50Info(const char *Cmd) { return PM3_ETIMEOUT; } + if (etd.pwd_given) { + bool login = resp.status & STATUS_LOGIN; + if (login == false) { + PrintAndLogEx(FAILED, "Login failed"); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); + } + bool success = (resp.status & STATUS_SUCCESS) >> 1; if (success) { - print_info_result(resp.data.asBytes, verbose); + print_info_result(resp.data.asBytes); return PM3_SUCCESS; } @@ -431,55 +251,57 @@ int CmdEM4x50Write(const char *Cmd) { // envoke writing a single word (32 bit) to a EM4x50 tag - em4x50_data_t etd = { .pwd_given = false }; + int wordLen = 0, pwdLen = 0; + int addr = 0; + uint8_t word[4] = {0x0}; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd = {.pwd_given = false}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_write", + "Write EM4x50 word. Tag must be on antenna.", + "lf em 4x50_write -b 3 -d 4f22e7ff\n" + "lf em 4x50_write -b 3 -d 4f22e7ff -p 12345678\n" + ); - bool errors = false, bword = false, baddr = false; - uint8_t address = 0x0; - uint8_t cmdp = 0; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - - switch (tolower(param_getchar(Cmd, cmdp))) { - - case 'h': - return usage_lf_em4x50_write(); - - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - cmdp += 2; - break; - - case 'd': - etd.word = param_get32ex(Cmd, cmdp + 1, 0, 16); - bword = true; - cmdp += 2; - break; - - case 'b': - param_getdec(Cmd, cmdp + 1, &address); - - // validation - if (address < 1 || address > 31) { - PrintAndLogEx(FAILED, "Error, address has to be in range [1-31]"); - return PM3_EINVARG; - } - etd.addresses = address; // lwr - etd.addresses <<= 8; - etd.addresses |= address; // fwr - baddr = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "
", "block/word address, dec"), + arg_str1("d", "data", "", "data, hex, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + addr = arg_get_int_def(ctx, 1, 0); + CLIGetHexWithReturn(ctx, 2, word, &wordLen); + CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + PrintAndLogEx(ERR, "address has to be within range [0, 31]"); + return PM3_EINVARG; + } else { + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + } + if (wordLen != 4) { + PrintAndLogEx(ERR, "word/data length must be 4 bytes instead of %d", wordLen); + return PM3_EINVARG; + } else { + etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; + } + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; } } - if (errors || !bword || !baddr) - return usage_lf_em4x50_write(); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); @@ -511,74 +333,78 @@ int CmdEM4x50Write(const char *Cmd) { uint8_t *data = resp.data.asBytes; em4x50_word_t words[EM4X50_NO_WORDS]; - prepare_result(data, address, address, words); - print_result(words, address, address); + prepare_result(data, addr, addr, words); + print_result(words, addr, addr); PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", address); + PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", addr); return PM3_SUCCESS; } -int CmdEM4x50WritePassword(const char *Cmd) { +int CmdEM4x50WritePwd(const char *Cmd) { // envokes changing the password of EM4x50 tag - bool errors = false, bpwd = false, bnpwd = false, success = false; - uint8_t cmdp = 0; - em4x50_data_t etd; + int status = 0; + int pwdLen = 0, npwdLen = 0; + uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; PacketResponseNG resp; + em4x50_data_t etd; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_writepwd", + "Write EM4x50 password. Tag must be on antenna.", + "lf em 4x50_writepwd -p 4f22e7ff -n 12345678\n" + ); - // init - etd.pwd_given = false; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_em4x50_write_password(); - - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - bpwd = true; - cmdp += 2; - break; - - case 'n': - etd.password2 = param_get32ex(Cmd, cmdp + 1, 0, 16); - bnpwd = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + void *argtable[] = { + arg_param_begin, + arg_str1("p", "pwd", "", "password, hex, 4 bytes, lsb"), + arg_str1("n", "newpwd", "", "new password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); + + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + } + if (npwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", npwdLen); + return PM3_EINVARG; + } else { + etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; } - if (errors || !bpwd || !bnpwd) - return usage_lf_em4x50_write_password(); + CLIParserFree(ctx); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd)); + SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE_PASSWORD, &resp, TIMEOUT)) { + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - if (resp.status == PM3_ETEAROFF) + status = resp.status; + + if (status == PM3_ETEAROFF) return PM3_SUCCESS; - success = (bool)resp.status; - // print response - if (success) - PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); - else + if (status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); + return PM3_ESOFT; + } - return (success) ? PM3_SUCCESS : PM3_ESOFT; + PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); + + return PM3_SUCCESS; } int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { @@ -630,94 +456,102 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { int CmdEM4x50Read(const char *Cmd) { - uint8_t address = 0x0; + int pwdLen = 0; + int addr = 0; + uint8_t pwd[4] = {0x0}; em4x50_data_t etd; + + // init memset(&etd, 0x00, sizeof(em4x50_data_t)); - - etd.pwd_given = false; etd.addr_given = false; + etd.pwd_given = false; - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_read", + "Read EM4x50 block/word. Tag must be on antenna.", + "lf em 4x50_read -b 3\n" + "lf em 4x50_read -b 32 -p 12345678\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "
", "block/word address, dec"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; - case 'h': - return usage_lf_em4x50_read(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + addr = arg_get_int_def(ctx, 1, 0); + CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + return PM3_EINVARG; + } else { + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + } - case 'b': { - param_getdec(Cmd, cmdp + 1, &address); - // lsb: byte 1 = fwr, byte 2 = lwr, byte 3 = 0x0, byte 4 = 0x0 - etd.addresses = (address << 8) | address; - - // validation - if (address <= 0 || address >= EM4X50_NO_WORDS) { - PrintAndLogEx(FAILED, "Error, address has to be in range [1-33]"); - return PM3_EINVARG; - } - etd.addr_given = true; - cmdp += 2; - break; - } - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; } } - if (errors || strlen(Cmd) == 0 || etd.addr_given == false) - return usage_lf_em4x50_read(); + CLIParserFree(ctx); return em4x50_read(&etd, NULL); } int CmdEM4x50Dump(const char *Cmd) { - em4x50_data_t etd; - etd.pwd_given = false; - etd.addr_given = false; - - char filename[FILE_PATH_SIZE] = {0x00}; + int fnLen = 0, pwdLen = 0; + uint8_t pwd[4] = {0x0}; + char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; + em4x50_data_t etd = {.pwd_given = false}; + uint8_t data[DUMP_FILESIZE] = {0}; - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_dump", + "Dump EM4x50 tag. Tag must be on antenna.", + "lf em 4x50_dump\n" + "lf em 4x50_dump -f lf-4x50dump.eml\n" + "lf em 4x50_dump -p 12345678\n" + "lf em 4x50_dump -f lf-4x50dump.eml -p 12345678\n" + ); - case 'h': - return usage_lf_em4x50_dump(); - break; + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; - case 'f': - param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - cmdp += 2; - break; - - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIParamStrToBuf(arg_get_str(ctx, 1), + (uint8_t *)filename, + FILE_PATH_SIZE, + &fnLen + ); + CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } } - - // validation - if (errors) - return usage_lf_em4x50_dump(); + + CLIParserFree(ctx); PrintAndLogEx(INFO, "Reading EM4x50 tag"); clearCommandBuffer(); @@ -738,20 +572,19 @@ int CmdEM4x50Dump(const char *Cmd) { em4x50_word_t words[EM4X50_NO_WORDS]; prepare_result(resp.data.asBytes, 0, EM4X50_NO_WORDS - 1, words); + // result output PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:")); print_result(words, 0, EM4X50_NO_WORDS - 1); // user supplied filename? - if (strlen(filename) == 0) { + if (fnLen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); fptr += sprintf(fptr, "lf-4x50-"); FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); } - uint8_t data[EM4X50_NO_WORDS * 4] = {0}; - for (int i = 0; i < EM4X50_NO_WORDS; i++) { + for (int i = 0; i < EM4X50_NO_WORDS; i++) memcpy(data + (i * 4), words[i].byte, 4); - } // saveFileEML will add .eml extension to filename // saveFile (binary) passes in the .bin extension. @@ -767,34 +600,34 @@ int CmdEM4x50Wipe(const char *Cmd) { // fills EM4x50 tag with zeros including password - bool errors = false, pwd_given = false; - uint8_t cmdp = 0; + int pwdLen = 0; + uint8_t pwd[4] = {0x0}; uint32_t password = 0x0; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_wipe", + "Wipe EM4x50 tag. Tag must be on antenna.", + "lf em 4x50_wipe -p 12345678\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { - - case 'h': - return usage_lf_em4x50_wipe(); + void *argtable[] = { + arg_param_begin, + arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; } - if (errors || !pwd_given) - return usage_lf_em4x50_wipe(); - + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_LF_EM4X50_WIPE, &resp); @@ -813,41 +646,44 @@ int CmdEM4x50Wipe(const char *Cmd) { int CmdEM4x50Brute(const char *Cmd) { - bool startpwd = false, stoppwd = false, errors = false; const int speed = 27; // 27 passwords/second (empirical value) int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; - uint8_t cmdp = 0; + + int pwd1Len = 0, pwd2Len = 0; + uint8_t pwd1[4] = {0x0}, pwd2[4] = {0x0}; em4x50_data_t etd; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_brute", + "Bruteforce password of EM4x50 tag. Tag must be on antenna.", + "lf em 4x50_brute -f 12330000 -l 12340000\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { + void *argtable[] = { + arg_param_begin, + arg_str1("f", "fwr", "", "first password (start), hex, 4 bytes, lsb"), + arg_str1("l", "lwr", "", "last password (stop), hex, 4 bytes, lsb"), + arg_param_end + }; - case 'h': - return usage_lf_em4x50_brute(); - - case 'f': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - startpwd = true; - cmdp += 2; - break; - - case 'l': - etd.password2 = param_get32ex(Cmd, cmdp + 1, 0, 16); - stoppwd = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + CLIExecWithReturn(ctx, Cmd, argtable, true); - if (errors || !startpwd || !stoppwd) - return usage_lf_em4x50_brute(); + CLIGetHexWithReturn(ctx, 1, pwd1, &pwd1Len); + CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); + + if (pwd1Len != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwd1Len); + return PM3_EINVARG; + } else if (pwd2Len != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwd2Len); + return PM3_EINVARG; + } else { + etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; + etd.password2 = (pwd2[0] << 24) | (pwd2[1] << 16) | (pwd2[2] << 8) | pwd2[3]; + } + + CLIParserFree(ctx); // print some information no_iter = etd.password2 - etd.password1 + 1; @@ -875,33 +711,34 @@ int CmdEM4x50Brute(const char *Cmd) { int CmdEM4x50Login(const char *Cmd) { - bool errors = false, pwd_given = false; - uint8_t cmdp = 0; + int pwdLen = 0; + uint8_t pwd[4] = {0x0}; uint32_t password = 0x0; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_login", + "Login into EM4x50 tag. Tag must be on antenna.", + "lf em 4x50_login -p 12345678\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { + void *argtable[] = { + arg_param_begin, + arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; - case 'h': - return usage_lf_em4x50_login(); - - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + CLIExecWithReturn(ctx, Cmd, argtable, true); - if (errors || !pwd_given) - return usage_lf_em4x50_login(); + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + } + + CLIParserFree(ctx); // start clearCommandBuffer(); @@ -919,26 +756,21 @@ int CmdEM4x50Login(const char *Cmd) { int CmdEM4x50Reset(const char *Cmd) { - bool errors = false; - uint8_t cmdp = 0; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_reset", + "Reset EM4x50 tag. Tag must be on antenna", + "lf em 4x50_reset\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { + void *argtable[] = { + arg_param_begin, + arg_param_end + }; - case 'h': - return usage_lf_em4x50_reset(); - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - if (errors) - return usage_lf_em4x50_reset(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // start clearCommandBuffer(); @@ -958,26 +790,21 @@ int CmdEM4x50Watch(const char *Cmd) { // continously envoke reading of a EM4x50 tag - bool errors = false; - uint8_t cmdp = 0; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_watch", + "Watch for EM4x50 tag. Tag must be on antenna", + "lf em 4x50_watch\n" + ); - case 'h': - return usage_lf_em4x50_watch(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - // validation - if (errors) - return usage_lf_em4x50_watch(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); @@ -992,69 +819,73 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { - size_t fn_len = 0; + int uidLen = 0, fnLen = 0, pwdLen = 0; + uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; char filename[FILE_PATH_SIZE] = {0}; - char szTemp[FILE_PATH_SIZE - 20] = {0x00}; - em4x50_data_t etd; - uint8_t *data = calloc(DUMP_FILESIZE, sizeof(uint8_t)); + em4x50_data_t etd = {.pwd_given = false}; + uint8_t data[DUMP_FILESIZE] = {0x0}; - if (!data) { - PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); - return PM3_EMALLOC; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_restore", + "Restore EM4x50 dump to tag. Tag must be on antenna", + "lf em 4x50_restore -u 1b5aff5c\n" + "lf em 4x50_restore -f lf-4x50dump.eml\n" + "lf em 4x50_restore -u 1b5aff5c -p 12345678\n" + "lf em 4x50_restore -f lf-4x50dump.eml -p 12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("u", "uid", "", "uid, hex, 4 bytes, msb, restore from lf-4x50--dump.bin"), + arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, uid, &uidLen); + CLIParamStrToBuf(arg_get_str(ctx, 2), + (uint8_t *)filename, + FILE_PATH_SIZE, + &fnLen + ); + CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + + if ((uidLen && fnLen) || (!uidLen && !fnLen)) { + PrintAndLogEx(ERR, "either use option 'u' or option 'f'"); + return PM3_EINVARG; + } + + if (uidLen) { + snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%02x%02x%02x%02x-dump.bin", + uid[0], + uid[1], + uid[2], + uid[3] + ); + } + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } } - etd.pwd_given = false; - - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - - case 'h': - return usage_lf_em4x50_restore(); - break; - - case 'u': - param_getstr(Cmd, cmdp + 1, szTemp, FILE_PATH_SIZE - 20); - if (filename[0] == 0x00) - snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%s-dump.bin", szTemp); - cmdp += 2; - break; - - case 'f': - fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (fn_len == 0) - errors = true; - cmdp += 2; - break; - - case 'p': - etd.password1 = param_get32ex(Cmd, cmdp + 1, 0, 16); - etd.pwd_given = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - }; - } - - // validation - if (errors) - return usage_lf_em4x50_restore(); + CLIParserFree(ctx); PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Read error"); + if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) return PM3_EFILE; - } + // upload to emulator memory em4x50_seteml(data, 0, DUMP_FILESIZE); - free(data); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); @@ -1089,46 +920,29 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - bool errors = false, fn_given = false; - size_t fn_len = 0; - uint8_t cmdp = 0; + int slen = 0; char filename[FILE_PATH_SIZE] = {0}; - uint8_t *data = calloc(DUMP_FILESIZE, sizeof(uint8_t)); + uint8_t data[DUMP_FILESIZE] = {0x0}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_sim", + "Simulate dump (bin/eml/json) of EM4x50 tag in emulator memory", + "lf em 4x50_sim\n" + "lf em 4x50_sim -f lf-4x50dump.eml\n" + ); - if (!data) { - PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); - return PM3_EMALLOC; - } + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "dump filename, bin/eml/json"), + arg_param_end + }; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - - case 'h': - return usage_lf_em4x50_sim(); - break; - - case 'f': - fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (fn_len != 0) - fn_given = true; - else - errors = true; - cmdp += 2; - break; - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - }; - } - - // validations - if (errors) - return usage_lf_em4x50_sim(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + CLIParserFree(ctx); // read data from dump file; file type has to be "bin", "eml" or "json" - if (fn_given) { + if (slen != 0) { if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; @@ -1137,7 +951,6 @@ int CmdEM4x50Sim(const char *Cmd) { PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); em4x50_seteml(data, 0, DUMP_FILESIZE); - free(data); } PrintAndLogEx(INFO, "Simulating data in emulator memory " _YELLOW_("%s"), filename); @@ -1148,37 +961,35 @@ int CmdEM4x50Sim(const char *Cmd) { PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - if (resp.status == PM3_ETEAROFF) + if (resp.status == PM3_ETEAROFF) { return PM3_SUCCESS; + } else if (resp.status == PM3_ENODATA) { + PrintAndLogEx(INFO, "No valid em4x50 data in emulator memory."); + return PM3_ENODATA; + } PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } int CmdEM4x50StdRead(const char *Cmd) { - bool errors = false; - uint8_t cmdp = 0; int now = 0; PacketResponseNG resp; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_stdread", + "Show standard read data of EM4x50 tag", + "lf em 4x50_stdread\n" + ); - switch (tolower(param_getchar(Cmd, cmdp))) { + void *argtable[] = { + arg_param_begin, + arg_param_end + }; - case 'h': - return usage_lf_em4x50_stdread(); - - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - if (errors) - return usage_lf_em4x50_stdread(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // start clearCommandBuffer(); @@ -1226,9 +1037,8 @@ int CmdEM4x50StdRead(const char *Cmd) { int CmdEM4x50ELoad(const char *Cmd) { - bool errors = false, fn_given = false; - size_t nobytes = DUMP_FILESIZE, fn_len = 0; - uint8_t cmdp = 0; + int slen = 0; + size_t nobytes = DUMP_FILESIZE; char filename[FILE_PATH_SIZE] = {0}; uint8_t *data = calloc(nobytes, sizeof(uint8_t)); @@ -1237,33 +1047,22 @@ int CmdEM4x50ELoad(const char *Cmd) { return PM3_EMALLOC; } - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_eload", + "Load dump file (bin/eml/json) into emulator memory", + "lf em 4x50_eload -f lf-4x50dump.json\n" + ); - case 'h': - return usage_lf_em4x50_eload(); - break; + void *argtable[] = { + arg_param_begin, + arg_str1("f", "filename", "", "dump filename"), + arg_param_end + }; - case 'f': - fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (fn_len != 0) - fn_given = true; - else - errors = true; - cmdp += 2; - break; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + CLIParserFree(ctx); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - }; - } - - // validations - if (errors || (fn_given == false)) - return usage_lf_em4x50_eload(); - // read data from dump file; file type has to be "bin", "eml" or "json" if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); @@ -1280,9 +1079,9 @@ int CmdEM4x50ELoad(const char *Cmd) { int CmdEM4x50ESave(const char *Cmd) { - bool errors = false; - size_t nobytes = DUMP_FILESIZE, fn_len = 0; - uint8_t cmdp = 0; + int slen = 0; + size_t nobytes = DUMP_FILESIZE; + uint32_t serial = 0x0, device_id = 0x0; char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; uint8_t *data = calloc(nobytes, sizeof(uint8_t)); @@ -1292,31 +1091,23 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_EMALLOC; } - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_esave", + "Save emulator memory to file (bin, elm, json)", + "lf em 4x50_esave\n" + "lf em 4x50_esave -f lf-4x50dump.json\n" + ); - case 'h': - return usage_lf_em4x50_esave(); - break; + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "data filename"), + arg_param_end + }; - case 'f': - fn_len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (fn_len == 0) - errors = true; - cmdp += 2; - break; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + CLIParserFree(ctx); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - }; - } - - // validations - if (errors) - return usage_lf_em4x50_esave(); - // download emulator memory PrintAndLogEx(SUCCESS, "Reading emulator memory..."); if (!GetFromDevice(BIG_BUF_EML, data, nobytes, 0, NULL, 0, NULL, 2500, false)) { @@ -1325,18 +1116,89 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_ETIMEOUT; } + // valid data regarding em4x50? + serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + if ((serial == 0x0) && (device_id == 0x0)) { + PrintAndLogEx(WARNING, "No valid data in emulator memory."); + free(data); + return PM3_ENODATA; + } + // user supplied filename? - if (fn_len == 0) { + if (slen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); fptr += snprintf(fptr, sizeof(filename), "lf-4x50-"); FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); } - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); - em4x50_seteml(data, 0, nobytes); - saveFile(filename, ".bin", data, nobytes); saveFileEML(filename, data, nobytes, 4); saveFileJSON(filename, jsfEM4x50, data, nobytes, NULL); + free(data); + return PM3_SUCCESS; +} + +int CmdEM4x50Chk(const char *Cmd) { + + int res = 0; + char filename[FILE_PATH_SIZE] = {0}; + PacketResponseNG resp; + uint32_t keycnt = 0; + uint8_t *data = NULL; + int slen = 0; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_chk", + "Check passwords from dictionary in flash memory", + "lf em 4x50_chk\n" + "lf em 4x50_chk -f t55xx_default_pwds.dic\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "dictionary filename"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + CLIParserFree(ctx); + + res = loadFileDICTIONARY_safe(filename, (void **)&data, 4, &keycnt); + if (res != PM3_SUCCESS || keycnt == 0 || data == NULL) { + PrintAndLogEx(WARNING, "no keys found in file"); + if (data != NULL) + free(data); + + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + em4x50_seteml(data, 0, 4 * keycnt); + free(data); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&keycnt, sizeof(keycnt)); + WaitForResponse(CMD_LF_EM4X50_CHK, &resp); + /* + if (!WaitForResponseTimeout(CMD_LF_EM4X50_CHK, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + */ + + // print response + if ((bool)resp.status) + PrintAndLogEx(SUCCESS, "Password " _GREEN_("found: %02x %02x %02x %02x"), + resp.data.asBytes[3], + resp.data.asBytes[2], + resp.data.asBytes[1], + resp.data.asBytes[0] + ); + else + PrintAndLogEx(FAILED, "No password found"); + + PrintAndLogEx(SUCCESS, "Done"); return PM3_SUCCESS; } From f2dad2f566cc91c5fa42eac0297ff185d7a33e9e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 1 Nov 2020 23:37:42 +0100 Subject: [PATCH 078/174] added possibility for manual interruption of 4x50_watch --- armsrc/em4x50.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 3dba0edb1..d6e1a6926 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -210,6 +210,10 @@ static uint32_t get_pulse_length(void) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + // for manual interruption + if (BUTTON_PRESS()) + return 0; + while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -1264,18 +1268,24 @@ void em4x50_watch() { memset(words, 0, sizeof(words)); now = 0; - if (get_signalproperties() && find_em4x50_tag()) { - - standard_read(&now, words); + //if (get_signalproperties()) && find_em4x50_tag()) { + if (get_signalproperties()) { + Dbprintf("ghet 1"); + if (find_em4x50_tag()) { + Dbprintf("ghet 2"); - if (now > 0) { + standard_read(&now, words); + Dbprintf("ghet 3"); - Dbprintf(""); - for (int i = 0; i < now; i++) { - - Dbprintf("EM4x50 TAG ID: " - _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", - words[i], reflect32(words[i])); + if (now > 0) { + + Dbprintf(""); + for (int i = 0; i < now; i++) { + + Dbprintf("EM4x50 TAG ID: " + _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", + words[i], reflect32(words[i])); + } } } } From ff0c4f924adfb08290d75459851a1982129f2a8d Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 10 Nov 2020 00:37:43 +0100 Subject: [PATCH 079/174] updated short descriptions of em4x50 functions --- client/src/cmdlfem4x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 0c038a438..115034a31 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -654,18 +654,18 @@ static command_t CommandTable[] = { {"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, {"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"4x50_writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50 tag"}, + {"4x50_writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, - {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, + {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, - {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "read EM4x50 continously"}, + {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "watch for EM4x50 tags"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, - {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate single EM4x50 word (uid)"}, - {"4x50_stdread",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50 tag"}, - {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "load a binary dump into emulator memory"}, - {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, + {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, + {"4x50_stdread",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50"}, + {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, + {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, {"4x50_chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {NULL, NULL, NULL, NULL} }; From b791d392b61abafab10c8a73360532f1beee90e3 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 10 Nov 2020 00:39:48 +0100 Subject: [PATCH 080/174] switched from emulator memory to flash memory for various functions --- client/src/cmdlfem4x50.c | 281 +++++++++++++++++++++++++++------------ 1 file changed, 193 insertions(+), 88 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index cef36a5ba..db058b761 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -16,28 +16,100 @@ #include "util.h" #include "commonutil.h" #include "cmdparser.h" +#include "pmflash.h" +#include "cmdflashmem.h" #include "em4x50.h" -static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len) { +#define FLASH_MEM_PAGE_SIZE 0x10000 + +static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { // read data from dump file; file type is derived from file name extension int res = 0; - size_t bytes_read = 0; if (str_endswith(filename, ".eml")) - res = loadFileEML(filename, data, &bytes_read) != PM3_SUCCESS; + res = loadFileEML(filename, data, bytes_read) != PM3_SUCCESS; else if (str_endswith(filename, ".json")) - res = loadFileJSON(filename, data, data_len, &bytes_read, NULL); + res = loadFileJSON(filename, data, data_len, bytes_read, NULL); else - res = loadFile(filename, ".bin", data, data_len, &bytes_read); + res = loadFile(filename, ".bin", data, data_len, bytes_read); - if ((res != PM3_SUCCESS) && (bytes_read != DUMP_FILESIZE)) + if ((res != PM3_SUCCESS) && (*bytes_read != DUMP_FILESIZE)) return PM3_EFILE; return PM3_SUCCESS; } +static int em4x50_wipe_flash(int page) { + + int isok = 0; + + clearCommandBuffer(); + SendCommandMIX(CMD_FLASHMEM_WIPE, page, false, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + isok = resp.oldarg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(WARNING, "Flash error"); + return PM3_EFLASH; + } + + return PM3_SUCCESS; +} + +static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { + + int isok = 0; + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = datalen; + uint32_t bytes_in_packet = 0; + PacketResponseNG resp; + + // wipe + em4x50_wipe_flash(0); + em4x50_wipe_flash(1); + em4x50_wipe_flash(2); + + // fast push mode + conn.block_after_ACK = true; + + while (bytes_remaining > 0) { + bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + clearCommandBuffer(); + SendCommandOLD(CMD_FLASHMEM_WRITE, offset + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + conn.block_after_ACK = false; + //free(data); + return PM3_ETIMEOUT; + } + + isok = resp.oldarg[0] & 0xFF; + if (!isok) { + conn.block_after_ACK = false; + PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); + return PM3_EFLASH; + } + } + + conn.block_after_ACK = false; + PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset); + + return PM3_SUCCESS; +} + +/* static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { // fast push mode @@ -55,6 +127,7 @@ static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); } } +*/ static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { @@ -209,7 +282,7 @@ int CmdEM4x50Info(const char *Cmd) { if (pwdLen) { if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -279,21 +352,21 @@ int CmdEM4x50Write(const char *Cmd) { CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); if (addr <= 0 || addr >= EM4X50_NO_WORDS) { - PrintAndLogEx(ERR, "address has to be within range [0, 31]"); + PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); return PM3_EINVARG; } else { etd.addresses = (addr << 8) | addr; etd.addr_given = true; } if (wordLen != 4) { - PrintAndLogEx(ERR, "word/data length must be 4 bytes instead of %d", wordLen); + PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); return PM3_EINVARG; } else { etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; } if (pwdLen) { if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -369,13 +442,13 @@ int CmdEM4x50WritePwd(const char *Cmd) { CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; } if (npwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", npwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); return PM3_EINVARG; } else { etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; @@ -494,7 +567,7 @@ int CmdEM4x50Read(const char *Cmd) { if (pwdLen) { if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -543,7 +616,7 @@ int CmdEM4x50Dump(const char *Cmd) { if (pwdLen) { if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -621,7 +694,7 @@ int CmdEM4x50Wipe(const char *Cmd) { CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -673,10 +746,10 @@ int CmdEM4x50Brute(const char *Cmd) { CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); if (pwd1Len != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwd1Len); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd1Len); return PM3_EINVARG; } else if (pwd2Len != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwd2Len); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); return PM3_EINVARG; } else { etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; @@ -732,7 +805,7 @@ int CmdEM4x50Login(const char *Cmd) { CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -819,8 +892,9 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { - int uidLen = 0, fnLen = 0, pwdLen = 0; + int uidLen = 0, fnLen = 0, pwdLen = 0, res = 0; uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; + size_t bytes_read = 0; char filename[FILE_PATH_SIZE] = {0}; em4x50_data_t etd = {.pwd_given = false}; uint8_t data[DUMP_FILESIZE] = {0x0}; @@ -853,7 +927,7 @@ int CmdEM4x50Restore(const char *Cmd) { CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); if ((uidLen && fnLen) || (!uidLen && !fnLen)) { - PrintAndLogEx(ERR, "either use option 'u' or option 'f'"); + PrintAndLogEx(FAILED, "either use option 'u' or option 'f'"); return PM3_EINVARG; } @@ -868,7 +942,7 @@ int CmdEM4x50Restore(const char *Cmd) { if (pwdLen) { if (pwdLen != 4) { - PrintAndLogEx(ERR, "password length must be 4 bytes instead of %d", pwdLen); + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; @@ -881,11 +955,15 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) + if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; - // upload to emulator memory - em4x50_seteml(data, 0, DUMP_FILESIZE); + // upload to flash memory + res = em4x50_write_flash(data, 0, bytes_read); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); @@ -920,9 +998,11 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - int slen = 0; - char filename[FILE_PATH_SIZE] = {0}; + int slen = 0, res = 0; + size_t bytes_read = 0; uint8_t data[DUMP_FILESIZE] = {0x0}; + char filename[FILE_PATH_SIZE] = {0}; + PacketResponseNG resp; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_sim", @@ -943,28 +1023,45 @@ int CmdEM4x50Sim(const char *Cmd) { // read data from dump file; file type has to be "bin", "eml" or "json" if (slen != 0) { - if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { + + // load file content + if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + if (bytes_read * 8 > FLASH_MEM_MAX_SIZE) { + PrintAndLogEx(FAILED, "Filesize is larger than available memory"); + //free(data); + return PM3_EOVFLOW; + } - em4x50_seteml(data, 0, DUMP_FILESIZE); + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); + + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error wiping flash."); + return res; + } + + // upload to device + res = em4x50_write_flash(data, 0, bytes_read); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } } - PrintAndLogEx(INFO, "Simulating data in emulator memory " _YELLOW_("%s"), filename); + PrintAndLogEx(INFO, "Simulating data in " _YELLOW_("%s"), filename); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); - PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); if (resp.status == PM3_ETEAROFF) { return PM3_SUCCESS; } else if (resp.status == PM3_ENODATA) { - PrintAndLogEx(INFO, "No valid em4x50 data in emulator memory."); + PrintAndLogEx(FAILED, "No valid em4x50 data in flash memory."); return PM3_ENODATA; } @@ -1037,19 +1134,14 @@ int CmdEM4x50StdRead(const char *Cmd) { int CmdEM4x50ELoad(const char *Cmd) { - int slen = 0; - size_t nobytes = DUMP_FILESIZE; + int slen = 0, res = 0; + size_t bytes_read = 0; char filename[FILE_PATH_SIZE] = {0}; - uint8_t *data = calloc(nobytes, sizeof(uint8_t)); - - if (!data) { - PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); - return PM3_EMALLOC; - } + uint8_t data[DUMP_FILESIZE] = {0x0}; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_eload", - "Load dump file (bin/eml/json) into emulator memory", + "Load dump file (bin/eml/json) into flash memory", "lf em 4x50_eload -f lf-4x50dump.json\n" ); @@ -1064,36 +1156,34 @@ int CmdEM4x50ELoad(const char *Cmd) { CLIParserFree(ctx); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, data, DUMP_FILESIZE) != PM3_SUCCESS) { + if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); - em4x50_seteml(data, 0, nobytes); + // upload to flash memory + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); + res = em4x50_write_flash(data, 0, DUMP_FILESIZE); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } - free(data); - PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } int CmdEM4x50ESave(const char *Cmd) { int slen = 0; - size_t nobytes = DUMP_FILESIZE; uint32_t serial = 0x0, device_id = 0x0; char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; - uint8_t *data = calloc(nobytes, sizeof(uint8_t)); - - if (!data) { - PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); - return PM3_EMALLOC; - } + uint8_t data[DUMP_FILESIZE] = {0x0}; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_esave", - "Save emulator memory to file (bin, elm, json)", + "Save flash memory to file (bin, elm, json)", "lf em 4x50_esave\n" "lf em 4x50_esave -f lf-4x50dump.json\n" ); @@ -1108,20 +1198,18 @@ int CmdEM4x50ESave(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - // download emulator memory - PrintAndLogEx(SUCCESS, "Reading emulator memory..."); - if (!GetFromDevice(BIG_BUF_EML, data, nobytes, 0, NULL, 0, NULL, 2500, false)) { + // download flash memory + PrintAndLogEx(SUCCESS, "Reading flash memory..."); + if (!GetFromDevice(FLASH_MEM, data, DUMP_FILESIZE, 0, NULL, 0, NULL, -1, true)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); - free(data); return PM3_ETIMEOUT; } // valid data regarding em4x50? serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); - if ((serial == 0x0) && (device_id == 0x0)) { - PrintAndLogEx(WARNING, "No valid data in emulator memory."); - free(data); + if (serial == device_id) { + PrintAndLogEx(WARNING, "No valid em4x50 data in flash memory."); return PM3_ENODATA; } @@ -1132,27 +1220,28 @@ int CmdEM4x50ESave(const char *Cmd) { FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); } - saveFile(filename, ".bin", data, nobytes); - saveFileEML(filename, data, nobytes, 4); - saveFileJSON(filename, jsfEM4x50, data, nobytes, NULL); - free(data); + saveFile(filename, ".bin", data, DUMP_FILESIZE); + saveFileEML(filename, data, DUMP_FILESIZE, 4); + saveFileJSON(filename, jsfEM4x50, data, DUMP_FILESIZE, NULL); return PM3_SUCCESS; } int CmdEM4x50Chk(const char *Cmd) { - int res = 0; + // upload passwords from dictionary to flash memory and start password check + + int res = 0, slen = 0; + size_t datalen = 0; + uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; + uint32_t keycnt = 0, offset = 0; char filename[FILE_PATH_SIZE] = {0}; PacketResponseNG resp; - uint32_t keycnt = 0; - uint8_t *data = NULL; - int slen = 0; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_chk", "Check passwords from dictionary in flash memory", "lf em 4x50_chk\n" - "lf em 4x50_chk -f t55xx_default_pwds.dic\n" + "lf em 4x50_chk -f 4_byte_password_file.dic\n" ); void *argtable[] = { @@ -1165,28 +1254,44 @@ int CmdEM4x50Chk(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - res = loadFileDICTIONARY_safe(filename, (void **)&data, 4, &keycnt); - if (res != PM3_SUCCESS || keycnt == 0 || data == NULL) { - PrintAndLogEx(WARNING, "no keys found in file"); - if (data != NULL) - free(data); + //data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); + + // no filename -> default = t55xx_default_pwds + if (strlen(filename) == 0) { + snprintf(filename, sizeof(filename), "t55xx_default_pwds"); + offset = DEFAULT_T55XX_KEYS_OFFSET; + PrintAndLogEx(INFO, "treating file as T55xx passwords"); + } + + res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycnt); + if (res || !keycnt) { + //free(data); + return PM3_EFILE; + } + // limited space on flash mem + if (keycnt > 0xFFFF) + keycnt &= 0xFFFF; - return PM3_ESOFT; + data[0] = (keycnt >> 0) & 0xFF; + data[1] = (keycnt >> 8) & 0xFF; + datalen += 2; + + if (datalen > FLASH_MEM_MAX_SIZE) { + PrintAndLogEx(FAILED, "error, filesize is larger than available memory"); + //free(data); + return PM3_EOVFLOW; } - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); - em4x50_seteml(data, 0, 4 * keycnt); - free(data); + // send to device + res = em4x50_write_flash(data, offset, datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&keycnt, sizeof(keycnt)); - WaitForResponse(CMD_LF_EM4X50_CHK, &resp); - /* - if (!WaitForResponseTimeout(CMD_LF_EM4X50_CHK, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - */ + SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); + WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); // print response if ((bool)resp.status) @@ -1199,6 +1304,6 @@ int CmdEM4x50Chk(const char *Cmd) { else PrintAndLogEx(FAILED, "No password found"); - PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } From 8682d48419c8fc702f31c782bfe86da8ee0d901e Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 10 Nov 2020 00:43:08 +0100 Subject: [PATCH 081/174] - switched from emulator memory to flash memory for various functions - completed 4x50_chk functions -> segmented password list if size is > max size of emulator memory - various corrections/modifications --- armsrc/em4x50.c | 209 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 155 insertions(+), 54 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index d6e1a6926..b6098aa11 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -12,8 +12,10 @@ #include "ticks.h" #include "dbprint.h" #include "lfadc.h" +#include "pmflash.h" #include "commonutil.h" #include "em4x50.h" +#include "flashmem.h" #include "BigBuf.h" #include "appmain.h" // tear @@ -32,8 +34,13 @@ #define EM4X50_T_TAG_FULL_PERIOD 64 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 -#define EM4X50_T_WAITING_FOR_SNGLLIW 100 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 +#define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be + // critical; if it's too + // low (e.g. < 120) some + // cards are no longer + // readable although + // they're ok #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 @@ -48,8 +55,8 @@ #define EM4X50_COMMAND_WRITE_PASSWORD 0x11 #define EM4X50_COMMAND_SELECTIVE_READ 0x0A -int gHigh = 0; -int gLow = 0; +int gHigh = 190; +int gLow = 60; // auxiliary functions @@ -144,7 +151,7 @@ static bool get_signalproperties(void) { // about 2 samples per bit period wait_timer0(T0 * EM4X50_T_TAG_HALF_PERIOD); - + if (AT91C_BASE_SSC->SSC_RHR > noise) { signal_found = true; break; @@ -780,6 +787,8 @@ static bool login(uint32_t password) { // send password em4x50_reader_send_word(password); + + wait_timer0(T0 * EM4X50_T_TAG_TPP); // check if ACK is returned if (check_ack(false)) @@ -1079,8 +1088,8 @@ void em4x50_write(em4x50_data_t *etd) { void em4x50_writepwd(em4x50_data_t *etd) { // simple change of password - - bool bsuccess = false; + + int res = PM3_ENODATA; em4x50_setup_read(); @@ -1090,17 +1099,16 @@ void em4x50_writepwd(em4x50_data_t *etd) { // login and change password if (login(etd->password1)) { - int res = write_password(etd->password1, etd->password2); + res = write_password(etd->password1, etd->password2); if (res == PM3_ETEAROFF) { lf_finalize(); return; } - bsuccess = (res == PM3_SUCCESS); } } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITEPWD, bsuccess, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITEPWD, res, 0, 0); } void em4x50_wipe(uint32_t *password) { @@ -1268,25 +1276,16 @@ void em4x50_watch() { memset(words, 0, sizeof(words)); now = 0; - //if (get_signalproperties()) && find_em4x50_tag()) { - if (get_signalproperties()) { - Dbprintf("ghet 1"); - if (find_em4x50_tag()) { - Dbprintf("ghet 2"); + if (get_signalproperties() && find_em4x50_tag()) { - standard_read(&now, words); - Dbprintf("ghet 3"); + standard_read(&now, words); + if (now > 0) { - if (now > 0) { - - Dbprintf(""); - for (int i = 0; i < now; i++) { - - Dbprintf("EM4x50 TAG ID: " - _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", - words[i], reflect32(words[i])); - } - } + Dbprintf(""); + for (int i = 0; i < now; i++) + Dbprintf("EM4x50 TAG ID: " + _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", + words[i], reflect32(words[i])); } } } @@ -1340,17 +1339,25 @@ void em4x50_restore(em4x50_data_t *etd) { int res = 0; int start_word = 0; uint8_t status = 0; - uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; uint32_t words_read[EM4X50_NO_WORDS] = {0x0}; - em4x50_setup_read(); + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it will + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // read data from emulator memory + // read data from flash memory + Flash_ReadData(0, em4x50_mem, 4 * EM4X50_NO_WORDS); for (int i = 0; i < EM4X50_NO_WORDS; i++) words_client[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + em4x50_setup_read(); + // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { @@ -1396,25 +1403,33 @@ void em4x50_restore(em4x50_data_t *etd) { void em4x50_sim(void) { - // simulate uploaded data in emulator memory + // simulate uploaded data in flash memory // (currently only a one-way communication is possible) int status = PM3_SUCCESS; - uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; uint32_t words[EM4X50_NO_WORDS] = {0x0}; + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it will + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + // read data from flash memory + Flash_ReadData(0, em4x50_mem, 4 * EM4X50_NO_WORDS); + for (int i = 0; i < EM4X50_NO_WORDS; i++) + words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + em4x50_setup_sim(); - // read data from emulator memory - for (int i = 0; i < EM4X50_NO_WORDS; i++) - words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - - if ((words[EM4X50_DEVICE_SERIAL] != 0x0) && (words[EM4X50_DEVICE_ID] != 0X0)) { + // only if valid em4x50 data (e.g. uid == serial) + if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { // extract control data int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read - // extract protection data int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected @@ -1437,6 +1452,7 @@ void em4x50_sim(void) { status = PM3_ENODATA; } + BigBuf_free(); lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); } @@ -1459,32 +1475,117 @@ void em4x50_stdread(void) { reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); } -void em4x50_chk(uint32_t *numkeys) { +static uint32_t get_pwd(uint8_t *pwds, int cnt) { - // reads data that tag transmits "voluntarily" -> standard read mode + uint32_t pwd = 0x0; + + for (int j = 0; j < 4; j++) + pwd |= (*(pwds + 4 * cnt + j)) << ((3 - j) * 8); + + return pwd; + +} + +void em4x50_chk(uint32_t *offset) { + + // check passwords from dictionary in flash memory bool bsuccess = false; - uint32_t password = 0x0; - uint32_t keys[200] = {0x0}; - uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + int block_count = 1; + int pwds_remain = 0; + uint8_t counter[2] = {0x00, 0x00}; + uint16_t isok = 0; + uint16_t pwd_count = 0; + uint16_t pwd_size_available = 0; + uint32_t pwd = 0x0; + uint8_t *pwd_block = BigBuf_get_EM_addr(); - em4x50_setup_read(); + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it will + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // read data from emulator memory - for (int i = 0; i < *numkeys; i++) - keys[i] = bytes_to_num(em4x50_mem + (i * 4), 4); + BigBuf_Clear_EM(); + + // initialize passwords and get number of passwords + if (Flash_ReadData(*offset, counter, sizeof(counter)) != sizeof(counter)) + goto OUT; + + *offset += 2; + + pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); + if (pwd_count == 0) + goto OUT; + + pwd_size_available = 4 * pwd_count; + + // since flash can report way too many pwds, we need to limit it. + // bigbuff EM size is determined by CARD_MEMORY_SIZE + // a password is 4bytes. + // pwd_size_available = MIN(CARD_MEMORY_SIZE, pwd_count * 4); + if (pwd_size_available > CARD_MEMORY_SIZE) { + + // we have to use more than one block of passwords + block_count = (4 * pwd_count) / CARD_MEMORY_SIZE; + pwds_remain = pwd_count - block_count * CARD_MEMORY_SIZE / 4; - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - for (int i = 0; i < *numkeys; i++) { - if (login(keys[i])) { - bsuccess = true; - password = keys[i]; - break; + if (pwds_remain != 0) + block_count++; + + // adjust pwd_size_available and pwd_count + pwd_size_available = CARD_MEMORY_SIZE; + pwd_count = pwd_size_available / 4; + + Dbprintf("Passwords divided into %i blocks", block_count); + + } + + for (int n = 0; n < block_count; n++) { + + // adjust parameters if more than 1 block + if (n != 0) { + *offset += pwd_size_available; + + // final run with remaining passwords + if (n == block_count - 1) { + pwd_count = pwds_remain; + pwd_size_available = 4 * pwds_remain; + } + } + + Dbprintf("Using block #%i with %i passwords", n + 1, pwd_count); + + // read next password block + isok = Flash_ReadData(*offset, pwd_block, pwd_size_available); + if (isok != pwd_size_available) + goto OUT; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + // try to login with current password + for (int i = 0; i < pwd_count; i++) { + + // manual interruption + if (BUTTON_PRESS()) + goto OUT; + + // get next password from flash memory + pwd = get_pwd(pwd_block, i); + + bsuccess = login(pwd); + if (bsuccess) + break; } } } +OUT: + lf_finalize(); - reply_ng(CMD_LF_EM4X50_CHK, bsuccess, (uint8_t *)&password, 32); + reply_ng(CMD_LF_EM4X50_CHK, bsuccess, (uint8_t *)&pwd, 32); } From ae96cd869a8cc65269b479941b80850626056519 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 11 Nov 2020 01:11:09 +0100 Subject: [PATCH 082/174] relocated "pwd block management" from device to client --- armsrc/em4x50.c | 82 ++++++++++---------------------------- client/src/cmdlfem4x50.c | 86 ++++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 87 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b6098aa11..32862ab97 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1488,17 +1488,15 @@ static uint32_t get_pwd(uint8_t *pwds, int cnt) { void em4x50_chk(uint32_t *offset) { - // check passwords from dictionary in flash memory + // check passwords from dictionary content in flash memory bool bsuccess = false; - int block_count = 1; - int pwds_remain = 0; uint8_t counter[2] = {0x00, 0x00}; uint16_t isok = 0; uint16_t pwd_count = 0; uint16_t pwd_size_available = 0; uint32_t pwd = 0x0; - uint8_t *pwd_block = BigBuf_get_EM_addr(); + uint8_t *pwds = BigBuf_get_EM_addr(); //----------------------------------------------------------------------------- // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not @@ -1513,74 +1511,34 @@ void em4x50_chk(uint32_t *offset) { if (Flash_ReadData(*offset, counter, sizeof(counter)) != sizeof(counter)) goto OUT; - *offset += 2; - pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); if (pwd_count == 0) goto OUT; pwd_size_available = 4 * pwd_count; - // since flash can report way too many pwds, we need to limit it. - // bigbuff EM size is determined by CARD_MEMORY_SIZE - // a password is 4bytes. - // pwd_size_available = MIN(CARD_MEMORY_SIZE, pwd_count * 4); - if (pwd_size_available > CARD_MEMORY_SIZE) { + isok = Flash_ReadData(*offset + 2, pwds, pwd_size_available); + if (isok != pwd_size_available) + goto OUT; + + em4x50_setup_read(); - // we have to use more than one block of passwords - block_count = (4 * pwd_count) / CARD_MEMORY_SIZE; - pwds_remain = pwd_count - block_count * CARD_MEMORY_SIZE / 4; - - if (pwds_remain != 0) - block_count++; - - // adjust pwd_size_available and pwd_count - pwd_size_available = CARD_MEMORY_SIZE; - pwd_count = pwd_size_available / 4; + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { - Dbprintf("Passwords divided into %i blocks", block_count); - - } + // try to login with current password + for (int i = 0; i < pwd_count; i++) { - for (int n = 0; n < block_count; n++) { + // manual interruption + if (BUTTON_PRESS()) + goto OUT; - // adjust parameters if more than 1 block - if (n != 0) { - *offset += pwd_size_available; - - // final run with remaining passwords - if (n == block_count - 1) { - pwd_count = pwds_remain; - pwd_size_available = 4 * pwds_remain; - } - } - - Dbprintf("Using block #%i with %i passwords", n + 1, pwd_count); - - // read next password block - isok = Flash_ReadData(*offset, pwd_block, pwd_size_available); - if (isok != pwd_size_available) - goto OUT; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // try to login with current password - for (int i = 0; i < pwd_count; i++) { - - // manual interruption - if (BUTTON_PRESS()) - goto OUT; - - // get next password from flash memory - pwd = get_pwd(pwd_block, i); - - bsuccess = login(pwd); - if (bsuccess) - break; - } + // get next password from flash memory + pwd = get_pwd(pwds, i); + + bsuccess = login(pwd); + if (bsuccess) + break; } } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index db058b761..2ce7d7985 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -21,6 +21,7 @@ #include "em4x50.h" #define FLASH_MEM_PAGE_SIZE 0x10000 +#define CARD_MEMORY_SIZE 4096 static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { @@ -91,7 +92,6 @@ static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); conn.block_after_ACK = false; - //free(data); return PM3_ETIMEOUT; } @@ -104,7 +104,6 @@ static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { } conn.block_after_ACK = false; - PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset); return PM3_SUCCESS; } @@ -1032,7 +1031,6 @@ int CmdEM4x50Sim(const char *Cmd) { if (bytes_read * 8 > FLASH_MEM_MAX_SIZE) { PrintAndLogEx(FAILED, "Filesize is larger than available memory"); - //free(data); return PM3_EOVFLOW; } @@ -1230,10 +1228,14 @@ int CmdEM4x50Chk(const char *Cmd) { // upload passwords from dictionary to flash memory and start password check + bool key_found = false; int res = 0, slen = 0; + int keys_remain = 0; + int block_count = 1; size_t datalen = 0; uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; - uint32_t keycnt = 0, offset = 0; + uint8_t *keys = data; + uint32_t key_count = 0, offset = 0; char filename[FILE_PATH_SIZE] = {0}; PacketResponseNG resp; @@ -1263,38 +1265,72 @@ int CmdEM4x50Chk(const char *Cmd) { PrintAndLogEx(INFO, "treating file as T55xx passwords"); } - res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycnt); - if (res || !keycnt) { - //free(data); + res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &key_count); + if (res || !key_count) return PM3_EFILE; - } - // limited space on flash mem - if (keycnt > 0xFFFF) - keycnt &= 0xFFFF; - data[0] = (keycnt >> 0) & 0xFF; - data[1] = (keycnt >> 8) & 0xFF; - datalen += 2; + // limited space on flash mem + if (key_count > 0xFFFF) + key_count &= 0xFFFF; if (datalen > FLASH_MEM_MAX_SIZE) { PrintAndLogEx(FAILED, "error, filesize is larger than available memory"); - //free(data); return PM3_EOVFLOW; } - // send to device - res = em4x50_write_flash(data, offset, datalen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return res; + if (datalen > CARD_MEMORY_SIZE) { + + // we have to use more than one block of passwords + block_count = (4 * key_count) / CARD_MEMORY_SIZE; + keys_remain = key_count - block_count * CARD_MEMORY_SIZE / 4; + + if (keys_remain != 0) + block_count++; + + // adjust pwd_size_available and pwd_count + datalen = CARD_MEMORY_SIZE; + key_count = datalen / 4; + + PrintAndLogEx(INFO, "Passwords divided into %i blocks", block_count); + } + + for (int n = 0; n < block_count; n++) { + + // adjust parameters if more than 1 block + if (n != 0) { + + keys += datalen; + + // final run with remaining passwords + if (n == block_count - 1) { + key_count = keys_remain; + datalen = 4 * keys_remain; + } + } + + keys[0] = (key_count >> 0) & 0xFF; + keys[1] = (key_count >> 8) & 0xFF; + + PrintAndLogEx(INFO, "Checking block #%i (%i passwords)", n + 1, key_count); + + // send to device + res = em4x50_write_flash(keys, offset, datalen + 2); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); + WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); + + key_found = (bool)resp.status; + if (key_found) + break; } - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); - WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - // print response - if ((bool)resp.status) + if (key_found) PrintAndLogEx(SUCCESS, "Password " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], From 3d14dbfbd0e5886388ec73370bb554401750b5e2 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 11 Nov 2020 01:37:54 +0100 Subject: [PATCH 083/174] pressing the pm3 button now stops 4x50_chk function --- armsrc/em4x50.c | 14 ++++++++------ client/src/cmdlfem4x50.c | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 32862ab97..4c443dbc5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1490,7 +1490,7 @@ void em4x50_chk(uint32_t *offset) { // check passwords from dictionary content in flash memory - bool bsuccess = false; + int status = 0; uint8_t counter[2] = {0x00, 0x00}; uint16_t isok = 0; uint16_t pwd_count = 0; @@ -1530,14 +1530,16 @@ void em4x50_chk(uint32_t *offset) { for (int i = 0; i < pwd_count; i++) { // manual interruption - if (BUTTON_PRESS()) - goto OUT; + if (BUTTON_PRESS()) { + status = BUTTON_SINGLE_CLICK; + break; + } // get next password from flash memory pwd = get_pwd(pwds, i); - bsuccess = login(pwd); - if (bsuccess) + status = login(pwd); + if (status == 1) break; } } @@ -1545,5 +1547,5 @@ void em4x50_chk(uint32_t *offset) { OUT: lf_finalize(); - reply_ng(CMD_LF_EM4X50_CHK, bsuccess, (uint8_t *)&pwd, 32); + reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 2ce7d7985..2a1513cac 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1228,7 +1228,7 @@ int CmdEM4x50Chk(const char *Cmd) { // upload passwords from dictionary to flash memory and start password check - bool key_found = false; + int status = 0; int res = 0, slen = 0; int keys_remain = 0; int block_count = 1; @@ -1277,7 +1277,9 @@ int CmdEM4x50Chk(const char *Cmd) { PrintAndLogEx(FAILED, "error, filesize is larger than available memory"); return PM3_EOVFLOW; } - + + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); + if (datalen > CARD_MEMORY_SIZE) { // we have to use more than one block of passwords @@ -1324,13 +1326,13 @@ int CmdEM4x50Chk(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - key_found = (bool)resp.status; - if (key_found) + status = resp.status; + if (status != false) break; } // print response - if (key_found) + if (status == 1) PrintAndLogEx(SUCCESS, "Password " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], From 5d34efc6e663a3f51937a6b6f84c36f4a2fda3c4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 11 Nov 2020 22:36:24 +0100 Subject: [PATCH 084/174] =?UTF-8?q?Relocated=20write=20requests=20of=20fun?= =?UTF-8?q?ction=20=E2=80=9E4x50=5Fwipe"=20from=20device=20to=20client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- armsrc/appmain.c | 4 --- armsrc/em4x50.c | 62 ----------------------------------------------- armsrc/em4x50.h | 1 - include/pm3_cmd.h | 1 - 4 files changed, 68 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 1fb2d2658..f06f30278 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1107,10 +1107,6 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_read((em4x50_data_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_WIPE: { - em4x50_wipe((uint32_t *)packet->data.asBytes); - break; - } case CMD_LF_EM4X50_BRUTE: { em4x50_brute((em4x50_data_t *)packet->data.asBytes); break; diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 4c443dbc5..f2a0ce972 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1111,68 +1111,6 @@ void em4x50_writepwd(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITEPWD, res, 0, 0); } -void em4x50_wipe(uint32_t *password) { - - // set all data of EM4x50 tag to 0x0 including password - - bool bsuccess = false; - uint32_t addresses = 0x00001E01; // from fwr = 1 to lwr = 31 (0x1E) - uint32_t words[EM4X50_NO_WORDS] = {0x0}; - uint32_t zero = 0x0; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // login first - if (login(*password)) { - - // write 0x0 to each address but ignore addresses - // 0 -> password, 32 -> serial, 33 -> uid - for (int i = 1; i <= 33; i++) - write(zero, i); - - // to verify result -> reset EM4x50 - if (reset()) { - - // login not necessary because protected word has been set to 0 - // -> no read protected words - // -> selective read can be called immediately - if (selective_read(addresses, words)) { - - // check if everything is zero - bsuccess = true; - for (int i = 1; i <= 33; i++) - bsuccess &= (words[i] == 0); - - } - - if (bsuccess) { - - // so far everything is fine - // last task: reset password - if (login(*password)) { - - int res = write_password(*password, zero); - if (res == PM3_ETEAROFF) { - lf_finalize(); - return; - } - bsuccess = (res == PM3_SUCCESS); - } - // verify by login with new password - if (bsuccess) - bsuccess = login(zero); - } - } - } - } - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, 0, 0); -} - void em4x50_reset(void) { // reset EM4x50 diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index d1a94d662..a6030d7ba 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -23,7 +23,6 @@ void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); -void em4x50_wipe(uint32_t *password); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); void em4x50_reset(void); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index d90b78f60..10799cb13 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -507,7 +507,6 @@ typedef struct { #define CMD_LF_EM4X50_WRITE 0x0241 #define CMD_LF_EM4X50_WRITEPWD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 -#define CMD_LF_EM4X50_WIPE 0x0244 #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 #define CMD_LF_EM4X50_RESET 0x0247 From f1b0b91585881a9b81d46ed4bb5771f40e0b3e15 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 11 Nov 2020 22:37:17 +0100 Subject: [PATCH 085/174] =?UTF-8?q?-=20Relocated=20write=20requests=20of?= =?UTF-8?q?=20function=20=E2=80=9E4x50=5Fwipe"=20from=20device=20to=20clie?= =?UTF-8?q?nt=20-=20used=20"INPLACE"=20attribute=20for=20messages=20in=20f?= =?UTF-8?q?unction=204x50=5Fchk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/cmdlfem4x50.c | 67 ++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 2a1513cac..f3bca700d 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -672,9 +672,10 @@ int CmdEM4x50Wipe(const char *Cmd) { // fills EM4x50 tag with zeros including password + bool isOK = false; int pwdLen = 0; uint8_t pwd[4] = {0x0}; - uint32_t password = 0x0; + em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; PacketResponseNG resp; CLIParserContext *ctx; @@ -696,23 +697,59 @@ int CmdEM4x50Wipe(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; } CLIParserFree(ctx); - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password)); - WaitForResponse(CMD_LF_EM4X50_WIPE, &resp); - // print response - bool isOK = resp.status; - if (isOK) { - PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); + // clear password + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Resetting password " _GREEN_("ok")); } else { - PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); + PrintAndLogEx(FAILED, "Resetting password " _RED_("failed")); return PM3_ESOFT; } + // from now on new password 0x0 + etd.password1 = 0x0; + + // clear data (words 1 to 31) + for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { + + // no login necessary for blocks 3 to 31 + etd.pwd_given = (i <= EM4X50_CONTROL); + + PrintAndLogEx(INPLACE, "Wiping block %i", i); + + etd.addresses = i << 8 | i; + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + isOK = resp.status; + if (!isOK) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); + return PM3_ESOFT; + } + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); + + PrintAndLogEx(INFO, "Done"); + return PM3_SUCCESS; } @@ -1313,11 +1350,12 @@ int CmdEM4x50Chk(const char *Cmd) { keys[0] = (key_count >> 0) & 0xFF; keys[1] = (key_count >> 8) & 0xFF; - PrintAndLogEx(INFO, "Checking block #%i (%i passwords)", n + 1, key_count); + PrintAndLogEx(INPLACE, "Checking block #%i (%i passwords)", n + 1, key_count); // send to device res = em4x50_write_flash(keys, offset, datalen + 2); if (res != PM3_SUCCESS) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Error uploading to flash."); return res; } @@ -1332,15 +1370,18 @@ int CmdEM4x50Chk(const char *Cmd) { } // print response - if (status == 1) + if (status == 1) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Password " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], resp.data.asBytes[1], resp.data.asBytes[0] ); - else + } else { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "No password found"); + } PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; From dcfd7f4a01718857f7daa94f574ce649a9893af7 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 12 Nov 2020 01:23:51 +0100 Subject: [PATCH 086/174] - wait function can now be left with pm3 button -> e.g. no inf. loop in 4x50_wath - merged function get_pwd(...) into 4x50_chk --- armsrc/em4x50.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index f2a0ce972..e396491d8 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -62,10 +62,10 @@ int gLow = 60; static void wait_timer0(uint32_t period) { - // do nothing for using timer + // do nothing for using timer0 AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < period); + while ((AT91C_BASE_TC0->TC_CV < period) && !BUTTON_PRESS()); } static void em4x50_setup_read(void) { @@ -1413,17 +1413,6 @@ void em4x50_stdread(void) { reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); } -static uint32_t get_pwd(uint8_t *pwds, int cnt) { - - uint32_t pwd = 0x0; - - for (int j = 0; j < 4; j++) - pwd |= (*(pwds + 4 * cnt + j)) << ((3 - j) * 8); - - return pwd; - -} - void em4x50_chk(uint32_t *offset) { // check passwords from dictionary content in flash memory @@ -1473,8 +1462,10 @@ void em4x50_chk(uint32_t *offset) { break; } - // get next password from flash memory - pwd = get_pwd(pwds, i); + // get next password + pwd = 0x0; + for (int j = 0; j < 4; j++) + pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); status = login(pwd); if (status == 1) From 9415363262fb623c2d29817ba994873bdc2a4085 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 13 Nov 2020 00:50:49 +0100 Subject: [PATCH 087/174] updated usage information --- client/src/cmdlfem4x50.c | 101 ++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index f3bca700d..2526868fe 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -28,6 +28,7 @@ static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len, // read data from dump file; file type is derived from file name extension int res = 0; + uint32_t serial = 0x0, device_id = 0x0; if (str_endswith(filename, ".eml")) res = loadFileEML(filename, data, bytes_read) != PM3_SUCCESS; @@ -39,6 +40,14 @@ static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len, if ((res != PM3_SUCCESS) && (*bytes_read != DUMP_FILESIZE)) return PM3_EFILE; + // valid em4x50 data? + serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + if (serial == device_id) { + PrintAndLogEx(WARNING, "No valid em4x50 data in file %s.", filename); + return PM3_ENODATA; + } + return PM3_SUCCESS; } @@ -264,9 +273,9 @@ int CmdEM4x50Info(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_info", - "Read all information of EM4x50 tag. Tag must be on antenna.", + "Tag information EM4x50.", "lf em 4x50_info\n" - "lf em 4x50_info -p 12345678\n" + "lf em 4x50_info -p 12345678 -> uses password 0x12345678\n" ); void *argtable[] = { @@ -331,8 +340,8 @@ int CmdEM4x50Write(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_write", - "Write EM4x50 word. Tag must be on antenna.", - "lf em 4x50_write -b 3 -d 4f22e7ff\n" + "Writes single block/word to EM4x50 tag.", + "lf em 4x50_write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" "lf em 4x50_write -b 3 -d 4f22e7ff -p 12345678\n" ); @@ -424,8 +433,8 @@ int CmdEM4x50WritePwd(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_writepwd", - "Write EM4x50 password. Tag must be on antenna.", - "lf em 4x50_writepwd -p 4f22e7ff -n 12345678\n" + "Writes EM4x50 password.", + "lf em 4x50_writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" ); void *argtable[] = { @@ -540,9 +549,9 @@ int CmdEM4x50Read(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_read", - "Read EM4x50 block/word. Tag must be on antenna.", - "lf em 4x50_read -b 3\n" - "lf em 4x50_read -b 32 -p 12345678\n" + "Reads single EM4x50 block/word.", + "lf em 4x50_read -b 3 -> reads block 3\n" + "lf em 4x50_read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" ); void *argtable[] = { @@ -590,11 +599,11 @@ int CmdEM4x50Dump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_dump", - "Dump EM4x50 tag. Tag must be on antenna.", - "lf em 4x50_dump\n" - "lf em 4x50_dump -f lf-4x50dump.eml\n" + "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", + "lf em 4x50_dump -> saves dump in lf-4x50--dump.bin/eml/json\n" + "lf em 4x50_dump -f mydump.eml -> saves dump in mydump.eml\n" "lf em 4x50_dump -p 12345678\n" - "lf em 4x50_dump -f lf-4x50dump.eml -p 12345678\n" + "lf em 4x50_dump -f mydump.eml -p 12345678\n" ); void *argtable[] = { @@ -680,8 +689,8 @@ int CmdEM4x50Wipe(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_wipe", - "Wipe EM4x50 tag. Tag must be on antenna.", - "lf em 4x50_wipe -p 12345678\n" + "Wipes EM4x50 tag.", + "lf em 4x50_wipe -p 12345678 -> wipes tag with password 0x12345678\n" ); void *argtable[] = { @@ -765,14 +774,14 @@ int CmdEM4x50Brute(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_brute", - "Bruteforce password of EM4x50 tag. Tag must be on antenna.", - "lf em 4x50_brute -f 12330000 -l 12340000\n" + "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", + "lf em 4x50_brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" ); void *argtable[] = { arg_param_begin, - arg_str1("f", "fwr", "", "first password (start), hex, 4 bytes, lsb"), - arg_str1("l", "lwr", "", "last password (stop), hex, 4 bytes, lsb"), + arg_str1("f", "fp", "", "first password (start), hex, 4 bytes, lsb"), + arg_str1("l", "lp", "", "last password (stop), hex, 4 bytes, lsb"), arg_param_end }; @@ -827,8 +836,8 @@ int CmdEM4x50Login(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_login", - "Login into EM4x50 tag. Tag must be on antenna.", - "lf em 4x50_login -p 12345678\n" + "Login into EM4x50 tag.", + "lf em 4x50_login -p 12345678 -< login with password 12345678\n" ); void *argtable[] = { @@ -869,7 +878,7 @@ int CmdEM4x50Reset(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_reset", - "Reset EM4x50 tag. Tag must be on antenna", + "Reseta EM4x50 tag.", "lf em 4x50_reset\n" ); @@ -903,7 +912,7 @@ int CmdEM4x50Watch(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_watch", - "Watch for EM4x50 tag. Tag must be on antenna", + "Watches for EM4x50 tags. Function runs until button is pressed.", "lf em 4x50_watch\n" ); @@ -937,11 +946,11 @@ int CmdEM4x50Restore(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_restore", - "Restore EM4x50 dump to tag. Tag must be on antenna", - "lf em 4x50_restore -u 1b5aff5c\n" - "lf em 4x50_restore -f lf-4x50dump.eml\n" - "lf em 4x50_restore -u 1b5aff5c -p 12345678\n" - "lf em 4x50_restore -f lf-4x50dump.eml -p 12345678\n" + "Restores data from dumpfile onto a Em4x50 tag.", + "lf em 4x50_restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" + "lf em 4x50_restore -f mydump.eml -> uses mydump.eml\n" + "lf em 4x50_restore -u 1b5aff5c -p 12345678 -> \n" + "lf em 4x50_restore -f mydump.eml -p 12345678 -> \n" ); void *argtable[] = { @@ -1042,9 +1051,9 @@ int CmdEM4x50Sim(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_sim", - "Simulate dump (bin/eml/json) of EM4x50 tag in emulator memory", - "lf em 4x50_sim\n" - "lf em 4x50_sim -f lf-4x50dump.eml\n" + "Simulates a EM4x50 tag", + "lf em 4x50_sim -> simulates EM4x50 data in flash memory.\n" + "lf em 4x50_sim -f mydump.eml -> simulates content of file ./mydump\n" ); void *argtable[] = { @@ -1111,7 +1120,7 @@ int CmdEM4x50StdRead(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_stdread", - "Show standard read data of EM4x50 tag", + "Shows standard read data of EM4x50 tag.", "lf em 4x50_stdread\n" ); @@ -1176,8 +1185,10 @@ int CmdEM4x50ELoad(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_eload", - "Load dump file (bin/eml/json) into flash memory", - "lf em 4x50_eload -f lf-4x50dump.json\n" + "Loads EM4x50 tag dump into flash memory on device.", + "lf em 4x50_eload -f mydump.bin -> uploads bin file ./mydump.bin\n" + "lf em 4x50_eload -f mydump.eml -> uploads eml file ./mydump.eml\n" + "lf em 4x50_eload -f mydump.json -> uploads json file ./mydump.json\n" ); void *argtable[] = { @@ -1218,9 +1229,11 @@ int CmdEM4x50ESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_esave", - "Save flash memory to file (bin, elm, json)", - "lf em 4x50_esave\n" - "lf em 4x50_esave -f lf-4x50dump.json\n" + "Saves bin/eml/json dump file of flash memory.", + "lf em 4x50_esave -> use UID as filename\n" + "lf em 4x50_esave -f mydump.bin -> saves to bin file ./mydump.bin\n" + "lf em 4x50_esave -f mydump.eml -> saves to eml file ./mydump.eml\n" + "lf em 4x50_esave -f mydump.json -> saves to json file ./mydump.json\n" ); void *argtable[] = { @@ -1240,7 +1253,7 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_ETIMEOUT; } - // valid data regarding em4x50? + // valid em4x50 data? serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); if (serial == device_id) { @@ -1263,7 +1276,9 @@ int CmdEM4x50ESave(const char *Cmd) { int CmdEM4x50Chk(const char *Cmd) { - // upload passwords from dictionary to flash memory and start password check + // upload passwords from given dictionary to flash memory and + // start password check; + // if no filename is given dictionary "t55xx_default_pwds.dic" is used int status = 0; int res = 0, slen = 0; @@ -1278,9 +1293,9 @@ int CmdEM4x50Chk(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_chk", - "Check passwords from dictionary in flash memory", - "lf em 4x50_chk\n" - "lf em 4x50_chk -f 4_byte_password_file.dic\n" + "Dictionary attack against EM4x50.", + "lf em 4x50_chk -> uses T55xx default dictionary\n" + "lf em 4x50_chk -f my.dic -> uses dictionary ./my.dic\n" ); void *argtable[] = { @@ -1293,8 +1308,6 @@ int CmdEM4x50Chk(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - //data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); - // no filename -> default = t55xx_default_pwds if (strlen(filename) == 0) { snprintf(filename, sizeof(filename), "t55xx_default_pwds"); From b91792f1d7196a72c06996abb36ddd89511602c4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 13 Nov 2020 20:27:57 +0100 Subject: [PATCH 088/174] deleted uneccessary includes --- armsrc/em4x50.c | 1 - client/src/cmdlfem4x50.c | 6 ------ client/src/cmdlfem4x50.h | 1 - 3 files changed, 8 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index e396491d8..e4a4109c2 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -12,7 +12,6 @@ #include "ticks.h" #include "dbprint.h" #include "lfadc.h" -#include "pmflash.h" #include "commonutil.h" #include "em4x50.h" #include "flashmem.h" diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 2526868fe..dca26cbc8 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -10,15 +10,9 @@ #include "cliparser.h" #include "cmdlfem4x50.h" -#include #include "fileutils.h" -#include "comms.h" -#include "util.h" #include "commonutil.h" -#include "cmdparser.h" #include "pmflash.h" -#include "cmdflashmem.h" -#include "em4x50.h" #define FLASH_MEM_PAGE_SIZE 0x10000 #define CARD_MEMORY_SIZE 4096 diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 753210f0a..a8d637f4e 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -11,7 +11,6 @@ #ifndef CMDLFEM4X50_H__ #define CMDLFEM4X50_H__ -#include"common.h" #include "em4x50.h" int read_em4x50_uid(void); From 7c0c4e2e7dbc3780632a2f54a7f354e9360e3b1e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 14 Nov 2020 00:08:37 +0100 Subject: [PATCH 089/174] deleted unnecessary memory checks (passwords are uploaded blockwise, the more passwords the more blocks) --- client/src/cmdlfem4x50.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index dca26cbc8..03749eb77 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1312,15 +1312,6 @@ int CmdEM4x50Chk(const char *Cmd) { res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &key_count); if (res || !key_count) return PM3_EFILE; - - // limited space on flash mem - if (key_count > 0xFFFF) - key_count &= 0xFFFF; - - if (datalen > FLASH_MEM_MAX_SIZE) { - PrintAndLogEx(FAILED, "error, filesize is larger than available memory"); - return PM3_EOVFLOW; - } PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); From d36645334aa5e9a404a5472d63798864377d30e8 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 15 Nov 2020 01:56:00 +0100 Subject: [PATCH 090/174] renaming --- client/src/cmdlfem4x50.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 03749eb77..d27a51797 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -17,7 +17,7 @@ #define FLASH_MEM_PAGE_SIZE 0x10000 #define CARD_MEMORY_SIZE 4096 -static int loadFileEM4x50(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { +static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { // read data from dump file; file type is derived from file name extension @@ -919,13 +919,13 @@ int CmdEM4x50Watch(const char *Cmd) { CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); - WaitForResponse(CMD_LF_EM4X50_WATCH, &resp); + WaitForResponseTimeoutW(CMD_LF_EM4X50_WATCH, &resp, -1, false); PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } @@ -994,7 +994,7 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; // upload to flash memory @@ -1064,7 +1064,7 @@ int CmdEM4x50Sim(const char *Cmd) { if (slen != 0) { // load file content - if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } @@ -1196,7 +1196,7 @@ int CmdEM4x50ELoad(const char *Cmd) { CLIParserFree(ctx); // read data from dump file; file type has to be "bin", "eml" or "json" - if (loadFileEM4x50(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; } From 7aebe20dd6a46383bd8e34f517858ed16c0e7c0e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 15 Nov 2020 17:15:18 +0100 Subject: [PATCH 091/174] - enhanced reliability of manual interruption - switched to PM3 error/status codes for reset function --- armsrc/em4x50.c | 57 +++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index e4a4109c2..ba1033708 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -59,12 +59,16 @@ int gLow = 60; // auxiliary functions -static void wait_timer0(uint32_t period) { +static int wait_timer0(uint32_t period) { // do nothing for using timer0 AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while ((AT91C_BASE_TC0->TC_CV < period) && !BUTTON_PRESS()); + while (AT91C_BASE_TC0->TC_CV < period) + if (BUTTON_PRESS()) + return BUTTON_SINGLE_CLICK; + + return BUTTON_NO_CLICK; } static void em4x50_setup_read(void) { @@ -149,7 +153,8 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - wait_timer0(T0 * EM4X50_T_TAG_HALF_PERIOD); + if (wait_timer0(T0 * EM4X50_T_TAG_HALF_PERIOD) == BUTTON_SINGLE_CLICK) + return false; if (AT91C_BASE_SSC->SSC_RHR > noise) { signal_found = true; @@ -195,11 +200,13 @@ static bool invalid_bit(void) { // "find_double_listen_window" and "check_ack" // get sample at 3/4 of bit period - wait_timer0(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + if (wait_timer0(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD) == BUTTON_SINGLE_CLICK) + return false; uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - wait_timer0(T0 * EM4X50_T_TAG_QUARTER_PERIOD); + if (wait_timer0(T0 * EM4X50_T_TAG_QUARTER_PERIOD) == BUTTON_SINGLE_CLICK) + return false; // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -382,7 +389,8 @@ static int find_double_listen_window(bool bcommand) { // second window follows - sync on this to issue a command // skip the next bit... - wait_timer0(T0 * EM4X50_T_TAG_FULL_PERIOD); + if (wait_timer0(T0 * EM4X50_T_TAG_FULL_PERIOD) == BUTTON_SINGLE_CLICK) + return false; // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -604,7 +612,8 @@ static bool check_ack(bool bliw) { // wait for 2 bits (remaining "bit" of ACK signal + first // "bit" of listen window) - wait_timer0(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); + if (wait_timer0(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD) == BUTTON_SINGLE_CLICK) + return false; // check for listen window (if first bit cannot be interpreted // as a valid bit it must belong to a listen window) @@ -714,7 +723,7 @@ static int get_word_from_bitstream(uint32_t *data) { // identify remaining bits based on pulse lengths // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (true) { + while (BUTTON_PRESS() == false) { cnt++; word <<= 1; @@ -768,6 +777,8 @@ static int get_word_from_bitstream(uint32_t *data) { } } + + return BUTTON_SINGLE_CLICK; } //============================================================================== @@ -805,7 +816,7 @@ static bool login(uint32_t password) { // reset function //============================================================================== -static bool reset(void) { +static int reset(void) { // resets EM4x50 tag (used by write function) @@ -815,14 +826,14 @@ static bool reset(void) { em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); if (check_ack(false)) - return true; + return PM3_SUCCESS; } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("error in command request"); } - return false; + return PM3_EFAILED; } @@ -830,31 +841,29 @@ static bool reset(void) { // read functions //============================================================================== -static bool standard_read(int *now, uint32_t *words) { +static int standard_read(int *now, uint32_t *words) { // reads data that tag transmits when exposed to reader field // (standard read mode); number of read words is saved in - int fwr = *now; + int fwr = *now, res = PM3_EFAILED; // start with the identification of two successive listening windows if (find_double_listen_window(false)) { // read and save words until following double listen window is detected - while (get_word_from_bitstream(&words[*now]) == EM4X50_TAG_WORD) + while ((res = get_word_from_bitstream(&words[*now])) == EM4X50_TAG_WORD) (*now)++; // number of detected words *now -= fwr; - return true; - } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("didn't find a listen window"); } - return false; + return res; } static bool selective_read(uint32_t addresses, uint32_t *words) { @@ -878,7 +887,7 @@ static bool selective_read(uint32_t addresses, uint32_t *words) { if (check_ack(false)) // save and verify via standard read mode (compare number of words) - if (standard_read(&now, words)) + if (standard_read(&now, words) == PM3_SUCCESS) if (now == (lwr - fwr + 1)) return true; @@ -1063,7 +1072,7 @@ void em4x50_write(em4x50_data_t *etd) { if (res == PM3_SUCCESS) { // to verify result reset EM4x50 - if (reset()) { + if (reset() == PM3_SUCCESS) { // if password is given login if (etd->pwd_given) @@ -1114,7 +1123,7 @@ void em4x50_reset(void) { // reset EM4x50 - uint8_t status = 0; + uint8_t status = PM3_EFAILED; em4x50_setup_read(); @@ -1215,12 +1224,14 @@ void em4x50_watch() { if (get_signalproperties() && find_em4x50_tag()) { - standard_read(&now, words); + if (standard_read(&now, words) == BUTTON_SINGLE_CLICK) + break; + if (now > 0) { Dbprintf(""); for (int i = 0; i < now; i++) - Dbprintf("EM4x50 TAG ID: " + Dbprintf("EM4x50 tag data: " _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", words[i], reflect32(words[i])); } @@ -1317,7 +1328,7 @@ void em4x50_restore(em4x50_data_t *etd) { } // to verify result -> reset EM4x50 - if (reset()) { + if (reset() == PM3_SUCCESS) { // login not necessary because protected word has been set to 0 // -> no read protected words From 2b301b140ef0e20218259ce6bad00d06ec703948 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 15 Nov 2020 17:15:56 +0100 Subject: [PATCH 092/174] - switched to PM3 error/status codes for reset function - wording --- client/src/cmdlfem4x50.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index d27a51797..048eff1ea 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -890,12 +890,12 @@ int CmdEM4x50Reset(const char *Cmd) { WaitForResponse(CMD_LF_EM4X50_RESET, &resp); // print response - if ((bool)resp.status) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Reset " _GREEN_("ok")); else PrintAndLogEx(FAILED, "Reset " _RED_("failed")); - return PM3_SUCCESS; + return resp.status; } int CmdEM4x50Watch(const char *Cmd) { @@ -1306,7 +1306,7 @@ int CmdEM4x50Chk(const char *Cmd) { if (strlen(filename) == 0) { snprintf(filename, sizeof(filename), "t55xx_default_pwds"); offset = DEFAULT_T55XX_KEYS_OFFSET; - PrintAndLogEx(INFO, "treating file as T55xx passwords"); + PrintAndLogEx(INFO, "treating file as T55xx keys"); } res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &key_count); @@ -1328,7 +1328,7 @@ int CmdEM4x50Chk(const char *Cmd) { datalen = CARD_MEMORY_SIZE; key_count = datalen / 4; - PrintAndLogEx(INFO, "Passwords divided into %i blocks", block_count); + PrintAndLogEx(INFO, "Keys subdivided into %i blocks", block_count); } for (int n = 0; n < block_count; n++) { @@ -1348,7 +1348,7 @@ int CmdEM4x50Chk(const char *Cmd) { keys[0] = (key_count >> 0) & 0xFF; keys[1] = (key_count >> 8) & 0xFF; - PrintAndLogEx(INPLACE, "Checking block #%i (%i passwords)", n + 1, key_count); + PrintAndLogEx(INPLACE, "Checking block #%i (%i keys)", n + 1, key_count); // send to device res = em4x50_write_flash(keys, offset, datalen + 2); @@ -1370,7 +1370,7 @@ int CmdEM4x50Chk(const char *Cmd) { // print response if (status == 1) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Password " _GREEN_("found: %02x %02x %02x %02x"), + PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], resp.data.asBytes[1], @@ -1378,7 +1378,7 @@ int CmdEM4x50Chk(const char *Cmd) { ); } else { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(FAILED, "No password found"); + PrintAndLogEx(FAILED, "No key found"); } PrintAndLogEx(INFO, "Done"); From f6e37d868edd54f018b19608d2b04f7ee25e18fe Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 15 Nov 2020 19:54:51 +0100 Subject: [PATCH 093/174] switched to PM3 status/error codes as return codes (if possible/sensible) --- armsrc/em4x50.c | 53 ++++++++++++++++++++-------------------- client/src/cmdlfem4x50.c | 39 +++++++++++++++-------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ba1033708..b76f8c436 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -802,14 +802,14 @@ static bool login(uint32_t password) { // check if ACK is returned if (check_ack(false)) - return true; + return PM3_SUCCESS; } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("error in command request"); } - return false; + return PM3_EFAILED; } //============================================================================== @@ -822,7 +822,7 @@ static int reset(void) { if (request_receive_mode()) { - // send login command + // send reset command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); if (check_ack(false)) @@ -866,11 +866,12 @@ static int standard_read(int *now, uint32_t *words) { return res; } -static bool selective_read(uint32_t addresses, uint32_t *words) { +static int selective_read(uint32_t addresses, uint32_t *words) { // reads from "first word read" (fwr) to "last word read" (lwr) // result is verified by "standard read mode" + int status = PM3_EFAILED; uint8_t fwr = addresses & 0xFF; // first word read (first byte) uint8_t lwr = (addresses >> 8) & 0xFF; // last word read (second byte) int now = fwr; // number of words @@ -887,16 +888,16 @@ static bool selective_read(uint32_t addresses, uint32_t *words) { if (check_ack(false)) // save and verify via standard read mode (compare number of words) - if (standard_read(&now, words) == PM3_SUCCESS) + if ((status = standard_read(&now, words)) == PM3_SUCCESS) if (now == (lwr - fwr + 1)) - return true; + return status; } else { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("error in command request"); } - return false; + return status; } void em4x50_info(em4x50_data_t *etd) { @@ -915,9 +916,9 @@ void em4x50_info(em4x50_data_t *etd) { // login with given password if (etd->pwd_given) - blogin = login(etd->password1); + blogin = (login(etd->password1) == PM3_SUCCESS); - bsuccess = selective_read(addresses, words); + bsuccess = (selective_read(addresses, words) == PM3_SUCCESS); } status = (bsuccess << 1) + blogin; @@ -941,11 +942,10 @@ void em4x50_read(em4x50_data_t *etd) { // try to login with given password if (etd->pwd_given) - blogin = login(etd->password1); + blogin = (login(etd->password1) == PM3_SUCCESS); // only one word has to be read -> first word read = last word read - bsuccess = selective_read(etd->addresses, words); - + bsuccess = (selective_read(etd->addresses, words) == PM3_SUCCESS); } status = (bsuccess << 1) + blogin; @@ -961,8 +961,8 @@ void em4x50_read(em4x50_data_t *etd) { static int write(uint32_t word, uint32_t addresses) { - // writes to specified
- + // writes to specified + if (request_receive_mode()) { // send write command @@ -997,7 +997,7 @@ static int write(uint32_t word, uint32_t addresses) { Dbprintf("error in command request"); } - return false; + return PM3_EFAILED; } static int write_password(uint32_t password, uint32_t new_password) { @@ -1060,7 +1060,7 @@ void em4x50_write(em4x50_data_t *etd) { // if password is given try to login first if (etd->pwd_given) - blogin = login(etd->password1); + blogin = (login(etd->password1) == PM3_SUCCESS); // write word to given address int res = write(etd->word, etd->addresses); @@ -1076,10 +1076,10 @@ void em4x50_write(em4x50_data_t *etd) { // if password is given login if (etd->pwd_given) - blogin &= login(etd->password1); + blogin &= (login(etd->password1) == PM3_SUCCESS); // call a selective read - if (selective_read(etd->addresses, words)) { + if (selective_read(etd->addresses, words) == PM3_SUCCESS) { // compare with given word bsuccess = (words[etd->addresses & 0xFF] == reflect32(etd->word)); @@ -1097,7 +1097,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simple change of password - int res = PM3_ENODATA; + int res = PM3_EFAILED; em4x50_setup_read(); @@ -1105,7 +1105,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { if (get_signalproperties() && find_em4x50_tag()) { // login and change password - if (login(etd->password1)) { + if (login(etd->password1) == PM3_SUCCESS) { res = write_password(etd->password1, etd->password2); if (res == PM3_ETEAROFF) { @@ -1139,7 +1139,7 @@ void em4x50_login(uint32_t *password) { // login into EM4x50 - uint8_t status = false; + uint8_t status = PM3_EFAILED; em4x50_setup_read(); @@ -1160,7 +1160,7 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { for (*pwd = start; *pwd <= stop; (*pwd)++) { - if (login(*pwd)) { + if (login(*pwd) == PM3_SUCCESS) { pwd_found = true; break; } @@ -1311,7 +1311,7 @@ void em4x50_restore(em4x50_data_t *etd) { // login first if password is available if (etd->pwd_given) - blogin = login(etd->password1); + blogin = (login(etd->password1) == PM3_SUCCESS); // write data to each address but ignore addresses // 0 -> password, 32 -> serial, 33 -> uid @@ -1333,7 +1333,7 @@ void em4x50_restore(em4x50_data_t *etd) { // login not necessary because protected word has been set to 0 // -> no read protected words // -> selective read can be called immediately - if (selective_read(addresses, words_read)) { + if (selective_read(addresses, words_read) == PM3_SUCCESS) { // check if everything is zero bsuccess = true; @@ -1427,7 +1427,7 @@ void em4x50_chk(uint32_t *offset) { // check passwords from dictionary content in flash memory - int status = 0; + int status = PM3_EFAILED; uint8_t counter[2] = {0x00, 0x00}; uint16_t isok = 0; uint16_t pwd_count = 0; @@ -1477,8 +1477,7 @@ void em4x50_chk(uint32_t *offset) { for (int j = 0; j < 4; j++) pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); - status = login(pwd); - if (status == 1) + if ((status = login(pwd)) == PM3_SUCCESS) break; } } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 048eff1ea..18eddf7dc 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -303,17 +303,18 @@ int CmdEM4x50Info(const char *Cmd) { return PM3_ETIMEOUT; } - if (etd.pwd_given) { - bool login = resp.status & STATUS_LOGIN; - if (login == false) { - PrintAndLogEx(FAILED, "Login failed"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); - } - + bool login = resp.status & STATUS_LOGIN; bool success = (resp.status & STATUS_SUCCESS) >> 1; + if (success) { + if (etd.pwd_given) { + if (login == false) { + PrintAndLogEx(FAILED, "Login failed"); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); + } + print_info_result(resp.data.asBytes); return PM3_SUCCESS; } @@ -419,7 +420,7 @@ int CmdEM4x50WritePwd(const char *Cmd) { // envokes changing the password of EM4x50 tag - int status = 0; + int status = PM3_EFAILED; int pwdLen = 0, npwdLen = 0; uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; PacketResponseNG resp; @@ -474,7 +475,7 @@ int CmdEM4x50WritePwd(const char *Cmd) { // print response if (status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); - return PM3_ESOFT; + return PM3_EFAILED; } PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); @@ -858,12 +859,12 @@ int CmdEM4x50Login(const char *Cmd) { WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); // print response - if ((bool)resp.status) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Login " _GREEN_("ok")); else PrintAndLogEx(FAILED, "Login " _RED_("failed")); - return PM3_SUCCESS; + return resp.status; } int CmdEM4x50Reset(const char *Cmd) { @@ -1109,7 +1110,7 @@ int CmdEM4x50Sim(const char *Cmd) { int CmdEM4x50StdRead(const char *Cmd) { - int now = 0; + int now = 0, status = PM3_EFAILED; PacketResponseNG resp; CLIParserContext *ctx; @@ -1160,6 +1161,7 @@ int CmdEM4x50StdRead(const char *Cmd) { ); } + status = PM3_SUCCESS; PrintAndLogEx(INFO, "----+-------------+-------------"); PrintAndLogEx(SUCCESS, "Standard read " _GREEN_("ok")); @@ -1167,7 +1169,7 @@ int CmdEM4x50StdRead(const char *Cmd) { PrintAndLogEx(FAILED, "Standard read " _RED_("failed")); } - return PM3_SUCCESS; + return status; } int CmdEM4x50ELoad(const char *Cmd) { @@ -1274,7 +1276,7 @@ int CmdEM4x50Chk(const char *Cmd) { // start password check; // if no filename is given dictionary "t55xx_default_pwds.dic" is used - int status = 0; + int status = PM3_EFAILED; int res = 0, slen = 0; int keys_remain = 0; int block_count = 1; @@ -1362,13 +1364,12 @@ int CmdEM4x50Chk(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - status = resp.status; - if (status != false) + if ((status = resp.status) == PM3_SUCCESS) break; } // print response - if (status == 1) { + if (status == PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], From 333fb5cbd40f4a626158b990f3dd4108dba4d606 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 15 Nov 2020 21:59:25 +0100 Subject: [PATCH 094/174] clean up --- armsrc/em4x50.c | 14 +++----------- client/src/cmdlfem4x50.c | 3 +-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b76f8c436..a47ea476a 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -44,10 +44,6 @@ #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 -#define EM4X50_BIT_0 0 -#define EM4X50_BIT_1 1 -#define EM4X50_BIT_OTHER 2 - #define EM4X50_COMMAND_LOGIN 0x01 #define EM4X50_COMMAND_RESET 0x80 #define EM4X50_COMMAND_WRITE 0x12 @@ -97,23 +93,19 @@ static void em4x50_setup_read(void) { // Enable Peripheral Clock for // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); + 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; - AT91C_BASE_TC1->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 - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // synchronized startup procedure while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero @@ -233,7 +225,7 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); while (sample < gHigh && (timeout--)) @@ -249,7 +241,7 @@ static uint32_t get_pulse_length(void) { if (timeout == 0) return 0; - return (uint32_t)AT91C_BASE_TC1->TC_CV; + return (uint32_t)AT91C_BASE_TC0->TC_CV; } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 18eddf7dc..b3c53a22d 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -14,8 +14,7 @@ #include "commonutil.h" #include "pmflash.h" -#define FLASH_MEM_PAGE_SIZE 0x10000 -#define CARD_MEMORY_SIZE 4096 +#define CARD_MEMORY_SIZE 4096 static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { From 0bca672fbda5bd04ba9bf137ce02ca3d9fb3ef60 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 16 Nov 2020 00:33:36 +0100 Subject: [PATCH 095/174] deleted button test in wait_timer function --- armsrc/em4x50.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index a47ea476a..841bfe973 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -55,16 +55,12 @@ int gLow = 60; // auxiliary functions -static int wait_timer0(uint32_t period) { +static void wait_timer(uint32_t period) { // do nothing for using timer0 AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < period) - if (BUTTON_PRESS()) - return BUTTON_SINGLE_CLICK; - - return BUTTON_NO_CLICK; + while (AT91C_BASE_TC0->TC_CV < period); } static void em4x50_setup_read(void) { @@ -145,8 +141,7 @@ static bool get_signalproperties(void) { if (BUTTON_PRESS()) return false; // about 2 samples per bit period - if (wait_timer0(T0 * EM4X50_T_TAG_HALF_PERIOD) == BUTTON_SINGLE_CLICK) - return false; + wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); if (AT91C_BASE_SSC->SSC_RHR > noise) { signal_found = true; @@ -192,13 +187,12 @@ static bool invalid_bit(void) { // "find_double_listen_window" and "check_ack" // get sample at 3/4 of bit period - if (wait_timer0(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD) == BUTTON_SINGLE_CLICK) - return false; + wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period - if (wait_timer0(T0 * EM4X50_T_TAG_QUARTER_PERIOD) == BUTTON_SINGLE_CLICK) - return false; + wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -215,10 +209,6 @@ static uint32_t get_pulse_length(void) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // for manual interruption - if (BUTTON_PRESS()) - return 0; - while (sample > gLow && (timeout--)) sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -260,7 +250,7 @@ static void em4x50_reader_send_bit(int bit) { if (bit == 0) { - // disable modulation (drop the field) for 7 cycles of carrier + // disable modulation (drops the field) for 7 cycles of carrier // period (Opt64) LOW(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * 7); @@ -381,8 +371,7 @@ static int find_double_listen_window(bool bcommand) { // second window follows - sync on this to issue a command // skip the next bit... - if (wait_timer0(T0 * EM4X50_T_TAG_FULL_PERIOD) == BUTTON_SINGLE_CLICK) - return false; + wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -604,8 +593,7 @@ static bool check_ack(bool bliw) { // wait for 2 bits (remaining "bit" of ACK signal + first // "bit" of listen window) - if (wait_timer0(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD) == BUTTON_SINGLE_CLICK) - return false; + wait_timer(T0 * 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) @@ -790,7 +778,7 @@ static bool login(uint32_t password) { // send password em4x50_reader_send_word(password); - wait_timer0(T0 * EM4X50_T_TAG_TPP); + wait_timer(T0 * EM4X50_T_TAG_TPP); // check if ACK is returned if (check_ack(false)) @@ -972,7 +960,7 @@ static int write(uint32_t word, uint32_t addresses) { } else { // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer0(T0 * EM4X50_T_TAG_TWA); + wait_timer(T0 * EM4X50_T_TAG_TWA); // look for ACK sequence if (check_ack(false)) { @@ -1010,7 +998,7 @@ static int write_password(uint32_t password, uint32_t new_password) { } else { // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer0(T0 * EM4X50_T_TAG_TPP); + wait_timer(T0 * EM4X50_T_TAG_TPP); // look for ACK sequence and send rm request // during following listen window @@ -1020,7 +1008,7 @@ 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_timer0(T0 * EM4X50_T_TAG_TWA); + wait_timer(T0 * EM4X50_T_TAG_TWA); if (check_ack(false)) if (check_ack(false)) From 6e6f016460755139b63a0c9b5b3cf72499952cd2 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 18 Nov 2020 22:43:16 +0100 Subject: [PATCH 096/174] deleted uneccessary function --- client/src/cmdlfem4x50.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index b3c53a22d..c0980e7f6 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -110,26 +110,6 @@ static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { return PM3_SUCCESS; } -/* -static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) { - - // fast push mode - conn.block_after_ACK = true; - - for (size_t i = offset; i < nobytes; i += PM3_CMD_DATA_SIZE) { - - size_t len = MIN((nobytes - i), PM3_CMD_DATA_SIZE); - if (len == nobytes - i) { - // Disable fast mode on last packet - conn.block_after_ACK = false; - } - - clearCommandBuffer(); - SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); - } -} -*/ - static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure From 56efc8adecf5135c8cbf6789fa41ffabf0812581 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 19 Nov 2020 23:18:04 +0100 Subject: [PATCH 097/174] rearrangements --- armsrc/em4x50.c | 1064 ++++++++++---------- client/src/cmdlfem4x50.c | 2000 +++++++++++++++++++------------------- 2 files changed, 1537 insertions(+), 1527 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 841bfe973..2d3a24f89 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -35,11 +35,11 @@ #define EM4X50_T_TAG_TWA 64 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be - // critical; if it's too - // low (e.g. < 120) some - // cards are no longer - // readable although - // they're ok + // critical; + // if it's too low + // (e.g. < 120) some cards + // are no longer readable + // although they're ok #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 @@ -53,7 +53,9 @@ int gHigh = 190; int gLow = 60; +//============================================================================== // auxiliary functions +//============================================================================== static void wait_timer(uint32_t period) { @@ -63,6 +65,58 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } +static bool extract_parities(uint64_t word, uint32_t *data) { + + // extract and check parities + // return result of parity check and extracted plain data + + uint8_t row_parities = 0x0, col_parities = 0x0; + uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; + + *data = 0x0; + + // extract plain data (32 bits) from raw word (45 bits) + for (int i = 0; i < 4; i++) { + *data <<= 8; + *data |= (word >> ((4 - i) * 9 + 1)) & 0xFF; + } + + // extract row parities (4 bits + stop bit) from raw word (45 bits) + for (int i = 0; i < 5; i++) { + row_parities <<= 1; + row_parities |= (word >> ((4 - i) * 9)) & 0x1; + } + + // extract col_parities (8 bits, no stop bit) from raw word (45 bits) + col_parities = (word >> 1) & 0xFF; + + // check extracted parities against extracted data + + // calculate row parities from data + for (int i = 0; i < 4; i++) { + row_parities_calculated <<= 1; + for (int j = 0; j < 8; j++) { + row_parities_calculated ^= (*data >> ((3 - i) * 8 + (7 - j))) & 0x1; + } + } + + // add stop bit (always zero) + row_parities_calculated <<= 1; + + // calculate column parities from data + for (int i = 0; i < 8; i++) { + col_parities_calculated <<= 1; + for (int j = 0; j < 4; j++) { + col_parities_calculated ^= (*data >> ((3 - j) * 8 + (7 - i))) & 0x1; + } + } + + if ((row_parities == row_parities_calculated) && (col_parities == col_parities_calculated)) + return true; + + return false; +} + static void em4x50_setup_read(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -120,7 +174,9 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } +//============================================================================== // functions for "reader" use case +//============================================================================== static bool get_signalproperties(void) { @@ -402,6 +458,170 @@ static int find_double_listen_window(bool bcommand) { return false; } +static bool find_em4x50_tag(void) { + + // function is used to check wether a tag on the proxmark is an + // EM4x50 tag or not -> speed up "lf search" process + return find_single_listen_window(); +} + +static int request_receive_mode(void) { + + // To issue a command we have to find a listen window first. + // Because identification and synchronization at the same time is not + // possible when using pulse lengths a double listen window is used. + return find_double_listen_window(true); +} + +static bool check_ack(bool bliw) { + + // returns true if signal structue corresponds to ACK, anything else is + // counted as NAK (-> false) + // Only relevant for pasword writing function: + // If is true then within the single listen window right after the + // ack signal a RM request has to be sent. + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { + + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { + + // The received signal is either ACK or NAK. + + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { + + // Now the signal must be ACK. + + if (!bliw) { + + return true; + + } else { + + // send RM request after ack signal + + // wait for 2 bits (remaining "bit" of ACK signal + first + // "bit" of listen window) + wait_timer(T0 * 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) + if (invalid_bit()) { + + // send RM for request mode + em4x50_reader_send_bit(0); + em4x50_reader_send_bit(0); + + return true; + } + } + } else { + + // It's NAK -> stop searching + break; + } + } + } + + return false; +} + +static int get_word_from_bitstream(uint32_t *data) { + + // decodes one word by evaluating pulse lengths and previous bit; + // word must have 45 bits in total: + // 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit + + bool bitchange = false; + int cnt = 0; + uint32_t pl = 0; + uint64_t word = 0x0; + + *data = 0x0; + + // initial bit value depends on last pulse length of listen window + pl = get_pulse_length(); + if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { + + // pulse length = 1.5 + word = 0x1; + + } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { + + // pulse length = 2 + bitchange = true; + + } else { + + // pulse length = 2.5 + word = 0x1; + cnt++; + } + + // identify remaining bits based on pulse lengths + // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible + while (BUTTON_PRESS() == false) { + + cnt++; + word <<= 1; + + pl = get_pulse_length(); + + if (check_pulse_length(pl, EM4X50_T_TAG_FULL_PERIOD)) { + + // pulse length = 1 -> keep former bit value + word |= (word >> 1) & 0x1; + + } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { + + // pulse length = 1.5 -> decision on bit change + + if (bitchange) { + + // if number of pulse lengths with 1.5 periods is even -> add bit + word |= (word >> 1) & 0x1; + word <<= 1; + + // pulse length of 1.5 changes bit value + word |= ((word >> 1) & 0x1) ^ 0x1; + cnt++; + + // next time add only one bit + bitchange = false; + + } else { + + word |= ((word >> 1) & 0x1) ^ 0x1; + + // next time two bits have to be added + bitchange = true; + } + + } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { + + // pulse length of 2 means: adding 2 bits "01" + cnt++; + + word <<= 1; + word |= 0x1; + + } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_FULL_PERIOD)) { + + // pulse length of 3 indicates listen window -> clear last + // bit (= 0) and return (without parities) + word >>= 2; + return (extract_parities(word, data)) ? --cnt : 0; + + } + } + + return BUTTON_SINGLE_CLICK; +} + +//============================================================================== +// functions for "simulating" use case +//============================================================================== + static bool em4x50_sim_send_bit(uint8_t bit) { uint16_t check = 0; @@ -548,221 +768,8 @@ bool em4x50_sim_send_listen_window(void) { return true; } - -static bool find_em4x50_tag(void) { - - // function is used to check wether a tag on the proxmark is an - // EM4x50 tag or not -> speed up "lf search" process - return find_single_listen_window(); -} - -static int request_receive_mode(void) { - - // To issue a command we have to find a listen window first. - // Because identification and synchronization at the same time is not - // possible when using pulse lengths a double listen window is used. - return find_double_listen_window(true); -} - -static bool check_ack(bool bliw) { - - // returns true if signal structue corresponds to ACK, anything else is - // counted as NAK (-> false) - // Only relevant for pasword writing function: - // If is true then within the single listen window right after the - // ack signal a RM request has to be sent. - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { - - if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { - - // The received signal is either ACK or NAK. - - if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { - - // Now the signal must be ACK. - - if (!bliw) { - - return true; - - } else { - - // send RM request after ack signal - - // wait for 2 bits (remaining "bit" of ACK signal + first - // "bit" of listen window) - wait_timer(T0 * 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) - if (invalid_bit()) { - - // send RM for request mode - em4x50_reader_send_bit(0); - em4x50_reader_send_bit(0); - - return true; - } - } - } else { - - // It's NAK -> stop searching - break; - } - } - } - - return false; -} - -static bool extract_parities(uint64_t word, uint32_t *data) { - - // extract and check parities - // return result of parity check and extracted plain data - - uint8_t row_parities = 0x0, col_parities = 0x0; - uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; - - *data = 0x0; - - // extract plain data (32 bits) from raw word (45 bits) - for (int i = 0; i < 4; i++) { - *data <<= 8; - *data |= (word >> ((4 - i) * 9 + 1)) & 0xFF; - } - - // extract row parities (4 bits + stop bit) from raw word (45 bits) - for (int i = 0; i < 5; i++) { - row_parities <<= 1; - row_parities |= (word >> ((4 - i) * 9)) & 0x1; - } - - // extract col_parities (8 bits, no stop bit) from raw word (45 bits) - col_parities = (word >> 1) & 0xFF; - - // check extracted parities against extracted data - - // calculate row parities from data - for (int i = 0; i < 4; i++) { - row_parities_calculated <<= 1; - for (int j = 0; j < 8; j++) { - row_parities_calculated ^= (*data >> ((3 - i) * 8 + (7 - j))) & 0x1; - } - } - - // add stop bit (always zero) - row_parities_calculated <<= 1; - - // calculate column parities from data - for (int i = 0; i < 8; i++) { - col_parities_calculated <<= 1; - for (int j = 0; j < 4; j++) { - col_parities_calculated ^= (*data >> ((3 - j) * 8 + (7 - i))) & 0x1; - } - } - - if ((row_parities == row_parities_calculated) && (col_parities == col_parities_calculated)) - return true; - - return false; -} - -static int get_word_from_bitstream(uint32_t *data) { - - // decodes one word by evaluating pulse lengths and previous bit; - // word must have 45 bits in total: - // 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit - - bool bitchange = false; - int cnt = 0; - uint32_t pl = 0; - uint64_t word = 0x0; - - *data = 0x0; - - // initial bit value depends on last pulse length of listen window - pl = get_pulse_length(); - if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { - - // pulse length = 1.5 - word = 0x1; - - } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { - - // pulse length = 2 - bitchange = true; - - } else { - - // pulse length = 2.5 - word = 0x1; - cnt++; - } - - // identify remaining bits based on pulse lengths - // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (BUTTON_PRESS() == false) { - - cnt++; - word <<= 1; - - pl = get_pulse_length(); - - if (check_pulse_length(pl, EM4X50_T_TAG_FULL_PERIOD)) { - - // pulse length = 1 -> keep former bit value - word |= (word >> 1) & 0x1; - - } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) { - - // pulse length = 1.5 -> decision on bit change - - if (bitchange) { - - // if number of pulse lengths with 1.5 periods is even -> add bit - word |= (word >> 1) & 0x1; - word <<= 1; - - // pulse length of 1.5 changes bit value - word |= ((word >> 1) & 0x1) ^ 0x1; - cnt++; - - // next time add only one bit - bitchange = false; - - } else { - - word |= ((word >> 1) & 0x1) ^ 0x1; - - // next time two bits have to be added - bitchange = true; - } - - } else if (check_pulse_length(pl, 2 * EM4X50_T_TAG_FULL_PERIOD)) { - - // pulse length of 2 means: adding 2 bits "01" - cnt++; - - word <<= 1; - word |= 0x1; - - } else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_FULL_PERIOD)) { - - // pulse length of 3 indicates listen window -> clear last - // bit (= 0) and return (without parities) - word >>= 2; - return (extract_parities(word, data)) ? --cnt : 0; - - } - } - - return BUTTON_SINGLE_CLICK; -} - //============================================================================== -// login function +// login functions //============================================================================== static bool login(uint32_t password) { @@ -792,8 +799,145 @@ static bool login(uint32_t password) { return PM3_EFAILED; } +static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { + + // searching for password in given range + + bool pwd_found = false; + int cnt = 0; + + for (*pwd = start; *pwd <= stop; (*pwd)++) { + + if (login(*pwd) == PM3_SUCCESS) { + pwd_found = true; + break; + } + + // print password every 500 iterations + if ((++cnt % 500) == 0) { + + // print header + if (cnt == 500) { + Dbprintf("|---------+------------+------------|"); + Dbprintf("| no. | pwd (msb) | pwd (lsb) |"); + Dbprintf("|---------+------------+------------|"); + } + + // print data + Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, reflect32(*pwd), *pwd); + } + + if (BUTTON_PRESS()) + break; + + } + + // print footer + if (cnt >= 500) + Dbprintf("|---------+------------+------------|"); + + return pwd_found; +} + +void em4x50_login(uint32_t *password) { + + // login into EM4x50 + + uint8_t status = PM3_EFAILED; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) + status = login(*password); + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_LOGIN, status, 0, 0); +} + +void em4x50_brute(em4x50_data_t *etd) { + + // envoke password search + + bool bsuccess = false; + uint32_t pwd = 0x0; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) + bsuccess = brute(etd->password1, etd->password2, &pwd); + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); +} + +void em4x50_chk(uint32_t *offset) { + + // check passwords from dictionary content in flash memory + + int status = PM3_EFAILED; + uint8_t counter[2] = {0x00, 0x00}; + uint16_t isok = 0; + uint16_t pwd_count = 0; + uint16_t pwd_size_available = 0; + uint32_t pwd = 0x0; + uint8_t *pwds = BigBuf_get_EM_addr(); + + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it will + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + BigBuf_Clear_EM(); + + // initialize passwords and get number of passwords + if (Flash_ReadData(*offset, counter, sizeof(counter)) != sizeof(counter)) + goto OUT; + + pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); + if (pwd_count == 0) + goto OUT; + + pwd_size_available = 4 * pwd_count; + + isok = Flash_ReadData(*offset + 2, pwds, pwd_size_available); + if (isok != pwd_size_available) + goto OUT; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + // try to login with current password + for (int i = 0; i < pwd_count; i++) { + + // manual interruption + if (BUTTON_PRESS()) { + status = BUTTON_SINGLE_CLICK; + break; + } + + // get next password + pwd = 0x0; + for (int j = 0; j < 4; j++) + pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); + + if ((status = login(pwd)) == PM3_SUCCESS) + break; + } + } + +OUT: + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); +} + //============================================================================== -// reset function +// reset functions //============================================================================== static int reset(void) { @@ -816,6 +960,21 @@ static int reset(void) { return PM3_EFAILED; } +void em4x50_reset(void) { + + // reset EM4x50 + + uint8_t status = PM3_EFAILED; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) + status = reset(); + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_RESET, status, 0, 0); +} //============================================================================== // read functions @@ -880,39 +1039,12 @@ static int selective_read(uint32_t addresses, uint32_t *words) { return status; } -void em4x50_info(em4x50_data_t *etd) { - - // collects as much information as possible via selective read mode - - bool bsuccess = false, blogin = false; - uint8_t status = 0; - uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) - uint32_t words[EM4X50_NO_WORDS] = {0x0}; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // login with given password - if (etd->pwd_given) - blogin = (login(etd->password1) == PM3_SUCCESS); - - bsuccess = (selective_read(addresses, words) == PM3_SUCCESS); - } - - status = (bsuccess << 1) + blogin; - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); -} - void em4x50_read(em4x50_data_t *etd) { // reads by using "selective read mode" -> bidirectional communication - bool bsuccess = false, blogin = false; - uint8_t status = 0; + bool blogin = true; + int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -925,16 +1057,95 @@ void em4x50_read(em4x50_data_t *etd) { blogin = (login(etd->password1) == PM3_SUCCESS); // only one word has to be read -> first word read = last word read - bsuccess = (selective_read(etd->addresses, words) == PM3_SUCCESS); + if (blogin) + status = selective_read(etd->addresses, words); } - status = (bsuccess << 1) + blogin; - LOW(GPIO_SSC_DOUT); lf_finalize(); reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); } +void em4x50_stdread(void) { + + // reads data that tag transmits "voluntarily" -> standard read mode + + int now = 0; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) + standard_read(&now, words); + + LOW(GPIO_SSC_DOUT); + lf_finalize(); + reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); +} + +void em4x50_info(em4x50_data_t *etd) { + + // collects as much information as possible via selective read mode + + bool blogin = true; + int status = PM3_EFAILED; + uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) + uint32_t words[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) { + + // login with given password + if (etd->pwd_given) + blogin = (login(etd->password1) == PM3_SUCCESS); + + if (blogin) + status = selective_read(addresses, words); + } + + lf_finalize(); + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); +} + +void em4x50_watch() { + + // read continuously and display standard reads of tag + + int now = 0; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + while (BUTTON_PRESS() == false) { + + WDT_HIT(); + memset(words, 0, sizeof(words)); + now = 0; + + if (get_signalproperties() && find_em4x50_tag()) { + + if (standard_read(&now, words) == BUTTON_SINGLE_CLICK) + break; + + if (now > 0) { + + Dbprintf(""); + for (int i = 0; i < now; i++) + Dbprintf("EM4x50 tag data: " + _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", + words[i], reflect32(words[i])); + } + } + } + + LOW(GPIO_SSC_DOUT); + lf_finalize(); + reply_ng(CMD_LF_EM4X50_WATCH, 1, 0, 0); +} + //============================================================================== // write functions //============================================================================== @@ -1028,9 +1239,9 @@ void em4x50_write(em4x50_data_t *etd) { // write operation process for EM4x50 tag, // single word is written to given address, verified by selective read operation + // wrong password -> return with PM3_EFAILED - bool bsuccess = false, blogin = false; - uint8_t status = 0; + int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); @@ -1039,36 +1250,45 @@ void em4x50_write(em4x50_data_t *etd) { if (get_signalproperties() && find_em4x50_tag()) { // if password is given try to login first + status = PM3_SUCCESS; if (etd->pwd_given) - blogin = (login(etd->password1) == PM3_SUCCESS); + status = login(etd->password1); - // write word to given address - int res = write(etd->word, etd->addresses); - if (res == PM3_ETEAROFF) { - lf_finalize(); - return; - } + if (status == PM3_SUCCESS) { - if (res == PM3_SUCCESS) { + // write word to given address + status = write(etd->word, etd->addresses); + if (status == PM3_ETEAROFF) { + lf_finalize(); + return; + } - // to verify result reset EM4x50 - if (reset() == PM3_SUCCESS) { + if (status == PM3_SUCCESS) { - // if password is given login - if (etd->pwd_given) - blogin &= (login(etd->password1) == PM3_SUCCESS); + // to verify result reset EM4x50 + status = reset(); + if (status == PM3_SUCCESS) { - // call a selective read - if (selective_read(etd->addresses, words) == PM3_SUCCESS) { + // if password is given renew login after reset + if (etd->pwd_given) + status = login(etd->password1); + + if (status == PM3_SUCCESS) { - // compare with given word - bsuccess = (words[etd->addresses & 0xFF] == reflect32(etd->word)); + // call a selective read + status = selective_read(etd->addresses, words); + if (status == PM3_SUCCESS) { + + // compare result with given word + if (words[etd->addresses & 0xFF] != reflect32(etd->word)) + status = PM3_EFAILED; + } + } } } } } - status = (bsuccess << 1) + blogin; lf_finalize(); reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); } @@ -1077,7 +1297,7 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simple change of password - int res = PM3_EFAILED; + int status = PM3_EFAILED; em4x50_setup_read(); @@ -1087,8 +1307,8 @@ void em4x50_writepwd(em4x50_data_t *etd) { // login and change password if (login(etd->password1) == PM3_SUCCESS) { - res = write_password(etd->password1, etd->password2); - if (res == PM3_ETEAROFF) { + status = write_password(etd->password1, etd->password2); + if (status == PM3_ETEAROFF) { lf_finalize(); return; } @@ -1096,177 +1316,16 @@ void em4x50_writepwd(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITEPWD, res, 0, 0); -} - -void em4x50_reset(void) { - - // reset EM4x50 - - uint8_t status = PM3_EFAILED; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) - status = reset(); - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_RESET, status, 0, 0); -} - -void em4x50_login(uint32_t *password) { - - // login into EM4x50 - - uint8_t status = PM3_EFAILED; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) - status = login(*password); - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_LOGIN, status, 0, 0); -} - -static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // searching for password in given range - - bool pwd_found = false; - int cnt = 0; - - for (*pwd = start; *pwd <= stop; (*pwd)++) { - - if (login(*pwd) == PM3_SUCCESS) { - pwd_found = true; - break; - } - - // print password every 500 iterations - if ((++cnt % 500) == 0) { - - // print header - if (cnt == 500) { - Dbprintf("|---------+------------+------------|"); - Dbprintf("| no. | pwd (msb) | pwd (lsb) |"); - Dbprintf("|---------+------------+------------|"); - } - - // print data - Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, reflect32(*pwd), *pwd); - } - - if (BUTTON_PRESS()) - break; - - } - - // print footer - if (cnt >= 500) - Dbprintf("|---------+------------+------------|"); - - return pwd_found; -} - -void em4x50_brute(em4x50_data_t *etd) { - - // envoke password search - - bool bsuccess = false; - uint32_t pwd = 0x0; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - bsuccess = brute(etd->password1, etd->password2, &pwd); - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); -} - -void em4x50_watch() { - - // read continuously and display standard reads of tag - - int now = 0; - uint32_t words[EM4X50_NO_WORDS] = {0x0}; - - em4x50_setup_read(); - - while (BUTTON_PRESS() == false) { - - WDT_HIT(); - memset(words, 0, sizeof(words)); - now = 0; - - if (get_signalproperties() && find_em4x50_tag()) { - - if (standard_read(&now, words) == BUTTON_SINGLE_CLICK) - break; - - if (now > 0) { - - Dbprintf(""); - for (int i = 0; i < now; i++) - Dbprintf("EM4x50 tag data: " - _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", - words[i], reflect32(words[i])); - } - } - } - - LOW(GPIO_SSC_DOUT); - lf_finalize(); - reply_ng(CMD_LF_EM4X50_WATCH, 1, 0, 0); -} - -//============================================================================== -// standalone mode functions -//============================================================================== - -int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // envoke password search in standalone mode - - int status = false; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - status = brute(start, stop, pwd); - else - status = PM3_ETIMEOUT; - - lf_finalize(); - - return status; -} - -int em4x50_standalone_read(uint32_t *words) { - - int now = 0; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - if (find_double_listen_window(false)) - while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) - now++; - - return now; + reply_ng(CMD_LF_EM4X50_WRITEPWD, status, 0, 0); } void em4x50_restore(em4x50_data_t *etd) { // restore em4x50 dump file to tag - bool bsuccess = false, blogin = false; - int res = 0; - int start_word = 0; - uint8_t status = 0; + bool bsuccess = false; + int status = PM3_EFAILED; + int start_word = 3; // first block/address with user data uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; @@ -1290,18 +1349,19 @@ void em4x50_restore(em4x50_data_t *etd) { if (get_signalproperties() && find_em4x50_tag()) { // login first if password is available - if (etd->pwd_given) - blogin = (login(etd->password1) == PM3_SUCCESS); + if (etd->pwd_given) { + if (login(etd->password1) == PM3_SUCCESS) { + + // successful login allows words 1 and 2 to be written + start_word = 1; + } + } // write data to each address but ignore addresses // 0 -> password, 32 -> serial, 33 -> uid - - // without login words 1 and 2 cannot be written - start_word = (blogin) ? 1 : 3; - for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) { - res = write(words_client[i], i); - if (res == PM3_ETEAROFF) { + status = write(words_client[i], i); + if (status == PM3_ETEAROFF) { lf_finalize(); return; } @@ -1323,12 +1383,17 @@ void em4x50_restore(em4x50_data_t *etd) { } } - status = (bsuccess << 1) + blogin; + if (bsuccess) + status = PM3_SUCCESS; lf_finalize(); reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); } +//============================================================================== +// simulate functions +//============================================================================== + void em4x50_sim(void) { // simulate uploaded data in flash memory @@ -1385,85 +1450,38 @@ void em4x50_sim(void) { reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); } -void em4x50_stdread(void) { +//============================================================================== +// standalone mode functions +//============================================================================== - // reads data that tag transmits "voluntarily" -> standard read mode +int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { + + // envoke password search in standalone mode + + int status = false; + + em4x50_setup_read(); + + if (get_signalproperties() && find_em4x50_tag()) + status = brute(start, stop, pwd); + else + status = PM3_ETIMEOUT; + + lf_finalize(); + + return status; +} + +int em4x50_standalone_read(uint32_t *words) { int now = 0; - uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) - standard_read(&now, words); - - LOW(GPIO_SSC_DOUT); - lf_finalize(); - reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); -} - -void em4x50_chk(uint32_t *offset) { - - // check passwords from dictionary content in flash memory - - int status = PM3_EFAILED; - uint8_t counter[2] = {0x00, 0x00}; - uint16_t isok = 0; - uint16_t pwd_count = 0; - uint16_t pwd_size_available = 0; - uint32_t pwd = 0x0; - uint8_t *pwds = BigBuf_get_EM_addr(); - - //----------------------------------------------------------------------------- - // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not - // involved in dealing with emulator memory. But if it is called later, it will - // destroy the Emulator Memory. - //----------------------------------------------------------------------------- - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - BigBuf_Clear_EM(); - - // initialize passwords and get number of passwords - if (Flash_ReadData(*offset, counter, sizeof(counter)) != sizeof(counter)) - goto OUT; - - pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); - if (pwd_count == 0) - goto OUT; - - pwd_size_available = 4 * pwd_count; - - isok = Flash_ReadData(*offset + 2, pwds, pwd_size_available); - if (isok != pwd_size_available) - goto OUT; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // try to login with current password - for (int i = 0; i < pwd_count; i++) { - - // manual interruption - if (BUTTON_PRESS()) { - status = BUTTON_SINGLE_CLICK; - break; - } - - // get next password - pwd = 0x0; - for (int j = 0; j < 4; j++) - pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); - - if ((status = login(pwd)) == PM3_SUCCESS) - break; - } - } - -OUT: - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); + if (find_double_listen_window(false)) + while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) + now++; + + return now; } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index c0980e7f6..44e5297a8 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -16,99 +16,9 @@ #define CARD_MEMORY_SIZE 4096 -static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { - - // read data from dump file; file type is derived from file name extension - - int res = 0; - uint32_t serial = 0x0, device_id = 0x0; - - if (str_endswith(filename, ".eml")) - res = loadFileEML(filename, data, bytes_read) != PM3_SUCCESS; - else if (str_endswith(filename, ".json")) - res = loadFileJSON(filename, data, data_len, bytes_read, NULL); - else - res = loadFile(filename, ".bin", data, data_len, bytes_read); - - if ((res != PM3_SUCCESS) && (*bytes_read != DUMP_FILESIZE)) - return PM3_EFILE; - - // valid em4x50 data? - serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); - device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); - if (serial == device_id) { - PrintAndLogEx(WARNING, "No valid em4x50 data in file %s.", filename); - return PM3_ENODATA; - } - - return PM3_SUCCESS; -} - -static int em4x50_wipe_flash(int page) { - - int isok = 0; - - clearCommandBuffer(); - SendCommandMIX(CMD_FLASHMEM_WIPE, page, false, 0, NULL, 0); - PacketResponseNG resp; - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - isok = resp.oldarg[0] & 0xFF; - if (!isok) { - PrintAndLogEx(WARNING, "Flash error"); - return PM3_EFLASH; - } - - return PM3_SUCCESS; -} - -static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { - - int isok = 0; - uint32_t bytes_sent = 0; - uint32_t bytes_remaining = datalen; - uint32_t bytes_in_packet = 0; - PacketResponseNG resp; - - // wipe - em4x50_wipe_flash(0); - em4x50_wipe_flash(1); - em4x50_wipe_flash(2); - - // fast push mode - conn.block_after_ACK = true; - - while (bytes_remaining > 0) { - bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); - - clearCommandBuffer(); - SendCommandOLD(CMD_FLASHMEM_WRITE, offset + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); - - bytes_remaining -= bytes_in_packet; - bytes_sent += bytes_in_packet; - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - conn.block_after_ACK = false; - return PM3_ETIMEOUT; - } - - isok = resp.oldarg[0] & 0xFF; - if (!isok) { - conn.block_after_ACK = false; - PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); - return PM3_EFLASH; - } - } - - conn.block_after_ACK = false; - - return PM3_SUCCESS; -} +//============================================================================== +// output functions +//============================================================================== static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { @@ -211,944 +121,102 @@ static void print_info_result(uint8_t *data) { PrintAndLogEx(NORMAL, ""); } -//quick test for EM4x50 tag -bool detect_4x50_block(void) { - em4x50_data_t etd = { - .pwd_given = false, - .addr_given = true, - .addresses = (EM4X50_DEVICE_ID << 8) | EM4X50_DEVICE_ID, - }; - em4x50_word_t words[EM4X50_NO_WORDS]; - return (em4x50_read(&etd, words) == PM3_SUCCESS); -} +//============================================================================== +// file/memory functions +//============================================================================== -int read_em4x50_uid(void) { - em4x50_data_t etd = { - .pwd_given = false, - .addr_given = true, - .addresses = (EM4X50_DEVICE_SERIAL << 8) | EM4X50_DEVICE_SERIAL, - }; - em4x50_word_t words[EM4X50_NO_WORDS]; - int res = em4x50_read(&etd, words); - if (res == PM3_SUCCESS) - PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4)); - return res; -} +static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { -int CmdEM4x50Info(const char *Cmd) { + // read data from dump file; file type is derived from file name extension - // envoke reading of a EM4x50 tag which has to be on the antenna because - // decoding is done by the device (not on client side) - - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_info", - "Tag information EM4x50.", - "lf em 4x50_info\n" - "lf em 4x50_info -p 12345678 -> uses password 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - } - - CLIParserFree(ctx); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); - - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - bool login = resp.status & STATUS_LOGIN; - bool success = (resp.status & STATUS_SUCCESS) >> 1; - - if (success) { - if (etd.pwd_given) { - if (login == false) { - PrintAndLogEx(FAILED, "Login failed"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); - } - - print_info_result(resp.data.asBytes); - return PM3_SUCCESS; - } - - PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); - return PM3_ESOFT; -} - -int CmdEM4x50Write(const char *Cmd) { - - // envoke writing a single word (32 bit) to a EM4x50 tag - - int wordLen = 0, pwdLen = 0; - int addr = 0; - uint8_t word[4] = {0x0}; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_write", - "Writes single block/word to EM4x50 tag.", - "lf em 4x50_write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" - "lf em 4x50_write -b 3 -d 4f22e7ff -p 12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_int1("b", "block", "
", "block/word address, dec"), - arg_str1("d", "data", "", "data, hex, 4 bytes, lsb"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, word, &wordLen); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); - - if (addr <= 0 || addr >= EM4X50_NO_WORDS) { - PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); - return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - if (wordLen != 4) { - PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); - return PM3_EINVARG; - } else { - etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; - } - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - } - - CLIParserFree(ctx); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - if (resp.status == PM3_ETEAROFF) - return PM3_SUCCESS; - - bool isOK = (resp.status & STATUS_SUCCESS) >> 1; - if (isOK == false) { - PrintAndLogEx(FAILED, "Writing " _RED_("failed")); - return PM3_ESOFT; - } - - if (etd.pwd_given) { - bool login = resp.status & STATUS_LOGIN; - if (login == false) { - PrintAndLogEx(FAILED, "Login failed"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); - } - - // display result of writing operation in structured format - uint8_t *data = resp.data.asBytes; - em4x50_word_t words[EM4X50_NO_WORDS]; - - prepare_result(data, addr, addr, words); - print_result(words, addr, addr); - PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", addr); - return PM3_SUCCESS; -} - -int CmdEM4x50WritePwd(const char *Cmd) { - - // envokes changing the password of EM4x50 tag - - int status = PM3_EFAILED; - int pwdLen = 0, npwdLen = 0; - uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; - PacketResponseNG resp; - em4x50_data_t etd; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_writepwd", - "Writes EM4x50 password.", - "lf em 4x50_writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str1("p", "pwd", "", "password, hex, 4 bytes, lsb"), - arg_str1("n", "newpwd", "", "new password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); - - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - } - if (npwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); - return PM3_EINVARG; - } else { - etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; - } - - CLIParserFree(ctx); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); - - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - status = resp.status; - - if (status == PM3_ETEAROFF) - return PM3_SUCCESS; - - // print response - if (status != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); - return PM3_EFAILED; - } - - PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); - - return PM3_SUCCESS; -} - -int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { - - // envoke reading - // - with given address (option b) (and optional password if address is - // read protected) -> selective read mode - - em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; - - if (etd != NULL) { - edata = *etd; - } - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata)); - - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - bool isOK = (resp.status & STATUS_SUCCESS) >> 1; - if (isOK == false) - return PM3_ESOFT; - - if (edata.pwd_given) { - bool login = resp.status & STATUS_LOGIN; - if (login == false) { - PrintAndLogEx(FAILED, "Login failed"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd->password1); - } - - uint8_t *data = resp.data.asBytes; - em4x50_word_t words[EM4X50_NO_WORDS]; - prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); - - if (out != NULL) { - memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); - } - - print_result(words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF); - - return PM3_SUCCESS; -} - -int CmdEM4x50Read(const char *Cmd) { - - int pwdLen = 0; - int addr = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd; - - // init - memset(&etd, 0x00, sizeof(em4x50_data_t)); - etd.addr_given = false; - etd.pwd_given = false; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_read", - "Reads single EM4x50 block/word.", - "lf em 4x50_read -b 3 -> reads block 3\n" - "lf em 4x50_read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_int1("b", "block", "
", "block/word address, dec"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (addr <= 0 || addr >= EM4X50_NO_WORDS) { - return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - } - - CLIParserFree(ctx); - - return em4x50_read(&etd, NULL); -} - -int CmdEM4x50Dump(const char *Cmd) { - - int fnLen = 0, pwdLen = 0; - uint8_t pwd[4] = {0x0}; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - em4x50_data_t etd = {.pwd_given = false}; - uint8_t data[DUMP_FILESIZE] = {0}; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_dump", - "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", - "lf em 4x50_dump -> saves dump in lf-4x50--dump.bin/eml/json\n" - "lf em 4x50_dump -f mydump.eml -> saves dump in mydump.eml\n" - "lf em 4x50_dump -p 12345678\n" - "lf em 4x50_dump -f mydump.eml -p 12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIParamStrToBuf(arg_get_str(ctx, 1), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - } - - CLIParserFree(ctx); - - PrintAndLogEx(INFO, "Reading EM4x50 tag"); - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - bool success = (resp.status & STATUS_SUCCESS) >> 1; - if (success == false) { - PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); - return PM3_ESOFT; - } - - // structured format - em4x50_word_t words[EM4X50_NO_WORDS]; - prepare_result(resp.data.asBytes, 0, EM4X50_NO_WORDS - 1, words); - - // result output - PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:")); - print_result(words, 0, EM4X50_NO_WORDS - 1); - - // user supplied filename? - if (fnLen == 0) { - PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "lf-4x50-"); - FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); - } - - for (int i = 0; i < EM4X50_NO_WORDS; i++) - memcpy(data + (i * 4), words[i].byte, 4); - - // saveFileEML will add .eml extension to filename - // saveFile (binary) passes in the .bin extension. - // saveFileJSON adds .json extension - saveFileEML(filename, data, sizeof(data), 4); - saveFile(filename, ".bin", data, sizeof(data)); - saveFileJSON(filename, jsfEM4x50, data, sizeof(data), NULL); - - return PM3_SUCCESS; -} - -int CmdEM4x50Wipe(const char *Cmd) { - - // fills EM4x50 tag with zeros including password - - bool isOK = false; - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_wipe", - "Wipes EM4x50 tag.", - "lf em 4x50_wipe -p 12345678 -> wipes tag with password 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - - CLIParserFree(ctx); - - // clear password - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Resetting password " _GREEN_("ok")); - } else { - PrintAndLogEx(FAILED, "Resetting password " _RED_("failed")); - return PM3_ESOFT; - } - - // from now on new password 0x0 - etd.password1 = 0x0; - - // clear data (words 1 to 31) - for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { - - // no login necessary for blocks 3 to 31 - etd.pwd_given = (i <= EM4X50_CONTROL); - - PrintAndLogEx(INPLACE, "Wiping block %i", i); - - etd.addresses = i << 8 | i; - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - isOK = resp.status; - if (!isOK) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); - return PM3_ESOFT; - } - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); - - PrintAndLogEx(INFO, "Done"); - - return PM3_SUCCESS; -} - -int CmdEM4x50Brute(const char *Cmd) { - - const int speed = 27; // 27 passwords/second (empirical value) - int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; - - int pwd1Len = 0, pwd2Len = 0; - uint8_t pwd1[4] = {0x0}, pwd2[4] = {0x0}; - em4x50_data_t etd; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_brute", - "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", - "lf em 4x50_brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str1("f", "fp", "", "first password (start), hex, 4 bytes, lsb"), - arg_str1("l", "lp", "", "last password (stop), hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd1, &pwd1Len); - CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); - - if (pwd1Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd1Len); - return PM3_EINVARG; - } else if (pwd2Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); - return PM3_EINVARG; - } else { - etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; - etd.password2 = (pwd2[0] << 24) | (pwd2[1] << 16) | (pwd2[2] << 8) | pwd2[3]; - } - - CLIParserFree(ctx); - - // print some information - no_iter = etd.password2 - etd.password1 + 1; - dur_s = no_iter / speed; - dur_h = dur_s / 3600; - dur_m = (dur_s - dur_h * 3600) / 60; - dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]", - no_iter, etd.password1, etd.password2); - PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); - - // start - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); - WaitForResponse(CMD_LF_EM4X50_BRUTE, &resp); - - // print response - if ((bool)resp.status) - PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]); + int res = 0; + uint32_t serial = 0x0, device_id = 0x0; + + if (str_endswith(filename, ".eml")) + res = loadFileEML(filename, data, bytes_read) != PM3_SUCCESS; + else if (str_endswith(filename, ".json")) + res = loadFileJSON(filename, data, data_len, bytes_read, NULL); else - PrintAndLogEx(FAILED, "Password: " _RED_("not found")); + res = loadFile(filename, ".bin", data, data_len, bytes_read); - return PM3_SUCCESS; -} - -int CmdEM4x50Login(const char *Cmd) { - - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - uint32_t password = 0x0; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_login", - "Login into EM4x50 tag.", - "lf em 4x50_login -p 12345678 -< login with password 12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - } - - CLIParserFree(ctx); - - // start - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); - WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); - - // print response - if (resp.status == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Login " _GREEN_("ok")); - else - PrintAndLogEx(FAILED, "Login " _RED_("failed")); - - return resp.status; -} - -int CmdEM4x50Reset(const char *Cmd) { - - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_reset", - "Reseta EM4x50 tag.", - "lf em 4x50_reset\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - // start - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_RESET, 0, 0); - WaitForResponse(CMD_LF_EM4X50_RESET, &resp); - - // print response - if (resp.status == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Reset " _GREEN_("ok")); - else - PrintAndLogEx(FAILED, "Reset " _RED_("failed")); - - return resp.status; -} - -int CmdEM4x50Watch(const char *Cmd) { - - // continously envoke reading of a EM4x50 tag - - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_watch", - "Watches for EM4x50 tags. Function runs until button is pressed.", - "lf em 4x50_watch\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); - PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); - WaitForResponseTimeoutW(CMD_LF_EM4X50_WATCH, &resp, -1, false); - - PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; -} - -int CmdEM4x50Restore(const char *Cmd) { - - int uidLen = 0, fnLen = 0, pwdLen = 0, res = 0; - uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; - size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0}; - em4x50_data_t etd = {.pwd_given = false}; - uint8_t data[DUMP_FILESIZE] = {0x0}; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_restore", - "Restores data from dumpfile onto a Em4x50 tag.", - "lf em 4x50_restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" - "lf em 4x50_restore -f mydump.eml -> uses mydump.eml\n" - "lf em 4x50_restore -u 1b5aff5c -p 12345678 -> \n" - "lf em 4x50_restore -f mydump.eml -p 12345678 -> \n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("u", "uid", "", "uid, hex, 4 bytes, msb, restore from lf-4x50--dump.bin"), - arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, uid, &uidLen); - CLIParamStrToBuf(arg_get_str(ctx, 2), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); - - if ((uidLen && fnLen) || (!uidLen && !fnLen)) { - PrintAndLogEx(FAILED, "either use option 'u' or option 'f'"); - return PM3_EINVARG; - } - - if (uidLen) { - snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%02x%02x%02x%02x-dump.bin", - uid[0], - uid[1], - uid[2], - uid[3] - ); - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; - etd.pwd_given = true; - } - } - - CLIParserFree(ctx); - - PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); - - // read data from dump file; file type has to be "bin", "eml" or "json" - if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) + if ((res != PM3_SUCCESS) && (*bytes_read != DUMP_FILESIZE)) return PM3_EFILE; - // upload to flash memory - res = em4x50_write_flash(data, 0, bytes_read); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return res; - } - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X50_RESTORE, &resp, 2 * TIMEOUT)) { - PrintAndLogEx(FAILED, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - if (resp.status == PM3_ETEAROFF) - return PM3_SUCCESS; - - bool isOK = (resp.status & STATUS_SUCCESS) >> 1; - if (isOK == false) { - PrintAndLogEx(FAILED, "Restore " _RED_("failed")); - return PM3_ESOFT; - } - - if (etd.pwd_given) { - bool login = resp.status & STATUS_LOGIN; - if (login == false) { - PrintAndLogEx(FAILED, "Login failed"); - return PM3_ESOFT; - } - PrintAndLogEx(SUCCESS, "Login with password " _YELLOW_("%08x"), etd.password1); - } - PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); - PrintAndLogEx(INFO, "Finished restoring"); - - return PM3_SUCCESS; -} - -int CmdEM4x50Sim(const char *Cmd) { - - int slen = 0, res = 0; - size_t bytes_read = 0; - uint8_t data[DUMP_FILESIZE] = {0x0}; - char filename[FILE_PATH_SIZE] = {0}; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_sim", - "Simulates a EM4x50 tag", - "lf em 4x50_sim -> simulates EM4x50 data in flash memory.\n" - "lf em 4x50_sim -f mydump.eml -> simulates content of file ./mydump\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("f", "filename", "", "dump filename, bin/eml/json"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); - CLIParserFree(ctx); - - // read data from dump file; file type has to be "bin", "eml" or "json" - if (slen != 0) { - - // load file content - if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Read error"); - return PM3_EFILE; - } - - if (bytes_read * 8 > FLASH_MEM_MAX_SIZE) { - PrintAndLogEx(FAILED, "Filesize is larger than available memory"); - return PM3_EOVFLOW; - } - - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); - - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error wiping flash."); - return res; - } - - // upload to device - res = em4x50_write_flash(data, 0, bytes_read); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return res; - } - } - - PrintAndLogEx(INFO, "Simulating data in " _YELLOW_("%s"), filename); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); - - WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - - if (resp.status == PM3_ETEAROFF) { - return PM3_SUCCESS; - } else if (resp.status == PM3_ENODATA) { - PrintAndLogEx(FAILED, "No valid em4x50 data in flash memory."); + // valid em4x50 data? + serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + if (serial == device_id) { + PrintAndLogEx(WARNING, "No valid em4x50 data in file %s.", filename); return PM3_ENODATA; } - PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } -int CmdEM4x50StdRead(const char *Cmd) { - - int now = 0, status = PM3_EFAILED; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_stdread", - "Shows standard read data of EM4x50 tag.", - "lf em 4x50_stdread\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - // start +static int em4x50_wipe_flash(int page) { + + int isok = 0; + clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_STDREAD, 0, 0); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_STDREAD, &resp, TIMEOUT)) { + SendCommandMIX(CMD_FLASHMEM_WIPE, page, false, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - - now = resp.status; - // print response - if (now > 0) { + isok = resp.oldarg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(WARNING, "Flash error"); + return PM3_EFLASH; + } + + return PM3_SUCCESS; +} - em4x50_word_t words[EM4X50_NO_WORDS]; - - prepare_result(resp.data.asBytes, 0, now - 1, words); +static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { + + int isok = 0; + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = datalen; + uint32_t bytes_in_packet = 0; + PacketResponseNG resp; - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, " # | word (msb) | word (lsb) "); - PrintAndLogEx(INFO, "----+-------------+-------------"); + // wipe + em4x50_wipe_flash(0); + em4x50_wipe_flash(1); + em4x50_wipe_flash(2); - for (int i = 0; i < now; i++) { + // fast push mode + conn.block_after_ACK = true; - char r[30] = {0}; - for (int j = 3; j >= 0; j--) - sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + while (bytes_remaining > 0) { + bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); - PrintAndLogEx(INFO, " %2i | " _GREEN_("%s") "| %s", - i, - sprint_hex(words[i].byte, 4), - r - ); + clearCommandBuffer(); + SendCommandOLD(CMD_FLASHMEM_WRITE, offset + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + conn.block_after_ACK = false; + return PM3_ETIMEOUT; } - - status = PM3_SUCCESS; - PrintAndLogEx(INFO, "----+-------------+-------------"); - PrintAndLogEx(SUCCESS, "Standard read " _GREEN_("ok")); - } else { - PrintAndLogEx(FAILED, "Standard read " _RED_("failed")); + isok = resp.oldarg[0] & 0xFF; + if (!isok) { + conn.block_after_ACK = false; + PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); + return PM3_EFLASH; + } } - return status; + conn.block_after_ACK = false; + + return PM3_SUCCESS; } int CmdEM4x50ELoad(const char *Cmd) { @@ -1249,6 +317,120 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_SUCCESS; } +//============================================================================== +// login functions +//============================================================================== + +int CmdEM4x50Login(const char *Cmd) { + + int pwdLen = 0; + uint8_t pwd[4] = {0x0}; + uint32_t password = 0x0; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_login", + "Login into EM4x50 tag.", + "lf em 4x50_login -p 12345678 -< login with password 12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + } + + CLIParserFree(ctx); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); + WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); + + // print response + if (resp.status == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Login " _GREEN_("ok")); + else + PrintAndLogEx(FAILED, "Login " _RED_("failed")); + + return resp.status; +} + +int CmdEM4x50Brute(const char *Cmd) { + + const int speed = 27; // 27 passwords/second (empirical value) + int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; + + int pwd1Len = 0, pwd2Len = 0; + uint8_t pwd1[4] = {0x0}, pwd2[4] = {0x0}; + em4x50_data_t etd; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_brute", + "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", + "lf em 4x50_brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("f", "fp", "", "first password (start), hex, 4 bytes, lsb"), + arg_str1("l", "lp", "", "last password (stop), hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd1, &pwd1Len); + CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); + + if (pwd1Len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd1Len); + return PM3_EINVARG; + } else if (pwd2Len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); + return PM3_EINVARG; + } else { + etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; + etd.password2 = (pwd2[0] << 24) | (pwd2[1] << 16) | (pwd2[2] << 8) | pwd2[3]; + } + + CLIParserFree(ctx); + + // print some information + no_iter = etd.password2 - etd.password1 + 1; + dur_s = no_iter / speed; + dur_h = dur_s / 3600; + dur_m = (dur_s - dur_h * 3600) / 60; + dur_s -= dur_h * 3600 + dur_m * 60; + PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]", + no_iter, etd.password1, etd.password2); + PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); + WaitForResponse(CMD_LF_EM4X50_BRUTE, &resp); + + // print response + if ((bool)resp.status) + PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]); + else + PrintAndLogEx(FAILED, "Password: " _RED_("not found")); + + return PM3_SUCCESS; +} + int CmdEM4x50Chk(const char *Cmd) { // upload passwords from given dictionary to flash memory and @@ -1364,3 +546,813 @@ int CmdEM4x50Chk(const char *Cmd) { PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } + +//============================================================================== +// reset functions +//============================================================================== + +int CmdEM4x50Reset(const char *Cmd) { + + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_reset", + "Reseta EM4x50 tag.", + "lf em 4x50_reset\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_RESET, 0, 0); + WaitForResponse(CMD_LF_EM4X50_RESET, &resp); + + // print response + if (resp.status == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Reset " _GREEN_("ok")); + else + PrintAndLogEx(FAILED, "Reset " _RED_("failed")); + + return resp.status; +} + +//============================================================================== +// read functions +//============================================================================== + +//quick test for EM4x50 tag +bool detect_4x50_block(void) { + em4x50_data_t etd = { + .pwd_given = false, + .addr_given = true, + .addresses = (EM4X50_DEVICE_ID << 8) | EM4X50_DEVICE_ID, + }; + em4x50_word_t words[EM4X50_NO_WORDS]; + return (em4x50_read(&etd, words) == PM3_SUCCESS); +} + +int read_em4x50_uid(void) { + em4x50_data_t etd = { + .pwd_given = false, + .addr_given = true, + .addresses = (EM4X50_DEVICE_SERIAL << 8) | EM4X50_DEVICE_SERIAL, + }; + em4x50_word_t words[EM4X50_NO_WORDS]; + int res = em4x50_read(&etd, words); + if (res == PM3_SUCCESS) + PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4)); + return res; +} + +int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { + + // envoke reading + // - with given address (option b) (and optional password if address is + // read protected) -> selective read mode + + em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; + + if (etd != NULL) { + edata = *etd; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status != PM3_SUCCESS) + return PM3_ESOFT; + + uint8_t *data = resp.data.asBytes; + em4x50_word_t words[EM4X50_NO_WORDS]; + prepare_result(data, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); + + if (out != NULL) + memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); + + print_result(words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF); + + return PM3_SUCCESS; +} + +int CmdEM4x50Read(const char *Cmd) { + + int pwdLen = 0; + int addr = 0; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd; + + // init + memset(&etd, 0x00, sizeof(em4x50_data_t)); + etd.addr_given = false; + etd.pwd_given = false; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_read", + "Reads single EM4x50 block/word.", + "lf em 4x50_read -b 3 -> reads block 3\n" + "lf em 4x50_read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "
", "block/word address, dec"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + addr = arg_get_int_def(ctx, 1, 0); + CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + return PM3_EINVARG; + } else { + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + } + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + } + + CLIParserFree(ctx); + + return em4x50_read(&etd, NULL); +} + +int CmdEM4x50StdRead(const char *Cmd) { + + int now = 0, status = PM3_EFAILED; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_stdread", + "Shows standard read data of EM4x50 tag.", + "lf em 4x50_stdread\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // start + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_STDREAD, 0, 0); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_STDREAD, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + now = resp.status; + + // print response + if (now > 0) { + + em4x50_word_t words[EM4X50_NO_WORDS]; + + prepare_result(resp.data.asBytes, 0, now - 1, words); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " # | word (msb) | word (lsb) "); + PrintAndLogEx(INFO, "----+-------------+-------------"); + + for (int i = 0; i < now; i++) { + + char r[30] = {0}; + for (int j = 3; j >= 0; j--) + sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + + PrintAndLogEx(INFO, " %2i | " _GREEN_("%s") "| %s", + i, + sprint_hex(words[i].byte, 4), + r + ); + } + + status = PM3_SUCCESS; + PrintAndLogEx(INFO, "----+-------------+-------------"); + PrintAndLogEx(SUCCESS, "Standard read " _GREEN_("ok")); + + } else { + PrintAndLogEx(FAILED, "Standard read " _RED_("failed")); + } + + return status; +} + +int CmdEM4x50Info(const char *Cmd) { + + // envoke reading of a EM4x50 tag which has to be on the antenna because + // decoding is done by the device (not on client side) + + int pwdLen = 0; + int status = 0; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd = {.pwd_given = false}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_info", + "Tag information EM4x50.", + "lf em 4x50_info\n" + "lf em 4x50_info -p 12345678 -> uses password 0x12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + } + + CLIParserFree(ctx); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + status = resp.status; + + if (status == PM3_SUCCESS) + print_info_result(resp.data.asBytes); + else + PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); + + return status; +} + +int CmdEM4x50Watch(const char *Cmd) { + + // continously envoke reading of a EM4x50 tag + + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_watch", + "Watches for EM4x50 tags. Function runs until button is pressed.", + "lf em 4x50_watch\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); + WaitForResponseTimeoutW(CMD_LF_EM4X50_WATCH, &resp, -1, false); + + PrintAndLogEx(INFO, "Done"); + return PM3_SUCCESS; +} + +int CmdEM4x50Dump(const char *Cmd) { + + int fnLen = 0, pwdLen = 0; + uint8_t pwd[4] = {0x0}; + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + em4x50_data_t etd = {.pwd_given = false}; + uint8_t data[DUMP_FILESIZE] = {0}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_dump", + "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", + "lf em 4x50_dump -> saves dump in lf-4x50--dump.bin/eml/json\n" + "lf em 4x50_dump -f mydump.eml -> saves dump in mydump.eml\n" + "lf em 4x50_dump -p 12345678\n" + "lf em 4x50_dump -f mydump.eml -p 12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIParamStrToBuf(arg_get_str(ctx, 1), + (uint8_t *)filename, + FILE_PATH_SIZE, + &fnLen + ); + CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + } + + CLIParserFree(ctx); + + PrintAndLogEx(INFO, "Reading EM4x50 tag"); + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + bool success = (resp.status & STATUS_SUCCESS) >> 1; + if (success == false) { + PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); + return PM3_ESOFT; + } + + // structured format + em4x50_word_t words[EM4X50_NO_WORDS]; + prepare_result(resp.data.asBytes, 0, EM4X50_NO_WORDS - 1, words); + + // result output + PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:")); + print_result(words, 0, EM4X50_NO_WORDS - 1); + + // user supplied filename? + if (fnLen == 0) { + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += sprintf(fptr, "lf-4x50-"); + FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); + } + + for (int i = 0; i < EM4X50_NO_WORDS; i++) + memcpy(data + (i * 4), words[i].byte, 4); + + // saveFileEML will add .eml extension to filename + // saveFile (binary) passes in the .bin extension. + // saveFileJSON adds .json extension + saveFileEML(filename, data, sizeof(data), 4); + saveFile(filename, ".bin", data, sizeof(data)); + saveFileJSON(filename, jsfEM4x50, data, sizeof(data), NULL); + + return PM3_SUCCESS; +} + +//============================================================================== +// write functions +//============================================================================== + +int CmdEM4x50Write(const char *Cmd) { + + // envoke writing a single word (32 bit) to a EM4x50 tag + + int wordLen = 0, pwdLen = 0, addr = 0; + int status = 0; + uint8_t word[4] = {0x0}; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd = {.pwd_given = false}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_write", + "Writes single block/word to EM4x50 tag.", + "lf em 4x50_write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" + "lf em 4x50_write -b 3 -d 4f22e7ff -p 12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "
", "block/word address, dec"), + arg_str1("d", "data", "", "data, hex, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + addr = arg_get_int_def(ctx, 1, 0); + CLIGetHexWithReturn(ctx, 2, word, &wordLen); + CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); + return PM3_EINVARG; + } else { + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + } + if (wordLen != 4) { + PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); + return PM3_EINVARG; + } else { + etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; + } + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + } + + CLIParserFree(ctx); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + status = resp.status; + if (status == PM3_ETEAROFF) + return PM3_SUCCESS; + + if (status != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Writing " _RED_("failed")); + return PM3_ESOFT; + } + + // display result of writing operation in structured format + uint8_t *data = resp.data.asBytes; + em4x50_word_t words[EM4X50_NO_WORDS]; + + prepare_result(data, addr, addr, words); + print_result(words, addr, addr); + PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", addr); + + return PM3_SUCCESS; +} + +int CmdEM4x50WritePwd(const char *Cmd) { + + // envokes changing the password of EM4x50 tag + + int status = PM3_EFAILED; + int pwdLen = 0, npwdLen = 0; + uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; + PacketResponseNG resp; + em4x50_data_t etd; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_writepwd", + "Writes EM4x50 password.", + "lf em 4x50_writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("p", "pwd", "", "password, hex, 4 bytes, lsb"), + arg_str1("n", "newpwd", "", "new password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); + + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + } + if (npwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); + return PM3_EINVARG; + } else { + etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; + } + + CLIParserFree(ctx); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); + + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + status = resp.status; + + if (status == PM3_ETEAROFF) + return PM3_SUCCESS; + + // print response + if (status != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); + return PM3_EFAILED; + } + + PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); + + return PM3_SUCCESS; +} + +int CmdEM4x50Wipe(const char *Cmd) { + + // fills EM4x50 tag with zeros including password + + bool isOK = false; + int pwdLen = 0; + uint8_t pwd[4] = {0x0}; + em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_wipe", + "Wipes EM4x50 tag.", + "lf em 4x50_wipe -p 12345678 -> wipes tag with password 0x12345678\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + + CLIParserFree(ctx); + + // clear password + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Resetting password " _GREEN_("ok")); + } else { + PrintAndLogEx(FAILED, "Resetting password " _RED_("failed")); + return PM3_ESOFT; + } + + // from now on new password 0x0 + etd.password1 = 0x0; + + // clear data (words 1 to 31) + for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { + + // no login necessary for blocks 3 to 31 + etd.pwd_given = (i <= EM4X50_CONTROL); + + PrintAndLogEx(INPLACE, "Wiping block %i", i); + + etd.addresses = i << 8 | i; + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + isOK = resp.status; + if (!isOK) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); + return PM3_ESOFT; + } + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); + + PrintAndLogEx(INFO, "Done"); + + return PM3_SUCCESS; +} + +int CmdEM4x50Restore(const char *Cmd) { + + int uidLen = 0, fnLen = 0, pwdLen = 0, status = 0; + uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; + size_t bytes_read = 0; + char filename[FILE_PATH_SIZE] = {0}; + em4x50_data_t etd = {.pwd_given = false}; + uint8_t data[DUMP_FILESIZE] = {0x0}; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_restore", + "Restores data from dumpfile onto a Em4x50 tag.", + "lf em 4x50_restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" + "lf em 4x50_restore -f mydump.eml -> uses mydump.eml\n" + "lf em 4x50_restore -u 1b5aff5c -p 12345678 -> \n" + "lf em 4x50_restore -f mydump.eml -p 12345678 -> \n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("u", "uid", "", "uid, hex, 4 bytes, msb, restore from lf-4x50--dump.bin"), + arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), + arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + CLIGetHexWithReturn(ctx, 1, uid, &uidLen); + CLIParamStrToBuf(arg_get_str(ctx, 2), + (uint8_t *)filename, + FILE_PATH_SIZE, + &fnLen + ); + CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + + if ((uidLen && fnLen) || (!uidLen && !fnLen)) { + PrintAndLogEx(FAILED, "either use option 'u' or option 'f'"); + return PM3_EINVARG; + } + + if (uidLen) { + snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%02x%02x%02x%02x-dump.bin", + uid[0], + uid[1], + uid[2], + uid[3] + ); + } + + if (pwdLen) { + if (pwdLen != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + return PM3_EINVARG; + } else { + etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.pwd_given = true; + } + } + + CLIParserFree(ctx); + + PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); + + // read data from dump file; file type has to be "bin", "eml" or "json" + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) + return PM3_EFILE; + + // upload to flash memory + status = em4x50_write_flash(data, 0, bytes_read); + if (status != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return status; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X50_RESTORE, &resp, 2 * TIMEOUT)) { + PrintAndLogEx(FAILED, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + status = resp.status; + + if (status == PM3_ETEAROFF) { + return PM3_SUCCESS; + } else if (status != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Restore " _RED_("failed")); + return status; + } + + PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); + PrintAndLogEx(INFO, "Finished restoring"); + + return PM3_SUCCESS; +} + +//============================================================================== +// simulate functions +//============================================================================== + +int CmdEM4x50Sim(const char *Cmd) { + + int slen = 0, res = 0; + size_t bytes_read = 0; + uint8_t data[DUMP_FILESIZE] = {0x0}; + char filename[FILE_PATH_SIZE] = {0}; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_sim", + "Simulates a EM4x50 tag", + "lf em 4x50_sim -> simulates EM4x50 data in flash memory.\n" + "lf em 4x50_sim -f mydump.eml -> simulates content of file ./mydump\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("f", "filename", "", "dump filename, bin/eml/json"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + CLIParserFree(ctx); + + // read data from dump file; file type has to be "bin", "eml" or "json" + if (slen != 0) { + + // load file content + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Read error"); + return PM3_EFILE; + } + + if (bytes_read * 8 > FLASH_MEM_MAX_SIZE) { + PrintAndLogEx(FAILED, "Filesize is larger than available memory"); + return PM3_EOVFLOW; + } + + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); + + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error wiping flash."); + return res; + } + + // upload to device + res = em4x50_write_flash(data, 0, bytes_read); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Error uploading to flash."); + return res; + } + } + + PrintAndLogEx(INFO, "Simulating data in " _YELLOW_("%s"), filename); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); + + WaitForResponse(CMD_LF_EM4X50_SIM, &resp); + + if (resp.status == PM3_ETEAROFF) { + return PM3_SUCCESS; + } else if (resp.status == PM3_ENODATA) { + PrintAndLogEx(FAILED, "No valid em4x50 data in flash memory."); + return PM3_ENODATA; + } + + PrintAndLogEx(INFO, "Done"); + return PM3_SUCCESS; +} From 86b9d2c62098d9df635565bd747054619b5f1e5a Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 20 Nov 2020 22:03:19 +0100 Subject: [PATCH 098/174] cosmetics --- armsrc/em4x50.c | 6 ++---- client/src/cmdlfem4x50.c | 28 ++++++++++------------------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 2d3a24f89..a5b2f7553 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1078,7 +1078,7 @@ void em4x50_stdread(void) { // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) standard_read(&now, words); - + LOW(GPIO_SSC_DOUT); lf_finalize(); reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); @@ -1180,7 +1180,6 @@ static int write(uint32_t word, uint32_t addresses) { // for saving data and should return with ACK if (check_ack(false)) return PM3_SUCCESS; - } } } else { @@ -1224,7 +1223,6 @@ static int write_password(uint32_t password, uint32_t new_password) { if (check_ack(false)) if (check_ack(false)) return PM3_SUCCESS; - } } } else { @@ -1232,7 +1230,7 @@ static int write_password(uint32_t password, uint32_t new_password) { Dbprintf("error in command request"); } - return PM3_ESOFT; + return PM3_EFAILED; } void em4x50_write(em4x50_data_t *etd) { diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 44e5297a8..86a0876b8 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1187,10 +1187,11 @@ int CmdEM4x50Restore(const char *Cmd) { int uidLen = 0, fnLen = 0, pwdLen = 0, status = 0; uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; + uint8_t data[DUMP_FILESIZE] = {0x0}; size_t bytes_read = 0; char filename[FILE_PATH_SIZE] = {0}; em4x50_data_t etd = {.pwd_given = false}; - uint8_t data[DUMP_FILESIZE] = {0x0}; + PacketResponseNG resp; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_restore", @@ -1260,25 +1261,20 @@ int CmdEM4x50Restore(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_RESTORE, &resp, 2 * TIMEOUT)) { PrintAndLogEx(FAILED, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } status = resp.status; - - if (status == PM3_ETEAROFF) { - return PM3_SUCCESS; - } else if (status != PM3_SUCCESS) { + if (status == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); + else PrintAndLogEx(FAILED, "Restore " _RED_("failed")); - return status; - } - PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); PrintAndLogEx(INFO, "Finished restoring"); - return PM3_SUCCESS; + return status; } //============================================================================== @@ -1343,16 +1339,12 @@ int CmdEM4x50Sim(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); - WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - if (resp.status == PM3_ETEAROFF) { - return PM3_SUCCESS; - } else if (resp.status == PM3_ENODATA) { + if (resp.status == PM3_SUCCESS) + PrintAndLogEx(INFO, "Done"); + else PrintAndLogEx(FAILED, "No valid em4x50 data in flash memory."); - return PM3_ENODATA; - } - PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; + return resp.status; } From 35404eb20766af1597ef5d2a997598f4909023a1 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 27 Nov 2020 22:21:45 +0100 Subject: [PATCH 099/174] added LED signals (A -> signal_properties, B -> listening windows, C -> reading) stabilized noise detection by ignoring first samples --- armsrc/em4x50.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index a5b2f7553..ae40e7876 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -12,6 +12,7 @@ #include "ticks.h" #include "dbprint.h" #include "lfadc.h" +#include "lfdemod.h" #include "commonutil.h" #include "em4x50.h" #include "flashmem.h" @@ -191,6 +192,8 @@ static bool get_signalproperties(void) { uint32_t sample_max_sum = 0; memcpy(sample_max, 0x00, sizeof(sample_max)); + LED_A_ON(); + // wait until signal/noise > 1 (max. 32 periods) for (int i = 0; i < T0 * no_periods; i++) { @@ -198,15 +201,18 @@ static bool get_signalproperties(void) { // about 2 samples per bit period wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); - - if (AT91C_BASE_SSC->SSC_RHR > noise) { + + // ignore first samples + if ((i > SIGNAL_IGNORE_FIRST_SAMPLES) && (AT91C_BASE_SSC->SSC_RHR > noise)) { signal_found = true; break; } } - if (signal_found == false) + if (signal_found == false) { + LED_A_OFF(); return false; + } // calculate mean maximum value of 32 periods, each period has a length of // 3 single "full periods" to eliminate the influence of a listen window @@ -231,6 +237,8 @@ static bool get_signalproperties(void) { // set global envelope variables 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; } @@ -295,6 +303,7 @@ static bool check_pulse_length(uint32_t pl, int length) { // check if pulse length corresponds to given length return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); + } static void em4x50_reader_send_bit(int bit) { @@ -404,6 +413,8 @@ static int find_double_listen_window(bool bcommand) { // -> 34 words + 34 single listen windows -> about 1600 pulses int cnt_pulses = 0; + + LED_B_ON(); while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) { @@ -438,6 +449,8 @@ static int find_double_listen_window(bool bcommand) { em4x50_reader_send_bit(0); em4x50_reader_send_bit(0); + LED_B_OFF(); + return true; } @@ -445,6 +458,8 @@ 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,6 +470,8 @@ static int find_double_listen_window(bool bcommand) { cnt_pulses++; } + LED_B_OFF(); + return false; } @@ -462,7 +479,11 @@ static bool find_em4x50_tag(void) { // function is used to check wether a tag on the proxmark is an // EM4x50 tag or not -> speed up "lf search" process + LED_B_ON(); + return find_single_listen_window(); + + LED_B_OFF(); } static int request_receive_mode(void) { @@ -537,6 +558,8 @@ 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,14 +630,17 @@ 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; return (extract_parities(word, data)) ? --cnt : 0; - } } + LED_C_OFF(); + return BUTTON_SINGLE_CLICK; } From 7bc372633fdee0e75072b5b5608c3283d42ab8bf Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 00:19:42 +0100 Subject: [PATCH 100/174] - changed return values from Boolean to "pm3" - added LED signals --- armsrc/em4x50.c | 56 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ae40e7876..952f9cc8e 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -34,6 +34,7 @@ #define EM4X50_T_TAG_FULL_PERIOD 64 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 +#define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be // critical; @@ -195,7 +196,7 @@ static bool get_signalproperties(void) { LED_A_ON(); // wait until signal/noise > 1 (max. 32 periods) - for (int i = 0; i < T0 * no_periods; i++) { + for (int i = 0; i < EM4X50_T_TAG_WAITING_FOR_SIGNAL; i++) { if (BUTTON_PRESS()) return false; @@ -385,6 +386,8 @@ static bool find_single_listen_window(void) { // find single listen window int cnt_pulses = 0; + + LED_B_ON(); while (cnt_pulses < EM4X50_T_WAITING_FOR_SNGLLIW) { @@ -394,13 +397,16 @@ static bool find_single_listen_window(void) { if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { - // listen window found + // found listen window + LED_B_OFF(); return true; } } cnt_pulses++; } + LED_B_OFF(); + return false; } @@ -418,10 +424,16 @@ static int find_double_listen_window(bool bcommand) { while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) { + if (BUTTON_PRESS()) + return BUTTON_SINGLE_CLICK; + // identification of listen window is done via evaluation of // pulse lengths if (check_pulse_length(get_pulse_length(), 3 * EM4X50_T_TAG_FULL_PERIOD)) { + //if (BUTTON_PRESS()) + // return BUTTON_SINGLE_CLICK; + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // first listen window found @@ -451,7 +463,7 @@ static int find_double_listen_window(bool bcommand) { LED_B_OFF(); - return true; + return PM3_SUCCESS; } } @@ -463,7 +475,7 @@ static int find_double_listen_window(bool bcommand) { // return although second listen window consists of one // more bit period but this period is necessary for // evaluating further pulse lengths - return true; + return PM3_SUCCESS; } } } @@ -472,18 +484,14 @@ static int find_double_listen_window(bool bcommand) { LED_B_OFF(); - return false; + return PM3_EFAILED; } static bool find_em4x50_tag(void) { // function is used to check wether a tag on the proxmark is an // EM4x50 tag or not -> speed up "lf search" process - LED_B_ON(); - return find_single_listen_window(); - - LED_B_OFF(); } static int request_receive_mode(void) { @@ -505,6 +513,9 @@ static bool check_ack(bool bliw) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { + if (BUTTON_PRESS()) + return false; + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // The received signal is either ACK or NAK. @@ -803,7 +814,7 @@ static bool login(uint32_t password) { // simple login to EM4x50, // used in operations that require authentication - if (request_receive_mode()) { + if (request_receive_mode() == PM3_SUCCESS) { // send login command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_LOGIN); @@ -835,8 +846,19 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { for (*pwd = start; *pwd <= stop; (*pwd)++) { if (login(*pwd) == PM3_SUCCESS) { + pwd_found = true; - break; + + // to be safe login 5 more times + for (int i = 0; i < 5; i++) { + if (login(*pwd) != PM3_SUCCESS) { + pwd_found = false; + break; + } + } + + if (pwd_found) + break; } // print password every 500 iterations @@ -970,7 +992,7 @@ static int reset(void) { // resets EM4x50 tag (used by write function) - if (request_receive_mode()) { + if (request_receive_mode() == PM3_SUCCESS) { // send reset command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_RESET); @@ -1014,7 +1036,7 @@ static int standard_read(int *now, uint32_t *words) { int fwr = *now, res = PM3_EFAILED; // start with the identification of two successive listening windows - if (find_double_listen_window(false)) { + 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) @@ -1041,7 +1063,7 @@ static int selective_read(uint32_t addresses, uint32_t *words) { uint8_t lwr = (addresses >> 8) & 0xFF; // last word read (second byte) int now = fwr; // number of words - if (request_receive_mode()) { + if (request_receive_mode() == PM3_SUCCESS) { // send selective read command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_SELECTIVE_READ); @@ -1180,7 +1202,7 @@ static int write(uint32_t word, uint32_t addresses) { // writes to specified - if (request_receive_mode()) { + if (request_receive_mode() == PM3_SUCCESS) { // send write command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_WRITE); @@ -1220,7 +1242,7 @@ static int write_password(uint32_t password, uint32_t new_password) { // changes password from to - if (request_receive_mode()) { + if (request_receive_mode() == PM3_SUCCESS) { // send write password command em4x50_reader_send_byte_with_parity(EM4X50_COMMAND_WRITE_PASSWORD); @@ -1503,7 +1525,7 @@ int em4x50_standalone_read(uint32_t *words) { em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) - if (find_double_listen_window(false)) + if (find_double_listen_window(false) == PM3_SUCCESS) while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) now++; From eb501dc8a7094c23fe0f5c16a44f590323940515 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 00:37:29 +0100 Subject: [PATCH 101/174] added missing adaptions due to changes in 4x50_info --- client/src/cmdlfem4x50.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 86a0876b8..3eea3739b 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -855,7 +855,7 @@ int CmdEM4x50Watch(const char *Cmd) { int CmdEM4x50Dump(const char *Cmd) { - int fnLen = 0, pwdLen = 0; + int fnLen = 0, pwdLen = 0, status = 0; uint8_t pwd[4] = {0x0}; char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; @@ -908,8 +908,8 @@ int CmdEM4x50Dump(const char *Cmd) { return PM3_ETIMEOUT; } - bool success = (resp.status & STATUS_SUCCESS) >> 1; - if (success == false) { + status = resp.status; + if (status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); return PM3_ESOFT; } From beed73b0954ccd34ba0b22809f1cb6ff31ecf3ec Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 01:09:30 +0100 Subject: [PATCH 102/174] deleted em4x50 standalone mode --- armsrc/Standalone/Makefile.hal | 7 ++----- armsrc/Standalone/Makefile.inc | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index fa0de9610..14bd80951 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 | read and sim em4x50 tags | -| (RDV4 only) | | -+----------------------------------------------------------+ | 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_THAREXDE LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN +STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN 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 From 427577fee6a52a52b35e92636fe7795019d2d8b9 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 01:09:54 +0100 Subject: [PATCH 103/174] deleted em4x50 standalone mode --- armsrc/em4x50.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 952f9cc8e..c85de02b1 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1495,39 +1495,3 @@ void em4x50_sim(void) { lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); } - -//============================================================================== -// standalone mode functions -//============================================================================== - -int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // envoke password search in standalone mode - - int status = false; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - status = brute(start, stop, pwd); - else - status = PM3_ETIMEOUT; - - lf_finalize(); - - return status; -} - -int em4x50_standalone_read(uint32_t *words) { - - int now = 0; - - em4x50_setup_read(); - - if (get_signalproperties() && find_em4x50_tag()) - if (find_double_listen_window(false) == PM3_SUCCESS) - while (get_word_from_bitstream(&words[now]) == EM4X50_TAG_WORD) - now++; - - return now; -} From b3f1438c6be7c99da4dfa5ff30950d559cd89f72 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 01:10:45 +0100 Subject: [PATCH 104/174] fixed missing adaption due to changes in 4x50_write --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 3eea3739b..e88e7fd52 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1168,7 +1168,7 @@ int CmdEM4x50Wipe(const char *Cmd) { } isOK = resp.status; - if (!isOK) { + if (isOK != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); return PM3_ESOFT; From 9ff29b8d4eb03a5b2578f44c7bb5faa171adab56 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 01:44:37 +0100 Subject: [PATCH 105/174] fixed status (BUTTON_SINGLE_CLICK not available in client) --- client/src/cmdlfem4x50.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index e88e7fd52..fab325e46 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -525,7 +525,8 @@ int CmdEM4x50Chk(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - if ((status = resp.status) == PM3_SUCCESS) + status = resp.status; // status = -1 -> BUTTON_SINGLE_CLICK + if ((status == PM3_SUCCESS) || (status == -1)) break; } From 00338079597f0ecb6edb450d4d0700134adc77e9 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:57:04 +0100 Subject: [PATCH 106/174] changed 4x50_stdread to 4x50_reader --- include/pm3_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 10799cb13..56d7ec1b5 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -513,7 +513,7 @@ typedef struct { #define CMD_LF_EM4X50_WATCH 0x0248 #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 -#define CMD_LF_EM4X50_STDREAD 0x0251 +#define CMD_LF_EM4X50_READER 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 #define CMD_LF_EM4X50_CHK 0x0253 // Sampling configuration for LF reader/sniffer From a319b076906cb7163a1b66e66d34cc1469d58517 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:57:33 +0100 Subject: [PATCH 107/174] changed 4x50_stdread to 4x50_reader --- client/src/cmdlfem4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 290e0b4df..c6a97943c 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -664,7 +664,7 @@ static command_t CommandTable[] = { {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "watch for EM4x50 tags"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, - {"4x50_stdread",CmdEM4x50StdRead, IfPm3EM4x50, "show standard read mode data of EM4x50"}, + {"4x50_reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"4x50_eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, {"4x50_esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, {"4x50_chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, From 96fc27a869d303fef11dc82b5a9e141afa881717 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:57:43 +0100 Subject: [PATCH 108/174] changed 4x50_stdread to 4x50_reader --- client/src/cmdlfem4x50.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index a8d637f4e..cd19e7297 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -29,7 +29,7 @@ int CmdEM4x50Reset(const char *Cmd); int CmdEM4x50Watch(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); int CmdEM4x50Sim(const char *Cmd); -int CmdEM4x50StdRead(const char *Cmd); +int CmdEM4x50Reader(const char *Cmd); int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); int CmdEM4x50Chk(const char *Cmd); From fdd289027299b5bac61fb41a84e5376e356acd36 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:57:55 +0100 Subject: [PATCH 109/174] changed 4x50_stdread to 4x50_reader --- armsrc/appmain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2added25f..22f919d56 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1132,8 +1132,8 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_sim(); break; } - case CMD_LF_EM4X50_STDREAD: { - em4x50_stdread(); + case CMD_LF_EM4X50_READER: { + em4x50_reader(); break; } case CMD_LF_EM4X50_ESET: { From 96cceab10a0f04679d79db2b3c0985fc23956b9b Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:58:10 +0100 Subject: [PATCH 110/174] changed 4x50_stdread to 4x50_reader --- armsrc/em4x50.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index a6030d7ba..c09c09d17 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -29,7 +29,7 @@ void em4x50_reset(void); void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); -void em4x50_stdread(void); +void em4x50_reader(void); void em4x50_chk(uint32_t *numkeys); #endif /* EM4X50_H */ From 8215955ba8076c76b4aa83114a781c6e459d0afe Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 29 Nov 2020 23:59:36 +0100 Subject: [PATCH 111/174] - changed CmdEM4x50StRread tp CmdEM4x50Reader - changed return value --- client/src/cmdlfem4x50.c | 128 +++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 66 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index fab325e46..5830ae040 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -525,8 +525,8 @@ int CmdEM4x50Chk(const char *Cmd) { SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - status = resp.status; // status = -1 -> BUTTON_SINGLE_CLICK - if ((status == PM3_SUCCESS) || (status == -1)) + status = resp.status; + if ((status == PM3_SUCCESS) || (status == PM3_EOPABORTED)) break; } @@ -701,70 +701,6 @@ int CmdEM4x50Read(const char *Cmd) { return em4x50_read(&etd, NULL); } -int CmdEM4x50StdRead(const char *Cmd) { - - int now = 0, status = PM3_EFAILED; - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_stdread", - "Shows standard read data of EM4x50 tag.", - "lf em 4x50_stdread\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - // start - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_STDREAD, 0, 0); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_STDREAD, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - now = resp.status; - - // print response - if (now > 0) { - - em4x50_word_t words[EM4X50_NO_WORDS]; - - prepare_result(resp.data.asBytes, 0, now - 1, words); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, " # | word (msb) | word (lsb) "); - PrintAndLogEx(INFO, "----+-------------+-------------"); - - for (int i = 0; i < now; i++) { - - char r[30] = {0}; - for (int j = 3; j >= 0; j--) - sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); - - PrintAndLogEx(INFO, " %2i | " _GREEN_("%s") "| %s", - i, - sprint_hex(words[i].byte, 4), - r - ); - } - - status = PM3_SUCCESS; - PrintAndLogEx(INFO, "----+-------------+-------------"); - PrintAndLogEx(SUCCESS, "Standard read " _GREEN_("ok")); - - } else { - PrintAndLogEx(FAILED, "Standard read " _RED_("failed")); - } - - return status; -} - int CmdEM4x50Info(const char *Cmd) { // envoke reading of a EM4x50 tag which has to be on the antenna because @@ -823,6 +759,66 @@ int CmdEM4x50Info(const char *Cmd) { return status; } +int CmdEM4x50Reader(const char *Cmd) { + + int now = 0; + PacketResponseNG resp; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50_reader", + "Shows standard read data of EM4x50 tag.", + "lf em 4x50_reader\n" + "lf em 4x50_reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + // start + do { + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_READER, 0, 0); + WaitForResponse(CMD_LF_EM4X50_READER, &resp); + + now = resp.status; + + // print response + if (now > 0) { + + em4x50_word_t words[EM4X50_NO_WORDS]; + prepare_result(resp.data.asBytes, 0, now - 1, words); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " word (msb) | word (lsb) "); + PrintAndLogEx(INFO, "-------------+-------------"); + + for (int i = 0; i < now; i++) { + + char r[30] = {0}; + for (int j = 3; j >= 0; j--) + sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + + PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", + sprint_hex(words[i].byte, 4), + r + ); + } + + PrintAndLogEx(INFO, "-------------+-------------"); + } + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; +} + int CmdEM4x50Watch(const char *Cmd) { // continously envoke reading of a EM4x50 tag From e6eb6af9e3f0d3afe4f3addf35de45ad991ffcac Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 00:01:08 +0100 Subject: [PATCH 112/174] - replaced return value BUTTON_SINGLE_CLICK by PM3_EOPABORTED - changed 4x50_stdread to 4x50_reader --- armsrc/em4x50.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index c85de02b1..0afb1751c 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -425,15 +425,12 @@ static int find_double_listen_window(bool bcommand) { while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) { if (BUTTON_PRESS()) - return BUTTON_SINGLE_CLICK; + return PM3_EOPABORTED; // identification of listen window is done via evaluation of // pulse lengths if (check_pulse_length(get_pulse_length(), 3 * EM4X50_T_TAG_FULL_PERIOD)) { - //if (BUTTON_PRESS()) - // return BUTTON_SINGLE_CLICK; - if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // first listen window found @@ -652,7 +649,7 @@ static int get_word_from_bitstream(uint32_t *data) { LED_C_OFF(); - return BUTTON_SINGLE_CLICK; + return PM3_EOPABORTED; } //============================================================================== @@ -964,7 +961,7 @@ void em4x50_chk(uint32_t *offset) { // manual interruption if (BUTTON_PRESS()) { - status = BUTTON_SINGLE_CLICK; + status = PM3_EOPABORTED; break; } @@ -1114,24 +1111,6 @@ void em4x50_read(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); } -void em4x50_stdread(void) { - - // reads data that tag transmits "voluntarily" -> standard read mode - - int now = 0; - uint32_t words[EM4X50_NO_WORDS] = {0x0}; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) - standard_read(&now, words); - - LOW(GPIO_SSC_DOUT); - lf_finalize(); - reply_ng(CMD_LF_EM4X50_STDREAD, now, (uint8_t *)words, 4 * now); -} - void em4x50_info(em4x50_data_t *etd) { // collects as much information as possible via selective read mode @@ -1158,6 +1137,24 @@ void em4x50_info(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); } +void em4x50_reader(void) { + + // reads data that tag transmits "voluntarily" -> standard read mode + + int now = 0; + uint32_t words[EM4X50_NO_WORDS] = {0x0}; + + em4x50_setup_read(); + + // set gHigh and gLow + if (get_signalproperties() && find_em4x50_tag()) + standard_read(&now, words); + + LOW(GPIO_SSC_DOUT); + lf_finalize(); + reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); +} + void em4x50_watch() { // read continuously and display standard reads of tag @@ -1175,7 +1172,7 @@ void em4x50_watch() { if (get_signalproperties() && find_em4x50_tag()) { - if (standard_read(&now, words) == BUTTON_SINGLE_CLICK) + if (standard_read(&now, words) == PM3_EOPABORTED) break; if (now > 0) { From f03fac540a3b068f0c7b4a733144fb251be62725 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 00:03:22 +0100 Subject: [PATCH 113/174] delated watch function (em4x50) --- armsrc/appmain.c | 4 ---- armsrc/em4x50.c | 36 ------------------------------------ armsrc/em4x50.h | 1 - client/src/cmdlfem4x.c | 1 - client/src/cmdlfem4x50.c | 31 ------------------------------- client/src/cmdlfem4x50.h | 1 - include/pm3_cmd.h | 1 - 7 files changed, 75 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 22f919d56..72dfe87bd 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1120,10 +1120,6 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_reset(); break; } - case CMD_LF_EM4X50_WATCH: { - em4x50_watch(); - break; - } case CMD_LF_EM4X50_RESTORE: { em4x50_restore((em4x50_data_t *)packet->data.asBytes); break; diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 0afb1751c..36a86ee4b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1155,42 +1155,6 @@ void em4x50_reader(void) { reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } -void em4x50_watch() { - - // read continuously and display standard reads of tag - - int now = 0; - uint32_t words[EM4X50_NO_WORDS] = {0x0}; - - em4x50_setup_read(); - - while (BUTTON_PRESS() == false) { - - WDT_HIT(); - memset(words, 0, sizeof(words)); - now = 0; - - if (get_signalproperties() && find_em4x50_tag()) { - - if (standard_read(&now, words) == PM3_EOPABORTED) - break; - - if (now > 0) { - - Dbprintf(""); - for (int i = 0; i < now; i++) - Dbprintf("EM4x50 tag data: " - _GREEN_("%08x") " (msb) - " _GREEN_("%08x") " (lsb)", - words[i], reflect32(words[i])); - } - } - } - - LOW(GPIO_SSC_DOUT); - lf_finalize(); - reply_ng(CMD_LF_EM4X50_WATCH, 1, 0, 0); -} - //============================================================================== // write functions //============================================================================== diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index c09c09d17..979d9bca7 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -26,7 +26,6 @@ void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); void em4x50_reset(void); -void em4x50_watch(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); void em4x50_reader(void); diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index c6a97943c..06e8b8a03 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -661,7 +661,6 @@ static command_t CommandTable[] = { {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, - {"4x50_watch", CmdEM4x50Watch, IfPm3EM4x50, "watch for EM4x50 tags"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, {"4x50_reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 5830ae040..b4d787bbc 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -819,37 +819,6 @@ int CmdEM4x50Reader(const char *Cmd) { return PM3_SUCCESS; } -int CmdEM4x50Watch(const char *Cmd) { - - // continously envoke reading of a EM4x50 tag - - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_watch", - "Watches for EM4x50 tags. Function runs until button is pressed.", - "lf em 4x50_watch\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - PrintAndLogEx(SUCCESS, "Watching for EM4x50 cards - place tag on antenna"); - PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_WATCH, 0, 0); - WaitForResponseTimeoutW(CMD_LF_EM4X50_WATCH, &resp, -1, false); - - PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; -} - int CmdEM4x50Dump(const char *Cmd) { int fnLen = 0, pwdLen = 0, status = 0; diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index cd19e7297..fe45a16f6 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -26,7 +26,6 @@ int CmdEM4x50Wipe(const char *Cmd); int CmdEM4x50Brute(const char *Cmd); int CmdEM4x50Login(const char *Cmd); int CmdEM4x50Reset(const char *Cmd); -int CmdEM4x50Watch(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); int CmdEM4x50Sim(const char *Cmd); int CmdEM4x50Reader(const char *Cmd); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 56d7ec1b5..efdcafe33 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -510,7 +510,6 @@ typedef struct { #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 #define CMD_LF_EM4X50_RESET 0x0247 -#define CMD_LF_EM4X50_WATCH 0x0248 #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 #define CMD_LF_EM4X50_READER 0x0251 From 40d9880264bbd8f0937c8d07aa4d8c4c98d17b73 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 20:31:02 +0100 Subject: [PATCH 114/174] changed timeout behavior --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index b4d787bbc..ae55a8a18 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -786,7 +786,7 @@ int CmdEM4x50Reader(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_READER, 0, 0); - WaitForResponse(CMD_LF_EM4X50_READER, &resp); + WaitForResponseTimeoutW(CMD_LF_EM4X50_READER, &resp, -1, false); now = resp.status; From 66c71cbcd176a99bbafba30947f0e7001b52cb83 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 20:52:33 +0100 Subject: [PATCH 115/174] included EM4x50 updates --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ddaf4801..0b3ac7afc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,25 @@ 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] + - EM4x50: new function 4x50_reset: reset tag (@tharexde) + - EM4x50: new function 4x50_login: authenticate against tag (@tharexde) + - EM4x50: new function 4x50_brute: guess password within a given password range (@tharexde) + - EM4x50: new function 4x50_chk: guess password from dictionary (without option -> T55xx default dictionary or -f ) (@tharexde) + - EM4x50: new function 4x50_reader: read data from tag (configured data => standard read mode), incl. option "-@" (@tharexde) + - EM4x50: new function 4x50_sim: simulate dump from file or flash (@tharexde) + - EM4x50: new function 4x50_restore: restore dump file (bin, eml, json) onto tag (via flash memory) (@tharexde) + - EM4x50: new function 4x50_esave: dump em4x50 content from flash memory to file (bin + eml + json) (@tharexde) + - EM4x50: new function 4x50_eload: upload em4x50 file content (bin, eml, json) to flash memory (@tharexde) + - EM4x50: added LED signals (@tharexde) + - EM4x50: added json format for 4x50_dump (@tharexde) + - EM4x50: relocated write requests in function „4x50_wipe" from device to client (@tharexde) + - EM4x50: renamed „4x50_write_password" to „4x50_writepwd" (@tharexde) + - EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) + - EM4x50: changed cli parameter from „a
“ to „b " (@tharexde) + - EM4x50: changed cli parameter from „w " to „d “ (@tharexde) + - EM4x50: switched to cliparser for all functions (@tharexde) + - EM4x50: stabilized and accelerated tag detection (@tharexde) + - EM4x50: removed global tag structure on device side (@tharexde) - Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33) - Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) From 60e0402be9180b87abc565baf888349e6bae8b41 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 21:12:51 +0100 Subject: [PATCH 116/174] update --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b3ac7afc..d73bb2850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - EM4x50: relocated write requests in function „4x50_wipe" from device to client (@tharexde) - EM4x50: renamed „4x50_write_password" to „4x50_writepwd" (@tharexde) - EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) - - EM4x50: changed cli parameter from „a
“ to „b " (@tharexde) - - EM4x50: changed cli parameter from „w " to „d “ (@tharexde) + - EM4x50: changed cli parameter from „a (address)“ to „b (block)" (@tharexde) + - EM4x50: changed cli parameter from „w (word)" to „d (data)“ (@tharexde) - EM4x50: switched to cliparser for all functions (@tharexde) - EM4x50: stabilized and accelerated tag detection (@tharexde) - EM4x50: removed global tag structure on device side (@tharexde) From 7fa260b7fb9e09df2e738f5bb3091f0a3397d74b Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 21:15:14 +0100 Subject: [PATCH 117/174] next update --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d73bb2850..c0960aac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,19 +6,19 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - EM4x50: new function 4x50_reset: reset tag (@tharexde) - EM4x50: new function 4x50_login: authenticate against tag (@tharexde) - EM4x50: new function 4x50_brute: guess password within a given password range (@tharexde) - - EM4x50: new function 4x50_chk: guess password from dictionary (without option -> T55xx default dictionary or -f ) (@tharexde) - - EM4x50: new function 4x50_reader: read data from tag (configured data => standard read mode), incl. option "-@" (@tharexde) + - EM4x50: new function 4x50_chk: guess password from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) + - EM4x50: new function 4x50_reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) - EM4x50: new function 4x50_sim: simulate dump from file or flash (@tharexde) - EM4x50: new function 4x50_restore: restore dump file (bin, eml, json) onto tag (via flash memory) (@tharexde) - EM4x50: new function 4x50_esave: dump em4x50 content from flash memory to file (bin + eml + json) (@tharexde) - EM4x50: new function 4x50_eload: upload em4x50 file content (bin, eml, json) to flash memory (@tharexde) - EM4x50: added LED signals (@tharexde) - EM4x50: added json format for 4x50_dump (@tharexde) - - EM4x50: relocated write requests in function „4x50_wipe" from device to client (@tharexde) - - EM4x50: renamed „4x50_write_password" to „4x50_writepwd" (@tharexde) + - EM4x50: relocated write requests in function 4x50_wipe from device to client (@tharexde) + - EM4x50: renamed 4x50_write_password to 4x50_writepwd (@tharexde) - EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) - - EM4x50: changed cli parameter from „a (address)“ to „b (block)" (@tharexde) - - EM4x50: changed cli parameter from „w (word)" to „d (data)“ (@tharexde) + - EM4x50: changed cli parameter from a (address) to b (block) (@tharexde) + - EM4x50: changed cli parameter from w (word) to d (data) (@tharexde) - EM4x50: switched to cliparser for all functions (@tharexde) - EM4x50: stabilized and accelerated tag detection (@tharexde) - EM4x50: removed global tag structure on device side (@tharexde) From 98fbd89fb53053863830087e817ff195f8f2316c Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 22:28:06 +0100 Subject: [PATCH 118/174] restored unintentionally deleted parts --- armsrc/Standalone/Makefile.hal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index 14bd80951..d5414f661 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -70,7 +70,7 @@ endef 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 HF_14ASNIFF HF_BOG HF_COLIN +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)),) From a04d93e9aeb7aea011e1be641061e5365d16a6d4 Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 30 Nov 2020 23:38:27 +0100 Subject: [PATCH 119/174] replaced sprint by FillFileNameByUID --- client/src/cmdlfem4x50.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ae55a8a18..0672d75d1 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1156,6 +1156,7 @@ int CmdEM4x50Restore(const char *Cmd) { uint8_t data[DUMP_FILESIZE] = {0x0}; size_t bytes_read = 0; char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; em4x50_data_t etd = {.pwd_given = false}; PacketResponseNG resp; @@ -1192,12 +1193,9 @@ int CmdEM4x50Restore(const char *Cmd) { } if (uidLen) { - snprintf(filename, FILE_PATH_SIZE, "./lf-4x50-%02x%02x%02x%02x-dump.bin", - uid[0], - uid[1], - uid[2], - uid[3] - ); + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += sprintf(fptr, "lf-4x50-"); + FillFileNameByUID(fptr, uid, "-dump", 4); } if (pwdLen) { From 414b892b65599e2ffd7de5dd5fc6ecd16e10ab91 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 20:40:58 +0100 Subject: [PATCH 120/174] - introduced macro for uint8_t p[4] -> uint32_t - returned to emulator memory for eload and esave --- client/src/cmdlfem4x50.c | 66 ++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 0672d75d1..dc33e05fc 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -16,6 +16,8 @@ #define CARD_MEMORY_SIZE 4096 +#define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) + //============================================================================== // output functions //============================================================================== @@ -153,6 +155,21 @@ static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len return PM3_SUCCESS; } +static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { + // fast push mode + conn.block_after_ACK = true; + for (size_t i = offset; i < numofbytes; i += PM3_CMD_DATA_SIZE) { + + size_t len = MIN((numofbytes - i), PM3_CMD_DATA_SIZE); + if (len == numofbytes - i) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + clearCommandBuffer(); + SendCommandOLD(CMD_LF_EM4X50_ESET, i, len, 0, src + i, len); + } +} + static int em4x50_wipe_flash(int page) { int isok = 0; @@ -221,14 +238,14 @@ static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { int CmdEM4x50ELoad(const char *Cmd) { - int slen = 0, res = 0; + int slen = 0; size_t bytes_read = 0; char filename[FILE_PATH_SIZE] = {0}; uint8_t data[DUMP_FILESIZE] = {0x0}; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_eload", - "Loads EM4x50 tag dump into flash memory on device.", + "Loads EM4x50 tag dump into emulator memory on device.", "lf em 4x50_eload -f mydump.bin -> uploads bin file ./mydump.bin\n" "lf em 4x50_eload -f mydump.eml -> uploads eml file ./mydump.eml\n" "lf em 4x50_eload -f mydump.json -> uploads json file ./mydump.json\n" @@ -250,13 +267,9 @@ int CmdEM4x50ELoad(const char *Cmd) { return PM3_EFILE; } - // upload to flash memory - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); - res = em4x50_write_flash(data, 0, DUMP_FILESIZE); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return res; - } + // upload to emulator memory + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); + em4x50_seteml(data, 0, DUMP_FILESIZE); PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; @@ -272,7 +285,7 @@ int CmdEM4x50ESave(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_esave", - "Saves bin/eml/json dump file of flash memory.", + "Saves bin/eml/json dump file of emulator memory.", "lf em 4x50_esave -> use UID as filename\n" "lf em 4x50_esave -f mydump.bin -> saves to bin file ./mydump.bin\n" "lf em 4x50_esave -f mydump.eml -> saves to eml file ./mydump.eml\n" @@ -289,10 +302,11 @@ int CmdEM4x50ESave(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - // download flash memory - PrintAndLogEx(SUCCESS, "Reading flash memory..."); - if (!GetFromDevice(FLASH_MEM, data, DUMP_FILESIZE, 0, NULL, 0, NULL, -1, true)) { + // download emulator memory + PrintAndLogEx(SUCCESS, "Reading emulator memory..."); + if (!GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(data); return PM3_ETIMEOUT; } @@ -347,7 +361,7 @@ int CmdEM4x50Login(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + password = BYTES2UINT32(pwd); } CLIParserFree(ctx); @@ -401,8 +415,8 @@ int CmdEM4x50Brute(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); return PM3_EINVARG; } else { - etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; - etd.password2 = (pwd2[0] << 24) | (pwd2[1] << 16) | (pwd2[2] << 8) | pwd2[3]; + etd.password1 = BYTES2UINT32(pwd1); + etd.password2 = BYTES2UINT32(pwd2); } CLIParserFree(ctx); @@ -691,7 +705,7 @@ int CmdEM4x50Read(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } @@ -733,7 +747,7 @@ int CmdEM4x50Info(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } @@ -858,7 +872,7 @@ int CmdEM4x50Dump(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } @@ -954,14 +968,14 @@ int CmdEM4x50Write(const char *Cmd) { PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); return PM3_EINVARG; } else { - etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; + etd.word = BYTES2UINT32(word); } if (pwdLen) { if (pwdLen != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } @@ -1029,13 +1043,13 @@ int CmdEM4x50WritePwd(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); } if (npwdLen != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); return PM3_EINVARG; } else { - etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; + etd.password2 = BYTES2UINT32(npwd); } CLIParserFree(ctx); @@ -1093,7 +1107,7 @@ int CmdEM4x50Wipe(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } @@ -1203,7 +1217,7 @@ int CmdEM4x50Restore(const char *Cmd) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); return PM3_EINVARG; } else { - etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; + etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } @@ -1236,8 +1250,6 @@ int CmdEM4x50Restore(const char *Cmd) { else PrintAndLogEx(FAILED, "Restore " _RED_("failed")); - PrintAndLogEx(INFO, "Finished restoring"); - return status; } From e41e8555a3e7b64ca2f0044cb6e2e73ddc63a3e3 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 20:42:46 +0100 Subject: [PATCH 121/174] restore function now stops if password is wrong --- armsrc/em4x50.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 36a86ee4b..69b1d6919 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1331,7 +1331,7 @@ void em4x50_restore(em4x50_data_t *etd) { // restore em4x50 dump file to tag bool bsuccess = false; - int status = PM3_EFAILED; + int status = PM3_SUCCESS; int start_word = 3; // first block/address with user data uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) @@ -1357,35 +1357,38 @@ void em4x50_restore(em4x50_data_t *etd) { // login first if password is available if (etd->pwd_given) { - if (login(etd->password1) == PM3_SUCCESS) { + if ((status = login(etd->password1)) == PM3_SUCCESS) { // successful login allows words 1 and 2 to be written start_word = 1; } } - // write data to each address but ignore addresses - // 0 -> password, 32 -> serial, 33 -> uid - for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) { - status = write(words_client[i], i); - if (status == PM3_ETEAROFF) { - lf_finalize(); - return; + if (status == PM3_SUCCESS) { + + // write data to each address but ignore addresses + // 0 -> password, 32 -> serial, 33 -> uid + for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) { + status = write(words_client[i], i); + if (status == PM3_ETEAROFF) { + lf_finalize(); + return; + } } - } - // to verify result -> reset EM4x50 - if (reset() == PM3_SUCCESS) { + // to verify result -> reset EM4x50 + if (reset() == PM3_SUCCESS) { - // login not necessary because protected word has been set to 0 - // -> no read protected words - // -> selective read can be called immediately - if (selective_read(addresses, words_read) == PM3_SUCCESS) { + // login not necessary because protected word has been set to 0 + // -> no read protected words + // -> selective read can be called immediately + if (selective_read(addresses, words_read) == PM3_SUCCESS) { - // check if everything is zero - bsuccess = true; - for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) - bsuccess &= (reflect32(words_read[i]) == words_client[i]); + // check if everything is zero + bsuccess = true; + for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) + bsuccess &= (reflect32(words_read[i]) == words_client[i]); + } } } } From 6448ade0f2b771b65f0145812f1ab22c911abd70 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 20:47:01 +0100 Subject: [PATCH 122/174] deleted client call of reset function --- armsrc/appmain.c | 4 ---- armsrc/em4x50.c | 16 ---------------- armsrc/em4x50.h | 2 -- client/src/cmdlfem4x.c | 1 - client/src/cmdlfem4x50.c | 36 ------------------------------------ client/src/cmdlfem4x50.h | 1 - include/pm3_cmd.h | 1 - 7 files changed, 61 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 822b4beab..ec4770927 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1122,10 +1122,6 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_login((uint32_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_RESET: { - em4x50_reset(); - break; - } case CMD_LF_EM4X50_RESTORE: { em4x50_restore((em4x50_data_t *)packet->data.asBytes); break; diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 69b1d6919..905b935c0 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1005,22 +1005,6 @@ static int reset(void) { return PM3_EFAILED; } -void em4x50_reset(void) { - - // reset EM4x50 - - uint8_t status = PM3_EFAILED; - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) - status = reset(); - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_RESET, status, 0, 0); -} - //============================================================================== // read functions //============================================================================== diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 979d9bca7..1169bb986 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -18,14 +18,12 @@ int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd); bool em4x50_sim_send_listen_window(void); bool em4x50_sim_send_word(uint32_t word); - void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_reset(void); void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); void em4x50_reader(void); diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 06e8b8a03..83af74333 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -660,7 +660,6 @@ static command_t CommandTable[] = { {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, {"4x50_brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"4x50_login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, - {"4x50_reset", CmdEM4x50Reset, IfPm3EM4x50, "reset EM4x50"}, {"4x50_restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"4x50_sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, {"4x50_reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index dc33e05fc..cab5c1452 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -562,42 +562,6 @@ int CmdEM4x50Chk(const char *Cmd) { return PM3_SUCCESS; } -//============================================================================== -// reset functions -//============================================================================== - -int CmdEM4x50Reset(const char *Cmd) { - - PacketResponseNG resp; - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_reset", - "Reseta EM4x50 tag.", - "lf em 4x50_reset\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - // start - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_RESET, 0, 0); - WaitForResponse(CMD_LF_EM4X50_RESET, &resp); - - // print response - if (resp.status == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Reset " _GREEN_("ok")); - else - PrintAndLogEx(FAILED, "Reset " _RED_("failed")); - - return resp.status; -} - //============================================================================== // read functions //============================================================================== diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index fe45a16f6..2b76cb7ef 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -25,7 +25,6 @@ int CmdEM4x50Dump(const char *Cmd); int CmdEM4x50Wipe(const char *Cmd); int CmdEM4x50Brute(const char *Cmd); int CmdEM4x50Login(const char *Cmd); -int CmdEM4x50Reset(const char *Cmd); int CmdEM4x50Restore(const char *Cmd); int CmdEM4x50Sim(const char *Cmd); int CmdEM4x50Reader(const char *Cmd); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 9d6bf90ad..f929bca41 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -511,7 +511,6 @@ typedef struct { #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 -#define CMD_LF_EM4X50_RESET 0x0247 #define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 #define CMD_LF_EM4X50_READER 0x0251 From 139d4fca9db50a4a8806a8c2aece9543b78253e6 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 21:01:39 +0100 Subject: [PATCH 123/174] changed in cli: ->
-> -> -> --- client/src/cmdlfem4x50.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index cab5c1452..5be28adc1 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -350,7 +350,7 @@ int CmdEM4x50Login(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_str1("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -398,8 +398,8 @@ int CmdEM4x50Brute(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("f", "fp", "", "first password (start), hex, 4 bytes, lsb"), - arg_str1("l", "lp", "", "last password (stop), hex, 4 bytes, lsb"), + arg_str1("f", "fp", "", "first password (start), 4 bytes, lsb"), + arg_str1("l", "lp", "", "last password (stop), 4 bytes, lsb"), arg_param_end }; @@ -647,8 +647,8 @@ int CmdEM4x50Read(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_int1("b", "block", "
", "block/word address, dec"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_int1("b", "block", "", "block/word address"), + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -698,7 +698,7 @@ int CmdEM4x50Info(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -818,7 +818,7 @@ int CmdEM4x50Dump(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -909,9 +909,9 @@ int CmdEM4x50Write(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_int1("b", "block", "
", "block/word address, dec"), - arg_str1("d", "data", "", "data, hex, 4 bytes, lsb"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_int1("b", "block", "", "block/word address, dec"), + arg_str1("d", "data", "", "data, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -993,8 +993,8 @@ int CmdEM4x50WritePwd(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "password, hex, 4 bytes, lsb"), - arg_str1("n", "newpwd", "", "new password, hex, 4 bytes, lsb"), + arg_str1("p", "pwd", "", "password, 4 bytes, lsb"), + arg_str1("n", "newpwd", "", "new password, 4 bytes, lsb"), arg_param_end }; @@ -1060,7 +1060,7 @@ int CmdEM4x50Wipe(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_str1("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; @@ -1149,9 +1149,9 @@ int CmdEM4x50Restore(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("u", "uid", "", "uid, hex, 4 bytes, msb, restore from lf-4x50--dump.bin"), + arg_str0("u", "uid", "", "uid, 4 bytes, msb, restore from lf-4x50--dump.bin"), arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, hex, 4 bytes, lsb"), + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; From 1de4991bd00b98b4cd670719e882df27cda55701 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 21:11:10 +0100 Subject: [PATCH 124/174] missing command options for restore function --- client/src/cmdlfem4x50.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 5be28adc1..e8bc6bbd9 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1143,8 +1143,8 @@ int CmdEM4x50Restore(const char *Cmd) { "Restores data from dumpfile onto a Em4x50 tag.", "lf em 4x50_restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" "lf em 4x50_restore -f mydump.eml -> uses mydump.eml\n" - "lf em 4x50_restore -u 1b5aff5c -p 12345678 -> \n" - "lf em 4x50_restore -f mydump.eml -p 12345678 -> \n" + "lf em 4x50_restore -u 1b5aff5c -p 12345678\n" + "lf em 4x50_restore -f mydump.eml -p 12345678\n" ); void *argtable[] = { From 6876ff2f04495a7fa82e2a15830bb6ba7da35a55 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 3 Dec 2020 22:00:52 +0100 Subject: [PATCH 125/174] Relocated write requests in function 4x50_restore from device to client --- armsrc/appmain.c | 4 --- armsrc/em4x50.c | 74 ---------------------------------------- armsrc/em4x50.h | 1 - client/src/cmdlfem4x50.c | 44 ++++++++++++++---------- include/pm3_cmd.h | 1 - 5 files changed, 26 insertions(+), 98 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index ec4770927..053abf0d9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1122,10 +1122,6 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_login((uint32_t *)packet->data.asBytes); break; } - case CMD_LF_EM4X50_RESTORE: { - em4x50_restore((em4x50_data_t *)packet->data.asBytes); - break; - } case CMD_LF_EM4X50_SIM: { em4x50_sim(); break; diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 905b935c0..409cd7ba8 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1310,80 +1310,6 @@ void em4x50_writepwd(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITEPWD, status, 0, 0); } -void em4x50_restore(em4x50_data_t *etd) { - - // restore em4x50 dump file to tag - - bool bsuccess = false; - int status = PM3_SUCCESS; - int start_word = 3; // first block/address with user data - uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; - uint32_t addresses = 0x00001F01; // from fwr = 1 to lwr = 31 (0x1F) - uint32_t words_client[EM4X50_NO_WORDS] = {0x0}; - uint32_t words_read[EM4X50_NO_WORDS] = {0x0}; - - //----------------------------------------------------------------------------- - // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not - // involved in dealing with emulator memory. But if it is called later, it will - // destroy the Emulator Memory. - //----------------------------------------------------------------------------- - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // read data from flash memory - Flash_ReadData(0, em4x50_mem, 4 * EM4X50_NO_WORDS); - for (int i = 0; i < EM4X50_NO_WORDS; i++) - words_client[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - - em4x50_setup_read(); - - // set gHigh and gLow - if (get_signalproperties() && find_em4x50_tag()) { - - // login first if password is available - if (etd->pwd_given) { - if ((status = login(etd->password1)) == PM3_SUCCESS) { - - // successful login allows words 1 and 2 to be written - start_word = 1; - } - } - - if (status == PM3_SUCCESS) { - - // write data to each address but ignore addresses - // 0 -> password, 32 -> serial, 33 -> uid - for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) { - status = write(words_client[i], i); - if (status == PM3_ETEAROFF) { - lf_finalize(); - return; - } - } - - // to verify result -> reset EM4x50 - if (reset() == PM3_SUCCESS) { - - // login not necessary because protected word has been set to 0 - // -> no read protected words - // -> selective read can be called immediately - if (selective_read(addresses, words_read) == PM3_SUCCESS) { - - // check if everything is zero - bsuccess = true; - for (int i = start_word; i < EM4X50_NO_WORDS - 2; i++) - bsuccess &= (reflect32(words_read[i]) == words_client[i]); - } - } - } - } - - if (bsuccess) - status = PM3_SUCCESS; - - lf_finalize(); - reply_ng(CMD_LF_EM4X50_RESTORE, status, 0, 0); -} - //============================================================================== // simulate functions //============================================================================== diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 1169bb986..9b029647d 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -24,7 +24,6 @@ void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_restore(em4x50_data_t *etd); void em4x50_sim(void); void em4x50_reader(void); void em4x50_chk(uint32_t *numkeys); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index e8bc6bbd9..342227e56 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -156,6 +156,7 @@ static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len } static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { + // fast push mode conn.block_after_ACK = true; for (size_t i = offset; i < numofbytes; i += PM3_CMD_DATA_SIZE) { @@ -1194,27 +1195,34 @@ int CmdEM4x50Restore(const char *Cmd) { if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; - // upload to flash memory - status = em4x50_write_flash(data, 0, bytes_read); - if (status != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return status; + for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { + + PrintAndLogEx(INPLACE, "Restoring block %i", i); + + etd.addresses = i << 8 | i; + etd.word = reflect32(BYTES2UINT32((data + 4 * i))); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); + if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + status = resp.status; + if (status != PM3_SUCCESS) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(FAILED, "Restoring data " _RED_("failed")); + return PM3_ESOFT; + } } - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); - if (!WaitForResponseTimeout(CMD_LF_EM4X50_RESTORE, &resp, 2 * TIMEOUT)) { - PrintAndLogEx(FAILED, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Restoring data " _GREEN_("ok")); + + PrintAndLogEx(INFO, "Done"); - status = resp.status; - if (status == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Restore " _GREEN_("ok")); - else - PrintAndLogEx(FAILED, "Restore " _RED_("failed")); - - return status; + return PM3_SUCCESS; } //============================================================================== diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f929bca41..bce9b57d7 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -511,7 +511,6 @@ typedef struct { #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_BRUTE 0x0245 #define CMD_LF_EM4X50_LOGIN 0x0246 -#define CMD_LF_EM4X50_RESTORE 0x0249 #define CMD_LF_EM4X50_SIM 0x0250 #define CMD_LF_EM4X50_READER 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 From e50f386ad28df9c76fa1f345bf27e16f9381110e Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 4 Dec 2020 22:37:47 +0100 Subject: [PATCH 126/174] changed parameter in parameter list of em4x50_chk --- armsrc/appmain.c | 2 +- armsrc/em4x50.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 053abf0d9..bc1b59ea2 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1141,7 +1141,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_CHK: { - em4x50_chk((uint32_t *)packet->data.asBytes); + em4x50_chk((uint8_t *)packet->data.asBytes); break; } #endif diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 9b029647d..33c18e794 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -26,6 +26,6 @@ void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); void em4x50_sim(void); void em4x50_reader(void); -void em4x50_chk(uint32_t *numkeys); +void em4x50_chk(uint8_t *filename); #endif /* EM4X50_H */ From 952845722c986ccdea8ccbf0a44560acafeecb05 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 4 Dec 2020 22:38:48 +0100 Subject: [PATCH 127/174] use piffs instead of direct writing to flash memory --- armsrc/em4x50.c | 41 +++++++++++------------ client/src/cmdlfem4x50.c | 70 +++++++++++----------------------------- 2 files changed, 36 insertions(+), 75 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 409cd7ba8..e63d63a76 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -17,6 +17,7 @@ #include "em4x50.h" #include "flashmem.h" #include "BigBuf.h" +#include "spiffs.h" #include "appmain.h" // tear // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) @@ -916,41 +917,33 @@ void em4x50_brute(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); } -void em4x50_chk(uint32_t *offset) { +void em4x50_chk(uint8_t *filename) { // check passwords from dictionary content in flash memory int status = PM3_EFAILED; - uint8_t counter[2] = {0x00, 0x00}; - uint16_t isok = 0; uint16_t pwd_count = 0; - uint16_t pwd_size_available = 0; uint32_t pwd = 0x0; - uint8_t *pwds = BigBuf_get_EM_addr(); +#ifdef WITH_FLASH //----------------------------------------------------------------------------- - // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not - // involved in dealing with emulator memory. But if it is called later, it will - // destroy the Emulator Memory. + // without calling FpgaDownloadAndGo the initial em4x50_chk call doesn't find + // a password (altough the correct password is in the dictionary) //----------------------------------------------------------------------------- FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - BigBuf_Clear_EM(); + BigBuf_free(); - // initialize passwords and get number of passwords - if (Flash_ReadData(*offset, counter, sizeof(counter)) != sizeof(counter)) - goto OUT; + int changed = rdv40_spiffs_lazy_mount(); + uint32_t size = size_in_spiffs((char *)filename); + pwd_count = size / 4; + uint8_t *pwds = BigBuf_malloc(size); - pwd_count = (uint16_t)(counter[1] << 8 | counter[0]); - if (pwd_count == 0) - goto OUT; + rdv40_spiffs_read_as_filetype((char *)filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE); + + if (changed) + rdv40_spiffs_lazy_unmount(); - pwd_size_available = 4 * pwd_count; - - isok = Flash_ReadData(*offset + 2, pwds, pwd_size_available); - if (isok != pwd_size_available) - goto OUT; - em4x50_setup_read(); // set gHigh and gLow @@ -975,8 +968,10 @@ void em4x50_chk(uint32_t *offset) { } } -OUT: - + BigBuf_free(); + +#endif + lf_finalize(); reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 342227e56..601f499f1 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -13,6 +13,8 @@ #include "fileutils.h" #include "commonutil.h" #include "pmflash.h" +#include "cmdflashmemspiffs.h" +#include "cmdparser.h" #define CARD_MEMORY_SIZE 4096 @@ -171,6 +173,7 @@ static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { } } + static int em4x50_wipe_flash(int page) { int isok = 0; @@ -193,6 +196,7 @@ static int em4x50_wipe_flash(int page) { return PM3_SUCCESS; } + static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { int isok = 0; @@ -448,19 +452,18 @@ int CmdEM4x50Brute(const char *Cmd) { int CmdEM4x50Chk(const char *Cmd) { - // upload passwords from given dictionary to flash memory and - // start password check; + // upload passwords from given dictionary to device and start check; // if no filename is given dictionary "t55xx_default_pwds.dic" is used int status = PM3_EFAILED; int res = 0, slen = 0; - int keys_remain = 0; - int block_count = 1; size_t datalen = 0; uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; uint8_t *keys = data; uint32_t key_count = 0, offset = 0; char filename[FILE_PATH_SIZE] = {0}; + uint8_t destfn[32] = "em4x50_chk.bin"; + PacketResponseNG resp; CLIParserContext *ctx; @@ -487,63 +490,26 @@ int CmdEM4x50Chk(const char *Cmd) { PrintAndLogEx(INFO, "treating file as T55xx keys"); } - res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &key_count); + res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); if (res || !key_count) return PM3_EFILE; PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); - - if (datalen > CARD_MEMORY_SIZE) { - // we have to use more than one block of passwords - block_count = (4 * key_count) / CARD_MEMORY_SIZE; - keys_remain = key_count - block_count * CARD_MEMORY_SIZE / 4; - - if (keys_remain != 0) - block_count++; - - // adjust pwd_size_available and pwd_count - datalen = CARD_MEMORY_SIZE; - key_count = datalen / 4; - - PrintAndLogEx(INFO, "Keys subdivided into %i blocks", block_count); - } - - for (int n = 0; n < block_count; n++) { - - // adjust parameters if more than 1 block - if (n != 0) { - - keys += datalen; - - // final run with remaining passwords - if (n == block_count - 1) { - key_count = keys_remain; - datalen = 4 * keys_remain; - } - } - - keys[0] = (key_count >> 0) & 0xFF; - keys[1] = (key_count >> 8) & 0xFF; - - PrintAndLogEx(INPLACE, "Checking block #%i (%i keys)", n + 1, key_count); - - // send to device - res = em4x50_write_flash(keys, offset, datalen + 2); + if (IfPm3Flash()) { + // upload to flash. + res = flashmem_spiffs_load(destfn, keys, datalen + 2); if (res != PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "Error uploading to flash."); + PrintAndLogEx(WARNING, "\nSPIFFS upload failed"); return res; } - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset)); - WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - - status = resp.status; - if ((status == PM3_SUCCESS) || (status == PM3_EOPABORTED)) - break; } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_CHK, destfn, sizeof(destfn)); + WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); + + status = resp.status; // print response if (status == PM3_SUCCESS) { From 0e28c60fd05665fec27aeb310a9faabf8fee5a57 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 4 Dec 2020 22:42:54 +0100 Subject: [PATCH 128/174] additional message --- client/src/cmdlfem4x50.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 601f499f1..4da4fbeb2 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -500,9 +500,12 @@ int CmdEM4x50Chk(const char *Cmd) { // upload to flash. res = flashmem_spiffs_load(destfn, keys, datalen + 2); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "\nSPIFFS upload failed"); + PrintAndLogEx(WARNING, "SPIFFS upload failed"); return res; } + } else { + PrintAndLogEx(WARNING, "no flash memory available"); + return PM3_EFLASH; } clearCommandBuffer(); From ba963e1187390a6ca6713800e5155c84db7d0d19 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 4 Dec 2020 22:51:54 +0100 Subject: [PATCH 129/174] update --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c90152ed..6236e4ee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,14 @@ 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] - - EM4x50: new function 4x50_reset: reset tag (@tharexde) - EM4x50: new function 4x50_login: authenticate against tag (@tharexde) - EM4x50: new function 4x50_brute: guess password within a given password range (@tharexde) - EM4x50: new function 4x50_chk: guess password from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) - EM4x50: new function 4x50_reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) - EM4x50: new function 4x50_sim: simulate dump from file or flash (@tharexde) - - EM4x50: new function 4x50_restore: restore dump file (bin, eml, json) onto tag (via flash memory) (@tharexde) - - EM4x50: new function 4x50_esave: dump em4x50 content from flash memory to file (bin + eml + json) (@tharexde) - - EM4x50: new function 4x50_eload: upload em4x50 file content (bin, eml, json) to flash memory (@tharexde) + - EM4x50: new function 4x50_restore: restore dump file (bin, eml, json) onto tag (@tharexde) + - EM4x50: new function 4x50_esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde) + - EM4x50: new function 4x50_eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde) - EM4x50: added LED signals (@tharexde) - EM4x50: added json format for 4x50_dump (@tharexde) - EM4x50: relocated write requests in function 4x50_wipe from device to client (@tharexde) From 8fde0ba04745b7510ad5ea9c052af0318667007d Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 5 Dec 2020 23:44:18 +0100 Subject: [PATCH 130/174] relocated FpgaDownloadAndGo from em4x50_chk to appmain --- armsrc/appmain.c | 6 ++++++ armsrc/em4x50.c | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index bc1b59ea2..186f5a654 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1141,6 +1141,12 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_CHK: { + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it might + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); em4x50_chk((uint8_t *)packet->data.asBytes); break; } diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index e63d63a76..47e47e714 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -926,11 +926,6 @@ void em4x50_chk(uint8_t *filename) { uint32_t pwd = 0x0; #ifdef WITH_FLASH - //----------------------------------------------------------------------------- - // without calling FpgaDownloadAndGo the initial em4x50_chk call doesn't find - // a password (altough the correct password is in the dictionary) - //----------------------------------------------------------------------------- - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); BigBuf_free(); From 614ab55809826056d75649c0af7b27d27d411005 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 5 Dec 2020 17:47:03 -0500 Subject: [PATCH 131/174] Initial commit for em4x70 support. Initially I only have an em4x70 variant used for car transponders. Also known as the ID48. --- armsrc/Makefile | 7 + armsrc/appmain.c | 14 + armsrc/em4x70.c | 600 +++++++++++++++++++++++++++++++++++++++ armsrc/em4x70.h | 22 ++ client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdlf.c | 9 + client/src/cmdlfem.c | 2 + client/src/cmdlfem410x.c | 1 + client/src/cmdlfem4x70.c | 151 ++++++++++ client/src/cmdlfem4x70.h | 25 ++ client/src/cmdparser.c | 7 + client/src/cmdparser.h | 1 + common_arm/Makefile.hal | 3 + doc/commands.md | 1 + include/em4x70.h | 18 ++ include/pm3_cmd.h | 3 + 17 files changed, 866 insertions(+) create mode 100644 armsrc/em4x70.c create mode 100644 armsrc/em4x70.h create mode 100644 client/src/cmdlfem4x70.c create mode 100644 client/src/cmdlfem4x70.h create mode 100644 include/em4x70.h diff --git a/armsrc/Makefile b/armsrc/Makefile index f3caf6e22..46ba4f027 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -69,6 +69,12 @@ else SRC_EM4x50 = endif +ifneq (,$(findstring WITH_EM4x70,$(APP_CFLAGS))) + SRC_EM4x70 = em4x70.c +else + SRC_EM4x70 = +endif + ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS))) SRC_LCD = fonts.c LCD.c else @@ -106,6 +112,7 @@ THUMBSRC = start.c \ $(SRC_FPC) \ $(SRC_HITAG) \ $(SRC_EM4x50) \ + $(SRC_EM4x70) \ $(SRC_SPIFFS) \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e0178a8d7..596d50695 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -31,6 +31,7 @@ #include "hitag2.h" #include "hitagS.h" #include "em4x50.h" +#include "em4x70.h" #include "iclass.h" #include "legicrfsim.h" //#include "cryptorfsim.h" @@ -479,6 +480,12 @@ static void SendCapabilities(void) { #else capabilities.compiled_with_em4x50 = false; #endif +#ifdef WITH_EM4x70 + capabilities.compiled_with_em4x70 = true; +#else + capabilities.compiled_with_em4x70 = false; +#endif + #ifdef WITH_HFSNIFF capabilities.compiled_with_hfsniff = true; #else @@ -1120,6 +1127,13 @@ static void PacketReceived(PacketCommandNG *packet) { } #endif +#ifdef WITH_EM4x70 + case CMD_LF_EM4X70_INFO: { + em4x70_info((em4x70_data_t *)packet->data.asBytes); + break; + } +#endif + #ifdef WITH_ISO15693 case CMD_HF_ISO15693_ACQ_RAW_ADC: { AcquireRawAdcSamplesIso15693(); diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c new file mode 100644 index 000000000..c52fc1738 --- /dev/null +++ b/armsrc/em4x70.c @@ -0,0 +1,600 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 sirloins based on em4x50 +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency EM4170 commands +//----------------------------------------------------------------------------- + +#include "fpgaloader.h" +#include "ticks.h" +#include "dbprint.h" +#include "lfadc.h" +#include "commonutil.h" +#include "em4x70.h" +#include "appmain.h" // tear + +static em4x70_tag_t tag = { 0 }; + +// EM4170 requires a parity bit on commands, other variants do not. +static bool command_parity = true; + +#define EM4X70_T_TAG_QUARTER_PERIOD 8 +#define EM4X70_T_TAG_HALF_PERIOD 16 +#define EM4X70_T_TAG_THREE_QUARTER_PERIOD 24 +#define EM4X70_T_TAG_FULL_PERIOD 32 +#define EM4X70_T_TAG_TWA 128 // Write Access Time +#define EM4X70_T_TAG_DIV 224 // Divergency Time +#define EM4X70_T_TAG_AUTH 4224 // Authentication Time +#define EM4X70_T_TAG_WEE 3072 // EEPROM write Time +#define EM4X70_T_TAG_TWALB 128 // Write Access Time of Lock Bits + +#define EM4X70_T_WAITING_FOR_SNGLLIW 160 // Unsure + +#define TICKS_PER_FC 12 // 1 fc = 8us, 1.5us per tick = 12 ticks +#define EM4X70_MIN_AMPLITUDE 10 // Minimum difference between a high and low signal + +#define EM4X70_TAG_TOLERANCE 10 +#define EM4X70_TAG_WORD 48 + + +/** + * These IDs are from the EM4170 datasheet + * Some versions of the chip require a fourth + * (even) parity bit, others do not + */ +#define EM4X70_COMMAND_ID 0x01 +#define EM4X70_COMMAND_UM1 0x02 +#define EM4X70_COMMAND_AUTH 0x03 +#define EM4X70_COMMAND_PIN 0x04 +#define EM4X70_COMMAND_WRITE 0x05 +#define EM4X70_COMMAND_UM2 0x07 + +static uint8_t gHigh = 0; +static uint8_t gLow = 0; + +#define IS_HIGH(sample) (sample>gLow ? true : false) +#define IS_LOW(sample) (sample timeout_ticks) + + +static uint8_t bits2byte(uint8_t *bits, int length); +static void bits2bytes(uint8_t *bits, int length, uint8_t *out); +static int em4x70_receive(uint8_t *bits); +static bool find_listen_window(bool command); + +static void init_tag(void) { + memset(tag.data, 0x00, sizeof(tag.data)/sizeof(tag.data[0])); +} + +static void EM4170_setup_read(void) { + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // 50ms for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Steal this pin from the SSP (SPI communication channel with fpga) and + // use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); + + // Start the timer + StartTicks(); + + // Watchdog hit + WDT_HIT(); +} + +static bool get_signalproperties(void) { + + // calculate signal properties (mean amplitudes) from measured data: + // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow + bool signal_found = false; + int no_periods = 32, pct = 50, noise = 140; // pct originally 75, found 50 was working better for me + uint8_t sample_ref = 127; + uint8_t sample_max_mean = 0; + uint8_t sample_max[no_periods]; + uint32_t sample_max_sum = 0; + + memset(sample_max, 0x00, sizeof(sample_max)); + + // wait until signal/noise > 1 (max. 32 periods) + for (int i = 0; i < TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD * no_periods; i++) { + + // about 2 samples per bit period + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); + + if (AT91C_BASE_SSC->SSC_RHR > noise) { + signal_found = true; + break; + } + + } + + if (signal_found == false) + return false; + + // calculate mean maximum value of 32 periods, each period has a length of + // 3 single "full periods" to eliminate the influence of a listen window + for (int i = 0; i < no_periods; i++) { + + uint32_t start_ticks = GetTicks(); + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (GetTicks() - start_ticks < TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) { + + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + if (sample > sample_max[i]) + sample_max[i] = sample; + + } + + sample_max_sum += sample_max[i]; + } + + sample_max_mean = sample_max_sum / no_periods; + + // set global envelope variables + gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; + gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; + + // Basic sanity check + if(gHigh - gLow < EM4X70_MIN_AMPLITUDE) { + return false; + } + + Dbprintf("%s: gHigh %d gLow: %d", __func__, gHigh, gLow); + return true; +} + + + +/** + * record_liw + * + * prints the timing from 1->0->1... for LIW_TEST_LENGTH + * + */ +/*#define LIW_TEST_LENGTH 64 +static void record_liw(void) { + + uint32_t intervals[LIW_TEST_LENGTH]; + + uint8_t sample; + + // Count duration low, then duration high. + for(int count = 0; count < LIW_TEST_LENGTH-1; count+=2) { + + uint32_t start_ticks = GetTicks(); + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_LOW(sample)); + intervals[count] = GetTicks() - start_ticks; + + start_ticks = GetTicks(); + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_HIGH(sample)); + intervals[count+1] = GetTicks() - start_ticks; + } + + for(int count = 0; count < LIW_TEST_LENGTH-1; count+=2){ + Dbprintf("%d 0", intervals[count]/TICKS_PER_FC); + Dbprintf("%d 1", intervals[count+1]/TICKS_PER_FC); + } +}*/ + +/** + * get_pulse_length + * + * Times falling edge pulses + */ +static uint32_t get_pulse_length(void) { + + uint8_t sample; + uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + uint32_t start_ticks = GetTicks(); + timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + timeout = (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) + GetTicks(); + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + return GetTicks() - start_ticks; +} + +/** + * get_pulse_invert_length + * + * Times rising edge pules + * TODO: convert to single function with get_pulse_length() + */ +static uint32_t get_pulse_invert_length(void) { + + uint8_t sample; + uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + uint32_t start_ticks = GetTicks(); + timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + do { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + + if (IS_TIMEOUT(timeout)) + return 0; + + return GetTicks() - start_ticks; + +} + +static bool check_pulse_length(uint32_t pl, int length, int margin) { + // check if pulse length corresponds to given length + //Dbprintf("%s: pulse length %d vs %d", __func__, pl, length * TICKS_PER_FC); + return ((pl >= TICKS_PER_FC * (length - margin)) & (pl <= TICKS_PER_FC * (length + margin))); +} + +static void em4x70_send_bit(int bit) { + + // send single bit according to EM4170 application note and datasheet + + uint32_t start_ticks = GetTicks(); + + if (bit == 0) { + + // disable modulation (drop the field) for 4 cycles of carrier + LOW(GPIO_SSC_DOUT); + while (GetTicks() - start_ticks <= TICKS_PER_FC * 4); + + // enable modulation (activates the field) for remaining first + // half of bit period + HIGH(GPIO_SSC_DOUT); + while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); + + // disable modulation for second half of bit period + LOW(GPIO_SSC_DOUT); + while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + + } else { + + // bit = "1" means disable modulation for full bit period + LOW(GPIO_SSC_DOUT); + while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + } + +} + + +/** + * em4x70_send_command without parity + */ +static void em4170_send_command(uint8_t command) { + int parity = 0; + + for (int i = 0; i < 4; i++) { + int bit = (command >> (3 - i)) & 1; + em4x70_send_bit(bit); + parity ^= bit; + } + + if(command_parity) + em4x70_send_bit(parity); + +} + +static bool find_listen_window(bool command) { + + int cnt = 0; + while(cnt < EM4X70_T_WAITING_FOR_SNGLLIW) { + /* + 80 ( 64 + 16 ) + 80 ( 64 + 16 ) + Flip Polarity + 96 ( 64 + 32 ) + 64 ( 32 + 16 +16 )*/ + + if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) { + if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) { + if (check_pulse_length(get_pulse_length(), 96, EM4X70_TAG_TOLERANCE)) { + if (check_pulse_length(get_pulse_length(), 64, EM4X70_TAG_TOLERANCE)) { + if(command) { + /* Here we are after the 64 duration edge. + * em4170 says we need to wait about 48 RF clock cycles. + * depends on the delay between tag and us + * + * I've found between 4-5 quarter periods (32-40) works best + */ + WaitTicks(TICKS_PER_FC * 5 * EM4X70_T_TAG_QUARTER_PERIOD); + // Send RM Command + em4x70_send_bit(0); + em4x70_send_bit(0); + } + return true; + } + } + } + } + cnt++; + } + + return false; +} + +static void bits2bytes(uint8_t *bits, int length, uint8_t *out) { + + if(length%8 != 0) { + Dbprintf("Should have a multiple of 8 bits, was sent %d", length); + } + + int num_bytes = length / 8; // We should have a multiple of 8 here + + for(int i=1; i <= num_bytes; i++) { + out[num_bytes-i] = bits2byte(bits, 8); + bits+=8; + //Dbprintf("Read: %02X", out[num_bytes-i]); + } +} + +static uint8_t bits2byte(uint8_t *bits, int length) { + + // converts separate bits into a single "byte" + uint8_t byte = 0; + for (int i = 0; i < length; i++) { + + byte |= bits[i]; + + if (i != length - 1) + byte <<= 1; + } + + return byte; +} + +/*static void print_array(uint8_t *bits, int len) { + + if(len%8 != 0) { + Dbprintf("Should have a multiple of 8 bits, was sent %d", len); + } + + int num_bytes = len / 8; // We should have a multiple of 8 here + + uint8_t bytes[8]; + + for(int i=0;i speed up "lf search" process + return find_listen_window(false); +} + +static int em4x70_receive(uint8_t *bits) { + + bool bbitchange = false; + uint32_t pl; + int bit_pos = 0; + + // Set first bit to a 1 for starting off corectly + bits[0] = 1; + + bool foundheader = false; + + // Read out the header + // 12 Manchester 1's (may miss some during settle period) + // 4 Manchester 0's + + // Skip a few leading 1's as it could be noisy + WaitTicks(TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + + // wait until we get the transition from 1's to 0's which is 1.5 full windows + int pulse_count = 0; + while(pulse_count < 12){ + pl = get_pulse_invert_length(); + pulse_count++; + if(check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_TAG_TOLERANCE)) { + foundheader = true; + break; + } + } + + if(!foundheader) { + Dbprintf("Failed to find read header"); + return 0; + } + + // Skip next 3 0's, header check consumes the first 0 + for(int i = 0; i < 3; i++) { + get_pulse_invert_length(); + } + + // identify remaining bits based on pulse lengths + // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible + while (true) { + + bit_pos++; + pl = get_pulse_length(); + + if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + + // pulse length = 1 -> keep former bit value + bits[bit_pos] = bits[bit_pos - 1]; + + } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + + // pulse length = 1.5 -> decision on bit change + + if (bbitchange) { + + // if number of pulse lengths with 1.5 periods is even -> add bit + bits[bit_pos] = (bits[bit_pos - 1] == 1) ? 1 : 0; + + // pulse length of 1.5 changes bit value + bits[bit_pos + 1] = (bits[bit_pos] == 1) ? 0 : 1; + bit_pos++; + + // next time add only one bit + bbitchange = false; + + } else { + + bits[bit_pos] = (bits[bit_pos - 1] == 1) ? 0 : 1; + + // next time two bits have to be added + bbitchange = true; + } + + } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + + // pulse length of 2 means: adding 2 bits "01" + bits[bit_pos] = 0; + bits[bit_pos + 1] = 1; + bit_pos++; + + } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + // pulse length of 3 indicates listen window -> clear last + // bit (= 0) and return + return --bit_pos; + } + } + return bit_pos; + +} + +void em4x70_info(em4x70_data_t *etd) { + + uint8_t status = 0; + + // Support tags with and without command parity bits + command_parity = etd->parity; + + init_tag(); + EM4170_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_EM4X70_Tag()) { + // Read ID, UM1 and UM2 + status = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2(); + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, sizeof(tag.data)); +} diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h new file mode 100644 index 000000000..80fd977a9 --- /dev/null +++ b/armsrc/em4x70.h @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 sirloins +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency EM4x70 commands +//----------------------------------------------------------------------------- + +#ifndef EM4x70_H +#define EM4x70_H + +#include "../include/em4x70.h" + +typedef struct { + uint8_t data[32]; +} em4x70_tag_t; + +void em4x70_info(em4x70_data_t *etd); + +#endif /* EM4x70_H */ diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index b630bf5de..4ea7acf36 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -252,6 +252,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlfem410x.c ${PM3_ROOT}/client/src/cmdlfem4x05.c ${PM3_ROOT}/client/src/cmdlfem4x50.c + ${PM3_ROOT}/client/src/cmdlfem4x70.c ${PM3_ROOT}/client/src/cmdlffdxb.c ${PM3_ROOT}/client/src/cmdlfgallagher.c ${PM3_ROOT}/client/src/cmdlfguard.c diff --git a/client/Makefile b/client/Makefile index d577b0d25..9c624722c 100644 --- a/client/Makefile +++ b/client/Makefile @@ -493,6 +493,7 @@ SRCS = aiddesfire.c \ cmdlfem410x.c \ cmdlfem4x05.c \ cmdlfem4x50.c \ + cmdlfem4x70.c \ cmdlffdxb.c \ cmdlfguard.c \ cmdlfgallagher.c \ diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index cbecb8f87..89483bf00 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -31,6 +31,7 @@ #include "cmdlfem410x.h" // for em4x menu #include "cmdlfem4x05.h" // for em4x05 / 4x69 #include "cmdlfem4x50.h" // for em4x50 +#include "cmdlfem4x70.h" // for em4x70 #include "cmdlfhid.h" // for hid menu #include "cmdlfhitag.h" // for hitag menu #include "cmdlfidteck.h" // for idteck menu @@ -1370,6 +1371,14 @@ static bool CheckChipType(bool getDeviceData) { goto out; } + // check for em4x70 chips + if (detect_4x70_block()) { + PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x70")); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x70`") " commands"); + retval = true; + goto out; + } + PrintAndLogEx(NORMAL, "Couldn't identify a chipset"); out: save_restoreGB(GRAPH_RESTORE); diff --git a/client/src/cmdlfem.c b/client/src/cmdlfem.c index fbc7ac476..744a62e31 100644 --- a/client/src/cmdlfem.c +++ b/client/src/cmdlfem.c @@ -12,6 +12,7 @@ #include "cmdlfem410x.h" #include "cmdlfem4x05.h" #include "cmdlfem4x50.h" +#include "cmdlfem4x70.h" #include #include @@ -26,6 +27,7 @@ static command_t CommandTable[] = { {"410x", CmdLFEM410X, AlwaysAvailable, "EM 410x commands..."}, {"4x05", CmdLFEM4X05, AlwaysAvailable, "EM 4x05 commands..."}, {"4x50", CmdLFEM4X50, AlwaysAvailable, "EM 4x50 commands..."}, + {"4x70", CmdLFEM4X70, AlwaysAvailable, "EM 4x70 commands..."}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index ef35e95a0..c6437b931 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -10,6 +10,7 @@ #include "cmdlfem410x.h" #include "cmdlfem4x50.h" +#include "cmdlfem4x70.h" #include #include diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c new file mode 100644 index 000000000..4d67b82cd --- /dev/null +++ b/client/src/cmdlfem4x70.c @@ -0,0 +1,151 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 sirloins +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency EM4x70 commands +//----------------------------------------------------------------------------- + +#include "cmdlfem4x70.h" +#include +#include "cmdparser.h" // command_t +#include "fileutils.h" +#include "comms.h" +#include "commonutil.h" +#include "em4x70.h" + + +static int CmdHelp(const char *Cmd); + + +static int usage_lf_em4x70_info(void) { + PrintAndLogEx(NORMAL, "Read all information of EM4x70. Tag must be on antenna."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf em 4x70_info [h] [v] [p ]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " p - use even parity for commands"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x70_info")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x70_info p")); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + +static void print_info_result(uint8_t *data) { + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + + // data section + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, _YELLOW_("EM4x70 data:")); + + for(int i=1; i <= 32; i+=2) { + PrintAndLogEx(NORMAL, "%02X %02X", data[32-i], data[32-i-1]); + } + PrintAndLogEx(NORMAL, "Tag ID: %02X %02X %02X %02X", data[7], data[6], data[5], data[4]); + PrintAndLogEx(NORMAL, "Lockbit 0: %d", (data[3] & 0x40) ? 1:0); + PrintAndLogEx(NORMAL, "Lockbit 1: %d", (data[3] & 0x80) ? 1:0); + PrintAndLogEx(NORMAL, ""); + +} + +int em4x70_info(void) { + + em4x70_data_t edata = { + .parity = false // TODO: try both? or default to true + }; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_INFO, (uint8_t *)&edata, sizeof(edata)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "(em4x70) timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + return PM3_SUCCESS; + } + + return PM3_ESOFT; +} + +//quick test for EM4x70 tag +bool detect_4x70_block(void) { + + return em4x70_info() == PM3_SUCCESS; +} + +int CmdEM4x70Info(const char *Cmd) { + + // envoke reading of a EM4x70 tag which has to be on the antenna because + // decoding is done by the device (not on client side) + + bool errors = false; + uint8_t cmdp = 0; + + em4x70_data_t etd = {0}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + + case 'h': + return usage_lf_em4x70_info(); + + case 'p': + etd.parity = true; + cmdp +=1; + break; + + default: + PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + // validation + if (errors) + return usage_lf_em4x70_info(); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_INFO, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); + return PM3_ESOFT; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"info", CmdEM4x70Info, IfPm3EM4x70, "tag information EM4x70"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdLFEM4X70(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h new file mode 100644 index 000000000..a529678e7 --- /dev/null +++ b/client/src/cmdlfem4x70.h @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 sirloins +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency EM4x70 commands +//----------------------------------------------------------------------------- + +#ifndef CMDLFEM4X70_H__ +#define CMDLFEM4X70_H__ + +#include "common.h" +#include "em4x50.h" + +#define TIMEOUT 2000 + +int CmdLFEM4X70(const char *Cmd); +int CmdEM4x70Info(const char *Cmd); + +int em4x70_info(void); +bool detect_4x70_block(void); + +#endif diff --git a/client/src/cmdparser.c b/client/src/cmdparser.c index 2aee4af05..137f72dc7 100644 --- a/client/src/cmdparser.c +++ b/client/src/cmdparser.c @@ -101,6 +101,13 @@ bool IfPm3EM4x50(void) { return pm3_capabilities.compiled_with_em4x50; } +bool IfPm3EM4x70(void) { + + if (!IfPm3Present()) + return false; + return pm3_capabilities.compiled_with_em4x70; +} + bool IfPm3Hfsniff(void) { if (!IfPm3Present()) return false; diff --git a/client/src/cmdparser.h b/client/src/cmdparser.h index 4e1e37a77..ff59df705 100644 --- a/client/src/cmdparser.h +++ b/client/src/cmdparser.h @@ -35,6 +35,7 @@ bool IfPm3FpcUsartFromUsb(void); bool IfPm3Lf(void); bool IfPm3Hitag(void); bool IfPm3EM4x50(void); +bool IfPm3EM4x70(void); bool IfPm3Hfsniff(void); bool IfPm3Hfplot(void); bool IfPm3Iso14443a(void); diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index 40e0a2c51..24d31261e 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -105,6 +105,9 @@ endif ifneq ($(SKIP_EM4x50),1) PLATFORM_DEFS += -DWITH_EM4x50 endif +ifneq ($(SKIP_EM4x70),1) + PLATFORM_DEFS += -DWITH_EM4x70 +endif # common HF support ifneq ($(SKIP_ISO15693),1) diff --git a/doc/commands.md b/doc/commands.md index f496ef3fe..44489d546 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -580,6 +580,7 @@ Check column "offline" for their availability. |`lf em 410x `|Y |`EM 410x commands...` |`lf em 4x05 `|Y |`EM 4x05 commands...` |`lf em 4x50 `|Y |`EM 4x50 commands...` +|`lf em 4x70 `|Y |`EM 4x70 commands...` ### lf fdxb diff --git a/include/em4x70.h b/include/em4x70.h new file mode 100644 index 000000000..e54e09647 --- /dev/null +++ b/include/em4x70.h @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 sirloins +// +// 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. +//----------------------------------------------------------------------------- +// Low frequency EM4x70 structs +//----------------------------------------------------------------------------- + +#ifndef EM4X70_H__ +#define EM4X70_H__ + +typedef struct { + bool parity; +} PACKED em4x70_data_t; + +#endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 6acc1c1c5..d6a178a71 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -198,6 +198,7 @@ typedef struct { bool compiled_with_lf : 1; bool compiled_with_hitag : 1; bool compiled_with_em4x50 : 1; + bool compiled_with_em4x70 : 1; // hf bool compiled_with_hfsniff : 1; bool compiled_with_hfplot : 1; @@ -510,6 +511,8 @@ typedef struct { #define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242 #define CMD_LF_EM4X50_READ 0x0243 #define CMD_LF_EM4X50_WIPE 0x0244 +#define CMD_LF_EM4X70_INFO 0x0250 + // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 0a21f7dd8f959060549896ce9b0610118ebb84cd Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 5 Dec 2020 23:47:53 +0100 Subject: [PATCH 132/174] keys are copied blockwise via spiffs to device because of - flash memory limitation (big dictionaries) - user feedback (infos about progress) --- client/src/cmdlfem4x50.c | 48 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 4da4fbeb2..1c581c973 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -16,8 +16,6 @@ #include "cmdflashmemspiffs.h" #include "cmdparser.h" -#define CARD_MEMORY_SIZE 4096 - #define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) //============================================================================== @@ -456,13 +454,14 @@ int CmdEM4x50Chk(const char *Cmd) { // if no filename is given dictionary "t55xx_default_pwds.dic" is used int status = PM3_EFAILED; - int res = 0, slen = 0; + int keyblock = 2000; // block with 2000 bytes -> 500 keys + int res = 0, slen = 0, bytes_remaining = 0; size_t datalen = 0; uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; uint8_t *keys = data; - uint32_t key_count = 0, offset = 0; - char filename[FILE_PATH_SIZE] = {0}; + uint32_t key_count = 0; uint8_t destfn[32] = "em4x50_chk.bin"; + char filename[FILE_PATH_SIZE] = {0}; PacketResponseNG resp; @@ -486,7 +485,6 @@ int CmdEM4x50Chk(const char *Cmd) { // no filename -> default = t55xx_default_pwds if (strlen(filename) == 0) { snprintf(filename, sizeof(filename), "t55xx_default_pwds"); - offset = DEFAULT_T55XX_KEYS_OFFSET; PrintAndLogEx(INFO, "treating file as T55xx keys"); } @@ -496,24 +494,36 @@ int CmdEM4x50Chk(const char *Cmd) { PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); - if (IfPm3Flash()) { - // upload to flash. - res = flashmem_spiffs_load(destfn, keys, datalen + 2); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "SPIFFS upload failed"); - return res; - } - } else { + if (IfPm3Flash() == false) { PrintAndLogEx(WARNING, "no flash memory available"); return PM3_EFLASH; } - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_CHK, destfn, sizeof(destfn)); - WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - - status = resp.status; + bytes_remaining = datalen; + while (bytes_remaining > 0) { + + PrintAndLogEx(INPLACE, "Remaining keys: %i ", bytes_remaining / 4); + // upload to flash. + datalen = MIN(bytes_remaining, keyblock); + res = flashmem_spiffs_load(destfn, keys, datalen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "SPIFFS upload failed"); + return res; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X50_CHK, destfn, sizeof(destfn)); + WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); + + status = resp.status; + if ((status == PM3_SUCCESS) || (status == PM3_EOPABORTED)) + break; + + bytes_remaining -= keyblock; + keys += keyblock; + } + // print response if (status == PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); From 4ef311336c0bdfb45f84b6004958f64d352eae06 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sat, 5 Dec 2020 19:17:57 -0500 Subject: [PATCH 133/174] hf topaz - now use cliparser --- client/src/cmdhftopaz.c | 80 ++++++++++++++++++++++++++++++++++++----- doc/cliparser_todo.txt | 8 ++--- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index a64071c97..ba150cb71 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -14,6 +14,7 @@ #include #include #include +#include "cliparser.h" #include "cmdparser.h" // command_t #include "comms.h" #include "cmdtrace.h" @@ -393,21 +394,42 @@ static int topaz_print_NDEF(uint8_t *data, size_t maxsize) { } static int CmdHFTopazReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf topaz reader", + "Read UID from Topaz tags", + "hf topaz reader"); - bool verbose = true; - char ctmp = tolower(param_getchar(Cmd, 0)); - if (ctmp == 's') verbose = false; + void *argtable[] = { + arg_param_begin, + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool verbose = arg_get_lit(ctx, 1); + + CLIParserFree(ctx); return readTopazUid(verbose); } // read a Topaz tag and print some useful information static int CmdHFTopazInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf topaz info", + "Get info from Topaz tags", + "hf topaz info"); - bool verbose = true; - char ctmp = tolower(param_getchar(Cmd, 0)); - if (ctmp == 's') verbose = false; + void *argtable[] = { + arg_param_begin, + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool verbose = arg_get_lit(ctx, 1); + + CLIParserFree(ctx); int status = readTopazUid(verbose); if (status != PM3_SUCCESS) @@ -469,13 +491,34 @@ static int CmdHFTopazInfo(const char *Cmd) { } static int CmdHFTopazSim(const char *Cmd) { - (void)Cmd; // Cmd is not used so far + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf topaz sim", + "Simulate a Topaz tag", + "hf topaz sim <- Not yet implemented"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PrintAndLogEx(INFO, "not yet implemented"); return PM3_SUCCESS; } static int CmdHFTopazCmdRaw(const char *Cmd) { - (void)Cmd; // Cmd is not used so far + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf topaz raw", + "Send raw hex data to Topaz tags", + "hf topaz raw <- Not yet implemented"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + PrintAndLogEx(INFO, "not yet implemented. Use hf 14 raw with option -T."); return PM3_SUCCESS; } @@ -490,6 +533,25 @@ static int CmdHFTopazList(const char *Cmd) { return CmdTraceList(args); } +static int CmdHFTopazSniff(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf topaz sniff", + "Sniff Topaz reader-tag communication", + "hf topaz sniff"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + uint8_t param = 0; + SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)¶m, sizeof(uint8_t)); + + return PM3_SUCCESS; +} + static int CmdHelp(const char *Cmd); static command_t CommandTable[] = { @@ -498,7 +560,7 @@ static command_t CommandTable[] = { {"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"}, {"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"}, {"sim", CmdHFTopazSim, IfPm3Iso14443a, " -- Simulate Topaz tag"}, - {"sniff", CmdHF14ASniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"}, + {"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"}, {"raw", CmdHFTopazCmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} }; diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 4e1dc76cd..8dd9d65e2 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -143,11 +143,6 @@ hf mfdes getuid hf mfdes info hf thinfilm info hf thinfilm sim -hf topaz info -hf topaz reader -hf topaz sim -hf topaz sniff -hf topaz raw hw connect hw dbg hw detectreader @@ -174,11 +169,14 @@ lf simfsk lf simpsk lf simbidir lf sniff +lf tune lf em 410x lf em 4x05 lf em 4x50 +lf hitag info lf hitag reader lf hitag sim +lf hitag sniff lf hitag writer lf hitag dump lf hitag cc From 6427958e6189b43b6101a2f17fa47624369f9f83 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sat, 5 Dec 2020 19:35:52 -0500 Subject: [PATCH 134/174] hf thinfilm - now use cliparser --- client/src/cmdhfthinfilm.c | 106 ++++++++++++------------------------- doc/cliparser_todo.txt | 5 +- 2 files changed, 38 insertions(+), 73 deletions(-) diff --git a/client/src/cmdhfthinfilm.c b/client/src/cmdhfthinfilm.c index 34001be44..9f7f21912 100644 --- a/client/src/cmdhfthinfilm.c +++ b/client/src/cmdhfthinfilm.c @@ -12,7 +12,7 @@ #include #include #include - +#include "cliparser.h" #include "cmdparser.h" // command_t #include "comms.h" #include "cmdtrace.h" @@ -22,28 +22,6 @@ static int CmdHelp(const char *Cmd); -static int usage_thinfilm_info(void) { - PrintAndLogEx(NORMAL, "Usage: hf thinfilm info [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf thinfilm info"); - return PM3_SUCCESS; -} - -static int usage_thinfilm_sim(void) { - PrintAndLogEx(NORMAL, "Usage: hf thinfilm sim [h] [d ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " d bytes to send, in hex"); - PrintAndLogEx(NORMAL, " r raw, provided bytes should include CRC"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf thinfilm sim d B70470726f786d61726b2e636f6d"); - return PM3_SUCCESS; -} - // Printing function based upon the code in libnfc // ref // https://github.com/nfc-tools/libnfc/blob/master/utils/nfc-barcode.c @@ -119,25 +97,16 @@ static int print_barcode(uint8_t *barcode, const size_t barcode_len, bool verbos } static int CmdHfThinFilmInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf thinfilm info", + "Get info from Thinfilm tags", + "hf thinfilm info"); - uint8_t cmdp = 0; - bool errors = false; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_thinfilm_info(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors) { - usage_thinfilm_info(); - return PM3_EINVARG; - } + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); return infoThinFilm(true); } @@ -168,45 +137,40 @@ int infoThinFilm(bool verbose) { } static int CmdHfThinFilmSim(const char *Cmd) { - uint8_t cmdp = 0; - uint8_t data[512]; - int datalen = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf thinfilm sim", + "Simulate Thinfilm tag", + "hf thinfilm sim -d B70470726f786d61726b2e636f6d"); + + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "bytes to send"), + arg_lit0(NULL, "raw", "raw, provided bytes should include CRC"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int data_len = 0; + uint8_t data[512] = {0}; + CLIGetHexWithReturn(ctx, 1, data, &data_len); bool addcrc = true; - bool errors = false; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_thinfilm_sim(); - case 'd': - // Retrieve the data - param_gethex_ex(Cmd, cmdp + 1, data, &datalen); - datalen >>= 1; - cmdp += 2; - break; - case 'r': - addcrc = false; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + if (arg_get_lit(ctx, 2)) { + addcrc = false; } - //Validations - if (errors || cmdp == 0 || datalen == 0 || datalen > 512) return usage_thinfilm_sim(); - if (addcrc && datalen <= 510) { + CLIParserFree(ctx); + + if (addcrc && data_len <= 510) { uint8_t b1, b2; - compute_crc(CRC_14443_A, data, datalen, &b1, &b2); - data[datalen++] = b2; - data[datalen++] = b1; + compute_crc(CRC_14443_A, data, data_len, &b1, &b2); + data[data_len++] = b2; + data[data_len++] = b1; } clearCommandBuffer(); - SendCommandNG(CMD_HF_THINFILM_SIMULATE, (uint8_t *)&data, datalen); + SendCommandNG(CMD_HF_THINFILM_SIMULATE, (uint8_t *)&data, data_len); PacketResponseNG resp; PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 4e1dc76cd..9eac6d12e 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -141,8 +141,6 @@ hf mfu otptear hf mfdes enum hf mfdes getuid hf mfdes info -hf thinfilm info -hf thinfilm sim hf topaz info hf topaz reader hf topaz sim @@ -174,11 +172,14 @@ lf simfsk lf simpsk lf simbidir lf sniff +lf tune lf em 410x lf em 4x05 lf em 4x50 +lf hitag info lf hitag reader lf hitag sim +lf hitag sniff lf hitag writer lf hitag dump lf hitag cc From d5347ced4e15e20c70795e53a46669de88edc373 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 01:48:41 +0100 Subject: [PATCH 135/174] filename in spiffs is now a parameter of em4x50_sim --- armsrc/appmain.c | 8 +++++++- armsrc/em4x50.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 186f5a654..d4893359a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1123,7 +1123,13 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_EM4X50_SIM: { - em4x50_sim(); + //----------------------------------------------------------------------------- + // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not + // involved in dealing with emulator memory. But if it is called later, it might + // destroy the Emulator Memory. + //----------------------------------------------------------------------------- + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + em4x50_sim((uint8_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_READER: { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 33c18e794..12f0a64d8 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -24,7 +24,7 @@ void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_sim(void); +void em4x50_sim(uint8_t *filename); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); From 314450b73874fbc6c0237e867dd1d9bff386696e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 01:53:43 +0100 Subject: [PATCH 136/174] transferring data of dump file to device via - em4x50_eload or - file option "-f ": - via spiffs if flash memory is available - via emulator memory if flash memory is not available --- armsrc/em4x50.c | 44 +++++++++------ client/src/cmdlfem4x50.c | 112 ++++++++------------------------------- 2 files changed, 51 insertions(+), 105 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 47e47e714..010e51a60 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -922,7 +922,6 @@ void em4x50_chk(uint8_t *filename) { // check passwords from dictionary content in flash memory int status = PM3_EFAILED; - uint16_t pwd_count = 0; uint32_t pwd = 0x0; #ifdef WITH_FLASH @@ -930,6 +929,7 @@ void em4x50_chk(uint8_t *filename) { BigBuf_free(); int changed = rdv40_spiffs_lazy_mount(); + uint16_t pwd_count = 0; uint32_t size = size_in_spiffs((char *)filename); pwd_count = size / 4; uint8_t *pwds = BigBuf_malloc(size); @@ -1304,29 +1304,41 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simulate functions //============================================================================== -void em4x50_sim(void) { +void em4x50_sim(uint8_t *filename) { - // simulate uploaded data in flash memory - // (currently only a one-way communication is possible) + // simulate uploaded data in emulator memory + // (currently simulation allows only a one-way communication) int status = PM3_SUCCESS; - uint8_t em4x50_mem[DUMP_FILESIZE] = {0x0}; + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; + +#ifdef WITH_FLASH - //----------------------------------------------------------------------------- - // Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not - // involved in dealing with emulator memory. But if it is called later, it will - // destroy the Emulator Memory. - //----------------------------------------------------------------------------- - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + if (strlen((char *)filename) != 0) { + + BigBuf_free(); + + int changed = rdv40_spiffs_lazy_mount(); + uint32_t size = size_in_spiffs((char *)filename); + em4x50_mem = BigBuf_malloc(size); + + rdv40_spiffs_read_as_filetype((char *)filename, em4x50_mem, size, RDV40_SPIFFS_SAFETY_SAFE); + + if (changed) + rdv40_spiffs_lazy_unmount(); + + Dbprintf("bin tatsächlich durchs #define gelaufen."); + } + +#endif - // read data from flash memory - Flash_ReadData(0, em4x50_mem, 4 * EM4X50_NO_WORDS); for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - em4x50_setup_sim(); - + for (int i = 0; i < EM4X50_NO_WORDS; i++) + Dbprintf("%i %08x", i, words[i]); + // only if valid em4x50 data (e.g. uid == serial) if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { @@ -1337,6 +1349,8 @@ void em4x50_sim(void) { int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + em4x50_setup_sim(); + while (!BUTTON_PRESS()) { WDT_HIT(); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 1c581c973..6c21efe40 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -171,74 +171,6 @@ static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { } } - -static int em4x50_wipe_flash(int page) { - - int isok = 0; - - clearCommandBuffer(); - SendCommandMIX(CMD_FLASHMEM_WIPE, page, false, 0, NULL, 0); - PacketResponseNG resp; - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) { - PrintAndLogEx(WARNING, "Timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - - isok = resp.oldarg[0] & 0xFF; - if (!isok) { - PrintAndLogEx(WARNING, "Flash error"); - return PM3_EFLASH; - } - - return PM3_SUCCESS; -} - - -static int em4x50_write_flash(uint8_t *data, int offset, size_t datalen) { - - int isok = 0; - uint32_t bytes_sent = 0; - uint32_t bytes_remaining = datalen; - uint32_t bytes_in_packet = 0; - PacketResponseNG resp; - - // wipe - em4x50_wipe_flash(0); - em4x50_wipe_flash(1); - em4x50_wipe_flash(2); - - // fast push mode - conn.block_after_ACK = true; - - while (bytes_remaining > 0) { - bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); - - clearCommandBuffer(); - SendCommandOLD(CMD_FLASHMEM_WRITE, offset + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); - - bytes_remaining -= bytes_in_packet; - bytes_sent += bytes_in_packet; - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - conn.block_after_ACK = false; - return PM3_ETIMEOUT; - } - - isok = resp.oldarg[0] & 0xFF; - if (!isok) { - conn.block_after_ACK = false; - PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); - return PM3_EFLASH; - } - } - - conn.block_after_ACK = false; - - return PM3_SUCCESS; -} - int CmdEM4x50ELoad(const char *Cmd) { int slen = 0; @@ -1210,16 +1142,18 @@ int CmdEM4x50Restore(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) { - int slen = 0, res = 0; + int slen = 0, status = 0; size_t bytes_read = 0; uint8_t data[DUMP_FILESIZE] = {0x0}; + uint8_t destfn[32] = {0}; + char filename[FILE_PATH_SIZE] = {0}; PacketResponseNG resp; CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50_sim", "Simulates a EM4x50 tag", - "lf em 4x50_sim -> simulates EM4x50 data in flash memory.\n" + "lf em 4x50_sim -> simulates EM4x50 data in memory (upload via em4x50_eload).\n" "lf em 4x50_sim -f mydump.eml -> simulates content of file ./mydump\n" ); @@ -1242,36 +1176,34 @@ int CmdEM4x50Sim(const char *Cmd) { return PM3_EFILE; } - if (bytes_read * 8 > FLASH_MEM_MAX_SIZE) { - PrintAndLogEx(FAILED, "Filesize is larger than available memory"); - return PM3_EOVFLOW; - } - - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to flash memory", filename); - - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error wiping flash."); - return res; - } + PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to davice", filename); // upload to device - res = em4x50_write_flash(data, 0, bytes_read); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Error uploading to flash."); - return res; + if (IfPm3Flash()) { + sprintf((char *)destfn, "em4x50_sim.bin"); + status = flashmem_spiffs_load(destfn, data, DUMP_FILESIZE); + if (status != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "SPIFFS upload failed"); + return status; + } + } else { + em4x50_seteml(data, 0, DUMP_FILESIZE); } + + PrintAndLogEx(INFO, "Simulating data from " _YELLOW_("%s"), filename); + } else { + PrintAndLogEx(INFO, "Simulating data from emulator memory"); } - PrintAndLogEx(INFO, "Simulating data in " _YELLOW_("%s"), filename); - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); + SendCommandNG(CMD_LF_EM4X50_SIM, destfn, sizeof(destfn)); WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - if (resp.status == PM3_SUCCESS) + status = resp.status; + if (status == PM3_SUCCESS) PrintAndLogEx(INFO, "Done"); else - PrintAndLogEx(FAILED, "No valid em4x50 data in flash memory."); + PrintAndLogEx(FAILED, "No valid em4x50 data in memory."); return resp.status; } From f5135829670a5d7fcd5f3897fb6a3eb2f097fadf Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 01:58:07 +0100 Subject: [PATCH 137/174] removed debug output --- armsrc/em4x50.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 010e51a60..ddd0a159c 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1335,9 +1335,6 @@ void em4x50_sim(uint8_t *filename) { for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - - for (int i = 0; i < EM4X50_NO_WORDS; i++) - Dbprintf("%i %08x", i, words[i]); // only if valid em4x50 data (e.g. uid == serial) if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { From ce83a1cb5f3d18e0c97f6ec8de02780289ffce51 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 12:27:01 +0100 Subject: [PATCH 138/174] textual --- armsrc/em4x50.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ddd0a159c..d03e52661 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -1327,8 +1327,6 @@ void em4x50_sim(uint8_t *filename) { if (changed) rdv40_spiffs_lazy_unmount(); - - Dbprintf("bin tatsächlich durchs #define gelaufen."); } #endif From 136339898a3b535938e853cc89b4a4e6abb81cd0 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 19:26:20 +0100 Subject: [PATCH 139/174] block number to be wiped first has to be dynamic --- client/src/cmdlfem4x50.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 6c21efe40..5b9ad5796 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1042,6 +1042,7 @@ int CmdEM4x50Wipe(const char *Cmd) { int CmdEM4x50Restore(const char *Cmd) { int uidLen = 0, fnLen = 0, pwdLen = 0, status = 0; + int startblock = EM4X50_CONTROL + 1; uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; uint8_t data[DUMP_FILESIZE] = {0x0}; size_t bytes_read = 0; @@ -1095,6 +1096,8 @@ int CmdEM4x50Restore(const char *Cmd) { } else { etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; + // if password is available protection and control word can be restored + startblock = EM4X50_PROTECTION; } } @@ -1106,7 +1109,7 @@ int CmdEM4x50Restore(const char *Cmd) { if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; - for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { + for (int i = startblock; i < EM4X50_DEVICE_SERIAL; i++) { PrintAndLogEx(INPLACE, "Restoring block %i", i); From 1a173f69f9d286603a6990366873a4a021421f2d Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 20:13:51 +0100 Subject: [PATCH 140/174] cleanup --- armsrc/em4x50.c | 2 +- include/em4x50.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index d03e52661..9797ea057 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -15,7 +15,7 @@ #include "lfdemod.h" #include "commonutil.h" #include "em4x50.h" -#include "flashmem.h" +//#include "flashmem.h" #include "BigBuf.h" #include "spiffs.h" #include "appmain.h" // tear diff --git a/include/em4x50.h b/include/em4x50.h index a4c3cacd3..573c58375 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -34,12 +34,7 @@ #define LAST_WORD_WRITE_INHIBITED 3 // fourth byte // misc -#define STATUS_NO_WORDS 0xfc -#define STATUS_SUCCESS 0x2 -#define STATUS_LOGIN 0x1 -#define NO_CHARS_MAX 400 #define TIMEOUT 2000 -#define RESTORE_DEFAULT_FILENAME "lf-4x50restore.bin" #define DUMP_FILESIZE 136 typedef struct { From e4d0bfecedbc428ed41cad30eccba8b1849a896e Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 23:00:26 +0100 Subject: [PATCH 141/174] added missing commands for new "lf em" command structure --- client/src/cmdlfem4x50.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 24de8787f..1eb14252c 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1217,16 +1217,25 @@ int CmdEM4x50Sim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, - {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, - {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"}, - {"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, - {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, + {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, + {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, + {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, + {"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, + {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, + {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, + {"login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, + {"restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, + {"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, + {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, + {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, + {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, + {"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {NULL, NULL, NULL, NULL} }; + static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); From 0ba4394532db293b7006206093b4c1a00b3401ec Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 23:08:43 +0100 Subject: [PATCH 142/174] cleanup --- armsrc/em4x50.c | 33 --------------------------------- client/src/cmdlfem4x50.c | 26 +------------------------- 2 files changed, 1 insertion(+), 58 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 9797ea057..f63c03bbc 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -15,7 +15,6 @@ #include "lfdemod.h" #include "commonutil.h" #include "em4x50.h" -//#include "flashmem.h" #include "BigBuf.h" #include "spiffs.h" #include "appmain.h" // tear @@ -56,10 +55,6 @@ int gHigh = 190; int gLow = 60; -//============================================================================== -// auxiliary functions -//============================================================================== - static void wait_timer(uint32_t period) { // do nothing for using timer0 @@ -177,10 +172,6 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } -//============================================================================== -// functions for "reader" use case -//============================================================================== - static bool get_signalproperties(void) { // calculate signal properties (mean amplitudes) from measured data: @@ -653,10 +644,6 @@ static int get_word_from_bitstream(uint32_t *data) { return PM3_EOPABORTED; } -//============================================================================== -// functions for "simulating" use case -//============================================================================== - static bool em4x50_sim_send_bit(uint8_t bit) { uint16_t check = 0; @@ -803,10 +790,6 @@ bool em4x50_sim_send_listen_window(void) { return true; } -//============================================================================== -// login functions -//============================================================================== - static bool login(uint32_t password) { // simple login to EM4x50, @@ -971,10 +954,6 @@ void em4x50_chk(uint8_t *filename) { reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); } -//============================================================================== -// reset functions -//============================================================================== - static int reset(void) { // resets EM4x50 tag (used by write function) @@ -995,10 +974,6 @@ static int reset(void) { return PM3_EFAILED; } -//============================================================================== -// read functions -//============================================================================== - static int standard_read(int *now, uint32_t *words) { // reads data that tag transmits when exposed to reader field @@ -1129,10 +1104,6 @@ void em4x50_reader(void) { reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } -//============================================================================== -// write functions -//============================================================================== - static int write(uint32_t word, uint32_t addresses) { // writes to specified @@ -1300,10 +1271,6 @@ void em4x50_writepwd(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITEPWD, status, 0, 0); } -//============================================================================== -// simulate functions -//============================================================================== - void em4x50_sim(uint8_t *filename) { // simulate uploaded data in emulator memory diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 1eb14252c..b397ece54 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -21,10 +21,6 @@ #define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) -//============================================================================== -// output functions -//============================================================================== - static int CmdHelp(const char *Cmd); static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { @@ -128,10 +124,6 @@ static void print_info_result(uint8_t *data) { PrintAndLogEx(NORMAL, ""); } -//============================================================================== -// file/memory functions -//============================================================================== - static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len, size_t *bytes_read) { // read data from dump file; file type is derived from file name extension @@ -271,10 +263,6 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_SUCCESS; } -//============================================================================== -// login functions -//============================================================================== - int CmdEM4x50Login(const char *Cmd) { int pwdLen = 0; @@ -479,10 +467,6 @@ int CmdEM4x50Chk(const char *Cmd) { return PM3_SUCCESS; } -//============================================================================== -// read functions -//============================================================================== - //quick test for EM4x50 tag bool detect_4x50_block(void) { em4x50_data_t etd = { @@ -803,10 +787,6 @@ int CmdEM4x50Dump(const char *Cmd) { return PM3_SUCCESS; } -//============================================================================== -// write functions -//============================================================================== - int CmdEM4x50Write(const char *Cmd) { // envoke writing a single word (32 bit) to a EM4x50 tag @@ -1144,10 +1124,6 @@ int CmdEM4x50Restore(const char *Cmd) { return PM3_SUCCESS; } -//============================================================================== -// simulate functions -//============================================================================== - int CmdEM4x50Sim(const char *Cmd) { int slen = 0, status = 0; @@ -1217,7 +1193,7 @@ int CmdEM4x50Sim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, From 12880aa419b010c90926cf4a745a1d936178c85d Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 23:14:41 +0100 Subject: [PATCH 143/174] help text adjustments regarding new command structure --- client/src/cmdlfem4x50.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index b397ece54..4c3a2c04b 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -176,11 +176,11 @@ int CmdEM4x50ELoad(const char *Cmd) { uint8_t data[DUMP_FILESIZE] = {0x0}; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_eload", + CLIParserInit(&ctx, "lf em 4x50 eload", "Loads EM4x50 tag dump into emulator memory on device.", - "lf em 4x50_eload -f mydump.bin -> uploads bin file ./mydump.bin\n" - "lf em 4x50_eload -f mydump.eml -> uploads eml file ./mydump.eml\n" - "lf em 4x50_eload -f mydump.json -> uploads json file ./mydump.json\n" + "lf em 4x50 eload -f mydump.bin -> uploads bin file ./mydump.bin\n" + "lf em 4x50 eload -f mydump.eml -> uploads eml file ./mydump.eml\n" + "lf em 4x50 eload -f mydump.json -> uploads json file ./mydump.json\n" ); void *argtable[] = { @@ -216,12 +216,12 @@ int CmdEM4x50ESave(const char *Cmd) { uint8_t data[DUMP_FILESIZE] = {0x0}; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_esave", + CLIParserInit(&ctx, "lf em 4x50 esave", "Saves bin/eml/json dump file of emulator memory.", - "lf em 4x50_esave -> use UID as filename\n" - "lf em 4x50_esave -f mydump.bin -> saves to bin file ./mydump.bin\n" - "lf em 4x50_esave -f mydump.eml -> saves to eml file ./mydump.eml\n" - "lf em 4x50_esave -f mydump.json -> saves to json file ./mydump.json\n" + "lf em 4x50 esave -> use UID as filename\n" + "lf em 4x50 esave -f mydump.bin -> saves to bin file ./mydump.bin\n" + "lf em 4x50 esave -f mydump.eml -> saves to eml file ./mydump.eml\n" + "lf em 4x50 esave -f mydump.json -> saves to json file ./mydump.json\n" ); void *argtable[] = { @@ -271,9 +271,9 @@ int CmdEM4x50Login(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_login", + CLIParserInit(&ctx, "lf em 4x50 login", "Login into EM4x50 tag.", - "lf em 4x50_login -p 12345678 -< login with password 12345678\n" + "lf em 4x50 login -p 12345678 -< login with password 12345678\n" ); void *argtable[] = { @@ -319,9 +319,9 @@ int CmdEM4x50Brute(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_brute", + CLIParserInit(&ctx, "lf em 4x50 brute", "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", - "lf em 4x50_brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" + "lf em 4x50 brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" ); void *argtable[] = { @@ -391,10 +391,10 @@ int CmdEM4x50Chk(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_chk", + CLIParserInit(&ctx, "lf em 4x50 chk", "Dictionary attack against EM4x50.", - "lf em 4x50_chk -> uses T55xx default dictionary\n" - "lf em 4x50_chk -f my.dic -> uses dictionary ./my.dic\n" + "lf em 4x50 chk -> uses T55xx default dictionary\n" + "lf em 4x50 chk -f my.dic -> uses dictionary ./my.dic\n" ); void *argtable[] = { @@ -540,10 +540,10 @@ int CmdEM4x50Read(const char *Cmd) { etd.pwd_given = false; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_read", + CLIParserInit(&ctx, "lf em 4x50 read", "Reads single EM4x50 block/word.", - "lf em 4x50_read -b 3 -> reads block 3\n" - "lf em 4x50_read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" + "lf em 4x50 read -b 3 -> reads block 3\n" + "lf em 4x50 read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" ); void *argtable[] = { @@ -591,10 +591,10 @@ int CmdEM4x50Info(const char *Cmd) { em4x50_data_t etd = {.pwd_given = false}; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_info", + CLIParserInit(&ctx, "lf em 4x50 info", "Tag information EM4x50.", - "lf em 4x50_info\n" - "lf em 4x50_info -p 12345678 -> uses password 0x12345678\n" + "lf em 4x50 info\n" + "lf em 4x50 info -p 12345678 -> uses password 0x12345678\n" ); void *argtable[] = { @@ -644,10 +644,10 @@ int CmdEM4x50Reader(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_reader", + CLIParserInit(&ctx, "lf em 4x50 reader", "Shows standard read data of EM4x50 tag.", - "lf em 4x50_reader\n" - "lf em 4x50_reader -@ -> continuous reader mode" + "lf em 4x50 reader\n" + "lf em 4x50 reader -@ -> continuous reader mode" ); void *argtable[] = { @@ -708,12 +708,12 @@ int CmdEM4x50Dump(const char *Cmd) { uint8_t data[DUMP_FILESIZE] = {0}; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_dump", + CLIParserInit(&ctx, "lf em 4x50 dump", "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", - "lf em 4x50_dump -> saves dump in lf-4x50--dump.bin/eml/json\n" - "lf em 4x50_dump -f mydump.eml -> saves dump in mydump.eml\n" - "lf em 4x50_dump -p 12345678\n" - "lf em 4x50_dump -f mydump.eml -p 12345678\n" + "lf em 4x50 dump -> saves dump in lf-4x50--dump.bin/eml/json\n" + "lf em 4x50 dump -f mydump.eml -> saves dump in mydump.eml\n" + "lf em 4x50 dump -p 12345678\n" + "lf em 4x50 dump -f mydump.eml -p 12345678\n" ); void *argtable[] = { @@ -798,10 +798,10 @@ int CmdEM4x50Write(const char *Cmd) { em4x50_data_t etd = {.pwd_given = false}; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_write", + CLIParserInit(&ctx, "lf em 4x50 write", "Writes single block/word to EM4x50 tag.", - "lf em 4x50_write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" - "lf em 4x50_write -b 3 -d 4f22e7ff -p 12345678\n" + "lf em 4x50 write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" + "lf em 4x50 write -b 3 -d 4f22e7ff -p 12345678\n" ); void *argtable[] = { @@ -883,9 +883,9 @@ int CmdEM4x50WritePwd(const char *Cmd) { em4x50_data_t etd; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_writepwd", + CLIParserInit(&ctx, "lf em 4x50 writepwd", "Writes EM4x50 password.", - "lf em 4x50_writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" + "lf em 4x50 writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" ); void *argtable[] = { @@ -950,9 +950,9 @@ int CmdEM4x50Wipe(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_wipe", + CLIParserInit(&ctx, "lf em 4x50 wipe", "Wipes EM4x50 tag.", - "lf em 4x50_wipe -p 12345678 -> wipes tag with password 0x12345678\n" + "lf em 4x50 wipe -p 12345678 -> wipes tag with password 0x12345678\n" ); void *argtable[] = { @@ -1037,12 +1037,12 @@ int CmdEM4x50Restore(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_restore", + CLIParserInit(&ctx, "lf em 4x50 restore", "Restores data from dumpfile onto a Em4x50 tag.", - "lf em 4x50_restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" - "lf em 4x50_restore -f mydump.eml -> uses mydump.eml\n" - "lf em 4x50_restore -u 1b5aff5c -p 12345678\n" - "lf em 4x50_restore -f mydump.eml -p 12345678\n" + "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" + "lf em 4x50 restore -f mydump.eml -> uses mydump.eml\n" + "lf em 4x50 restore -u 1b5aff5c -p 12345678\n" + "lf em 4x50 restore -f mydump.eml -p 12345678\n" ); void *argtable[] = { @@ -1135,10 +1135,10 @@ int CmdEM4x50Sim(const char *Cmd) { PacketResponseNG resp; CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50_sim", + CLIParserInit(&ctx, "lf em 4x50 sim", "Simulates a EM4x50 tag", - "lf em 4x50_sim -> simulates EM4x50 data in memory (upload via em4x50_eload).\n" - "lf em 4x50_sim -f mydump.eml -> simulates content of file ./mydump\n" + "lf em 4x50 sim -> simulates EM4x50 data in memory (upload via em4x50_eload).\n" + "lf em 4x50 sim -f mydump.eml -> simulates content of file ./mydump\n" ); void *argtable[] = { From d9194e5109a05a97483529221e8bcb2397574f89 Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 6 Dec 2020 23:18:19 +0100 Subject: [PATCH 144/174] update for EM4x50 --- CHANGELOG.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6236e4ee9..ef36f69b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,21 +3,21 @@ 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] - - EM4x50: new function 4x50_login: authenticate against tag (@tharexde) - - EM4x50: new function 4x50_brute: guess password within a given password range (@tharexde) - - EM4x50: new function 4x50_chk: guess password from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) - - EM4x50: new function 4x50_reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) - - EM4x50: new function 4x50_sim: simulate dump from file or flash (@tharexde) - - EM4x50: new function 4x50_restore: restore dump file (bin, eml, json) onto tag (@tharexde) - - EM4x50: new function 4x50_esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde) - - EM4x50: new function 4x50_eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde) + - EM4x50: changed cli parameter from w (word) to d (data) (@tharexde) + - EM4x50: new function 4x50 login: authenticate against tag (@tharexde) + - EM4x50: new function 4x50 brute: guess password within a given password range (@tharexde) + - EM4x50: new function 4x50 chk: try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) + - EM4x50: new function 4x50 reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) + - EM4x50: new function 4x50 sim: simulate dump from file or emulator/flash (@tharexde) + - EM4x50: new function 4x50 restore: restore dump file (bin, eml, json) onto tag (@tharexde) + - EM4x50: new function 4x50 esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde) + - EM4x50: new function 4x50 eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde) - EM4x50: added LED signals (@tharexde) - - EM4x50: added json format for 4x50_dump (@tharexde) - - EM4x50: relocated write requests in function 4x50_wipe from device to client (@tharexde) - - EM4x50: renamed 4x50_write_password to 4x50_writepwd (@tharexde) + - EM4x50: added json format for 4x50 dump (@tharexde) + - EM4x50: relocated write requests in function 4x50 wipe from device to client (@tharexde) + - EM4x50: renamed 4x50_write_password to 4x50 writepwd (@tharexde) - EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) - EM4x50: changed cli parameter from a (address) to b (block) (@tharexde) - - EM4x50: changed cli parameter from w (word) to d (data) (@tharexde) - EM4x50: switched to cliparser for all functions (@tharexde) - EM4x50: stabilized and accelerated tag detection (@tharexde) - EM4x50: removed global tag structure on device side (@tharexde) From 9ea6665a244b7ec5e2ab2ad2a110d20dc0ca48fe Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Mon, 7 Dec 2020 12:55:11 +0000 Subject: [PATCH 145/174] Fix issue #844 --- CHANGELOG.md | 4 +- client/luascripts/hf_mf_unbrick_baduid.lua | 125 +++++++++++++++++++++ client/src/cmdlft55xx.c | 5 +- 3 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 client/luascripts/hf_mf_unbrick_baduid.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index de0373163..39c602ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ 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] - - Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim + - Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re) + - Add script hf_mf_unbrick_baduid.lua to revive mifare cards with bad BCC (@cyberpunk-re) + - Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim (@cyberpunk-re) - Added `mf mfu sim t 7 n ` - MFU emulation now supports automatic exit after blocks read. (@cyberpunk-re) - Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33) - Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001) diff --git a/client/luascripts/hf_mf_unbrick_baduid.lua b/client/luascripts/hf_mf_unbrick_baduid.lua new file mode 100644 index 000000000..b96b8828e --- /dev/null +++ b/client/luascripts/hf_mf_unbrick_baduid.lua @@ -0,0 +1,125 @@ +local getopt = require('getopt') +local ansicolors = require('ansicolors') + +copyright = '' +author = 'cyberpunk-re' +version = 'v1.0.0' +desc = [[ +This script brings back to life a mifare UID modifiable card which has bad data written to block 0 or block 1, typically having a bad BCC (Block Check Character). It should workd on Mifare classic 1k/4k and Mifare Ultralight UID Modifiable and Direct write tags. +]] +example = [[ + -- target a Ultralight based card + 1. script run hf_mf_unbrick_baduid -u + +]] +usage = [[ +script run hf_mf_unbrick_baduid [-h] [-u] +]] +arguments = [[ + -h this help + -u unbrick UID Modifiable/Direct Write Ultralight tag with 7 bytes UID. +]] + +-- Helper functions borrowed from Iceman script hf_mf_magicrevive.lua + +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end + +local function cmdUltralight() + return { + [0] = 'hf 14a config b 2', + [1] = 'hf 14a raw -k -a 43', + [2] = 'hf 14a raw -c -a A2005380712A', + [3] = 'hf 14a raw -k -a -b 7 40', + [4] = 'hf 14a raw -k -a 43', + [5] = 'hf 14a raw -c -a A2010200D980', + [6] = 'hf 14a raw -k -a -b 7 40', + [7] = 'hf 14a raw -k -a 43', + [8] = 'hf 14a raw -c -a A2025B480000', + [9] = 'hf 14a config b 0', + } +end +local function cmdClassic() + return { + [0] = 'hf 14a raw -k -a -b 7 40', + [1] = 'hf 14a raw -k -a 43', + [2] = 'hf 14a raw -c -k -a A000', + [3] = 'hf 14a raw -c -k -a 01020304049802000000000000001001', + [4] = 'hf 14a raw -c -a 5000', + } +end +local function cmdRestoreST() + local arr = {} + for i = 0, 15 do + local blk = 3 + (4*i) + arr[i] = 'hf mf csetbl '..blk..' FFFFFFFFFFFFFF078000FFFFFFFFFFFF' + end + return arr +end +local function sendCmds( cmds ) + for i = 0, #cmds do + if cmds[i] then + print ( cmds[i] ) + core.console( cmds[i] ) + core.clearCommandBuffer() + end + end +end +--- +-- The main entry point +function main(args) + + local i + local cmds = {} + local isUltralight = false + + -- Read the parameters + for o, a in getopt.getopt(args, 'hu') do + if o == 'h' then return help() end + if o == 'u' then isUltralight = true end + end + + core.clearCommandBuffer() + + if isUltralight then + sendCmds ( cmdUltralight() ) + else + sendCmds( cmdClassic() ) + sendCmds( cmdRestoreST() ) + end +end + +main(args) diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 80c8eda4f..df00da6b1 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -739,6 +739,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { for (; i < 9; i++) { if (rates[i] == bitRate) { config.bitrate = i; + config.block0 = ((config.block0 & ~(0x1c0000)) | (i << 18)); break; } } @@ -789,6 +790,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { PrintAndLogEx(WARNING, "Unknown modulation '%s'", modulation); errors = true; } + config.block0 = ((config.block0 & ~(0x1f0000)) | (config.modulation << 12)); break; case 'i': if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) { @@ -822,6 +824,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { config.ST = true; cmdp += 1; } + config.block0 = ((config.block0 & ~(0x8)) | (config.ST << 3)); break; case 'r': errors = param_getdec(Cmd, cmdp + 1, &downlink_mode); @@ -843,8 +846,6 @@ static int CmdT55xxSetConfig(const char *Cmd) { if (gotconf) { SetConfigWithBlock0Ex(block0, config.offset, config.Q5); - } else { - config.block0 = 0; } return printConfiguration(config); From cc324b83ec3b78a959988d1bdd79eeaea549e472 Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Mon, 7 Dec 2020 13:49:35 +0000 Subject: [PATCH 146/174] Correction on CHANGELOG --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c602ad9..a6e8e76b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re) - - Add script hf_mf_unbrick_baduid.lua to revive mifare cards with bad BCC (@cyberpunk-re) - Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim (@cyberpunk-re) - Added `mf mfu sim t 7 n ` - MFU emulation now supports automatic exit after blocks read. (@cyberpunk-re) - Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33) From dcf7e52b01f5756b3cf0fc6010b0e8c8403d2c4d Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Mon, 7 Dec 2020 13:51:23 +0000 Subject: [PATCH 147/174] Remove lua script not belonging to this PR --- client/luascripts/hf_mf_unbrick_baduid.lua | 125 --------------------- 1 file changed, 125 deletions(-) delete mode 100644 client/luascripts/hf_mf_unbrick_baduid.lua diff --git a/client/luascripts/hf_mf_unbrick_baduid.lua b/client/luascripts/hf_mf_unbrick_baduid.lua deleted file mode 100644 index b96b8828e..000000000 --- a/client/luascripts/hf_mf_unbrick_baduid.lua +++ /dev/null @@ -1,125 +0,0 @@ -local getopt = require('getopt') -local ansicolors = require('ansicolors') - -copyright = '' -author = 'cyberpunk-re' -version = 'v1.0.0' -desc = [[ -This script brings back to life a mifare UID modifiable card which has bad data written to block 0 or block 1, typically having a bad BCC (Block Check Character). It should workd on Mifare classic 1k/4k and Mifare Ultralight UID Modifiable and Direct write tags. -]] -example = [[ - -- target a Ultralight based card - 1. script run hf_mf_unbrick_baduid -u - -]] -usage = [[ -script run hf_mf_unbrick_baduid [-h] [-u] -]] -arguments = [[ - -h this help - -u unbrick UID Modifiable/Direct Write Ultralight tag with 7 bytes UID. -]] - --- Helper functions borrowed from Iceman script hf_mf_magicrevive.lua - ---- --- A debug printout-function -local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print('###', args) - end -end ---- --- This is only meant to be used when errors occur -local function oops(err) - print('ERROR:', err) - core.clearCommandBuffer() - return nil, err -end ---- --- Usage help -local function help() - print(copyright) - print(author) - print(version) - print(desc) - print(ansicolors.cyan..'Usage'..ansicolors.reset) - print(usage) - print(ansicolors.cyan..'Arguments'..ansicolors.reset) - print(arguments) - print(ansicolors.cyan..'Example usage'..ansicolors.reset) - print(example) -end - -local function cmdUltralight() - return { - [0] = 'hf 14a config b 2', - [1] = 'hf 14a raw -k -a 43', - [2] = 'hf 14a raw -c -a A2005380712A', - [3] = 'hf 14a raw -k -a -b 7 40', - [4] = 'hf 14a raw -k -a 43', - [5] = 'hf 14a raw -c -a A2010200D980', - [6] = 'hf 14a raw -k -a -b 7 40', - [7] = 'hf 14a raw -k -a 43', - [8] = 'hf 14a raw -c -a A2025B480000', - [9] = 'hf 14a config b 0', - } -end -local function cmdClassic() - return { - [0] = 'hf 14a raw -k -a -b 7 40', - [1] = 'hf 14a raw -k -a 43', - [2] = 'hf 14a raw -c -k -a A000', - [3] = 'hf 14a raw -c -k -a 01020304049802000000000000001001', - [4] = 'hf 14a raw -c -a 5000', - } -end -local function cmdRestoreST() - local arr = {} - for i = 0, 15 do - local blk = 3 + (4*i) - arr[i] = 'hf mf csetbl '..blk..' FFFFFFFFFFFFFF078000FFFFFFFFFFFF' - end - return arr -end -local function sendCmds( cmds ) - for i = 0, #cmds do - if cmds[i] then - print ( cmds[i] ) - core.console( cmds[i] ) - core.clearCommandBuffer() - end - end -end ---- --- The main entry point -function main(args) - - local i - local cmds = {} - local isUltralight = false - - -- Read the parameters - for o, a in getopt.getopt(args, 'hu') do - if o == 'h' then return help() end - if o == 'u' then isUltralight = true end - end - - core.clearCommandBuffer() - - if isUltralight then - sendCmds ( cmdUltralight() ) - else - sendCmds( cmdClassic() ) - sendCmds( cmdRestoreST() ) - end -end - -main(args) From b0ff0ed526dfc8fb76b701d8dd91fcee4ac556c8 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Mon, 7 Dec 2020 11:18:00 -0500 Subject: [PATCH 148/174] Fix bug with manchester receive function. Using suggested algorithm from em4x70 datasheet --- armsrc/em4x70.c | 60 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index c52fc1738..c2f320df9 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -488,12 +488,10 @@ static bool find_EM4X70_Tag(void) { static int em4x70_receive(uint8_t *bits) { - bool bbitchange = false; uint32_t pl; int bit_pos = 0; + uint8_t edge = 0; - // Set first bit to a 1 for starting off corectly - bits[0] = 1; bool foundheader = false; @@ -529,48 +527,44 @@ static int em4x70_receive(uint8_t *bits) { // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible while (true) { - bit_pos++; - pl = get_pulse_length(); + if(edge) + pl = get_pulse_length(); + else + pl = get_pulse_invert_length(); if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { - // pulse length = 1 -> keep former bit value - bits[bit_pos] = bits[bit_pos - 1]; + // pulse length = 1 + bits[bit_pos++] = edge; } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { - // pulse length = 1.5 -> decision on bit change - - if (bbitchange) { - - // if number of pulse lengths with 1.5 periods is even -> add bit - bits[bit_pos] = (bits[bit_pos - 1] == 1) ? 1 : 0; - - // pulse length of 1.5 changes bit value - bits[bit_pos + 1] = (bits[bit_pos] == 1) ? 0 : 1; - bit_pos++; - - // next time add only one bit - bbitchange = false; - + // pulse length = 1.5 -> flip edge detection + if(edge) { + bits[bit_pos++] = 0; + bits[bit_pos++] = 0; + edge = 0; } else { - - bits[bit_pos] = (bits[bit_pos - 1] == 1) ? 0 : 1; - - // next time two bits have to be added - bbitchange = true; + bits[bit_pos++] = 1; + bits[bit_pos++] = 1; + edge = 1; } } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { - // pulse length of 2 means: adding 2 bits "01" - bits[bit_pos] = 0; - bits[bit_pos + 1] = 1; - bit_pos++; + // pulse length of 2 + if(edge) { + bits[bit_pos++] = 0; + bits[bit_pos++] = 1; + } else { + bits[bit_pos++] = 1; + bits[bit_pos++] = 0; + } - } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { - // pulse length of 3 indicates listen window -> clear last - // bit (= 0) and return + } else if ( (edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) || + (!edge && check_pulse_length(pl, 80, EM4X70_T_TAG_QUARTER_PERIOD))) { + + // LIW detected (either invert or normal) return --bit_pos; } } From d63d359c14912a4b941168e8225cf662935c74af Mon Sep 17 00:00:00 2001 From: tharexde Date: Mon, 7 Dec 2020 20:31:27 +0100 Subject: [PATCH 149/174] fixed initialization (memset instead of memcpy) --- armsrc/em4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index f63c03bbc..620083a32 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -183,7 +183,7 @@ static bool get_signalproperties(void) { uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; uint32_t sample_max_sum = 0; - memcpy(sample_max, 0x00, sizeof(sample_max)); + memset(sample_max, 0x00, sizeof(sample_max)); LED_A_ON(); From 00cff49f9d985cfe1fa8691ff5ddf10c8c19bdce Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Mon, 7 Dec 2020 23:33:58 +0000 Subject: [PATCH 150/174] fixed incorrect bitmask on modulation --- client/src/cmdlft55xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index df00da6b1..9eed344d7 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -790,7 +790,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { PrintAndLogEx(WARNING, "Unknown modulation '%s'", modulation); errors = true; } - config.block0 = ((config.block0 & ~(0x1f0000)) | (config.modulation << 12)); + config.block0 = ((config.block0 & ~(0x1f000)) | (config.modulation << 12)); break; case 'i': if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) { From 2c4f7cad705250937a12e082e86a4b96d61f275d Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 8 Dec 2020 09:35:30 -0500 Subject: [PATCH 151/174] fix missing newline in iclass restore helptext --- client/src/cmdhficlass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index cd6017c8a..d884e7184 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1696,7 +1696,7 @@ static int CmdHFiClassRestore(const char *Cmd) { CLIParserInit(&ctx, "hf iclass restore", "Restore data from dumpfile onto a iCLASS tag", "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0\n" - "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite" + "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite\n" "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite\n" ); From ed031d9bd182a85db8f036ac7d7155b40659b45a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 8 Dec 2020 20:10:45 +0100 Subject: [PATCH 152/174] MAD SIO added --- client/resources/mad.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/resources/mad.json b/client/resources/mad.json index 535407ab4..d5c413d73 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -4066,6 +4066,13 @@ "service_provider": "PAYCULT", "system_integrator": "PAYCULT" }, + { + "application": "Access Control (SIO)", + "company": "HID Global", + "mad": "0x3D01", + "service_provider": "HID Corporation", + "system_integrator": "HID Corporation" + }, { "application": "City transport bus, ferry, administration", "company": "VFJ Technology Pty Ltd", From b83cbe8212a74107875b403d91dfc0d1ae21a102 Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 8 Dec 2020 20:20:49 +0100 Subject: [PATCH 153/174] fixed Appveyor complaint --- client/src/cmdlfem4x50.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 4c3a2c04b..6327f600d 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -238,7 +238,6 @@ int CmdEM4x50ESave(const char *Cmd) { PrintAndLogEx(SUCCESS, "Reading emulator memory..."); if (!GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); - free(data); return PM3_ETIMEOUT; } From 64dd8614d8f54d109b9c171c929b1751a6f3a422 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 8 Dec 2020 14:36:23 -0500 Subject: [PATCH 154/174] Remove unused cmflfem4x70 header from cmlfem410x.c --- client/src/cmdlfem410x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index c6437b931..ef35e95a0 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -10,7 +10,6 @@ #include "cmdlfem410x.h" #include "cmdlfem4x50.h" -#include "cmdlfem4x70.h" #include #include From be3af8d32c83898c26947a58e31ec615fda83f5d Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 8 Dec 2020 14:38:47 -0500 Subject: [PATCH 155/174] Fix command help spacing/order for em4x70 --- client/src/cmdlfem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem.c b/client/src/cmdlfem.c index 336a5a858..7ad0da3dc 100644 --- a/client/src/cmdlfem.c +++ b/client/src/cmdlfem.c @@ -27,7 +27,7 @@ static command_t CommandTable[] = { {"410x", CmdLFEM410X, AlwaysAvailable, "EM 4102 commands..."}, {"4x05", CmdLFEM4X05, AlwaysAvailable, "EM 4205 / 4305 / 4369 / 4469 commands..."}, {"4x50", CmdLFEM4X50, AlwaysAvailable, "EM 4350 / 4450 commands..."}, - {"4x70", CmdLFEM4X70, AlwaysAvailable, "EM 4170 /4070 commands..."}, + {"4x70", CmdLFEM4X70, AlwaysAvailable, "EM 4070 / 4170 commands..."}, {NULL, NULL, NULL, NULL} }; From a9dd75510b885448a6e7a6b2a2808493a45d0877 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 8 Dec 2020 16:40:24 -0500 Subject: [PATCH 156/174] Remove packed attribute on em4x70_data_t struct that only has one entry --- include/em4x70.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/em4x70.h b/include/em4x70.h index e54e09647..503b5f2e8 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -13,6 +13,6 @@ typedef struct { bool parity; -} PACKED em4x70_data_t; +} em4x70_data_t; #endif /* EM4X70_H__ */ From b52d50d30a8af37ad46180b54b11456841b83f1c Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Tue, 8 Dec 2020 22:54:29 +0000 Subject: [PATCH 157/174] Block0 source explicit in lf t55xx config and color coded --- client/src/cmdlft55xx.c | 28 +++++++++++++++++++++++++++- client/src/cmdlft55xx.h | 7 +++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 9eed344d7..40cc0be5a 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -51,6 +51,7 @@ t55xx_conf_block_t config = { .inverted = false, .offset = 0x00, .block0 = 0x00, + .block0Status = notSet, .Q5 = false, .usepwd = false, .downlink_mode = refFixedBit @@ -844,6 +845,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { //Validations if (errors) return usage_t55xx_config(); + config.block0Status = userSet; if (gotconf) { SetConfigWithBlock0Ex(block0, config.offset, config.Q5); } @@ -1336,6 +1338,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32 config.pwd = pwd & 0xffffffff; } + config.block0Status = autoDetect; if (print_config) printConfiguration(config); @@ -1371,6 +1374,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32 PrintAndLogEx(NORMAL, "--[%d]---------------", i + 1); } + config.block0Status = autoDetect; if (print_config) printConfiguration(tests[i]); } @@ -1641,7 +1645,7 @@ int printConfiguration(t55xx_conf_block_t b) { PrintAndLogEx(INFO, " Inverted : %s", (b.inverted) ? _GREEN_("Yes") : "No"); PrintAndLogEx(INFO, " Offset : %d", b.offset); PrintAndLogEx(INFO, " Seq. Term. : %s", (b.ST) ? _GREEN_("Yes") : "No"); - PrintAndLogEx(INFO, " Block0 : 0x%08X", b.block0); + PrintAndLogEx(INFO, " Block0 : 0x%08X %s", b.block0, GetConfigBlock0Source(b.block0Status)); PrintAndLogEx(INFO, " Downlink Mode : %s", GetDownlinkModeStr(b.downlink_mode)); PrintAndLogEx(INFO, " Password Set : %s", (b.usepwd) ? _RED_("Yes") : _GREEN_("No")); if (b.usepwd) { @@ -2801,6 +2805,28 @@ char *GetModelStrFromCID(uint32_t cid) { return buf; } +char *GetConfigBlock0Source(uint8_t id) { + + static char buf[20]; + char *retStr = buf; + + switch (id) { + case autoDetect: + snprintf(retStr, sizeof(buf), _YELLOW_("(Auto detect)")); + break; + case userSet: + snprintf(retStr, sizeof(buf), _YELLOW_("(User set)")); + break; + case tagRead: + snprintf(retStr, sizeof(buf), _GREEN_("(Tag read)")); + break; + default: + snprintf(retStr, sizeof(buf), _RED_("(Unknown)")); + break; + } + return buf; +} + char *GetSelectedModulationStr(uint8_t id) { static char buf[20]; diff --git a/client/src/cmdlft55xx.h b/client/src/cmdlft55xx.h index 4352eed64..90fbaa85d 100644 --- a/client/src/cmdlft55xx.h +++ b/client/src/cmdlft55xx.h @@ -125,6 +125,12 @@ typedef struct { bool inverted; uint8_t offset; uint32_t block0; + enum { + notSet = 0x00, + autoDetect = 0x01, + userSet = 0x02, + tagRead = 0x03, + } block0Status; enum { RF_8 = 0x00, RF_16 = 0x01, @@ -166,6 +172,7 @@ char *GetSaferStr(uint32_t id); char *GetQ5ModulationStr(uint32_t id); char *GetModulationStr(uint32_t id, bool xmode); char *GetModelStrFromCID(uint32_t cid); +char *GetConfigBlock0Source(uint8_t id); char *GetSelectedModulationStr(uint8_t id); char *GetDownlinkModeStr(uint8_t downlink_mode); void printT5xxHeader(uint8_t page); From 7f4fe79aaa44d6664627cf6f32ff1f1d44b06d6b Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Tue, 8 Dec 2020 23:32:23 +0000 Subject: [PATCH 158/174] Made GetConfigBlock0Source string buf larger to acomodate ASCII color escape expansion --- client/src/cmdlft55xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 40cc0be5a..a3f5ca20b 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -2807,7 +2807,7 @@ char *GetModelStrFromCID(uint32_t cid) { char *GetConfigBlock0Source(uint8_t id) { - static char buf[20]; + static char buf[40]; char *retStr = buf; switch (id) { From 93d00be4c0b61fe7f39e6af7667d966da45f359f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 9 Dec 2020 10:28:58 +0100 Subject: [PATCH 159/174] adapt indala test for new output --- tools/pm3_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index ad61dc13d..6f385e906 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -391,7 +391,7 @@ while true; do "Fmt 26 FC: 123 Card: 1337 checksum: 10"; then break; fi if ! CheckExecute slow "lf T55 indala_224 test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf search 1'" "Indala ID found"; then break; fi if ! CheckExecute slow "lf T55 indala_224 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf indala demod'" \ - "Indala - len 224 Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi + "Indala (len 224) Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi if ! CheckExecute slow "lf T55 io test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf search 1'" "IO Prox ID found"; then break; fi if ! CheckExecute slow "lf T55 io test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf io demod'" \ "IO Prox - XSF(01)01:01337, Raw: 007840603059cf3f (ok)"; then break; fi From 01b2c14616b6e09b37033f79b1620a6d071dc996 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 9 Dec 2020 12:18:01 +0100 Subject: [PATCH 160/174] adapt and fix memoryleaks in Em4x50 --- armsrc/em4x50.c | 217 +++++------ client/src/cmdhfthinfilm.c | 2 +- client/src/cmdlfem4x50.c | 733 ++++++++++++++++--------------------- client/src/cmdwiegand.c | 2 +- 4 files changed, 409 insertions(+), 545 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 620083a32..36923b6a5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -55,19 +55,17 @@ int gHigh = 190; int gLow = 60; +// do nothing for using timer0 static void wait_timer(uint32_t period) { - - // do nothing for using timer0 - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < period); } + +// extract and check parities +// return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { - // extract and check parities - // return result of parity check and extracted plain data - uint8_t row_parities = 0x0, col_parities = 0x0; uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; @@ -172,11 +170,10 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } +// calculate signal properties (mean amplitudes) from measured data: +// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow static bool get_signalproperties(void) { - // calculate signal properties (mean amplitudes) from measured data: - // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow - bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; uint8_t sample_ref = 127; @@ -236,13 +233,12 @@ static bool get_signalproperties(void) { return true; } +// returns true if bit is undefined by evaluating a single sample within +// a bit period (given there is no LIW, ACK or NAK) +// This function is used for identifying a listen window in functions +// "find_double_listen_window" and "check_ack" static bool invalid_bit(void) { - // returns true if bit is undefined by evaluating a single sample within - // a bit period (given there is no LIW, ACK or NAK) - // This function is used for identifying a listen window in functions - // "find_double_listen_window" and "check_ack" - // get sample at 3/4 of bit period wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); @@ -292,17 +288,13 @@ static uint32_t get_pulse_length(void) { } +// check if pulse length corresponds to given length static bool check_pulse_length(uint32_t pl, int length) { - - // check if pulse length corresponds to given 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))); } +// send single bit according to EM4x50 application note and datasheet static void em4x50_reader_send_bit(int bit) { - - // send single bit according to EM4x50 application note and datasheet - // reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; @@ -330,19 +322,15 @@ static void em4x50_reader_send_bit(int bit) { } } +// send byte (without parity) static void em4x50_reader_send_byte(uint8_t byte) { - - // send byte (without parity) - - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { em4x50_reader_send_bit((byte >> (7 - i)) & 1); - + } } +// send byte followed by its (equal) parity bit static void em4x50_reader_send_byte_with_parity(uint8_t byte) { - - // send byte followed by its (equal) parity bit - int parity = 0, bit = 0; for (int i = 0; i < 8; i++) { @@ -354,11 +342,9 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { em4x50_reader_send_bit(parity); } +// send 32 bit word with parity bits according to EM4x50 datasheet +// word hast be sent in msb notation static void em4x50_reader_send_word(const uint32_t word) { - - // send 32 bit word with parity bits according to EM4x50 datasheet - // word hast be sent in msb notation - uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; for (int i = 0; i < 4; i++) { @@ -373,10 +359,8 @@ static void em4x50_reader_send_word(const uint32_t word) { em4x50_reader_send_bit(0); } +// find single listen window static bool find_single_listen_window(void) { - - // find single listen window - int cnt_pulses = 0; LED_B_ON(); @@ -398,18 +382,15 @@ static bool find_single_listen_window(void) { } LED_B_OFF(); - return false; } +// find two successive listen windows that indicate the beginning of +// data transmission +// double listen window to be detected within 1600 pulses -> worst case +// reason: first detectable double listen window after 34 words +// -> 34 words + 34 single listen windows -> about 1600 pulses static int find_double_listen_window(bool bcommand) { - - // find two successive listen windows that indicate the beginning of - // data transmission - // double listen window to be detected within 1600 pulses -> worst case - // reason: first detectable double listen window after 34 words - // -> 34 words + 34 single listen windows -> about 1600 pulses - int cnt_pulses = 0; LED_B_ON(); @@ -471,34 +452,29 @@ static int find_double_listen_window(bool bcommand) { cnt_pulses++; } - LED_B_OFF(); - + LED_B_OFF(); return PM3_EFAILED; } +// 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) { - - // function is used to check wether a tag on the proxmark is an - // EM4x50 tag or not -> speed up "lf search" process return find_single_listen_window(); } +// To issue a command we have to find a listen window first. +// Because identification and synchronization at the same time is not +// possible when using pulse lengths a double listen window is used. static int request_receive_mode(void) { - - // To issue a command we have to find a listen window first. - // Because identification and synchronization at the same time is not - // possible when using pulse lengths a double listen window is used. return find_double_listen_window(true); } +// returns true if signal structue corresponds to ACK, anything else is +// counted as NAK (-> false) +// Only relevant for pasword writing function: +// If is true then within the single listen window right after the +// ack signal a RM request has to be sent. static bool check_ack(bool bliw) { - - // returns true if signal structue corresponds to ACK, anything else is - // counted as NAK (-> false) - // Only relevant for pasword writing function: - // If is true then within the single listen window right after the - // ack signal a RM request has to be sent. - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { @@ -547,12 +523,10 @@ static bool check_ack(bool bliw) { return false; } +// decodes one word by evaluating pulse lengths and previous bit; +// word must have 45 bits in total: +// 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit static int get_word_from_bitstream(uint32_t *data) { - - // decodes one word by evaluating pulse lengths and previous bit; - // word must have 45 bits in total: - // 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit - bool bitchange = false; int cnt = 0; uint32_t pl = 0; @@ -707,10 +681,10 @@ static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - if (!em4x50_sim_send_byte(byte)) + if (em4x50_sim_send_byte(byte) == false) return false;; - if (!em4x50_sim_send_bit(parity)) + if (em4x50_sim_send_bit(parity) == false) return false; return true; @@ -724,9 +698,11 @@ bool em4x50_sim_send_word(uint32_t word) { word = reflect32(word); // 4 bytes each with even row parity bit - for (int i = 0; i < 4; i++) - if (!em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF)) + for (int i = 0; i < 4; i++) { + if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == false) { return false; + } + } // column parity for (int i = 0; i < 8; i++) { @@ -735,11 +711,11 @@ bool em4x50_sim_send_word(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - if (!em4x50_sim_send_byte(cparity)) + if (em4x50_sim_send_byte(cparity) == false) return false; // stop bit - if (!em4x50_sim_send_bit(0)) + if (em4x50_sim_send_bit(0) == false) return false; return true; @@ -790,11 +766,9 @@ bool em4x50_sim_send_listen_window(void) { return true; } +// simple login to EM4x50, +// used in operations that require authentication static bool login(uint32_t password) { - - // simple login to EM4x50, - // used in operations that require authentication - if (request_receive_mode() == PM3_SUCCESS) { // send login command @@ -817,10 +791,8 @@ static bool login(uint32_t password) { return PM3_EFAILED; } +// searching for password in given range static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // searching for password in given range - bool pwd_found = false; int cnt = 0; @@ -868,42 +840,33 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { return pwd_found; } +// login into EM4x50 void em4x50_login(uint32_t *password) { - - // login into EM4x50 - - uint8_t status = PM3_EFAILED; - em4x50_setup_read(); - // set gHigh and gLow + uint8_t status = PM3_EFAILED; if (get_signalproperties() && find_em4x50_tag()) status = login(*password); lf_finalize(); - reply_ng(CMD_LF_EM4X50_LOGIN, status, 0, 0); + reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0); } +// envoke password search void em4x50_brute(em4x50_data_t *etd) { - - // envoke password search + em4x50_setup_read(); bool bsuccess = false; uint32_t pwd = 0x0; - - em4x50_setup_read(); - if (get_signalproperties() && find_em4x50_tag()) bsuccess = brute(etd->password1, etd->password2, &pwd); lf_finalize(); - reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); + reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess ? PM3_SUCCESS : PM3_EFAILED, (uint8_t *)(&pwd), sizeof(pwd)); } +// check passwords from dictionary content in flash memory void em4x50_chk(uint8_t *filename) { - - // check passwords from dictionary content in flash memory - int status = PM3_EFAILED; uint32_t pwd = 0x0; @@ -951,13 +914,11 @@ void em4x50_chk(uint8_t *filename) { #endif lf_finalize(); - reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); + reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, sizeof(pwd)); } +// resets EM4x50 tag (used by write function) static int reset(void) { - - // resets EM4x50 tag (used by write function) - if (request_receive_mode() == PM3_SUCCESS) { // send reset command @@ -974,11 +935,10 @@ static int reset(void) { return PM3_EFAILED; } +// 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) { - // reads data that tag transmits when exposed to reader field - // (standard read mode); number of read words is saved in - int fwr = *now, res = PM3_EFAILED; // start with the identification of two successive listening windows @@ -999,11 +959,10 @@ static int standard_read(int *now, uint32_t *words) { return res; } +// reads from "first word read" (fwr) to "last word read" (lwr) +// result is verified by "standard read mode" static int selective_read(uint32_t addresses, uint32_t *words) { - // reads from "first word read" (fwr) to "last word read" (lwr) - // result is verified by "standard read mode" - int status = PM3_EFAILED; uint8_t fwr = addresses & 0xFF; // first word read (first byte) uint8_t lwr = (addresses >> 8) & 0xFF; // last word read (second byte) @@ -1033,10 +992,8 @@ static int selective_read(uint32_t addresses, uint32_t *words) { return status; } +// reads by using "selective read mode" -> bidirectional communication void em4x50_read(em4x50_data_t *etd) { - - // reads by using "selective read mode" -> bidirectional communication - bool blogin = true; int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -1057,13 +1014,14 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); + + // iceman: this hardcoded 136 value.... reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); } +// collects as much information as possible via selective read mode void em4x50_info(em4x50_data_t *etd) { - // collects as much information as possible via selective read mode - bool blogin = true; int status = PM3_EFAILED; uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) @@ -1071,7 +1029,6 @@ void em4x50_info(em4x50_data_t *etd) { em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // login with given password @@ -1083,19 +1040,19 @@ void em4x50_info(em4x50_data_t *etd) { } lf_finalize(); + + // iceman: this hardcoded 136 value.... reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); } +// reads data that tag transmits "voluntarily" -> standard read mode void em4x50_reader(void) { - // reads data that tag transmits "voluntarily" -> standard read mode - int now = 0; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) standard_read(&now, words); @@ -1104,9 +1061,8 @@ void em4x50_reader(void) { reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } +// writes to specified static int write(uint32_t word, uint32_t addresses) { - - // writes to specified if (request_receive_mode() == PM3_SUCCESS) { @@ -1144,10 +1100,8 @@ static int write(uint32_t word, uint32_t addresses) { return PM3_EFAILED; } +// changes password from to static int write_password(uint32_t password, uint32_t new_password) { - - // changes password from to - if (request_receive_mode() == PM3_SUCCESS) { // send write password command @@ -1187,18 +1141,15 @@ static int write_password(uint32_t password, uint32_t new_password) { return PM3_EFAILED; } +// write operation process for EM4x50 tag, +// single word is written to given address, verified by selective read operation +// wrong password -> return with PM3_EFAILED void em4x50_write(em4x50_data_t *etd) { - - // write operation process for EM4x50 tag, - // single word is written to given address, verified by selective read operation - // wrong password -> return with PM3_EFAILED - int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // if password is given try to login first @@ -1245,15 +1196,12 @@ void em4x50_write(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); } +// simple change of password void em4x50_writepwd(em4x50_data_t *etd) { - - // simple change of password - int status = PM3_EFAILED; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // login and change password @@ -1268,14 +1216,12 @@ void em4x50_writepwd(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITEPWD, status, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITEPWD, status, NULL, 0); } +// simulate uploaded data in emulator memory +// (currently simulation allows only a one-way communication) void em4x50_sim(uint8_t *filename) { - - // simulate uploaded data in emulator memory - // (currently simulation allows only a one-way communication) - int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -1313,7 +1259,8 @@ void em4x50_sim(uint8_t *filename) { em4x50_setup_sim(); - while (!BUTTON_PRESS()) { + // iceman, will need a usb cmd check to break as well + while (BUTTON_PRESS() == false) { WDT_HIT(); em4x50_sim_send_listen_window(); @@ -1333,5 +1280,5 @@ void em4x50_sim(uint8_t *filename) { BigBuf_free(); lf_finalize(); - reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); + reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } diff --git a/client/src/cmdhfthinfilm.c b/client/src/cmdhfthinfilm.c index 9f7f21912..48844b759 100644 --- a/client/src/cmdhfthinfilm.c +++ b/client/src/cmdhfthinfilm.c @@ -107,7 +107,7 @@ static int CmdHfThinFilmInfo(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + CLIParserFree(ctx); return infoThinFilm(true); } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 6327f600d..ccdf30394 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -26,10 +26,11 @@ static int CmdHelp(const char *Cmd); static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure - - for (int i = fwr; i <= lwr; i++) - for (int j = 0; j < 4; j++) - words[i].byte[j] = data[i * 4 + (3 - j)]; + for (int i = fwr; i <= lwr; i++) { + for (int j = 0; j < 4; j++) { + words[i].byte[j] = data[i * 4 + (3 - j)]; + } + } } static void print_result(const em4x50_word_t *words, int fwr, int lwr) { @@ -169,18 +170,12 @@ static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { } int CmdEM4x50ELoad(const char *Cmd) { - - int slen = 0; - size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0}; - uint8_t data[DUMP_FILESIZE] = {0x0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 eload", "Loads EM4x50 tag dump into emulator memory on device.", - "lf em 4x50 eload -f mydump.bin -> uploads bin file ./mydump.bin\n" - "lf em 4x50 eload -f mydump.eml -> uploads eml file ./mydump.eml\n" - "lf em 4x50 eload -f mydump.json -> uploads json file ./mydump.json\n" + "lf em 4x50 eload -f mydump.bin\n" + "lf em 4x50 eload -f mydump.eml\n" + "lf em 4x50 eload -f mydump.json" ); void *argtable[] = { @@ -190,10 +185,15 @@ int CmdEM4x50ELoad(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); // read data from dump file; file type has to be "bin", "eml" or "json" + size_t bytes_read = 0; + uint8_t data[DUMP_FILESIZE] = {0x0}; + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; @@ -208,20 +208,13 @@ int CmdEM4x50ELoad(const char *Cmd) { } int CmdEM4x50ESave(const char *Cmd) { - - int slen = 0; - uint32_t serial = 0x0, device_id = 0x0; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - uint8_t data[DUMP_FILESIZE] = {0x0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 esave", "Saves bin/eml/json dump file of emulator memory.", - "lf em 4x50 esave -> use UID as filename\n" - "lf em 4x50 esave -f mydump.bin -> saves to bin file ./mydump.bin\n" - "lf em 4x50 esave -f mydump.eml -> saves to eml file ./mydump.eml\n" - "lf em 4x50 esave -f mydump.json -> saves to json file ./mydump.json\n" + "lf em 4x50 esave -> use UID as filename\n" + "lf em 4x50 esave -f mydump.bin\n" + "lf em 4x50 esave -f mydump.eml\n" + "lf em 4x50 esave -f mydump.json\n" ); void *argtable[] = { @@ -231,27 +224,31 @@ int CmdEM4x50ESave(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); // download emulator memory PrintAndLogEx(SUCCESS, "Reading emulator memory..."); - if (!GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false)) { + uint8_t data[DUMP_FILESIZE] = {0x0}; + if (GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); return PM3_ETIMEOUT; } // valid em4x50 data? - serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); - device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + uint32_t serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + uint32_t device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); if (serial == device_id) { PrintAndLogEx(WARNING, "No valid em4x50 data in flash memory."); return PM3_ENODATA; } // user supplied filename? - if (slen == 0) { + if (fnlen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; fptr += snprintf(fptr, sizeof(filename), "lf-4x50-"); FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); } @@ -263,16 +260,10 @@ int CmdEM4x50ESave(const char *Cmd) { } int CmdEM4x50Login(const char *Cmd) { - - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - uint32_t password = 0x0; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 login", "Login into EM4x50 tag.", - "lf em 4x50 login -p 12345678 -< login with password 12345678\n" + "lf em 4x50 login -p 12345678 -> login with password 12345678\n" ); void *argtable[] = { @@ -281,20 +272,22 @@ int CmdEM4x50Login(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - password = BYTES2UINT32(pwd); - } - + CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); CLIParserFree(ctx); + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + + uint32_t password = BYTES2UINT32(pwd); + // start clearCommandBuffer(); + PacketResponseNG resp; SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); @@ -308,63 +301,67 @@ int CmdEM4x50Login(const char *Cmd) { } int CmdEM4x50Brute(const char *Cmd) { - - const int speed = 27; // 27 passwords/second (empirical value) - int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; - - int pwd1Len = 0, pwd2Len = 0; - uint8_t pwd1[4] = {0x0}, pwd2[4] = {0x0}; - em4x50_data_t etd; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 brute", - "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", - "lf em 4x50 brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" + "Tries to bruteforce the password of a EM4x50.\n" + "Function can be stopped by pressing pm3 button.", + "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n" ); void *argtable[] = { arg_param_begin, - arg_str1("f", "fp", "", "first password (start), 4 bytes, lsb"), - arg_str1("l", "lp", "", "last password (stop), 4 bytes, lsb"), + arg_str1(NULL, "first", "", "first password (start), 4 bytes, lsb"), + arg_str1(NULL, "last", "", "last password (stop), 4 bytes, lsb"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd1, &pwd1Len); - CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); - - if (pwd1Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd1Len); - return PM3_EINVARG; - } else if (pwd2Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); - return PM3_EINVARG; - } else { - etd.password1 = BYTES2UINT32(pwd1); - etd.password2 = BYTES2UINT32(pwd2); - } - + CLIExecWithReturn(ctx, Cmd, argtable, true); + int first_len = 0; + uint8_t first[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 1, first, &first_len); + int last_len = 0; + uint8_t last[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 2, last, &last_len); CLIParserFree(ctx); + if (first_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + if (last_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + + em4x50_data_t etd; + etd.password1 = BYTES2UINT32(first); + etd.password2 = BYTES2UINT32(last); + + // 27 passwords/second (empirical value) + const int speed = 27; + // print some information - no_iter = etd.password2 - etd.password1 + 1; - dur_s = no_iter / speed; - dur_h = dur_s / 3600; - dur_m = (dur_s - dur_h * 3600) / 60; + int no_iter = etd.password2 - etd.password1 + 1; + int dur_s = no_iter / speed; + int dur_h = dur_s / 3600; + int dur_m = (dur_s - dur_h * 3600) / 60; + dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]", - no_iter, etd.password1, etd.password2); + PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]" + , no_iter + , etd.password1 + , etd.password2 + ); PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); // start clearCommandBuffer(); + PacketResponseNG resp; SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); WaitForResponse(CMD_LF_EM4X50_BRUTE, &resp); // print response - if ((bool)resp.status) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]); else PrintAndLogEx(FAILED, "Password: " _RED_("not found")); @@ -372,28 +369,14 @@ int CmdEM4x50Brute(const char *Cmd) { return PM3_SUCCESS; } +// upload passwords from given dictionary to device and start check; +// if no filename is given dictionary "t55xx_default_pwds.dic" is used int CmdEM4x50Chk(const char *Cmd) { - - // upload passwords from given dictionary to device and start check; - // if no filename is given dictionary "t55xx_default_pwds.dic" is used - - int status = PM3_EFAILED; - int keyblock = 2000; // block with 2000 bytes -> 500 keys - int res = 0, slen = 0, bytes_remaining = 0; - size_t datalen = 0; - uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; - uint8_t *keys = data; - uint32_t key_count = 0; - uint8_t destfn[32] = "em4x50_chk.bin"; - char filename[FILE_PATH_SIZE] = {0}; - - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 chk", "Dictionary attack against EM4x50.", - "lf em 4x50 chk -> uses T55xx default dictionary\n" - "lf em 4x50 chk -f my.dic -> uses dictionary ./my.dic\n" + "lf em 4x50 chk -> uses T55xx default dictionary\n" + "lf em 4x50 chk -f my.dic" ); void *argtable[] = { @@ -403,27 +386,39 @@ int CmdEM4x50Chk(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); - - // no filename -> default = t55xx_default_pwds - if (strlen(filename) == 0) { - snprintf(filename, sizeof(filename), "t55xx_default_pwds"); - PrintAndLogEx(INFO, "treating file as T55xx keys"); - } - - res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); - if (res || !key_count) - return PM3_EFILE; - - PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); if (IfPm3Flash() == false) { PrintAndLogEx(WARNING, "no flash memory available"); return PM3_EFLASH; } + + // no filename -> default = t55xx_default_pwds + if (strlen(filename) == 0) { + snprintf(filename, sizeof(filename), "t55xx_default_pwds"); + PrintAndLogEx(INFO, "treating file as T55xx keys"); + } + + size_t datalen = 0; + uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; + uint8_t *keys = data; + uint32_t key_count = 0; + + int res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); + if (res || !key_count) + return PM3_EFILE; - bytes_remaining = datalen; + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); + + int status = PM3_EFAILED; + int keyblock = 2000; // block with 2000 bytes -> 500 keys + uint8_t destfn[32] = "em4x50_chk.bin"; + + PacketResponseNG resp; + int bytes_remaining = datalen; while (bytes_remaining > 0) { PrintAndLogEx(INPLACE, "Remaining keys: %i ", bytes_remaining / 4); @@ -447,10 +442,11 @@ int CmdEM4x50Chk(const char *Cmd) { bytes_remaining -= keyblock; keys += keyblock; } - + + PrintAndLogEx(NORMAL, ""); + // print response if (status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], @@ -458,7 +454,6 @@ int CmdEM4x50Chk(const char *Cmd) { resp.data.asBytes[0] ); } else { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "No key found"); } @@ -490,12 +485,11 @@ int read_em4x50_uid(void) { return res; } +// envoke reading +// - with given address (option b) (and optional password if address is +// read protected) -> selective read mode int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { - // envoke reading - // - with given address (option b) (and optional password if address is - // read protected) -> selective read mode - em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; if (etd != NULL) { @@ -527,46 +521,44 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { } int CmdEM4x50Read(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50 read", + "Reads single EM4x50 block/word.", + "lf em 4x50 rdbl -b 3\n" + "lf em 4x50 rdbl -b 32 -p 12345678 -> reads block 32 with pwd 0x12345678\n" + ); - int pwdLen = 0; - int addr = 0; + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "", "block/word address"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int addr = arg_get_int_def(ctx, 1, 0); + int pwd_len = 0; uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len); + CLIParserFree(ctx); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + return PM3_EINVARG; + } + em4x50_data_t etd; // init memset(&etd, 0x00, sizeof(em4x50_data_t)); etd.addr_given = false; etd.pwd_given = false; + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50 read", - "Reads single EM4x50 block/word.", - "lf em 4x50 read -b 3 -> reads block 3\n" - "lf em 4x50 read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_int1("b", "block", "", "block/word address"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (addr <= 0 || addr >= EM4X50_NO_WORDS) { - return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -574,41 +566,35 @@ int CmdEM4x50Read(const char *Cmd) { } } - CLIParserFree(ctx); - return em4x50_read(&etd, NULL); } +// envoke reading of a EM4x50 tag which has to be on the antenna because +// decoding is done by the device (not on client side) int CmdEM4x50Info(const char *Cmd) { - - // envoke reading of a EM4x50 tag which has to be on the antenna because - // decoding is done by the device (not on client side) - - int pwdLen = 0; - int status = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 info", "Tag information EM4x50.", "lf em 4x50 info\n" - "lf em 4x50 info -p 12345678 -> uses password 0x12345678\n" + "lf em 4x50 info -p 12345678 -> uses pwd 0x12345678\n" ); void *argtable[] = { arg_param_begin, - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + em4x50_data_t etd = {.pwd_given = false}; + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -616,32 +602,23 @@ int CmdEM4x50Info(const char *Cmd) { } } - CLIParserFree(ctx); - clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - status = resp.status; - - if (status == PM3_SUCCESS) + if ( resp.status == PM3_SUCCESS) print_info_result(resp.data.asBytes); else PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); - return status; + return resp.status; } int CmdEM4x50Reader(const char *Cmd) { - - int now = 0; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 reader", "Shows standard read data of EM4x50 tag.", @@ -662,13 +639,14 @@ int CmdEM4x50Reader(const char *Cmd) { // start do { + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_READER, 0, 0); WaitForResponseTimeoutW(CMD_LF_EM4X50_READER, &resp, -1, false); - now = resp.status; - - // print response + // iceman, misuse of return status code. + int now = resp.status; + if (now > 0) { em4x50_word_t words[EM4X50_NO_WORDS]; @@ -680,14 +658,13 @@ int CmdEM4x50Reader(const char *Cmd) { for (int i = 0; i < now; i++) { - char r[30] = {0}; - for (int j = 3; j >= 0; j--) + char r[30]; + memset(r, 0, sizeof(r)); + for (int j = 3; j >= 0; j--) { sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + } - PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", - sprint_hex(words[i].byte, 4), - r - ); + PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", sprint_hex(words[i].byte, 4), r); } PrintAndLogEx(INFO, "-------------+-------------"); @@ -698,50 +675,44 @@ int CmdEM4x50Reader(const char *Cmd) { } int CmdEM4x50Dump(const char *Cmd) { - - int fnLen = 0, pwdLen = 0, status = 0; - uint8_t pwd[4] = {0x0}; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - em4x50_data_t etd = {.pwd_given = false}; - uint8_t data[DUMP_FILESIZE] = {0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 dump", "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", - "lf em 4x50 dump -> saves dump in lf-4x50--dump.bin/eml/json\n" - "lf em 4x50 dump -f mydump.eml -> saves dump in mydump.eml\n" + "lf em 4x50 dump\n" + "lf em 4x50 dump -f mydump.eml\n" "lf em 4x50 dump -p 12345678\n" - "lf em 4x50 dump -f mydump.eml -p 12345678\n" + "lf em 4x50 dump -f mydump.eml -p 12345678" ); void *argtable[] = { arg_param_begin, arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIParamStrToBuf(arg_get_str(ctx, 1), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int fnLen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnLen); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len); + CLIParserFree(ctx); + + em4x50_data_t etd = {.pwd_given = false}; + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + CLIParserFree(ctx); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } - - CLIParserFree(ctx); PrintAndLogEx(INFO, "Reading EM4x50 tag"); clearCommandBuffer(); @@ -752,8 +723,7 @@ int CmdEM4x50Dump(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; - if (status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); return PM3_ESOFT; } @@ -769,70 +739,66 @@ int CmdEM4x50Dump(const char *Cmd) { // user supplied filename? if (fnLen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; fptr += sprintf(fptr, "lf-4x50-"); FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); } - for (int i = 0; i < EM4X50_NO_WORDS; i++) + uint8_t data[DUMP_FILESIZE] = {0}; + for (int i = 0; i < EM4X50_NO_WORDS; i++) { memcpy(data + (i * 4), words[i].byte, 4); + } - // saveFileEML will add .eml extension to filename - // saveFile (binary) passes in the .bin extension. - // saveFileJSON adds .json extension - saveFileEML(filename, data, sizeof(data), 4); saveFile(filename, ".bin", data, sizeof(data)); + saveFileEML(filename, data, sizeof(data), 4); saveFileJSON(filename, jsfEM4x50, data, sizeof(data), NULL); - return PM3_SUCCESS; } +// envoke writing a single word (32 bit) to a EM4x50 tag int CmdEM4x50Write(const char *Cmd) { - - // envoke writing a single word (32 bit) to a EM4x50 tag - - int wordLen = 0, pwdLen = 0, addr = 0; - int status = 0; - uint8_t word[4] = {0x0}; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50 write", + CLIParserInit(&ctx, "lf em 4x50 wrbl", "Writes single block/word to EM4x50 tag.", - "lf em 4x50 write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" - "lf em 4x50 write -b 3 -d 4f22e7ff -p 12345678\n" + "lf em 4x50 wrbl -b 3 -d 4f22e7ff \n" + "lf em 4x50 wrbl -b 3 -d 4f22e7ff -p 12345678\n" ); void *argtable[] = { arg_param_begin, arg_int1("b", "block", "", "block/word address, dec"), arg_str1("d", "data", "", "data, 4 bytes, lsb"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + + int addr = arg_get_int_def(ctx, 1, 0); - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, word, &wordLen); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + int word_len = 0; + uint8_t word[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, word, &word_len); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); + CLIParserFree(ctx); if (addr <= 0 || addr >= EM4X50_NO_WORDS) { PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - if (wordLen != 4) { - PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); + } + + if (word_len != 4) { + PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", word_len); return PM3_EINVARG; - } else { - etd.word = BYTES2UINT32(word); } - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + + em4x50_data_t etd = {.pwd_given = false}; + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -840,7 +806,9 @@ int CmdEM4x50Write(const char *Cmd) { } } - CLIParserFree(ctx); + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + etd.word = BYTES2UINT32(word); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); @@ -850,9 +818,9 @@ int CmdEM4x50Write(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; + int status = resp.status; if (status == PM3_ETEAROFF) - return PM3_SUCCESS; + return status; if (status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Writing " _RED_("failed")); @@ -866,54 +834,53 @@ int CmdEM4x50Write(const char *Cmd) { prepare_result(data, addr, addr, words); print_result(words, addr, addr); PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", addr); + PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50 rdbl -a %u") "` - to read your data", addr); return PM3_SUCCESS; } +// envokes changing the password of EM4x50 tag int CmdEM4x50WritePwd(const char *Cmd) { - - // envokes changing the password of EM4x50 tag - - int status = PM3_EFAILED; - int pwdLen = 0, npwdLen = 0; - uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; - PacketResponseNG resp; - em4x50_data_t etd; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 writepwd", "Writes EM4x50 password.", - "lf em 4x50 writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" + "lf em 4x50 writepwd -p 4f22e7ff -n 12345678" ); void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "password, 4 bytes, lsb"), - arg_str1("n", "newpwd", "", "new password, 4 bytes, lsb"), + arg_str1("p", "pwd", "", "password, 4 hex bytes, lsb"), + arg_str1("n", "new", "", "new password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); - - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + + int npwd_len = 0; + uint8_t npwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, npwd, &npwd_len); + + CLIParserFree(ctx); + + em4x50_data_t etd; + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); } - if (npwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); + + if (npwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwd_len); return PM3_EINVARG; } else { etd.password2 = BYTES2UINT32(npwd); } - CLIParserFree(ctx); - + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); @@ -922,36 +889,28 @@ int CmdEM4x50WritePwd(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; - - if (status == PM3_ETEAROFF) + if (resp.status == PM3_ETEAROFF) return PM3_SUCCESS; - // print response - if (status != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Writing password (" _RED_("failed") ")"); return PM3_EFAILED; } - PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); - + PrintAndLogEx(SUCCESS, "Writing new password %s (%s)" + , sprint_hex_inrow(npwd, sizeof(npwd)) + , _GREEN_("ok") + ); return PM3_SUCCESS; } +// fills EM4x50 tag with zeros including password int CmdEM4x50Wipe(const char *Cmd) { - - // fills EM4x50 tag with zeros including password - - bool isOK = false; - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 wipe", - "Wipes EM4x50 tag.", - "lf em 4x50 wipe -p 12345678 -> wipes tag with password 0x12345678\n" + "Wipes EM4x50 tag by filling it with zeros, including the new password\n" + "Must give a password.", + "lf em 4x50 wipe -p 12345678" ); void *argtable[] = { @@ -960,20 +919,25 @@ int CmdEM4x50Wipe(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); + CLIParserFree(ctx); return PM3_EINVARG; - } else { - etd.password1 = BYTES2UINT32(pwd); - etd.pwd_given = true; } - CLIParserFree(ctx); + em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; + + etd.password1 = BYTES2UINT32(pwd); + etd.pwd_given = true; // clear password + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { @@ -982,7 +946,7 @@ int CmdEM4x50Wipe(const char *Cmd) { } if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Resetting password " _GREEN_("ok")); + PrintAndLogEx(SUCCESS, "Resetting password to 00000000 (" _GREEN_("ok") ")"); } else { PrintAndLogEx(FAILED, "Resetting password " _RED_("failed")); return PM3_ESOFT; @@ -1007,8 +971,7 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_ETIMEOUT; } - isOK = resp.status; - if (isOK != PM3_SUCCESS) { + if ( resp.status != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); return PM3_ESOFT; @@ -1016,66 +979,54 @@ int CmdEM4x50Wipe(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); - PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } int CmdEM4x50Restore(const char *Cmd) { - - int uidLen = 0, fnLen = 0, pwdLen = 0, status = 0; - int startblock = EM4X50_CONTROL + 1; - uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; - uint8_t data[DUMP_FILESIZE] = {0x0}; - size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - em4x50_data_t etd = {.pwd_given = false}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 restore", - "Restores data from dumpfile onto a Em4x50 tag.", - "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" - "lf em 4x50 restore -f mydump.eml -> uses mydump.eml\n" + "Restores data from dumpfile onto a Em4x50 tag.\n" + "if used with -u, the filetemplate `lf-4x50-UID-dump.bin` is used as filename", + "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" + "lf em 4x50 restore -f mydump.eml\n" "lf em 4x50 restore -u 1b5aff5c -p 12345678\n" "lf em 4x50 restore -f mydump.eml -p 12345678\n" ); void *argtable[] = { arg_param_begin, - arg_str0("u", "uid", "", "uid, 4 bytes, msb, restore from lf-4x50--dump.bin"), + arg_str0("u", "uid", "", "uid, 4 hex bytes, msb"), arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int uidLen = 0; + uint8_t uid[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, uid, &uidLen); - CLIParamStrToBuf(arg_get_str(ctx, 2), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); - - if ((uidLen && fnLen) || (!uidLen && !fnLen)) { + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); + CLIParserFree(ctx); + + if ((uidLen && fnlen) || (!uidLen && !fnlen)) { PrintAndLogEx(FAILED, "either use option 'u' or option 'f'"); return PM3_EINVARG; } - - if (uidLen) { - PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "lf-4x50-"); - FillFileNameByUID(fptr, uid, "-dump", 4); - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + + int startblock = EM4X50_CONTROL + 1; + em4x50_data_t etd = {.pwd_given = false}; + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -1085,11 +1036,18 @@ int CmdEM4x50Restore(const char *Cmd) { } } - CLIParserFree(ctx); + if (uidLen) { + PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; + fptr += sprintf(fptr, "lf-4x50-"); + FillFileNameByUID(fptr, uid, "-dump", 4); + } PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" + uint8_t data[DUMP_FILESIZE] = {0x0}; + size_t bytes_read = 0; if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; @@ -1100,90 +1058,50 @@ int CmdEM4x50Restore(const char *Cmd) { etd.addresses = i << 8 | i; etd.word = reflect32(BYTES2UINT32((data + 4 * i))); + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - status = resp.status; - if (status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Restoring data " _RED_("failed")); return PM3_ESOFT; } } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Restoring data " _GREEN_("ok")); - + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } int CmdEM4x50Sim(const char *Cmd) { - - int slen = 0, status = 0; - size_t bytes_read = 0; - uint8_t data[DUMP_FILESIZE] = {0x0}; - uint8_t destfn[32] = {0}; - - char filename[FILE_PATH_SIZE] = {0}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 sim", - "Simulates a EM4x50 tag", - "lf em 4x50 sim -> simulates EM4x50 data in memory (upload via em4x50_eload).\n" - "lf em 4x50 sim -f mydump.eml -> simulates content of file ./mydump\n" + "Simulates a EM4x50 tag.\n" + "Upload using `lf em 4x50 eload`", + "lf em 4x50 sim" ); void *argtable[] = { arg_param_begin, - arg_str0("f", "filename", "", "dump filename, bin/eml/json"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - - // read data from dump file; file type has to be "bin", "eml" or "json" - if (slen != 0) { - // load file content - if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Read error"); - return PM3_EFILE; - } - - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to davice", filename); - - // upload to device - if (IfPm3Flash()) { - sprintf((char *)destfn, "em4x50_sim.bin"); - status = flashmem_spiffs_load(destfn, data, DUMP_FILESIZE); - if (status != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "SPIFFS upload failed"); - return status; - } - } else { - em4x50_seteml(data, 0, DUMP_FILESIZE); - } - - PrintAndLogEx(INFO, "Simulating data from " _YELLOW_("%s"), filename); - } else { - PrintAndLogEx(INFO, "Simulating data from emulator memory"); - } + PrintAndLogEx(INFO, "Simulating data from emulator memory"); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, destfn, sizeof(destfn)); + SendCommandNG(CMD_LF_EM4X50_SIM, NULL, 0); + PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - - status = resp.status; - if (status == PM3_SUCCESS) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(INFO, "Done"); else PrintAndLogEx(FAILED, "No valid em4x50 data in memory."); @@ -1193,24 +1111,23 @@ int CmdEM4x50Sim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, + {"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, - {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, - {"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, - {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, - {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, + {"rdbl", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, + {"wrbl", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, + {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, + {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, + {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, - {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, - {"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {NULL, NULL, NULL, NULL} }; - static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index c38758679..8e154e300 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -123,7 +123,7 @@ int CmdWiegandDecode(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_lit0("p", "parity", "ignore invalid parity"), - arg_strx1(NULL, "raw", "", "raw hex to be decoded"), + arg_strx1("r", "raw", "", "raw hex to be decoded"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); From 3329e363e040f00b5e1b43a2e1d9469b665cdb4a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 9 Dec 2020 14:48:10 +0100 Subject: [PATCH 161/174] lf em 410x - now uses cliparser, support continuous mode, and reworked output --- client/src/cmddata.c | 2 +- client/src/cmdlfem410x.c | 570 ++++++++++++++++++++------------------- client/src/cmdlfem410x.h | 2 +- 3 files changed, 301 insertions(+), 273 deletions(-) diff --git a/client/src/cmddata.c b/client/src/cmddata.c index d1855aaff..daff73722 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -709,7 +709,7 @@ static int Cmdmandecoderaw(const char *Cmd) { if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) { //need to adjust to set bitstream back to manchester encoded data //setDemodBuff(bits, size, idx); - printEM410x(hi, id); + printEM410x(hi, id, false); } } return PM3_SUCCESS; diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index ef35e95a0..790e3e070 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -1,5 +1,8 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh + +// modified marshmellow +// modified Iceman, 2020 // // 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 @@ -10,13 +13,11 @@ #include "cmdlfem410x.h" #include "cmdlfem4x50.h" - #include #include #include #include #include - #include "fileutils.h" #include "cmdparser.h" // command_t #include "comms.h" @@ -37,88 +38,6 @@ static uint64_t g_em410xid = 0; static int CmdHelp(const char *Cmd); - -//////////////// 410x commands -static int usage_lf_em410x_demod(void) { - PrintAndLogEx(NORMAL, "Usage: lf em 410x_demod [h] [clock] <0|1> [maxError]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " clock - set clock as integer, optional, if not set, autodetect."); - PrintAndLogEx(NORMAL, " <0|1> - 0 normal output, 1 for invert output"); - PrintAndLogEx(NORMAL, " maxerror - set maximum allowed errors, default = 100."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod") " = demod an EM410x Tag ID from GraphBuffer"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32 1") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 1") " = demod an EM410x Tag ID from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 64 1 0") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors"); - return PM3_SUCCESS; -} -static int usage_lf_em410x_watch(void) { - PrintAndLogEx(NORMAL, "Enables IOProx compatible reader mode printing details of scanned tags."); - PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_watch"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_watch")); - return PM3_SUCCESS; -} - -static int usage_lf_em410x_clone(void) { - PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 or Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_clone [h] [clock]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " - ID number"); - PrintAndLogEx(NORMAL, " - 0|1 0 = Q5/T5555, 1 = T55x7"); - PrintAndLogEx(NORMAL, " - 16|32|40|64, optional, set R/F clock rate, defaults to 64"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_clone 0F0368568B 1") " = write ID to t55x7 card"); - return PM3_SUCCESS; -} -static int usage_lf_em410x_ws(void) { - PrintAndLogEx(NORMAL, "Watch 'nd Spoof, activates reader, waits until a EM410x tag gets presented then it starts simulating the found UID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_spoof [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_spoof")); - return PM3_SUCCESS; -} -static int usage_lf_em410x_sim(void) { - PrintAndLogEx(NORMAL, "Simulating EM410x tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " uid - uid (10 HEX symbols)"); - PrintAndLogEx(NORMAL, " clock - clock (32|64) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B 32")); - return PM3_SUCCESS; -} -static int usage_lf_em410x_brute(void) { - PrintAndLogEx(NORMAL, "Bruteforcing by emulating EM410x tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_brute [h] ids.txt [d 2000] [c clock]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " ids.txt - file with UIDs in HEX format, one per line"); - PrintAndLogEx(NORMAL, " d (2000) - pause delay in milliseconds between UIDs simulation, default 1000 ms (optional)"); - PrintAndLogEx(NORMAL, " c (32) - clock (32|64), default 64 (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt c 32")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000 c 32")); - return PM3_SUCCESS; -} - /* Read the ID of an EM410x tag. * Format: * 1111 1111 1 <-- standard non-repeatable header @@ -129,63 +48,62 @@ static int usage_lf_em410x_brute(void) { */ // Construct the graph for emulating an EM410X tag -static void ConstructEM410xEmulGraph(const char *uid, const uint8_t clock) { +static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock) { - int i, j, binary[4], parity[4]; - uint32_t n; - /* clear our graph */ + // clear our graph ClearGraph(true); - /* write 16 zero bit sledge */ - for (i = 0; i < 20; i++) + // write 16 zero bit sledge + for (uint8_t i = 0; i < 20; i++) AppendGraph(false, clock, 0); - /* write 9 start bits */ - for (i = 0; i < 9; i++) + // write 9 start bits + for (uint8_t i = 0; i < 9; i++) AppendGraph(false, clock, 1); - /* for each hex char */ - parity[0] = parity[1] = parity[2] = parity[3] = 0; - for (i = 0; i < 10; i++) { - /* read each hex char */ - sscanf(&uid[i], "%1x", &n); - for (j = 3; j >= 0; j--, n /= 2) - binary[j] = n % 2; + uint8_t bs[8], parity[8]; + memset(parity, 0, sizeof(parity)); - /* append each bit */ - AppendGraph(false, clock, binary[0]); - AppendGraph(false, clock, binary[1]); - AppendGraph(false, clock, binary[2]); - AppendGraph(false, clock, binary[3]); + for (uint8_t i = 0; i < 5; i++) { - /* append parity bit */ - AppendGraph(false, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); + for (uint8_t j = 0; j < 8; j++) { + bs[j] = (uid[i] >> (7 - j) & 1); + } + PrintAndLogEx(DEBUG, "uid[%d] 0x%02x (%s)", i, uid[i], sprint_bin(bs, 4)); - /* keep track of column parity */ - parity[0] ^= binary[0]; - parity[1] ^= binary[1]; - parity[2] ^= binary[2]; - parity[3] ^= binary[3]; + for (uint8_t j = 0; j < 2; j++) { + // append each bit + AppendGraph(false, clock, bs[0 + (4 * j)]); + AppendGraph(false, clock, bs[1 + (4 * j)]); + AppendGraph(false, clock, bs[2 + (4 * j)]); + AppendGraph(false, clock, bs[3 + (4 * j)]); + + // append parity bit + AppendGraph(false, clock, bs[0 + (4 * j)] ^ bs[1 + (4 * j)] ^ bs[2 + (4 * j)] ^ bs[3 + (4 * j)]); + + // keep track of column parity + parity[0] ^= bs[0 + (4 * j)]; + parity[1] ^= bs[1 + (4 * j)]; + parity[2] ^= bs[2 + (4 * j)]; + parity[3] ^= bs[3 + (4 * j)]; + } } - /* parity columns */ + // parity columns AppendGraph(false, clock, parity[0]); AppendGraph(false, clock, parity[1]); AppendGraph(false, clock, parity[2]); AppendGraph(false, clock, parity[3]); - /* stop bit */ + // stop bit AppendGraph(true, clock, 0); } -//by marshmellow //print 64 bit EM410x ID in multiple formats -void printEM410x(uint32_t hi, uint64_t id) { +void printEM410x(uint32_t hi, uint64_t id, bool verbose) { if (!id && !hi) return; - PrintAndLogEx(SUCCESS, "EM410x%s pattern found", (hi) ? " XL" : ""); - uint64_t n = 1; uint64_t id2lo = 0; uint8_t m, i; @@ -195,26 +113,36 @@ void printEM410x(uint32_t hi, uint64_t id) { } } + if (verbose == false) { + + if (hi) { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); + } else { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); + } + return; + } + if (hi) { //output 88 bit em id - PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%06X%016" PRIX64), hi, id); - PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock); + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); + PrintAndLogEx(SUCCESS, "EM410x XL ( RF/%d )", g_DemodClock); } else { //output 40 bit em id - PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%010" PRIX64), id); - PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock); - PrintAndLogEx(NORMAL, "\nPossible de-scramble patterns\n"); - PrintAndLogEx(NORMAL, "Unique TAG ID : %010" PRIX64, id2lo); - PrintAndLogEx(NORMAL, "HoneyWell IdentKey {"); - PrintAndLogEx(NORMAL, "DEZ 8 : %08" PRIu64, id & 0xFFFFFF); - PrintAndLogEx(NORMAL, "DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF); - PrintAndLogEx(NORMAL, "DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 14/IK2 : %014" PRIu64, id); - PrintAndLogEx(NORMAL, "DEZ 15/IK3 : %015" PRIu64, id2lo); - PrintAndLogEx(NORMAL, "DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64, + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); + PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock); + PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); + PrintAndLogEx(SUCCESS, "Unique TAG ID : %010" PRIX64, id2lo); + PrintAndLogEx(INFO, "HoneyWell IdentKey"); + PrintAndLogEx(SUCCESS, " DEZ 8 : %08" PRIu64, id & 0xFFFFFF); + PrintAndLogEx(SUCCESS, " DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF); + PrintAndLogEx(SUCCESS, " DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 14/IK2 : %014" PRIu64, id); + PrintAndLogEx(SUCCESS, " DEZ 15/IK3 : %015" PRIu64, id2lo); + PrintAndLogEx(SUCCESS, " DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64, (id2lo & 0xf000000000) >> 36, (id2lo & 0x0f00000000) >> 32, (id2lo & 0x00f0000000) >> 28, @@ -226,9 +154,11 @@ void printEM410x(uint32_t hi, uint64_t id) { (id2lo & 0x00000000f0) >> 4, (id2lo & 0x000000000f) ); + PrintAndLogEx(INFO, ""); + uint64_t paxton = (((id >> 32) << 24) | (id & 0xffffff)) + 0x143e00; - PrintAndLogEx(NORMAL, "}\nOther : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF)); - PrintAndLogEx(NORMAL, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton); + PrintAndLogEx(SUCCESS, "Other : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF)); + PrintAndLogEx(SUCCESS, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton); uint32_t p1id = (id & 0xFFFFFF); uint8_t arr[32] = {0x00}; @@ -268,12 +198,13 @@ void printEM410x(uint32_t hi, uint64_t id) { p1 |= arr[2] << 4; p1 |= arr[1] << 5; p1 |= arr[0] << 9; - PrintAndLogEx(NORMAL, "Pattern 1 : %d [0x%X]", p1, p1); + PrintAndLogEx(SUCCESS, "Pattern 1 : %d [0x%X]", p1, p1); uint16_t sebury1 = id & 0xFFFF; uint8_t sebury2 = (id >> 16) & 0x7F; uint32_t sebury3 = id & 0x7FFFFF; - PrintAndLogEx(NORMAL, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3); + PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3); + PrintAndLogEx(INFO, "------------------------------------------------"); } } /* Read the ID of an EM410x tag. @@ -321,9 +252,8 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) { printDemodBuff(0, false, false, true); } - if (verbose) - printEM410x(*hi, *lo); - + printEM410x(*hi, *lo, verbose); + g_em410xid = *lo; return PM3_SUCCESS; } @@ -342,8 +272,19 @@ int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, // this read loops on device side. // uses the demod in lfops.c static int CmdEM410xWatch(const char *Cmd) { - uint8_t c = tolower(param_getchar(Cmd, 0)); - if (c == 'h') return usage_lf_em410x_watch(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x watch", + "Enables Electro Marine (EM) compatible reader mode printing details of scanned tags.\n" + "Run until the button is pressed or another USB command is issued.", + "lf em 410x watch" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna"); PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); @@ -367,111 +308,189 @@ int demodEM410x(bool verbose) { } static int CmdEM410xDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x demod", + "Try to find EM 410x preamble, if found decode / descramble data", + "lf em 410x demod -> demod an EM410x Tag ID from GraphBuffer\n" + "lf em 410x demod --clk 32 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32\n" + "lf em 410x demod --clk 32 -i -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data\n" + "lf em 410x demod -i -> demod an EM410x Tag ID from GraphBuffer while inverting data\n" + "lf em 410x demod --clk 64 -i --err 0 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "optional - maximum length"), + arg_lit0("i", "invert", "optional - invert output"), + arg_lit0("a", "amp", "optional - amplify signal"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int clk = arg_get_u32_def(ctx, 1, 0); + int max_err = arg_get_u32_def(ctx, 2, 100); + size_t max_len = arg_get_u32_def(ctx, 3, 0); + bool invert = arg_get_lit(ctx, 4); + bool amplify = arg_get_lit(ctx, 5); + CLIParserFree(ctx); uint32_t hi = 0; uint64_t lo = 0; - int clk = 0; - int invert = 0; - int maxErr = 100; - size_t maxLen = 0; - char amp = tolower(param_getchar(Cmd, 0)); - sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - bool amplify = amp == 'a'; - if (AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true) != PM3_SUCCESS) + if (AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, true) != PM3_SUCCESS) return PM3_ESOFT; - g_em410xid = lo; return PM3_SUCCESS; } // this read is the "normal" read, which download lf signal and tries to demod here. -static int CmdEM410xRead(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod(); +static int CmdEM410xReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x reader", + "read EM 410x tag", + "lf em 410x reader -> reader\n" + "lf em 410x reader -@ -> continuous reader mode\n" + "lf em 410x reader --clk 32 -> reader using a clock of RF/32\n" + "lf em 410x reader --clk 32 -i -> reader using a clock of RF/32 and inverting data\n" + "lf em 410x reader -i -> reader while inverting data\n" + "lf em 410x reader --clk 64 -i --err 0 -> reader using a clock of RF/64 and inverting data and allowing 0 demod errors" + ); - uint32_t hi = 0; - uint64_t lo = 0; - int clk = 0; - int invert = 0; - int maxErr = 100; - size_t maxLen = 0; - char amp = tolower(param_getchar(Cmd, 0)); - sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - bool amplify = amp == 'a'; - lf_read(false, 12288); - return AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true); + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "optional - maximum length"), + arg_lit0("i", "invert", "optional - invert output"), + arg_lit0("a", "amp", "optional - amplify signal"), + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int clk = arg_get_u32_def(ctx, 1, 0); + int max_err = arg_get_u32_def(ctx, 2, 100); + size_t max_len = arg_get_u32_def(ctx, 3, 0); + bool invert = arg_get_lit(ctx, 4); + bool amplify = arg_get_lit(ctx, 5); + bool cm = arg_get_lit(ctx, 6); + bool verbose = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + } + + do { + uint32_t hi = 0; + uint64_t lo = 0; + lf_read(false, 12288); + AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } // emulate an EM410X tag static int CmdEM410xSim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_sim(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x sim", + "Enables simulation of EM 410x card.\n" + "Simulation runs until the button is pressed or another USB command is issued.", + "lf em 410x sim --id 0F0368568B\n" + "lf em 410x sim --id 0F0368568B --clk 32" + ); - uint8_t uid[5] = {0x00}; + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock [32|64] (default 64)"), + arg_str1("i", "id", "", "ID number (5 hex bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - /* clock is 64 in EM410x tags */ - uint8_t clk = 64; + // clock is 64 in EM410x tags + int clk = arg_get_u32_def(ctx, 1, 64); + int uid_len = 0; + uint8_t uid[5] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + CLIParserFree(ctx); - if (param_gethex(Cmd, 0, uid, 10)) { - PrintAndLogEx(FAILED, "UID must include 10 HEX symbols"); + if (uid_len != 5) { + PrintAndLogEx(FAILED, "UID must include 5 hex bytes (%u)", uid_len); return PM3_EINVARG; } - param_getdec(Cmd, 1, &clk); - - PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%02X%02X%02X%02X%02X")" clock: "_YELLOW_("%d"), uid[0], uid[1], uid[2], uid[3], uid[4], clk); + PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation"); - ConstructEM410xEmulGraph(Cmd, clk); + em410x_construct_emul_graph(uid, clk); - CmdLFSim("0"); //240 start_gap. + CmdLFSim("0"); // 240 start_gap. return PM3_SUCCESS; } -static int CmdEM410xBrute(const char *Cmd) { +static int CmdEM410xBrute(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x brute", + "bruteforcing by emulating EM 410x tag", + "lf em 410x brute -f ids.txt\n" + "lf em 410x brute -f ids.txt --clk 32\n" + "lf em 410x brute -f ids.txt --delay 3000\n" + "lf em 410x brute -f ids.txt --delay 3000 --clk 32\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "clk", "", "optional - clock [32|64] (default 64)"), + arg_u64_1(NULL, "delay", "", "optional - pause delay in milliseconds between UIDs simulation (default 1000ms)"), + arg_str1("f", "file", "", "file with UIDs in HEX format, one per line"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + // clock default 64 in EM410x + uint32_t clk = arg_get_u32_def(ctx, 1, 64); + + // default pause time: 1 second + uint32_t delay = arg_get_u32_def(ctx, 2, 1000); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - FILE *f = NULL; - char buf[11]; - uint32_t uidcnt = 0; - uint8_t stUidBlock = 20; - uint8_t *uidBlock = NULL, *p = NULL; - uint8_t uid[5] = {0x00}; - /* clock is 64 in EM410x tags */ - uint8_t clock1 = 64; - /* default pause time: 1 second */ - uint32_t delay = 1000; + CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_brute(); - - cmdp = tolower(param_getchar(Cmd, 1)); - if (cmdp == 'd') { - delay = param_get32ex(Cmd, 2, 1000, 10); - param_getdec(Cmd, 4, &clock1); - } else if (cmdp == 'c') { - param_getdec(Cmd, 2, &clock1); - delay = param_get32ex(Cmd, 4, 1000, 10); - } - - int filelen = param_getstr(Cmd, 0, filename, FILE_PATH_SIZE); - if (filelen == 0) { + if (fnlen == 0) { PrintAndLogEx(ERR, "Error: Please specify a filename"); return PM3_EINVARG; } + + uint32_t uidcnt = 0; + uint8_t stUidBlock = 20; + uint8_t *p = NULL; + uint8_t uid[5] = {0x00}; + // open file + FILE *f = NULL; if ((f = fopen(filename, "r")) == NULL) { PrintAndLogEx(ERR, "Error: Could not open UIDs file ["_YELLOW_("%s")"]", filename); return PM3_EFILE; } - uidBlock = calloc(stUidBlock, 5); - if (uidBlock == NULL) { + // allocate mem for file contents + uint8_t *uidblock = calloc(stUidBlock, 5); + if (uidblock == NULL) { fclose(f); - return PM3_ESOFT; + PrintAndLogEx(ERR, "Error: can't allocate memory"); + return PM3_EMALLOC; } + // read file into memory + char buf[11]; + while (fgets(buf, sizeof(buf), f)) { if (strlen(buf) < 10 || buf[9] == '\n') continue; while (fgetc(f) != '\n' && !feof(f)); //goto next line @@ -481,7 +500,7 @@ static int CmdEM410xBrute(const char *Cmd) { if (param_gethex(buf, 0, uid, 10)) { PrintAndLogEx(FAILED, "UIDs must include 10 HEX symbols"); - free(uidBlock); + free(uidblock); fclose(f); return PM3_ESOFT; } @@ -489,109 +508,118 @@ static int CmdEM410xBrute(const char *Cmd) { buf[10] = 0; if (stUidBlock - uidcnt < 2) { - p = realloc(uidBlock, 5 * (stUidBlock += 10)); + p = realloc(uidblock, 5 * (stUidBlock += 10)); if (!p) { PrintAndLogEx(WARNING, "Cannot allocate memory for UIDs"); - free(uidBlock); + free(uidblock); fclose(f); return PM3_ESOFT; } - uidBlock = p; + uidblock = p; } - memset(uidBlock + 5 * uidcnt, 0, 5); - num_to_bytes(strtoll(buf, NULL, 16), 5, uidBlock + 5 * uidcnt); + memset(uidblock + 5 * uidcnt, 0, 5); + num_to_bytes(strtoll(buf, NULL, 16), 5, uidblock + 5 * uidcnt); uidcnt++; memset(buf, 0, sizeof(buf)); } - fclose(f); if (uidcnt == 0) { PrintAndLogEx(FAILED, "No UIDs found in file"); - free(uidBlock); + free(uidblock); return PM3_ESOFT; } PrintAndLogEx(SUCCESS, "Loaded "_YELLOW_("%d")" UIDs from "_YELLOW_("%s")", pause delay:"_YELLOW_("%d")" ms", uidcnt, filename, delay); // loop + uint8_t testuid[5]; for (uint32_t c = 0; c < uidcnt; ++c) { - char testuid[11]; - testuid[10] = 0; - if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); - free(uidBlock); + free(uidblock); return PM3_EOPABORTED; } - sprintf(testuid, "%010" PRIX64, bytes_to_num(uidBlock + 5 * c, 5)); - PrintAndLogEx(NORMAL, "Bruteforce %d / %d: simulating UID %s, clock %d", c + 1, uidcnt, testuid, clock1); + memcpy(testuid, uidblock + 5 * c, 5); + PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s") + , c + 1 + , uidcnt + , sprint_hex_inrow(testuid, sizeof(testuid)) + ); - ConstructEM410xEmulGraph(testuid, clock1); + em410x_construct_emul_graph(testuid, clk); CmdLFSim("0"); //240 start_gap. msleep(delay); } - - free(uidBlock); + free(uidblock); return PM3_SUCCESS; } //currently only supports manchester modulations -static int CmdEM410xWatchnSpoof(const char *Cmd) { +static int CmdEM410xSpoof(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x spoof", + "Watch 'nd Spoof, activates reader\n" + "Waits until a EM 410x tag gets presented then Proxmark3 starts simulating the found UID", + "lf em 410x spoof" + ); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_ws(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // loops if the captured ID was in XL-format. - CmdEM410xWatch(Cmd); + CmdEM410xReader("-@"); PrintAndLogEx(SUCCESS, "# Replaying captured ID: "_YELLOW_("%010" PRIx64), g_em410xid); CmdLFaskSim(""); return PM3_SUCCESS; } static int CmdEM410xClone(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 0x00 || cmdp == 'h') return usage_lf_em410x_clone(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x clone", + "Writes EM410x ID to a T55x7 or Q5/T5555 tag", + "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" + "lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag" + ); - uint64_t id = param_get64ex(Cmd, 0, -1, 16); - uint8_t card = param_get8ex(Cmd, 1, 0xFF, 10); - uint8_t clock1 = param_get8ex(Cmd, 2, 0, 10); + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock <16|32|40|64> (default 64)"), + arg_str1("u", "uid", "", "ID number (5 hex bytes)"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - // Check ID - if (id == 0xFFFFFFFFFFFFFFFF) { - PrintAndLogEx(ERR, "error, ID is required\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } - if (id >= 0x10000000000) { - PrintAndLogEx(ERR, "error, given EM410x ID is longer than 40 bits\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } + // clock default 64 in EM410x + uint32_t clk = arg_get_u32_def(ctx, 1, 64); + int uid_len = 0; + uint8_t uid[5] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + bool q5 = arg_get_lit(ctx, 3); + CLIParserFree(ctx); - // Check Card - if (card > 1) { - PrintAndLogEx(FAILED, "error, bad card type selected\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } - - // Check Clock - if (clock1 == 0) - clock1 = 64; + uint64_t id = bytes_to_num(uid, uid_len); // Allowed clock rates: 16, 32, 40 and 64 - if ((clock1 != 16) && (clock1 != 32) && (clock1 != 64) && (clock1 != 40)) { - PrintAndLogEx(FAILED, "error, clock rate" _RED_("%d")" not valid", clock1); - PrintAndLogEx(INFO, "supported clock rates: " _YELLOW_("16, 32, 40, 60") "\n"); - usage_lf_em410x_clone(); + if ((clk != 16) && (clk != 32) && (clk != 64) && (clk != 40)) { + PrintAndLogEx(FAILED, "supported clock rates are " _YELLOW_("16, 32, 40, 64") " got " _RED_("%d") "\n", clk); return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Writing " _YELLOW_("%s") " tag with UID 0x%010" PRIx64 " (clock rate: %d)", (card == 1) ? "T55x7" : "Q5/T5555", id, clock1); + char cardtype[16] = {"T55x7"}; + if (q5) { + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with ID " _GREEN_("%010" PRIX64) " (RF/%d)", cardtype, id, clk); // NOTE: We really should pass the clock in as a separate argument, but to // provide for backwards-compatibility for older firmware, and to avoid // having to add another argument to CMD_LF_EM410X_WRITE, we just store @@ -604,8 +632,8 @@ static int CmdEM410xClone(const char *Cmd) { uint32_t low; } PACKED params; - params.card = card; - params.clock = clock1; + params.card = (q5) ? 0 : 1; + params.clock = clk; params.high = (uint32_t)(id >> 32); params.low = (uint32_t)id; @@ -617,7 +645,7 @@ static int CmdEM410xClone(const char *Cmd) { switch (resp.status) { case PM3_SUCCESS: { PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x reader`") " to verify"); break; } default: { @@ -629,15 +657,15 @@ static int CmdEM410xClone(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - //{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"}, - {"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"}, - {"read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"}, - {"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, - {"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + //{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"}, + {"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"}, + {"reader", CmdEM410xReader, IfPm3Lf, "attempt to read and extract tag data"}, + {"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"}, + {"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, + {"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"spoof", CmdEM410xSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, + {"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem410x.h b/client/src/cmdlfem410x.h index 62d35cf55..d31812b56 100644 --- a/client/src/cmdlfem410x.h +++ b/client/src/cmdlfem410x.h @@ -16,7 +16,7 @@ int CmdLFEM410X(const char *Cmd); int demodEM410x(bool verbose); -void printEM410x(uint32_t hi, uint64_t id); +void printEM410x(uint32_t hi, uint64_t id, bool verbose); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo); int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose); From 97a27c01566700b6cdea79fcbcd47bbbcd2e244b Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Wed, 9 Dec 2020 09:57:17 -0500 Subject: [PATCH 162/174] Remove debug code --- armsrc/em4x70.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index c2f320df9..80f04c8e9 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -162,43 +162,6 @@ static bool get_signalproperties(void) { return true; } - - -/** - * record_liw - * - * prints the timing from 1->0->1... for LIW_TEST_LENGTH - * - */ -/*#define LIW_TEST_LENGTH 64 -static void record_liw(void) { - - uint32_t intervals[LIW_TEST_LENGTH]; - - uint8_t sample; - - // Count duration low, then duration high. - for(int count = 0; count < LIW_TEST_LENGTH-1; count+=2) { - - uint32_t start_ticks = GetTicks(); - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_LOW(sample)); - intervals[count] = GetTicks() - start_ticks; - - start_ticks = GetTicks(); - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_HIGH(sample)); - intervals[count+1] = GetTicks() - start_ticks; - } - - for(int count = 0; count < LIW_TEST_LENGTH-1; count+=2){ - Dbprintf("%d 0", intervals[count]/TICKS_PER_FC); - Dbprintf("%d 1", intervals[count+1]/TICKS_PER_FC); - } -}*/ - /** * get_pulse_length * From e48d343c5c67b8b3384a372b916279b5f00f8260 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Wed, 9 Dec 2020 16:22:38 -0500 Subject: [PATCH 163/174] Fix issue with command parity, adding too many bits to command --- armsrc/em4x70.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 80f04c8e9..1feb448c7 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -278,12 +278,18 @@ static void em4x70_send_bit(int bit) { /** - * em4x70_send_command without parity + * em4x70_send_command */ static void em4170_send_command(uint8_t command) { int parity = 0; + int msb_bit = 0; + + // Non automotive EM4x70 based tags are 3 bits + 1 parity. + // So drop the MSB and send a parity bit instead after the command + if(command_parity) + msb_bit = 1; - for (int i = 0; i < 4; i++) { + for (int i = msb_bit; i < 4; i++) { int bit = (command >> (3 - i)) & 1; em4x70_send_bit(bit); parity ^= bit; From 76bf80a8dd743d75271ae934f8f9300856c6bde8 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Wed, 9 Dec 2020 16:22:52 -0500 Subject: [PATCH 164/174] Update em4x70 info to use cliparser --- client/src/cmdlfem4x70.c | 55 +++++++++++++--------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 4d67b82cd..ae0b3ad22 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -11,29 +11,14 @@ #include "cmdlfem4x70.h" #include #include "cmdparser.h" // command_t +#include "cliparser.h" #include "fileutils.h" -#include "comms.h" #include "commonutil.h" #include "em4x70.h" static int CmdHelp(const char *Cmd); - -static int usage_lf_em4x70_info(void) { - PrintAndLogEx(NORMAL, "Read all information of EM4x70. Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x70_info [h] [v] [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - use even parity for commands"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x70_info")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x70_info p")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - static void print_info_result(uint8_t *data) { PrintAndLogEx(NORMAL, ""); @@ -88,32 +73,28 @@ int CmdEM4x70Info(const char *Cmd) { // envoke reading of a EM4x70 tag which has to be on the antenna because // decoding is done by the device (not on client side) - bool errors = false; - uint8_t cmdp = 0; - em4x70_data_t etd = {0}; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { + CLIParserContext *ctx; - case 'h': - return usage_lf_em4x70_info(); - - case 'p': - etd.parity = true; - cmdp +=1; - break; + CLIParserInit(&ctx, "lf em 4x10 info", + "Tag Information EM4x70\n" + " Tag variants include ID48 automotive transponder.\n" + " ID48 does not use command parity (default).\n" + " V4070 and EM4170 do require parity bit.", + "lf em 4x70 info\n" + "lf em 4x70 -p -> adds parity bit to commands\n" + ); - default: - PrintAndLogEx(WARNING, " Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + void *argtable[] = { + arg_param_begin, + arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_param_end + }; - // validation - if (errors) - return usage_lf_em4x70_info(); + CLIExecWithReturn(ctx, Cmd, argtable, true); + etd.parity = arg_get_lit(ctx, 0); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X70_INFO, (uint8_t *)&etd, sizeof(etd)); From 9f78323c15245829bcb67c79b71853c16a105877 Mon Sep 17 00:00:00 2001 From: Ryan Saridar <8403417+VortixDev@users.noreply.github.com> Date: Thu, 10 Dec 2020 01:58:53 +0000 Subject: [PATCH 165/174] Fix mistaken increment and decrement constants --- include/protocols.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/protocols.h b/include/protocols.h index fcb446661..dafce0024 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -160,8 +160,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MIFARE_MAGICWUPC1 0x40 #define MIFARE_MAGICWUPC2 0x43 #define MIFARE_MAGICWIPEC 0x41 -#define MIFARE_CMD_INC 0xC0 -#define MIFARE_CMD_DEC 0xC1 +#define MIFARE_CMD_DEC 0xC0 +#define MIFARE_CMD_INC 0xC1 #define MIFARE_CMD_RESTORE 0xC2 #define MIFARE_CMD_TRANSFER 0xB0 From afc904cbc72ebb1bd31b281c3ab133aa292027a3 Mon Sep 17 00:00:00 2001 From: Ryan Saridar <8403417+VortixDev@users.noreply.github.com> Date: Thu, 10 Dec 2020 02:00:18 +0000 Subject: [PATCH 166/174] Fix mistaken increment and decrement constants --- tools/mf_nonce_brute/protocol.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/mf_nonce_brute/protocol.h b/tools/mf_nonce_brute/protocol.h index 50784392f..1eda47986 100644 --- a/tools/mf_nonce_brute/protocol.h +++ b/tools/mf_nonce_brute/protocol.h @@ -6,8 +6,8 @@ #define MIFARE_AUTH_KEYA 0x60 #define MIFARE_AUTH_KEYB 0x61 -#define MIFARE_CMD_INC 0xC0 -#define MIFARE_CMD_DEC 0xC1 +#define MIFARE_CMD_DEC 0xC0 +#define MIFARE_CMD_INC 0xC1 #define MIFARE_CMD_RESTORE 0xC2 #define MIFARE_CMD_TRANSFER 0xB0 From df288873ffe8f62f3c19e13e914fa70aca52c141 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 07:56:35 +0100 Subject: [PATCH 167/174] adapt test for new output --- tools/pm3_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index 6f385e906..da880cf00 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -364,7 +364,7 @@ while true; do "AWID - len: 50 FC: 2001 Card: 13371337 - Wiegand: 20fa201980f92, Raw: 0128b12eb1811d7117e22111"; then break; fi if ! CheckExecute slow "lf T55 em410x test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_em410x.pm3; lf search 1'" "EM410x ID found"; then break; fi if ! CheckExecute slow "lf T55 em410x test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_em410x.pm3; lf em 410x demod'" \ - "EM TAG ID : 0F0368568B"; then break; fi + "EM 410x ID 0F0368568B"; then break; fi if ! CheckExecute slow "lf T55 fdxb_animal test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf search 1'" "FDX-B ID found"; then break; fi if ! CheckExecute slow "lf T55 fdxb_animal test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf fdxb demod'" \ "Animal ID 999-000000112233"; then break; fi From 57b20f9392fc1a036f95c1a3a084f9b16257f8ec Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 11:41:04 +0100 Subject: [PATCH 168/174] added prime256v1 / secp256r1 curve --- tools/recover_pk.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 2431c7a5f..8a921c6e7 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -210,6 +210,19 @@ CURVES = { 0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34 ) ), + + ## openssl uses the name: prime256v1 + "secp256r1": ( + 415, + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, + -3, + 0x5AC635D8AA3A93E7B3EbBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B, + ( + 0x6B17D1F2E12c4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, + 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 + ) + ), } def get_curve(name): @@ -313,7 +326,13 @@ def recover(data, signature, alghash=None): recoverable = False elif len(signature) == 57: curve = get_curve("secp224r1") - recoverable = True + recoverable = True + elif len(signature) == 64: + curve = get_curve("secp256r1") + recoverable = False + elif len(signature) == 65: + curve = get_curve("secp256r1") + recoverable = True else: print("Unsupported signature size %i" % len(signature)) exit(1) @@ -408,6 +427,10 @@ def selftests(): {'name': "ICODE DNA, ICODE SLIX2", 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" }, +# ! uses secp256r1 , SHA-256, +# {'name': "Minecraft Earth", +# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], +# 'pk': "" }, ] succeeded = True for t in tests: From ab018ebe6d81d3243d595e1f895238e2fb7453a6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 11:48:09 +0100 Subject: [PATCH 169/174] added - a naive apdu fuzzer for ISO14443A --- client/src/cmdhf14a.c | 141 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index e5d5042f8..576979aad 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -11,12 +11,10 @@ // High frequency ISO14443A commands //----------------------------------------------------------------------------- #include "cmdhf14a.h" - #include #include - #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "cliparser.h" @@ -29,6 +27,9 @@ #include "aidsearch.h" #include "cmdhf.h" // handle HF plot #include "protocols.h" // MAGIC_GEN_1A +#include "cliparser.h" +#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "emv/apduinfo.h" // GetAPDUCodeDescription bool APDUInFramingEnable = true; @@ -2119,6 +2120,139 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return select_status; } +static uint16_t get_sw(uint8_t *d, uint8_t n) { + if (n < 2) + return 0; + + n -= 2; + return d[n] * 0x0100 + d[n + 1]; +} +static int CmdHf14AFuzzapdu(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a apdufuzz", + "Fuzz APDU's of ISO7816 protocol to find valid CLS/INS/P1P2/LE commands.\n" + "It loops all 256 possible values for each byte.\n" + "Tag must be on antenna before running.", + "hf 14a apdufuzz\n" + "hf 14a apdufuzz --cla 80\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, "cla", "", "start CLASS value (1 hex byte)"), + arg_str0(NULL, "ins", "", "start INSTRUCTION value (1 hex byte)"), + arg_str0(NULL, "p1", "", "start P1 value (1 hex byte)"), + arg_str0(NULL, "p2", "", "start P2 value (1 hex byte)"), + arg_str0(NULL, "le", "", "start LENGTH value (1 hex byte)"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int cla_len = 0; + uint8_t cla[1] = {0}; + CLIGetHexWithReturn(ctx, 1, cla, &cla_len); + + int ins_len = 0; + uint8_t ins[1] = {0}; + CLIGetHexWithReturn(ctx, 2, ins, &ins_len); + + int p1_len = 0; + uint8_t p1[1] = {0}; + CLIGetHexWithReturn(ctx, 3, p1, &p1_len); + + int p2_len = 0; + uint8_t p2[1] = {0}; + CLIGetHexWithReturn(ctx, 4, p2, &p2_len); + + int le_len = 0; + uint8_t le[1] = {0}; + CLIGetHexWithReturn(ctx, 5, le, &le_len); + + bool verbose = arg_get_lit(ctx, 6); + CLIParserFree(ctx); + + bool activate_field = true; + bool keep_field_on = true; + + uint8_t a = cla[0]; + uint8_t b = ins[0]; + uint8_t c = p1[0]; + uint8_t d = p2[0]; + uint8_t e = le[0]; + + PrintAndLogEx(SUCCESS, "Starting the apdu fuzzer [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " LE " _GREEN_("%02x")" ]", a,b,c,d,e); + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol("00a404000aa000000440000101000100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) { + DropField(); + return res; + } + + if (activate_field) + activate_field = false; + + uint64_t t1 = msclock(); + do { + do { + do { + do { + do { + if (kbd_enter_pressed()) { + goto out; + } + + uint8_t foo[5] = {a, b, c, d, e}; + int foo_n = sizeof(foo); + + if (verbose) { + PrintAndLogEx(INFO, "%s", sprint_hex(foo, sizeof(foo))); + } + res = ExchangeAPDU14a(foo, foo_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) { + e++; + continue; + } + + uint16_t sw = get_sw(response, resplen); + if (sw != 0x6a86 && + sw != 0x6986 && + sw != 0x6d00 + ) { + PrintAndLogEx(INFO, "%02X %02X %02X %02X %02X (%04x - %s)", a,b,c,d,e, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + } + e++; + if (verbose) { + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + } + + } while (e); + d++; + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + } while (d); + c++; + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + } while (c); + b++; + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + } while (b); + a++; + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + } while(a); + +out: + PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); + DropField(); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"}, @@ -2132,6 +2266,7 @@ static command_t CommandTable[] = { {"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, {"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, {"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"}, + {"apdufuzz", CmdHf14AFuzzapdu, IfPm3Iso14443a, "Fuzz APDU - CLA/INS/P1P2"}, {NULL, NULL, NULL, NULL} }; From 71108ea8226761910f6cab6cf35f0117c0e112da Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 16:02:27 +0100 Subject: [PATCH 170/174] missing zero padding in raw output --- client/src/cmdlfnexwatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c index eefbd03ad..6fa46907e 100644 --- a/client/src/cmdlfnexwatch.c +++ b/client/src/cmdlfnexwatch.c @@ -212,7 +212,7 @@ int demodNexWatch(bool verbose) { PrintAndLogEx(DEBUG, " checksum : %s (0x%02X)", (m_idx < ARRAYLEN(items)) ? _GREEN_("ok") : _RED_("fail"), chk); - PrintAndLogEx(INFO, " Raw : " _YELLOW_("%"PRIX32"%"PRIX32"%"PRIX32), raw1, raw2, raw3); + PrintAndLogEx(INFO, " Raw : " _YELLOW_("%08"PRIX32"%08"PRIX32"%08"PRIX32), raw1, raw2, raw3); return PM3_SUCCESS; } From 936efd160ee50a1eecddca0ee53355277a64b2b7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 17:07:33 +0100 Subject: [PATCH 171/174] lf nexwatch demod - pad hex --- client/src/cmdlfnexwatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c index 6fa46907e..ba6637731 100644 --- a/client/src/cmdlfnexwatch.c +++ b/client/src/cmdlfnexwatch.c @@ -196,12 +196,12 @@ int demodNexWatch(bool verbose) { } // output - PrintAndLogEx(SUCCESS, " NexWatch raw id : " _YELLOW_("0x%"PRIx32), rawid); + PrintAndLogEx(SUCCESS, " NexWatch raw id : " _YELLOW_("0x%08"PRIx32), rawid); if (m_idx < ARRAYLEN(items)) { PrintAndLogEx(SUCCESS, " fingerprint : " _GREEN_("%s"), items[m_idx].desc); } - PrintAndLogEx(SUCCESS, " 88bit id : " _YELLOW_("%"PRIu32) " (" _YELLOW_("0x%"PRIx32)")", cn, cn); + PrintAndLogEx(SUCCESS, " 88bit id : " _YELLOW_("%"PRIu32) " (" _YELLOW_("0x%08"PRIx32)")", cn, cn); PrintAndLogEx(SUCCESS, " mode : %x", mode); if (parity == calc_parity) { From 21f5edb4b99a57e827bf09eb3c5182373b672072 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 10 Dec 2020 21:33:37 +0100 Subject: [PATCH 172/174] more flexible recover_pk --- tools/recover_pk.py | 87 ++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 8a921c6e7..610d785e9 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -210,13 +210,23 @@ CURVES = { 0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34 ) ), - - ## openssl uses the name: prime256v1 + "secp256k1": ( + 714, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, + 0x0000000000000000000000000000000000000000000000000000000000000000, + 0x0000000000000000000000000000000000000000000000000000000000000007, + ( + 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, + 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 + ) + ), + ## openssl uses the name: prime256v1. "secp256r1": ( 415, 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, - -3, + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, 0x5AC635D8AA3A93E7B3EbBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B, ( 0x6B17D1F2E12c4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, @@ -313,30 +323,21 @@ class EllipticCurve: ####################################################################### -def recover(data, signature, alghash=None): - recovered = set() - if len(signature) == 32: - curve = get_curve("secp128r1") - recoverable = False - elif len(signature) == 33: - curve = get_curve("secp128r1") - recoverable = True - elif len(signature) == 56: - curve = get_curve("secp224r1") - recoverable = False - elif len(signature) == 57: - curve = get_curve("secp224r1") - recoverable = True - elif len(signature) == 64: - curve = get_curve("secp256r1") - recoverable = False - elif len(signature) == 65: - curve = get_curve("secp256r1") - recoverable = True +def guess_curvename(signature): + if (len(signature) // 2) & 0xfe == 32 : + curves = [ "secp128r1" ] + elif (len(signature) // 2) & 0xfe == 56: + curves = [ "secp224r1" ] + elif (len(signature) // 2) & 0xfe == 64: + curves = [ "secp256k1", "secp256r1" ] else: - print("Unsupported signature size %i" % len(signature)) - exit(1) + raise ValueError("Unsupported signature size %i" % len(signature)) + return curves +def recover(data, signature, curvename, alghash=None): + recovered = set() + curve = get_curve(curvename) + recoverable = len(signature) % 1 == 1 if (recoverable): try: pk = curve.recover(signature, data, hash=alghash) @@ -358,7 +359,7 @@ def recover(data, signature, alghash=None): pass return recovered -def recover_multiple(uids, sigs, alghash=None): +def recover_multiple(uids, sigs, curvename, alghash=None): recovered = set() assert len(uids) == len(sigs) for i in range(len(uids)): @@ -368,7 +369,7 @@ def recover_multiple(uids, sigs, alghash=None): signature = binascii.unhexlify(sigs[i]) if debug: print("Signature (%2i): " % len(signature), binascii.hexlify(signature)) - recovered_tmp = recover(data, signature, alghash) + recovered_tmp = recover(data, signature, curvename, alghash) if i == 0: if recovered_tmp == set(): break @@ -427,7 +428,7 @@ def selftests(): {'name': "ICODE DNA, ICODE SLIX2", 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" }, -# ! uses secp256r1 , SHA-256, +# uses secp256r1?, SHA-256, # {'name': "Minecraft Earth", # 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], # 'pk': "" }, @@ -435,8 +436,11 @@ def selftests(): succeeded = True for t in tests: print("Testing %-25s" % (t['name']+":"), end="") - recovered = recover_multiple(t['samples'][::2], t['samples'][1::2]) - recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], alghash="sha256") + curvenames = guess_curvename(t['samples'][1]) + recovered = set() + for c in curvenames: + for h in [None, "sha1", "sha256", "sha512"]: + recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], c, alghash=h) if (len(recovered) == 1): pk = recovered.pop() pk = binascii.hexlify(pk).decode('utf8') @@ -465,14 +469,15 @@ if __name__ == "__main__": print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0]) print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0]) exit(1) - - print("Assuming no hash was used in the signature generation:") - recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2]) - print("Possible uncompressed Pk(s):") - for pk in list(recovered): - print(binascii.hexlify(pk).decode('utf8')) - print("Assuming SHA-256 was used in the signature generation:") - recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2], alghash="sha256") - print("Possible uncompressed Pk(s):") - for pk in list(recovered): - print(binascii.hexlify(pk).decode('utf8')) + uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2] + curvenames = guess_curvename(sigs[0]) + for c in curvenames: + print("\nAssuming curve=%s" % c) + print("========================") + for h in [None, "sha1", "sha256", "sha512"]: + print("Assuming hash=%s" % h) + recovered = recover_multiple(uids, sigs, c, alghash=h) + if recovered: + print("Possible uncompressed Pk(s):") + for pk in list(recovered): + print(binascii.hexlify(pk).decode('utf8')) From 9a44a4afe1bf261a873d8ee52ba67d19156d12af Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 10 Dec 2020 21:55:10 +0100 Subject: [PATCH 173/174] recover_pk: more curvs --- tools/recover_pk.py | 70 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 610d785e9..45b0805be 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -199,6 +199,39 @@ CURVES = { 0xCF5AC8395BAFEB13C02DA292DDED7A83 ) ), + "secp192k1": ( + 711, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37, + 0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D, + 0x000000000000000000000000000000000000000000000000, + 0x000000000000000000000000000000000000000000000003, + ( + 0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D, + 0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D + ) + ), + "secp192r1": ( + 409, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC, + 0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1, + ( + 0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012, + 0x07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 + ) + ), + "secp224k1": ( + 712, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D, + 0x10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7, + 0x00000000000000000000000000000000000000000000000000000000, + 0x00000000000000000000000000000000000000000000000000000005, + ( + 0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C, + 0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5 + ) + ), "secp224r1": ( 713, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001, @@ -233,6 +266,28 @@ CURVES = { 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 ) ), + "secp384r1": ( + 715, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973, + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC, + 0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF, + ( + 0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7, + 0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F + ) + ), + "secp521r1": ( + 716, + 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, + 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409, + 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC, + 0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00, + ( + 0x00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66, + 0x011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650 + ) + ) } def get_curve(name): @@ -324,12 +379,19 @@ class EllipticCurve: ####################################################################### def guess_curvename(signature): - if (len(signature) // 2) & 0xfe == 32 : + l = (len(signature) // 2) & 0xfe + if l == 32 : curves = [ "secp128r1" ] - elif (len(signature) // 2) & 0xfe == 56: - curves = [ "secp224r1" ] - elif (len(signature) // 2) & 0xfe == 64: + elif l == 48: + curves = [ "secp192k1", "secp192r1" ] + elif l == 56: + curves = [ "secp224k1", "secp224r1" ] + elif l == 64: curves = [ "secp256k1", "secp256r1" ] + elif l == 96: + curves = [ "secp384r1" ] + elif l == 132: + curves = [ "secp521r1" ] else: raise ValueError("Unsupported signature size %i" % len(signature)) return curves From 6e43db06ae6da184a764e40fb216b4b208b8226f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 10 Dec 2020 22:37:36 +0100 Subject: [PATCH 174/174] adapt test to new output --- tools/pm3_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index da880cf00..cdbc5adb4 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -415,7 +415,7 @@ while true; do "NEDAP (64b) - ID: 12345 subtype: 1 customer code: 291 / 0x123 Raw: FF82246508209953"; then break; fi if ! CheckExecute slow "lf T55 nexwatch test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch.pm3; lf search 1'" "NexWatch ID found"; then break; fi if ! CheckExecute slow "lf T55 nexwatch test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch.pm3; lf nexwatch demod'" \ - "Raw : 56000000213C9F8F150C00"; then break; fi + "Raw : 5600000000213C9F8F150C00"; then break; fi if ! CheckExecute slow "lf T55 nexwatch_nexkey test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch_nexkey.pm3; lf search 1'" "NexWatch ID found"; then break; fi if ! CheckExecute slow "lf T55 nexwatch_nexkey test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch_nexkey.pm3; lf nexwatch demod'" \ "88bit id : 521512301 (0x1f15a56d)"; then break; fi