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