initial implementation of em4x50 standalone mode

This commit is contained in:
tharexde 2021-02-14 12:20:18 +01:00
commit 9a96157e82
4 changed files with 49 additions and 55 deletions

View file

@ -28,8 +28,8 @@
* *
* On entering stand-alone mode, this module will start simulating EM4x50 data. * On entering stand-alone mode, this module will start simulating EM4x50 data.
* Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml). * Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml).
* If reader sends password different from dump file password, 'new' password * If reader sends password different from dump file password, it is saved in
* is saved in file lf_em4x50_passwords.log in flash memory. * file lf_em4x50_passwords.log in flash memory.
* *
* On switching to read/record mode by pressing pm3 button, module will start * On switching to read/record mode by pressing pm3 button, module will start
* reading EM4x50 data. Each collected data set will be written/appended to the * reading EM4x50 data. Each collected data set will be written/appended to the
@ -65,7 +65,6 @@
#define STATE_SIM 0 #define STATE_SIM 0
#define STATE_READ 1 #define STATE_READ 1
#define EM4X50_TAG_WORD 45
#define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml" #define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml"
#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log" #define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log"
#define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log" #define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log"
@ -75,25 +74,24 @@ uint32_t gPassword;
static void LoadDataInstructions(const char *inputfile) { static void LoadDataInstructions(const char *inputfile) {
Dbprintf(""); Dbprintf("");
Dbprintf("To load datafile to flash and display it:"); Dbprintf("To load datafile to flash and display it:");
Dbprintf(_YELLOW_("1.") " edit input file %s", inputfile); Dbprintf("1. edit input file %s", inputfile);
Dbprintf(_YELLOW_("2.") " start proxmark3 client"); Dbprintf("2. start proxmark3 client");
Dbprintf(_YELLOW_("3.") " mem spiffs load f <filename> o %s", inputfile); Dbprintf("3. mem spiffs load f <filename> o %s", inputfile);
Dbprintf(_YELLOW_("4.") " start standalone mode"); Dbprintf("4. start standalone mode");
} }
static void DownloadLogInstructions(const char *logfile) { static void DownloadLogInstructions(const char *logfile) {
Dbprintf(""); Dbprintf("");
Dbprintf("To get the logfile from flash and display it:"); Dbprintf("To get the logfile from flash and display it:");
Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f <filename>", logfile); Dbprintf("1. mem spiffs dump o %s f <filename>", logfile);
Dbprintf(_YELLOW_("2.") " exit proxmark3 client"); Dbprintf("2. exit proxmark3 client");
Dbprintf(_YELLOW_("3.") " cat <filename>"); Dbprintf("3. cat <filename>");
} }
static bool get_input_data_from_file(uint32_t *tag, char *inputfile) { static bool get_input_data_from_file(uint32_t *tag, char *inputfile) {
size_t now = 0; size_t now = 0;
#ifdef WITH_FLASH
if (exists_in_spiffs(inputfile)) { if (exists_in_spiffs(inputfile)) {
uint32_t size = size_in_spiffs(inputfile); uint32_t size = size_in_spiffs(inputfile);
@ -111,23 +109,21 @@ static bool get_input_data_from_file(uint32_t *tag, char *inputfile) {
} }
Dbprintf(_YELLOW_("read tag data from input file")); Dbprintf(_YELLOW_("read tag data from input file"));
} else {
Dbprintf(_RED_("no input file %s"), inputfile);
} }
BigBuf_free(); BigBuf_free();
#endif
return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID])); return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]));
} }
static void append(const char *filename, uint8_t *entry, size_t entry_len) { static void append(const char *filename, uint8_t *entry, size_t entry_len) {
#ifdef WITH_FLASH
if (exists_in_spiffs(filename)) { if (exists_in_spiffs(filename)) {
rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
} else { } else {
rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
} }
#endif
} }
void ModInfo(void) { void ModInfo(void) {
@ -141,10 +137,8 @@ void RunMod(void) {
uint8_t entry[400], state = STATE_SIM; uint8_t entry[400], state = STATE_SIM;
uint32_t tag[EM4X50_NO_WORDS] = {0x0}; uint32_t tag[EM4X50_NO_WORDS] = {0x0};
#ifdef WITH_FLASH
rdv40_spiffs_lazy_mount(); rdv40_spiffs_lazy_mount();
#endif
StandAloneMode(); StandAloneMode();
Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); Dbprintf(_YELLOW_("Standalone mode THAREXDE started"));
@ -191,8 +185,9 @@ void RunMod(void) {
Dbprintf(_YELLOW_("tag data ok")); Dbprintf(_YELLOW_("tag data ok"));
} else { } else {
Dbprintf(_RED_("error in tag data")); Dbprintf(_RED_("error in tag data"));
LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM);
} }
// init; start with command = standard read mode // init; start with command = standard read mode
em4x50_setup_sim(); em4x50_setup_sim();
gLogin = false; gLogin = false;
@ -209,22 +204,22 @@ void RunMod(void) {
LED(LED_A, 200); LED(LED_A, 200);
SpinDelay(200); SpinDelay(200);
} }
em4x50_handle_commands(&command, tag); em4x50_handle_commands(&command, tag);
// check if new password was found // check if new password was found
if (gPassword != reflect32(tag[0])) { if (gPassword != reflect32(tag[EM4X50_DEVICE_PASSWORD])) {
Dbprintf("received password: %08"PRIx32"", gPassword); Dbprintf("received password: %08"PRIx32"", gPassword);
// append password to logfile in flash memory // append password to logfile in flash memory
memset(entry, 0, sizeof(entry)); memset(entry, 0, sizeof(entry));
sprintf((char *)entry, "%08"PRIx32"\n", gPassword); sprintf((char *)entry, "%08"PRIx32"\n", gPassword);
append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry)); append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry));
gPassword = reflect32(tag[0]); gPassword = reflect32(tag[EM4X50_DEVICE_PASSWORD]);
} }
// if timeout (e.g. no reader field) continue with standard read // if timeout (e.g. no reader field) continue with standard read
// mode and reset former authentication // mode and reset former authentication
if (command == PM3_ETIMEOUT) { if (command == PM3_ETIMEOUT) {
@ -232,7 +227,7 @@ void RunMod(void) {
gLogin = false; gLogin = false;
LED_D_OFF(); LED_D_OFF();
} }
} else if (state == STATE_READ) { } else if (state == STATE_READ) {
if (state_change) { if (state_change) {
@ -263,7 +258,7 @@ void RunMod(void) {
append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry)); append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry));
} }
} }
// reset timer // reset timer
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
@ -271,17 +266,15 @@ void RunMod(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
} }
#ifdef WITH_FLASH
if (state == STATE_READ) { if (state == STATE_READ) {
DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT); DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT);
} else { } else {
LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM); DownloadLogInstructions(LF_EM4X50_LOGFILE_SIM);
} }
LED_D_ON(); LED_D_ON();
rdv40_spiffs_lazy_unmount(); rdv40_spiffs_lazy_unmount();
LED_D_OFF(); LED_D_OFF();
#endif
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();

View file

@ -256,7 +256,7 @@ static uint32_t get_pulse_length(void) {
int32_t timeout = EM4X50_TIMEOUT_PULSE_EVAL, tval = 0; int32_t timeout = EM4X50_TIMEOUT_PULSE_EVAL, tval = 0;
// iterates pulse length (low -> high -> low) // iterates pulse lengths (low -> high -> low)
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
@ -267,7 +267,6 @@ static uint32_t get_pulse_length(void) {
return 0; return 0;
tval = GetTicks(); tval = GetTicks();
//timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
timeout = EM4X50_TIMEOUT_PULSE_EVAL; timeout = EM4X50_TIMEOUT_PULSE_EVAL;
while (sample < gHigh && (timeout--)) while (sample < gHigh && (timeout--))
@ -276,7 +275,6 @@ static uint32_t get_pulse_length(void) {
if (timeout <= 0) if (timeout <= 0)
return 0; return 0;
//timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
timeout = EM4X50_TIMEOUT_PULSE_EVAL; timeout = EM4X50_TIMEOUT_PULSE_EVAL;
while (sample > gLow && (timeout--)) while (sample > gLow && (timeout--))
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
@ -305,7 +303,6 @@ static void em4x50_reader_send_bit(int bit) {
// disable modulation (activate the field) for 7 cycles of carrier // disable modulation (activate the field) for 7 cycles of carrier
// period (Opt64) // period (Opt64)
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
//while (AT91C_BASE_TC0->TC_CV < T0 * 7);
while (GetTicks() - tval < 7 * CYCLES2TICKS); while (GetTicks() - tval < 7 * CYCLES2TICKS);
// enable modulation (drop the field) for remaining first // enable modulation (drop the field) for remaining first
@ -862,16 +859,16 @@ void em4x50_read(em4x50_data_t *etd) {
LED_C_ON(); LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) { if (get_signalproperties() && find_em4x50_tag()) {
LED_C_OFF(); LED_C_OFF();
LED_D_ON(); LED_D_ON();
// try to login with given password // try to login with given password
if (etd->pwd_given) if (etd->pwd_given)
blogin = (login(etd->password1) == PM3_SUCCESS); blogin = (login(etd->password1) == PM3_SUCCESS);
// only one word has to be read -> first word read = last word read // only one word has to be read -> first word read = last word read
if (blogin) if (blogin)
status = selective_read(etd->addresses, words); status = selective_read(etd->addresses, words);
} }
LEDsoff(); LEDsoff();
@ -914,7 +911,7 @@ void em4x50_reader(void) {
int now = 0; int now = 0;
uint32_t words[EM4X50_NO_WORDS] = {0x0}; uint32_t words[EM4X50_NO_WORDS] = {0x0};
em4x50_setup_read(); em4x50_setup_read();
LED_C_ON(); LED_C_ON();
if (get_signalproperties() && find_em4x50_tag()) { if (get_signalproperties() && find_em4x50_tag()) {
@ -1245,7 +1242,6 @@ static int em4x50_sim_read_bit(void) {
if (timeout <= 0) { if (timeout <= 0) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
//timeout = EM4X50_T_SIMULATION_TIMEOUT_READ;
// now we have a reference "position", from here it will take // now we have a reference "position", from here it will take
// slightly less than 32 cycles until the end of the bit period // slightly less than 32 cycles until the end of the bit period
@ -1447,7 +1443,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag) {
WDT_HIT(); WDT_HIT();
command = em4x50_sim_send_listen_window(tag); command = em4x50_sim_send_listen_window(tag);
if (command != PM3_SUCCESS) { if (command != PM3_SUCCESS) {
return command; return command;
} }
@ -1543,7 +1539,7 @@ static int em4x50_sim_handle_login_command(uint32_t *tag) {
em4x50_sim_send_nak(); em4x50_sim_send_nak();
gLogin = false; gLogin = false;
LED_D_OFF(); LED_D_OFF();
// save transmitted password for future use (e.g. standalone mode) // save transmitted password for future use (e.g. standalone mode)
gPassword = password; gPassword = password;
} }
@ -1782,7 +1778,7 @@ void em4x50_handle_commands(int *command, uint32_t *tag) {
// LED D -> operations that require authentication are possible // LED D -> operations that require authentication are possible
void em4x50_sim(uint32_t *password) { void em4x50_sim(uint32_t *password) {
int command = 0; int command = PM3_ENODATA;
uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t tag[EM4X50_NO_WORDS] = {0x0}; uint32_t tag[EM4X50_NO_WORDS] = {0x0};

View file

@ -920,14 +920,14 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
uint16_t checker = 0; uint16_t checker = 0;
for (;;) { for (;;) {
WDT_HIT(); WDT_HIT();
if (flip == 2) { if (flip == 3) {
if (data_available()) if (data_available())
return false; return false;
flip = 0; flip = 0;
} }
if (checker >= 4000) { if (checker >= 3000) {
if (BUTTON_PRESS()) if (BUTTON_PRESS())
return false; return false;

View file

@ -327,15 +327,19 @@ static int CmdHF14AJookiSim(const char *Cmd) {
jooki_print(b64, result, false); jooki_print(b64, result, false);
// copy UID from base64 url parameter
uint8_t uid[7] = {0};
memcpy(uid, result + 5, 7);
// hf mfu sim... // hf mfu sim...
uint8_t *data = calloc(144, sizeof(uint8_t)); uint8_t *data = calloc(144, sizeof(uint8_t));
// copy UID from base64 url parameter memcpy(data, uid, 3);
memcpy(data, result + 5, 3); memcpy(data + (1*4), uid + 3, 4);
// bbc0 // bbc0
data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2]; data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2];
memcpy(data + (1*4), result + 8, 4);
// bbc1 // bbc1
data[8] = data[4] ^ data[5] ^ data[6] ^ data[7]; data[8] = data[4] ^ data[5] ^ data[6] ^ data[7];
@ -398,8 +402,9 @@ static int CmdHF14AJookiSim(const char *Cmd) {
// NTAG, 7 byte UID in eloaded data. // NTAG, 7 byte UID in eloaded data.
payload.tagtype = 7; payload.tagtype = 7;
payload.flags = FLAG_7B_UID_IN_DATA; payload.flags = FLAG_UID_IN_EMUL;
payload.exitAfter = 0; payload.exitAfter = 0;
memcpy(payload.uid, uid, sizeof(uid));
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));