From 12071080a6abf6d84c65f6469ea7744fbcbb390e Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 7 Jan 2021 01:22:46 +0100 Subject: [PATCH] next step (half duplex simulation): all commands seem to work --- armsrc/appmain.c | 2 +- armsrc/em4x50.c | 247 ++++++++++++++++++++++++++++++--------- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x50.c | 20 +++- 4 files changed, 212 insertions(+), 59 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 6fba90e0e..b3f752fb8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1136,7 +1136,7 @@ static void PacketReceived(PacketCommandNG *packet) { // destroy the Emulator Memory. //----------------------------------------------------------------------------- FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - em4x50_sim(); + em4x50_sim((uint32_t *)packet->data.asBytes); break; } case CMD_LF_EM4X50_READER: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index e0b93ce0f..9ff516797 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -61,6 +61,8 @@ int gLow = 60; // a global parameter is needed to indicate whether a previous login was // successful, so operations that require authentication may be performed bool gLogin = 0; +// additionally a global variable to identify the WritePassword process +bool gWritePasswordProcess = 0; int gcount = 0; int gcycles = 0; @@ -218,6 +220,9 @@ static void em4x50_setup_sim(void) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Watchdog hit + WDT_HIT(); } // calculate signal properties (mean amplitudes) from measured data: @@ -840,7 +845,7 @@ static uint8_t em4x50_sim_read_byte_with_parity_check(void) { return (parity == pval) ? byte : 0; } -static uint32_t em4x50_sim_read_word(void) { +static bool em4x50_sim_read_word(uint32_t *word) { uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; uint8_t bytes[4] = {0}; @@ -864,10 +869,11 @@ static uint32_t em4x50_sim_read_word(void) { // check parities if ((parities == parities_calculated) && (stop_bit == 0)) { - return BYTES2UINT32(bytes); + *word = BYTES2UINT32(bytes); + return true; } - return 0; + return false; } static void em4x50_sim_send_ack(void) { @@ -969,10 +975,9 @@ static bool em4x50_sim_send_listen_window(void) { static void em4x50_sim_handle_login_command(uint32_t *tag) { - uint32_t password = 0; - // read password - password = em4x50_sim_read_word(); + uint32_t password = 0; + bool pwd_ok = em4x50_sim_read_word(&password); // processing pause time (corresponds to a "1" bit) em4x50_sim_send_bit(1); @@ -980,7 +985,7 @@ static void em4x50_sim_handle_login_command(uint32_t *tag) { // empirically determined delay (to be examined seperately) wait_cycles(1); - if (password == tag[0]) { + if (pwd_ok && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { em4x50_sim_send_ack(); gLogin = true; } else { @@ -1010,43 +1015,87 @@ static void em4x50_sim_handle_reset_command(uint32_t *tag) { static void em4x50_sim_handle_write_command(uint32_t *tag) { - uint8_t address = 0; - uint32_t data = 0; - // read address + uint8_t address = 0; address = em4x50_sim_read_byte_with_parity_check(); // read data - data = em4x50_sim_read_word(); - - // extract necessary control data - bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - - // save data to tag - tag[address] = data; + uint32_t data = 0; + bool word_ok = em4x50_sim_read_word(&data); // write access time wait_cycles(EM4X50_T_TAG_TWA); - if ((address >= fwrp) && (address <= lwrp)) { + if (word_ok == false) { em4x50_sim_send_nak(); - } else if ((address == EM4X50_DEVICE_SERIAL) - && (address == EM4X50_DEVICE_ID) - && (address == 0) - ) { - em4x50_sim_send_nak(); - } else { - em4x50_sim_send_ack(); + em4x50_sim_handle_command(0, tag); + } + + // extract necessary control data + bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; + // extract protection data: + // first word write protected + int fwwp = reflect8((tag[EM4X50_PROTECTION] >> 24) & 0xFF); + // last word write protected + int lwwp = reflect8((tag[EM4X50_PROTECTION] >> 16) & 0xFF); + + switch (address) { + + case EM4X50_DEVICE_PASSWORD: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + case EM4X50_PROTECTION: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } + break; + + case EM4X50_CONTROL: + if (gLogin) { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } + break; + + case EM4X50_DEVICE_SERIAL: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + case EM4X50_DEVICE_ID: + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + break; + + default: + if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } else { + tag[address] = reflect32(data); + em4x50_sim_send_ack(); + } + break; } // EEPROM write time wait_cycles(EM4X50_T_TAG_TWEE); + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" seems to solve the problem + em4x50_sim_send_bit(1); + em4x50_sim_send_ack(); - // if "read after write" (raw) bit is set, repeat written data once + // if "read after write" (raw) bit is set, send written data once if (raw) { em4x50_sim_send_listen_window(tag); em4x50_sim_send_listen_window(tag); @@ -1057,25 +1106,90 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) { em4x50_sim_handle_command(0, tag); } +static void em4x50_sim_handle_writepwd_command(uint32_t *tag) { + + bool pwd_ok = false; + + if (gWritePasswordProcess == false) { + + gWritePasswordProcess = true; + + // read password + uint32_t act_password = 0; + pwd_ok = em4x50_sim_read_word(&act_password); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (pwd_ok && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) { + em4x50_sim_send_ack(); + gLogin = true; + } else { + em4x50_sim_send_nak(); + gLogin = false; + em4x50_sim_handle_command(0, tag); + } + + em4x50_sim_send_listen_window(tag); + + } else { + + gWritePasswordProcess = false; + + // read new password + uint32_t new_password = 0; + pwd_ok = em4x50_sim_read_word(&new_password); + + // write access time + wait_cycles(EM4X50_T_TAG_TWA); + + if (pwd_ok) { + em4x50_sim_send_ack(); + tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password); + } else { + em4x50_sim_send_ack(); + em4x50_sim_handle_command(0, tag); + } + + // EEPROM write time + wait_cycles(EM4X50_T_TAG_TWEE); + + // strange: need some sort of 'waveform correction', otherwise ack signal + // will not be detected; sending a single "1" seems to solve the problem + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + // continue with standard read mode + em4x50_sim_handle_command(0, tag); + } +} + static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { - uint32_t address = 0; - // read password - address = em4x50_sim_read_word(); + uint32_t address = 0; + bool addr_ok = em4x50_sim_read_word(&address); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + if (addr_ok) { + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_nak(); + em4x50_sim_handle_command(0, tag); + } // extract control data int fwr = address & 0xFF; // first word read int lwr = (address >> 8) & 0xFF; // last word read - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - - // processing pause time (corresponds to a "1" bit) - em4x50_sim_send_bit(1); - - em4x50_sim_send_ack(); + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { @@ -1090,7 +1204,7 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); } else { - em4x50_sim_send_word(tag[i]); + em4x50_sim_send_word(reflect32(tag[i])); } } } @@ -1099,11 +1213,13 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { // extract control data - int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read - int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read - // extract protection data - int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected - int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read + int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read + // extract protection data: + // first word read protected + int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF; + // last word read protected + int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF; // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { @@ -1117,7 +1233,7 @@ static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { if ((i >= fwrp) && (i <= lwrp)) { em4x50_sim_send_word(0x00); } else { - em4x50_sim_send_word(tag[i]); + em4x50_sim_send_word(reflect32(tag[i])); } } } @@ -1140,7 +1256,7 @@ static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag) { break; case EM4X50_COMMAND_WRITE_PASSWORD: - Dbprintf("Command = write_password"); + em4x50_sim_handle_writepwd_command(tag); break; case EM4X50_COMMAND_SELECTIVE_READ: @@ -1164,9 +1280,15 @@ static void check_rm_request(uint32_t *tag) { // look for second zero if (get_cycles() < cond) { - // read mode request detected, get command from reader - uint8_t command = em4x50_sim_read_byte_with_parity_check(); - em4x50_sim_handle_command(command, tag); + // if command before was EM4X50_COMMAND_WRITE_PASSWORD + // switch to separate process + if (gWritePasswordProcess) { + em4x50_sim_handle_command(EM4X50_COMMAND_WRITE_PASSWORD, tag); + } else { + // read mode request detected, get command from reader + uint8_t command = em4x50_sim_read_byte_with_parity_check(); + em4x50_sim_handle_command(command, tag); + } } } } @@ -1514,8 +1636,13 @@ static int write(uint32_t word, uint32_t addresses) { // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) // for saving data and should return with ACK - if (check_ack(false)) + for (int i = 0; i < 50; i++) { + wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + } + + if (check_ack(false)) { return PM3_SUCCESS; + } } } } else { @@ -1554,9 +1681,12 @@ static int write_password(uint32_t password, uint32_t new_password) { // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer(T0 * EM4X50_T_TAG_TWA); - if (check_ack(false)) - if (check_ack(false)) + if (check_ack(false)) { + //Dbprintf("zweites ack"); + if (check_ack(false)) { return PM3_SUCCESS; + } + } } } } else { @@ -1646,13 +1776,18 @@ void em4x50_writepwd(em4x50_data_t *etd) { } // simulate uploaded data in emulator memory -void em4x50_sim() { +void em4x50_sim(uint32_t *password) { int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t tag[EM4X50_NO_WORDS] = {0x0}; for (int i = 0; i < EM4X50_NO_WORDS; i++) - tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + tag[i] = bytes_to_num(em4x50_mem + (i * 4), 4); + + // via eload uploaded dump usually does not contain a password + if (tag[EM4X50_DEVICE_PASSWORD] == 0) { + tag[EM4X50_DEVICE_PASSWORD] = reflect32(*password); + } // only if valid em4x50 data (e.g. uid == serial) if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) { diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index a753b0808..5d4812f42 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -19,7 +19,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(uint32_t *password); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); void em4x50_test(em4x50_test_t *ett); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index d4a458438..3aea9e981 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1211,25 +1211,43 @@ int CmdEM4x50Restore(const char *Cmd) { } int CmdEM4x50Sim(const char *Cmd) { + + uint32_t password = 0; + CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 sim", "Simulates a EM4x50 tag.\n" "Upload using `lf em 4x50 eload`", "lf em 4x50 sim" + "lf em 4x50 sim -p 27182818 -> uses password for eload data" ); void *argtable[] = { arg_param_begin, + arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); + return PM3_EINVARG; + } else { + password = BYTES2UINT32(pwd); + } + } CLIParserFree(ctx); PrintAndLogEx(INFO, "Simulating data from emulator memory"); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, NULL, 0); + SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&password, sizeof(password)); PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); if (resp.status == PM3_SUCCESS)