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);