switched from emulator memory to flash memory for various functions

This commit is contained in:
tharexde 2020-11-10 00:39:48 +01:00
commit b791d392b6

View file

@ -16,28 +16,100 @@
#include "util.h" #include "util.h"
#include "commonutil.h" #include "commonutil.h"
#include "cmdparser.h" #include "cmdparser.h"
#include "pmflash.h"
#include "cmdflashmem.h"
#include "em4x50.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 // read data from dump file; file type is derived from file name extension
int res = 0; int res = 0;
size_t bytes_read = 0;
if (str_endswith(filename, ".eml")) 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")) 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 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_EFILE;
return PM3_SUCCESS; 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) { static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t nobytes) {
// fast push mode // 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); 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) { 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) {
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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); CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen);
if (addr <= 0 || addr >= EM4X50_NO_WORDS) { 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; return PM3_EINVARG;
} else { } else {
etd.addresses = (addr << 8) | addr; etd.addresses = (addr << 8) | addr;
etd.addr_given = true; etd.addr_given = true;
} }
if (wordLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]; etd.word = (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3];
} }
if (pwdLen) { if (pwdLen) {
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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); CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen);
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3];
} }
if (npwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password2 = (npwd[0] << 24) | (npwd[1] << 16) | (npwd[2] << 8) | npwd[3]; 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) {
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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) {
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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); CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen);
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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); CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len);
if (pwd1Len != 4) { 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; return PM3_EINVARG;
} else if (pwd2Len != 4) { } 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd1[0] << 24) | (pwd1[1] << 16) | (pwd1[2] << 8) | pwd1[3]; 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); CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen);
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
password = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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 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}; uint8_t pwd[4] = {0x0}, uid[4] = {0x0};
size_t bytes_read = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
em4x50_data_t etd = {.pwd_given = false}; em4x50_data_t etd = {.pwd_given = false};
uint8_t data[DUMP_FILESIZE] = {0x0}; uint8_t data[DUMP_FILESIZE] = {0x0};
@ -853,7 +927,7 @@ int CmdEM4x50Restore(const char *Cmd) {
CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen);
if ((uidLen && fnLen) || (!uidLen && !fnLen)) { 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; return PM3_EINVARG;
} }
@ -868,7 +942,7 @@ int CmdEM4x50Restore(const char *Cmd) {
if (pwdLen) { if (pwdLen) {
if (pwdLen != 4) { 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; return PM3_EINVARG;
} else { } else {
etd.password1 = (pwd[0] << 24) | (pwd[1] << 16) | (pwd[2] << 8) | pwd[3]; 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); PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
// read data from dump file; file type has to be "bin", "eml" or "json" // 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; return PM3_EFILE;
// upload to emulator memory // upload to flash memory
em4x50_seteml(data, 0, DUMP_FILESIZE); res = em4x50_write_flash(data, 0, bytes_read);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Error uploading to flash.");
return res;
}
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_RESTORE, (uint8_t *)&etd, sizeof(etd)); 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 CmdEM4x50Sim(const char *Cmd) {
int slen = 0; int slen = 0, res = 0;
char filename[FILE_PATH_SIZE] = {0}; size_t bytes_read = 0;
uint8_t data[DUMP_FILESIZE] = {0x0}; uint8_t data[DUMP_FILESIZE] = {0x0};
char filename[FILE_PATH_SIZE] = {0};
PacketResponseNG resp;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50_sim", 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" // read data from dump file; file type has to be "bin", "eml" or "json"
if (slen != 0) { 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"); PrintAndLogEx(FAILED, "Read error");
return PM3_EFILE; 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(); clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0); SendCommandNG(CMD_LF_EM4X50_SIM, 0, 0);
PacketResponseNG resp;
WaitForResponse(CMD_LF_EM4X50_SIM, &resp); WaitForResponse(CMD_LF_EM4X50_SIM, &resp);
if (resp.status == PM3_ETEAROFF) { if (resp.status == PM3_ETEAROFF) {
return PM3_SUCCESS; return PM3_SUCCESS;
} else if (resp.status == PM3_ENODATA) { } 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; return PM3_ENODATA;
} }
@ -1037,19 +1134,14 @@ int CmdEM4x50StdRead(const char *Cmd) {
int CmdEM4x50ELoad(const char *Cmd) { int CmdEM4x50ELoad(const char *Cmd) {
int slen = 0; int slen = 0, res = 0;
size_t nobytes = DUMP_FILESIZE; size_t bytes_read = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
uint8_t *data = calloc(nobytes, sizeof(uint8_t)); uint8_t data[DUMP_FILESIZE] = {0x0};
if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50_eload", 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" "lf em 4x50_eload -f lf-4x50dump.json\n"
); );
@ -1064,36 +1156,34 @@ int CmdEM4x50ELoad(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
// read data from dump file; file type has to be "bin", "eml" or "json" // 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"); PrintAndLogEx(FAILED, "Read error");
return PM3_EFILE; return PM3_EFILE;
} }
PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); // upload to flash memory
em4x50_seteml(data, 0, nobytes); 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(INFO, "Done");
PrintAndLogEx(SUCCESS, "Done");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdEM4x50ESave(const char *Cmd) { int CmdEM4x50ESave(const char *Cmd) {
int slen = 0; int slen = 0;
size_t nobytes = DUMP_FILESIZE;
uint32_t serial = 0x0, device_id = 0x0; uint32_t serial = 0x0, device_id = 0x0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
char *fptr = filename; char *fptr = filename;
uint8_t *data = calloc(nobytes, sizeof(uint8_t)); uint8_t data[DUMP_FILESIZE] = {0x0};
if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50_esave", 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\n"
"lf em 4x50_esave -f lf-4x50dump.json\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); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen);
CLIParserFree(ctx); CLIParserFree(ctx);
// download emulator memory // download flash memory
PrintAndLogEx(SUCCESS, "Reading emulator memory..."); PrintAndLogEx(SUCCESS, "Reading flash memory...");
if (!GetFromDevice(BIG_BUF_EML, data, nobytes, 0, NULL, 0, NULL, 2500, false)) { if (!GetFromDevice(FLASH_MEM, data, DUMP_FILESIZE, 0, NULL, 0, NULL, -1, true)) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(data);
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
// valid data regarding em4x50? // valid data regarding em4x50?
serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4);
device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4);
if ((serial == 0x0) && (device_id == 0x0)) { if (serial == device_id) {
PrintAndLogEx(WARNING, "No valid data in emulator memory."); PrintAndLogEx(WARNING, "No valid em4x50 data in flash memory.");
free(data);
return PM3_ENODATA; return PM3_ENODATA;
} }
@ -1132,27 +1220,28 @@ int CmdEM4x50ESave(const char *Cmd) {
FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4);
} }
saveFile(filename, ".bin", data, nobytes); saveFile(filename, ".bin", data, DUMP_FILESIZE);
saveFileEML(filename, data, nobytes, 4); saveFileEML(filename, data, DUMP_FILESIZE, 4);
saveFileJSON(filename, jsfEM4x50, data, nobytes, NULL); saveFileJSON(filename, jsfEM4x50, data, DUMP_FILESIZE, NULL);
free(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdEM4x50Chk(const char *Cmd) { 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}; char filename[FILE_PATH_SIZE] = {0};
PacketResponseNG resp; PacketResponseNG resp;
uint32_t keycnt = 0;
uint8_t *data = NULL;
int slen = 0;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50_chk", CLIParserInit(&ctx, "lf em 4x50_chk",
"Check passwords from dictionary in flash memory", "Check passwords from dictionary in flash memory",
"lf em 4x50_chk\n" "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[] = { void *argtable[] = {
@ -1165,28 +1254,44 @@ int CmdEM4x50Chk(const char *Cmd) {
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen);
CLIParserFree(ctx); CLIParserFree(ctx);
res = loadFileDICTIONARY_safe(filename, (void **)&data, 4, &keycnt); //data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
if (res != PM3_SUCCESS || keycnt == 0 || data == NULL) {
PrintAndLogEx(WARNING, "no keys found in file");
if (data != NULL)
free(data);
return PM3_ESOFT; // 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");
} }
PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycnt);
em4x50_seteml(data, 0, 4 * keycnt); if (res || !keycnt) {
free(data); //free(data);
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;
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;
}
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&keycnt, sizeof(keycnt)); SendCommandNG(CMD_LF_EM4X50_CHK, (uint8_t *)&offset, sizeof(offset));
WaitForResponse(CMD_LF_EM4X50_CHK, &resp); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false);
/*
if (!WaitForResponseTimeout(CMD_LF_EM4X50_CHK, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "Timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
*/
// print response // print response
if ((bool)resp.status) if ((bool)resp.status)
@ -1199,6 +1304,6 @@ int CmdEM4x50Chk(const char *Cmd) {
else else
PrintAndLogEx(FAILED, "No password found"); PrintAndLogEx(FAILED, "No password found");
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(INFO, "Done");
return PM3_SUCCESS; return PM3_SUCCESS;
} }