From 01b2c14616b6e09b37033f79b1620a6d071dc996 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 9 Dec 2020 12:18:01 +0100 Subject: [PATCH] adapt and fix memoryleaks in Em4x50 --- armsrc/em4x50.c | 217 +++++------ client/src/cmdhfthinfilm.c | 2 +- client/src/cmdlfem4x50.c | 733 ++++++++++++++++--------------------- client/src/cmdwiegand.c | 2 +- 4 files changed, 409 insertions(+), 545 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 620083a32..36923b6a5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -55,19 +55,17 @@ int gHigh = 190; int gLow = 60; +// do nothing for using timer0 static void wait_timer(uint32_t period) { - - // do nothing for using timer0 - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < period); } + +// extract and check parities +// return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { - // extract and check parities - // return result of parity check and extracted plain data - uint8_t row_parities = 0x0, col_parities = 0x0; uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; @@ -172,11 +170,10 @@ static void em4x50_setup_sim(void) { AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; } +// calculate signal properties (mean amplitudes) from measured data: +// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow static bool get_signalproperties(void) { - // calculate signal properties (mean amplitudes) from measured data: - // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow - bool signal_found = false; int no_periods = 32, pct = 75, noise = 140; uint8_t sample_ref = 127; @@ -236,13 +233,12 @@ static bool get_signalproperties(void) { return true; } +// returns true if bit is undefined by evaluating a single sample within +// a bit period (given there is no LIW, ACK or NAK) +// This function is used for identifying a listen window in functions +// "find_double_listen_window" and "check_ack" static bool invalid_bit(void) { - // returns true if bit is undefined by evaluating a single sample within - // a bit period (given there is no LIW, ACK or NAK) - // This function is used for identifying a listen window in functions - // "find_double_listen_window" and "check_ack" - // get sample at 3/4 of bit period wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); @@ -292,17 +288,13 @@ static uint32_t get_pulse_length(void) { } +// check if pulse length corresponds to given length static bool check_pulse_length(uint32_t pl, int length) { - - // check if pulse length corresponds to given length - return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); - + return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); } +// send single bit according to EM4x50 application note and datasheet static void em4x50_reader_send_bit(int bit) { - - // send single bit according to EM4x50 application note and datasheet - // reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; @@ -330,19 +322,15 @@ static void em4x50_reader_send_bit(int bit) { } } +// send byte (without parity) static void em4x50_reader_send_byte(uint8_t byte) { - - // send byte (without parity) - - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { em4x50_reader_send_bit((byte >> (7 - i)) & 1); - + } } +// send byte followed by its (equal) parity bit static void em4x50_reader_send_byte_with_parity(uint8_t byte) { - - // send byte followed by its (equal) parity bit - int parity = 0, bit = 0; for (int i = 0; i < 8; i++) { @@ -354,11 +342,9 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { em4x50_reader_send_bit(parity); } +// send 32 bit word with parity bits according to EM4x50 datasheet +// word hast be sent in msb notation static void em4x50_reader_send_word(const uint32_t word) { - - // send 32 bit word with parity bits according to EM4x50 datasheet - // word hast be sent in msb notation - uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; for (int i = 0; i < 4; i++) { @@ -373,10 +359,8 @@ static void em4x50_reader_send_word(const uint32_t word) { em4x50_reader_send_bit(0); } +// find single listen window static bool find_single_listen_window(void) { - - // find single listen window - int cnt_pulses = 0; LED_B_ON(); @@ -398,18 +382,15 @@ static bool find_single_listen_window(void) { } LED_B_OFF(); - return false; } +// find two successive listen windows that indicate the beginning of +// data transmission +// double listen window to be detected within 1600 pulses -> worst case +// reason: first detectable double listen window after 34 words +// -> 34 words + 34 single listen windows -> about 1600 pulses static int find_double_listen_window(bool bcommand) { - - // find two successive listen windows that indicate the beginning of - // data transmission - // double listen window to be detected within 1600 pulses -> worst case - // reason: first detectable double listen window after 34 words - // -> 34 words + 34 single listen windows -> about 1600 pulses - int cnt_pulses = 0; LED_B_ON(); @@ -471,34 +452,29 @@ static int find_double_listen_window(bool bcommand) { cnt_pulses++; } - LED_B_OFF(); - + LED_B_OFF(); return PM3_EFAILED; } +// function is used to check wether a tag on the proxmark is an +// EM4x50 tag or not -> speed up "lf search" process static bool find_em4x50_tag(void) { - - // function is used to check wether a tag on the proxmark is an - // EM4x50 tag or not -> speed up "lf search" process return find_single_listen_window(); } +// To issue a command we have to find a listen window first. +// Because identification and synchronization at the same time is not +// possible when using pulse lengths a double listen window is used. static int request_receive_mode(void) { - - // To issue a command we have to find a listen window first. - // Because identification and synchronization at the same time is not - // possible when using pulse lengths a double listen window is used. return find_double_listen_window(true); } +// returns true if signal structue corresponds to ACK, anything else is +// counted as NAK (-> false) +// Only relevant for pasword writing function: +// If is true then within the single listen window right after the +// ack signal a RM request has to be sent. static bool check_ack(bool bliw) { - - // returns true if signal structue corresponds to ACK, anything else is - // counted as NAK (-> false) - // Only relevant for pasword writing function: - // If is true then within the single listen window right after the - // ack signal a RM request has to be sent. - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { @@ -547,12 +523,10 @@ static bool check_ack(bool bliw) { return false; } +// decodes one word by evaluating pulse lengths and previous bit; +// word must have 45 bits in total: +// 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit static int get_word_from_bitstream(uint32_t *data) { - - // decodes one word by evaluating pulse lengths and previous bit; - // word must have 45 bits in total: - // 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit - bool bitchange = false; int cnt = 0; uint32_t pl = 0; @@ -707,10 +681,10 @@ static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { for (int i = 0; i < 8; i++) parity ^= (byte >> i) & 1; - if (!em4x50_sim_send_byte(byte)) + if (em4x50_sim_send_byte(byte) == false) return false;; - if (!em4x50_sim_send_bit(parity)) + if (em4x50_sim_send_bit(parity) == false) return false; return true; @@ -724,9 +698,11 @@ bool em4x50_sim_send_word(uint32_t word) { 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)) + for (int i = 0; i < 4; i++) { + if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == false) { return false; + } + } // column parity for (int i = 0; i < 8; i++) { @@ -735,11 +711,11 @@ bool em4x50_sim_send_word(uint32_t word) { cparity ^= (((word >> ((3 - j) * 8)) & 0xFF) >> (7 - i)) & 1; } } - if (!em4x50_sim_send_byte(cparity)) + if (em4x50_sim_send_byte(cparity) == false) return false; // stop bit - if (!em4x50_sim_send_bit(0)) + if (em4x50_sim_send_bit(0) == false) return false; return true; @@ -790,11 +766,9 @@ bool em4x50_sim_send_listen_window(void) { return true; } +// simple login to EM4x50, +// used in operations that require authentication static bool login(uint32_t password) { - - // simple login to EM4x50, - // used in operations that require authentication - if (request_receive_mode() == PM3_SUCCESS) { // send login command @@ -817,10 +791,8 @@ static bool login(uint32_t password) { return PM3_EFAILED; } +// searching for password in given range static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { - - // searching for password in given range - bool pwd_found = false; int cnt = 0; @@ -868,42 +840,33 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { return pwd_found; } +// login into EM4x50 void em4x50_login(uint32_t *password) { - - // login into EM4x50 - - uint8_t status = PM3_EFAILED; - em4x50_setup_read(); - // set gHigh and gLow + uint8_t status = PM3_EFAILED; if (get_signalproperties() && find_em4x50_tag()) status = login(*password); lf_finalize(); - reply_ng(CMD_LF_EM4X50_LOGIN, status, 0, 0); + reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0); } +// envoke password search void em4x50_brute(em4x50_data_t *etd) { - - // envoke password search + em4x50_setup_read(); bool bsuccess = false; uint32_t pwd = 0x0; - - em4x50_setup_read(); - if (get_signalproperties() && find_em4x50_tag()) bsuccess = brute(etd->password1, etd->password2, &pwd); lf_finalize(); - reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess, (uint8_t *)(&pwd), 32); + reply_ng(CMD_LF_EM4X50_BRUTE, bsuccess ? PM3_SUCCESS : PM3_EFAILED, (uint8_t *)(&pwd), sizeof(pwd)); } +// check passwords from dictionary content in flash memory void em4x50_chk(uint8_t *filename) { - - // check passwords from dictionary content in flash memory - int status = PM3_EFAILED; uint32_t pwd = 0x0; @@ -951,13 +914,11 @@ void em4x50_chk(uint8_t *filename) { #endif lf_finalize(); - reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, 32); + reply_ng(CMD_LF_EM4X50_CHK, status, (uint8_t *)&pwd, sizeof(pwd)); } +// resets EM4x50 tag (used by write function) static int reset(void) { - - // resets EM4x50 tag (used by write function) - if (request_receive_mode() == PM3_SUCCESS) { // send reset command @@ -974,11 +935,10 @@ static int reset(void) { return PM3_EFAILED; } +// reads data that tag transmits when exposed to reader field +// (standard read mode); number of read words is saved in static int standard_read(int *now, uint32_t *words) { - // reads data that tag transmits when exposed to reader field - // (standard read mode); number of read words is saved in - int fwr = *now, res = PM3_EFAILED; // start with the identification of two successive listening windows @@ -999,11 +959,10 @@ static int standard_read(int *now, uint32_t *words) { return res; } +// reads from "first word read" (fwr) to "last word read" (lwr) +// result is verified by "standard read mode" static int selective_read(uint32_t addresses, uint32_t *words) { - // reads from "first word read" (fwr) to "last word read" (lwr) - // result is verified by "standard read mode" - int status = PM3_EFAILED; uint8_t fwr = addresses & 0xFF; // first word read (first byte) uint8_t lwr = (addresses >> 8) & 0xFF; // last word read (second byte) @@ -1033,10 +992,8 @@ static int selective_read(uint32_t addresses, uint32_t *words) { return status; } +// reads by using "selective read mode" -> bidirectional communication void em4x50_read(em4x50_data_t *etd) { - - // reads by using "selective read mode" -> bidirectional communication - bool blogin = true; int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -1057,13 +1014,14 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); + + // iceman: this hardcoded 136 value.... reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); } +// collects as much information as possible via selective read mode void em4x50_info(em4x50_data_t *etd) { - // collects as much information as possible via selective read mode - bool blogin = true; int status = PM3_EFAILED; uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) @@ -1071,7 +1029,6 @@ void em4x50_info(em4x50_data_t *etd) { em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // login with given password @@ -1083,19 +1040,19 @@ void em4x50_info(em4x50_data_t *etd) { } lf_finalize(); + + // iceman: this hardcoded 136 value.... reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); } +// reads data that tag transmits "voluntarily" -> standard read mode void em4x50_reader(void) { - // reads data that tag transmits "voluntarily" -> standard read mode - int now = 0; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) standard_read(&now, words); @@ -1104,9 +1061,8 @@ void em4x50_reader(void) { reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } +// writes to specified static int write(uint32_t word, uint32_t addresses) { - - // writes to specified if (request_receive_mode() == PM3_SUCCESS) { @@ -1144,10 +1100,8 @@ static int write(uint32_t word, uint32_t addresses) { return PM3_EFAILED; } +// changes password from to static int write_password(uint32_t password, uint32_t new_password) { - - // changes password from to - if (request_receive_mode() == PM3_SUCCESS) { // send write password command @@ -1187,18 +1141,15 @@ static int write_password(uint32_t password, uint32_t new_password) { return PM3_EFAILED; } +// write operation process for EM4x50 tag, +// single word is written to given address, verified by selective read operation +// wrong password -> return with PM3_EFAILED void em4x50_write(em4x50_data_t *etd) { - - // write operation process for EM4x50 tag, - // single word is written to given address, verified by selective read operation - // wrong password -> return with PM3_EFAILED - int status = PM3_EFAILED; uint32_t words[EM4X50_NO_WORDS] = {0x0}; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // if password is given try to login first @@ -1245,15 +1196,12 @@ void em4x50_write(em4x50_data_t *etd) { reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); } +// simple change of password void em4x50_writepwd(em4x50_data_t *etd) { - - // simple change of password - int status = PM3_EFAILED; em4x50_setup_read(); - // set gHigh and gLow if (get_signalproperties() && find_em4x50_tag()) { // login and change password @@ -1268,14 +1216,12 @@ void em4x50_writepwd(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITEPWD, status, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITEPWD, status, NULL, 0); } +// simulate uploaded data in emulator memory +// (currently simulation allows only a one-way communication) void em4x50_sim(uint8_t *filename) { - - // simulate uploaded data in emulator memory - // (currently simulation allows only a one-way communication) - int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; @@ -1313,7 +1259,8 @@ void em4x50_sim(uint8_t *filename) { em4x50_setup_sim(); - while (!BUTTON_PRESS()) { + // iceman, will need a usb cmd check to break as well + while (BUTTON_PRESS() == false) { WDT_HIT(); em4x50_sim_send_listen_window(); @@ -1333,5 +1280,5 @@ void em4x50_sim(uint8_t *filename) { BigBuf_free(); lf_finalize(); - reply_ng(CMD_LF_EM4X50_SIM, status, 0, 0); + reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } diff --git a/client/src/cmdhfthinfilm.c b/client/src/cmdhfthinfilm.c index 9f7f21912..48844b759 100644 --- a/client/src/cmdhfthinfilm.c +++ b/client/src/cmdhfthinfilm.c @@ -107,7 +107,7 @@ static int CmdHfThinFilmInfo(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + CLIParserFree(ctx); return infoThinFilm(true); } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 6327f600d..ccdf30394 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -26,10 +26,11 @@ static int CmdHelp(const char *Cmd); static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure - - for (int i = fwr; i <= lwr; i++) - for (int j = 0; j < 4; j++) - words[i].byte[j] = data[i * 4 + (3 - j)]; + for (int i = fwr; i <= lwr; i++) { + for (int j = 0; j < 4; j++) { + words[i].byte[j] = data[i * 4 + (3 - j)]; + } + } } static void print_result(const em4x50_word_t *words, int fwr, int lwr) { @@ -169,18 +170,12 @@ static void em4x50_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { } int CmdEM4x50ELoad(const char *Cmd) { - - int slen = 0; - size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0}; - uint8_t data[DUMP_FILESIZE] = {0x0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 eload", "Loads EM4x50 tag dump into emulator memory on device.", - "lf em 4x50 eload -f mydump.bin -> uploads bin file ./mydump.bin\n" - "lf em 4x50 eload -f mydump.eml -> uploads eml file ./mydump.eml\n" - "lf em 4x50 eload -f mydump.json -> uploads json file ./mydump.json\n" + "lf em 4x50 eload -f mydump.bin\n" + "lf em 4x50 eload -f mydump.eml\n" + "lf em 4x50 eload -f mydump.json" ); void *argtable[] = { @@ -190,10 +185,15 @@ int CmdEM4x50ELoad(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); // read data from dump file; file type has to be "bin", "eml" or "json" + size_t bytes_read = 0; + uint8_t data[DUMP_FILESIZE] = {0x0}; + if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Read error"); return PM3_EFILE; @@ -208,20 +208,13 @@ int CmdEM4x50ELoad(const char *Cmd) { } int CmdEM4x50ESave(const char *Cmd) { - - int slen = 0; - uint32_t serial = 0x0, device_id = 0x0; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - uint8_t data[DUMP_FILESIZE] = {0x0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 esave", "Saves bin/eml/json dump file of emulator memory.", - "lf em 4x50 esave -> use UID as filename\n" - "lf em 4x50 esave -f mydump.bin -> saves to bin file ./mydump.bin\n" - "lf em 4x50 esave -f mydump.eml -> saves to eml file ./mydump.eml\n" - "lf em 4x50 esave -f mydump.json -> saves to json file ./mydump.json\n" + "lf em 4x50 esave -> use UID as filename\n" + "lf em 4x50 esave -f mydump.bin\n" + "lf em 4x50 esave -f mydump.eml\n" + "lf em 4x50 esave -f mydump.json\n" ); void *argtable[] = { @@ -231,27 +224,31 @@ int CmdEM4x50ESave(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); // download emulator memory PrintAndLogEx(SUCCESS, "Reading emulator memory..."); - if (!GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false)) { + uint8_t data[DUMP_FILESIZE] = {0x0}; + if (GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); return PM3_ETIMEOUT; } // valid em4x50 data? - serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); - device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + uint32_t serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + uint32_t device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); if (serial == device_id) { PrintAndLogEx(WARNING, "No valid em4x50 data in flash memory."); return PM3_ENODATA; } // user supplied filename? - if (slen == 0) { + if (fnlen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; fptr += snprintf(fptr, sizeof(filename), "lf-4x50-"); FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); } @@ -263,16 +260,10 @@ int CmdEM4x50ESave(const char *Cmd) { } int CmdEM4x50Login(const char *Cmd) { - - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - uint32_t password = 0x0; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 login", "Login into EM4x50 tag.", - "lf em 4x50 login -p 12345678 -< login with password 12345678\n" + "lf em 4x50 login -p 12345678 -> login with password 12345678\n" ); void *argtable[] = { @@ -281,20 +272,22 @@ int CmdEM4x50Login(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); - return PM3_EINVARG; - } else { - password = BYTES2UINT32(pwd); - } - + CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); CLIParserFree(ctx); + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + + uint32_t password = BYTES2UINT32(pwd); + // start clearCommandBuffer(); + PacketResponseNG resp; SendCommandNG(CMD_LF_EM4X50_LOGIN, (uint8_t *)&password, sizeof(password)); WaitForResponse(CMD_LF_EM4X50_LOGIN, &resp); @@ -308,63 +301,67 @@ int CmdEM4x50Login(const char *Cmd) { } int CmdEM4x50Brute(const char *Cmd) { - - const int speed = 27; // 27 passwords/second (empirical value) - int no_iter = 0, dur_h = 0, dur_m = 0, dur_s = 0; - - int pwd1Len = 0, pwd2Len = 0; - uint8_t pwd1[4] = {0x0}, pwd2[4] = {0x0}; - em4x50_data_t etd; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 brute", - "Tries to bruteforce the password of a EM4x50. Function can be stopped by pressing pm3 button.", - "lf em 4x50 brute -f 12330000 -l 12340000 -> tries passwords from 0x12330000 to 0x1234000000\n" + "Tries to bruteforce the password of a EM4x50.\n" + "Function can be stopped by pressing pm3 button.", + "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n" ); void *argtable[] = { arg_param_begin, - arg_str1("f", "fp", "", "first password (start), 4 bytes, lsb"), - arg_str1("l", "lp", "", "last password (stop), 4 bytes, lsb"), + arg_str1(NULL, "first", "", "first password (start), 4 bytes, lsb"), + arg_str1(NULL, "last", "", "last password (stop), 4 bytes, lsb"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd1, &pwd1Len); - CLIGetHexWithReturn(ctx, 2, pwd2, &pwd2Len); - - if (pwd1Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd1Len); - return PM3_EINVARG; - } else if (pwd2Len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd2Len); - return PM3_EINVARG; - } else { - etd.password1 = BYTES2UINT32(pwd1); - etd.password2 = BYTES2UINT32(pwd2); - } - + CLIExecWithReturn(ctx, Cmd, argtable, true); + int first_len = 0; + uint8_t first[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 1, first, &first_len); + int last_len = 0; + uint8_t last[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 2, last, &last_len); CLIParserFree(ctx); + if (first_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + if (last_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } + + em4x50_data_t etd; + etd.password1 = BYTES2UINT32(first); + etd.password2 = BYTES2UINT32(last); + + // 27 passwords/second (empirical value) + const int speed = 27; + // print some information - no_iter = etd.password2 - etd.password1 + 1; - dur_s = no_iter / speed; - dur_h = dur_s / 3600; - dur_m = (dur_s - dur_h * 3600) / 60; + int no_iter = etd.password2 - etd.password1 + 1; + int dur_s = no_iter / speed; + int dur_h = dur_s / 3600; + int dur_m = (dur_s - dur_h * 3600) / 60; + dur_s -= dur_h * 3600 + dur_m * 60; - PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]", - no_iter, etd.password1, etd.password2); + PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]" + , no_iter + , etd.password1 + , etd.password2 + ); PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); // start clearCommandBuffer(); + PacketResponseNG resp; SendCommandNG(CMD_LF_EM4X50_BRUTE, (uint8_t *)&etd, sizeof(etd)); WaitForResponse(CMD_LF_EM4X50_BRUTE, &resp); // print response - if ((bool)resp.status) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Password " _GREEN_("found") ": 0x%08x", resp.data.asDwords[0]); else PrintAndLogEx(FAILED, "Password: " _RED_("not found")); @@ -372,28 +369,14 @@ int CmdEM4x50Brute(const char *Cmd) { return PM3_SUCCESS; } +// upload passwords from given dictionary to device and start check; +// if no filename is given dictionary "t55xx_default_pwds.dic" is used int CmdEM4x50Chk(const char *Cmd) { - - // upload passwords from given dictionary to device and start check; - // if no filename is given dictionary "t55xx_default_pwds.dic" is used - - int status = PM3_EFAILED; - int keyblock = 2000; // block with 2000 bytes -> 500 keys - int res = 0, slen = 0, bytes_remaining = 0; - size_t datalen = 0; - uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; - uint8_t *keys = data; - uint32_t key_count = 0; - uint8_t destfn[32] = "em4x50_chk.bin"; - char filename[FILE_PATH_SIZE] = {0}; - - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 chk", "Dictionary attack against EM4x50.", - "lf em 4x50 chk -> uses T55xx default dictionary\n" - "lf em 4x50 chk -f my.dic -> uses dictionary ./my.dic\n" + "lf em 4x50 chk -> uses T55xx default dictionary\n" + "lf em 4x50 chk -f my.dic" ); void *argtable[] = { @@ -403,27 +386,39 @@ int CmdEM4x50Chk(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); - - // no filename -> default = t55xx_default_pwds - if (strlen(filename) == 0) { - snprintf(filename, sizeof(filename), "t55xx_default_pwds"); - PrintAndLogEx(INFO, "treating file as T55xx keys"); - } - - res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); - if (res || !key_count) - return PM3_EFILE; - - PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); if (IfPm3Flash() == false) { PrintAndLogEx(WARNING, "no flash memory available"); return PM3_EFLASH; } + + // no filename -> default = t55xx_default_pwds + if (strlen(filename) == 0) { + snprintf(filename, sizeof(filename), "t55xx_default_pwds"); + PrintAndLogEx(INFO, "treating file as T55xx keys"); + } + + size_t datalen = 0; + uint8_t data[FLASH_MEM_MAX_SIZE] = {0x0}; + uint8_t *keys = data; + uint32_t key_count = 0; + + int res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); + if (res || !key_count) + return PM3_EFILE; - bytes_remaining = datalen; + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); + + int status = PM3_EFAILED; + int keyblock = 2000; // block with 2000 bytes -> 500 keys + uint8_t destfn[32] = "em4x50_chk.bin"; + + PacketResponseNG resp; + int bytes_remaining = datalen; while (bytes_remaining > 0) { PrintAndLogEx(INPLACE, "Remaining keys: %i ", bytes_remaining / 4); @@ -447,10 +442,11 @@ int CmdEM4x50Chk(const char *Cmd) { bytes_remaining -= keyblock; keys += keyblock; } - + + PrintAndLogEx(NORMAL, ""); + // print response if (status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"), resp.data.asBytes[3], resp.data.asBytes[2], @@ -458,7 +454,6 @@ int CmdEM4x50Chk(const char *Cmd) { resp.data.asBytes[0] ); } else { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "No key found"); } @@ -490,12 +485,11 @@ int read_em4x50_uid(void) { return res; } +// envoke reading +// - with given address (option b) (and optional password if address is +// read protected) -> selective read mode int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { - // envoke reading - // - with given address (option b) (and optional password if address is - // read protected) -> selective read mode - em4x50_data_t edata = { .pwd_given = false, .addr_given = false }; if (etd != NULL) { @@ -527,46 +521,44 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { } int CmdEM4x50Read(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50 read", + "Reads single EM4x50 block/word.", + "lf em 4x50 rdbl -b 3\n" + "lf em 4x50 rdbl -b 32 -p 12345678 -> reads block 32 with pwd 0x12345678\n" + ); - int pwdLen = 0; - int addr = 0; + void *argtable[] = { + arg_param_begin, + arg_int1("b", "block", "", "block/word address"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int addr = arg_get_int_def(ctx, 1, 0); + int pwd_len = 0; uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len); + CLIParserFree(ctx); + + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { + return PM3_EINVARG; + } + em4x50_data_t etd; // init memset(&etd, 0x00, sizeof(em4x50_data_t)); etd.addr_given = false; etd.pwd_given = false; + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50 read", - "Reads single EM4x50 block/word.", - "lf em 4x50 read -b 3 -> reads block 3\n" - "lf em 4x50 read -b 32 -p 12345678 -> reads block 32 with password 0x12345678\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_int1("b", "block", "", "block/word address"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, true); - - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (addr <= 0 || addr >= EM4X50_NO_WORDS) { - return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -574,41 +566,35 @@ int CmdEM4x50Read(const char *Cmd) { } } - CLIParserFree(ctx); - return em4x50_read(&etd, NULL); } +// envoke reading of a EM4x50 tag which has to be on the antenna because +// decoding is done by the device (not on client side) int CmdEM4x50Info(const char *Cmd) { - - // envoke reading of a EM4x50 tag which has to be on the antenna because - // decoding is done by the device (not on client side) - - int pwdLen = 0; - int status = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 info", "Tag information EM4x50.", "lf em 4x50 info\n" - "lf em 4x50 info -p 12345678 -> uses password 0x12345678\n" + "lf em 4x50 info -p 12345678 -> uses pwd 0x12345678\n" ); void *argtable[] = { arg_param_begin, - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + em4x50_data_t etd = {.pwd_given = false}; + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -616,32 +602,23 @@ int CmdEM4x50Info(const char *Cmd) { } } - CLIParserFree(ctx); - clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd)); - PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) { PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - status = resp.status; - - if (status == PM3_SUCCESS) + if ( resp.status == PM3_SUCCESS) print_info_result(resp.data.asBytes); else PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); - return status; + return resp.status; } int CmdEM4x50Reader(const char *Cmd) { - - int now = 0; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 reader", "Shows standard read data of EM4x50 tag.", @@ -662,13 +639,14 @@ int CmdEM4x50Reader(const char *Cmd) { // start do { + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_READER, 0, 0); WaitForResponseTimeoutW(CMD_LF_EM4X50_READER, &resp, -1, false); - now = resp.status; - - // print response + // iceman, misuse of return status code. + int now = resp.status; + if (now > 0) { em4x50_word_t words[EM4X50_NO_WORDS]; @@ -680,14 +658,13 @@ int CmdEM4x50Reader(const char *Cmd) { for (int i = 0; i < now; i++) { - char r[30] = {0}; - for (int j = 3; j >= 0; j--) + char r[30]; + memset(r, 0, sizeof(r)); + for (int j = 3; j >= 0; j--) { sprintf(r + strlen(r), "%02x ", reflect8(words[i].byte[j])); + } - PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", - sprint_hex(words[i].byte, 4), - r - ); + PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", sprint_hex(words[i].byte, 4), r); } PrintAndLogEx(INFO, "-------------+-------------"); @@ -698,50 +675,44 @@ int CmdEM4x50Reader(const char *Cmd) { } int CmdEM4x50Dump(const char *Cmd) { - - int fnLen = 0, pwdLen = 0, status = 0; - uint8_t pwd[4] = {0x0}; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - em4x50_data_t etd = {.pwd_given = false}; - uint8_t data[DUMP_FILESIZE] = {0}; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 dump", "Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format.", - "lf em 4x50 dump -> saves dump in lf-4x50--dump.bin/eml/json\n" - "lf em 4x50 dump -f mydump.eml -> saves dump in mydump.eml\n" + "lf em 4x50 dump\n" + "lf em 4x50 dump -f mydump.eml\n" "lf em 4x50 dump -p 12345678\n" - "lf em 4x50 dump -f mydump.eml -p 12345678\n" + "lf em 4x50 dump -f mydump.eml -p 12345678" ); void *argtable[] = { arg_param_begin, arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIParamStrToBuf(arg_get_str(ctx, 1), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 2, pwd, &pwdLen); - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int fnLen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnLen); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len); + CLIParserFree(ctx); + + em4x50_data_t etd = {.pwd_given = false}; + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + CLIParserFree(ctx); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; } } - - CLIParserFree(ctx); PrintAndLogEx(INFO, "Reading EM4x50 tag"); clearCommandBuffer(); @@ -752,8 +723,7 @@ int CmdEM4x50Dump(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; - if (status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); return PM3_ESOFT; } @@ -769,70 +739,66 @@ int CmdEM4x50Dump(const char *Cmd) { // user supplied filename? if (fnLen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; fptr += sprintf(fptr, "lf-4x50-"); FillFileNameByUID(fptr, words[EM4X50_DEVICE_ID].byte, "-dump", 4); } - for (int i = 0; i < EM4X50_NO_WORDS; i++) + uint8_t data[DUMP_FILESIZE] = {0}; + for (int i = 0; i < EM4X50_NO_WORDS; i++) { memcpy(data + (i * 4), words[i].byte, 4); + } - // saveFileEML will add .eml extension to filename - // saveFile (binary) passes in the .bin extension. - // saveFileJSON adds .json extension - saveFileEML(filename, data, sizeof(data), 4); saveFile(filename, ".bin", data, sizeof(data)); + saveFileEML(filename, data, sizeof(data), 4); saveFileJSON(filename, jsfEM4x50, data, sizeof(data), NULL); - return PM3_SUCCESS; } +// envoke writing a single word (32 bit) to a EM4x50 tag int CmdEM4x50Write(const char *Cmd) { - - // envoke writing a single word (32 bit) to a EM4x50 tag - - int wordLen = 0, pwdLen = 0, addr = 0; - int status = 0; - uint8_t word[4] = {0x0}; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false}; - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x50 write", + CLIParserInit(&ctx, "lf em 4x50 wrbl", "Writes single block/word to EM4x50 tag.", - "lf em 4x50 write -b 3 -d 4f22e7ff -> writes 0x4f22e7ff to block 3\n" - "lf em 4x50 write -b 3 -d 4f22e7ff -p 12345678\n" + "lf em 4x50 wrbl -b 3 -d 4f22e7ff \n" + "lf em 4x50 wrbl -b 3 -d 4f22e7ff -p 12345678\n" ); void *argtable[] = { arg_param_begin, arg_int1("b", "block", "", "block/word address, dec"), arg_str1("d", "data", "", "data, 4 bytes, lsb"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + + int addr = arg_get_int_def(ctx, 1, 0); - addr = arg_get_int_def(ctx, 1, 0); - CLIGetHexWithReturn(ctx, 2, word, &wordLen); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); + int word_len = 0; + uint8_t word[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, word, &word_len); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); + CLIParserFree(ctx); if (addr <= 0 || addr >= EM4X50_NO_WORDS) { PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); return PM3_EINVARG; - } else { - etd.addresses = (addr << 8) | addr; - etd.addr_given = true; - } - if (wordLen != 4) { - PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", wordLen); + } + + if (word_len != 4) { + PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", word_len); return PM3_EINVARG; - } else { - etd.word = BYTES2UINT32(word); } - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + + em4x50_data_t etd = {.pwd_given = false}; + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -840,7 +806,9 @@ int CmdEM4x50Write(const char *Cmd) { } } - CLIParserFree(ctx); + etd.addresses = (addr << 8) | addr; + etd.addr_given = true; + etd.word = BYTES2UINT32(word); clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); @@ -850,9 +818,9 @@ int CmdEM4x50Write(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; + int status = resp.status; if (status == PM3_ETEAROFF) - return PM3_SUCCESS; + return status; if (status != PM3_SUCCESS) { PrintAndLogEx(FAILED, "Writing " _RED_("failed")); @@ -866,54 +834,53 @@ int CmdEM4x50Write(const char *Cmd) { prepare_result(data, addr, addr, words); print_result(words, addr, addr); PrintAndLogEx(SUCCESS, "Successfully wrote to tag"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50_read a %u") "` - to read your data", addr); + PrintAndLogEx(HINT, "Try `" _YELLOW_("lf em 4x50 rdbl -a %u") "` - to read your data", addr); return PM3_SUCCESS; } +// envokes changing the password of EM4x50 tag int CmdEM4x50WritePwd(const char *Cmd) { - - // envokes changing the password of EM4x50 tag - - int status = PM3_EFAILED; - int pwdLen = 0, npwdLen = 0; - uint8_t pwd[4] = {0x0}, npwd[4] = {0x0}; - PacketResponseNG resp; - em4x50_data_t etd; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 writepwd", "Writes EM4x50 password.", - "lf em 4x50 writepwd -p 4f22e7ff -n 12345678 -> replaces password 0x4f22e7ff with 0x12345678\n" + "lf em 4x50 writepwd -p 4f22e7ff -n 12345678" ); void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "password, 4 bytes, lsb"), - arg_str1("n", "newpwd", "", "new password, 4 bytes, lsb"), + arg_str1("p", "pwd", "", "password, 4 hex bytes, lsb"), + arg_str1("n", "new", "", "new password, 4 hex bytes, lsb"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - CLIGetHexWithReturn(ctx, 2, npwd, &npwdLen); - - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + + int npwd_len = 0; + uint8_t npwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 2, npwd, &npwd_len); + + CLIParserFree(ctx); + + em4x50_data_t etd; + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); } - if (npwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwdLen); + + if (npwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", npwd_len); return PM3_EINVARG; } else { etd.password2 = BYTES2UINT32(npwd); } - CLIParserFree(ctx); - + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); @@ -922,36 +889,28 @@ int CmdEM4x50WritePwd(const char *Cmd) { return PM3_ETIMEOUT; } - status = resp.status; - - if (status == PM3_ETEAROFF) + if (resp.status == PM3_ETEAROFF) return PM3_SUCCESS; - // print response - if (status != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Writing password " _RED_("failed")); + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Writing password (" _RED_("failed") ")"); return PM3_EFAILED; } - PrintAndLogEx(SUCCESS, "Writing new password " _GREEN_("ok")); - + PrintAndLogEx(SUCCESS, "Writing new password %s (%s)" + , sprint_hex_inrow(npwd, sizeof(npwd)) + , _GREEN_("ok") + ); return PM3_SUCCESS; } +// fills EM4x50 tag with zeros including password int CmdEM4x50Wipe(const char *Cmd) { - - // fills EM4x50 tag with zeros including password - - bool isOK = false; - int pwdLen = 0; - uint8_t pwd[4] = {0x0}; - em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 wipe", - "Wipes EM4x50 tag.", - "lf em 4x50 wipe -p 12345678 -> wipes tag with password 0x12345678\n" + "Wipes EM4x50 tag by filling it with zeros, including the new password\n" + "Must give a password.", + "lf em 4x50 wipe -p 12345678" ); void *argtable[] = { @@ -960,20 +919,25 @@ int CmdEM4x50Wipe(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - CLIGetHexWithReturn(ctx, 1, pwd, &pwdLen); - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + CLIExecWithReturn(ctx, Cmd, argtable, true); + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + CLIParserFree(ctx); + + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); + CLIParserFree(ctx); return PM3_EINVARG; - } else { - etd.password1 = BYTES2UINT32(pwd); - etd.pwd_given = true; } - CLIParserFree(ctx); + em4x50_data_t etd = {.pwd_given = false, .word = 0x0, .password2 = 0x0}; + + etd.password1 = BYTES2UINT32(pwd); + etd.pwd_given = true; // clear password + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd)); if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, TIMEOUT)) { @@ -982,7 +946,7 @@ int CmdEM4x50Wipe(const char *Cmd) { } if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Resetting password " _GREEN_("ok")); + PrintAndLogEx(SUCCESS, "Resetting password to 00000000 (" _GREEN_("ok") ")"); } else { PrintAndLogEx(FAILED, "Resetting password " _RED_("failed")); return PM3_ESOFT; @@ -1007,8 +971,7 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_ETIMEOUT; } - isOK = resp.status; - if (isOK != PM3_SUCCESS) { + if ( resp.status != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); return PM3_ESOFT; @@ -1016,66 +979,54 @@ int CmdEM4x50Wipe(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Wiping data " _GREEN_("ok")); - PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } int CmdEM4x50Restore(const char *Cmd) { - - int uidLen = 0, fnLen = 0, pwdLen = 0, status = 0; - int startblock = EM4X50_CONTROL + 1; - uint8_t pwd[4] = {0x0}, uid[4] = {0x0}; - uint8_t data[DUMP_FILESIZE] = {0x0}; - size_t bytes_read = 0; - char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - em4x50_data_t etd = {.pwd_given = false}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 restore", - "Restores data from dumpfile onto a Em4x50 tag.", - "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" - "lf em 4x50 restore -f mydump.eml -> uses mydump.eml\n" + "Restores data from dumpfile onto a Em4x50 tag.\n" + "if used with -u, the filetemplate `lf-4x50-UID-dump.bin` is used as filename", + "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin\n" + "lf em 4x50 restore -f mydump.eml\n" "lf em 4x50 restore -u 1b5aff5c -p 12345678\n" "lf em 4x50 restore -f mydump.eml -p 12345678\n" ); void *argtable[] = { arg_param_begin, - arg_str0("u", "uid", "", "uid, 4 bytes, msb, restore from lf-4x50--dump.bin"), + arg_str0("u", "uid", "", "uid, 4 hex bytes, msb"), arg_str0("f", "filename", "", "dump filename (bin/eml/json)"), - arg_str0("p", "passsword", "", "password, 4 bytes, lsb"), + arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int uidLen = 0; + uint8_t uid[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, uid, &uidLen); - CLIParamStrToBuf(arg_get_str(ctx, 2), - (uint8_t *)filename, - FILE_PATH_SIZE, - &fnLen - ); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdLen); - - if ((uidLen && fnLen) || (!uidLen && !fnLen)) { + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int pwd_len = 0; + uint8_t pwd[4] = {0x0}; + CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); + CLIParserFree(ctx); + + if ((uidLen && fnlen) || (!uidLen && !fnlen)) { PrintAndLogEx(FAILED, "either use option 'u' or option 'f'"); return PM3_EINVARG; } - - if (uidLen) { - PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "lf-4x50-"); - FillFileNameByUID(fptr, uid, "-dump", 4); - } - - if (pwdLen) { - if (pwdLen != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwdLen); + + int startblock = EM4X50_CONTROL + 1; + em4x50_data_t etd = {.pwd_given = false}; + + if (pwd_len) { + if (pwd_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; } else { etd.password1 = BYTES2UINT32(pwd); @@ -1085,11 +1036,18 @@ int CmdEM4x50Restore(const char *Cmd) { } } - CLIParserFree(ctx); + if (uidLen) { + PrintAndLogEx(INFO, "Using UID as filename"); + char *fptr = filename; + fptr += sprintf(fptr, "lf-4x50-"); + FillFileNameByUID(fptr, uid, "-dump", 4); + } PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename); // read data from dump file; file type has to be "bin", "eml" or "json" + uint8_t data[DUMP_FILESIZE] = {0x0}; + size_t bytes_read = 0; if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) return PM3_EFILE; @@ -1100,90 +1058,50 @@ int CmdEM4x50Restore(const char *Cmd) { etd.addresses = i << 8 | i; etd.word = reflect32(BYTES2UINT32((data + 4 * i))); + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } - status = resp.status; - if (status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Restoring data " _RED_("failed")); return PM3_ESOFT; } } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Restoring data " _GREEN_("ok")); - + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Done"); - return PM3_SUCCESS; } int CmdEM4x50Sim(const char *Cmd) { - - int slen = 0, status = 0; - size_t bytes_read = 0; - uint8_t data[DUMP_FILESIZE] = {0x0}; - uint8_t destfn[32] = {0}; - - char filename[FILE_PATH_SIZE] = {0}; - PacketResponseNG resp; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 sim", - "Simulates a EM4x50 tag", - "lf em 4x50 sim -> simulates EM4x50 data in memory (upload via em4x50_eload).\n" - "lf em 4x50 sim -f mydump.eml -> simulates content of file ./mydump\n" + "Simulates a EM4x50 tag.\n" + "Upload using `lf em 4x50 eload`", + "lf em 4x50 sim" ); void *argtable[] = { arg_param_begin, - arg_str0("f", "filename", "", "dump filename, bin/eml/json"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &slen); CLIParserFree(ctx); - - // read data from dump file; file type has to be "bin", "eml" or "json" - if (slen != 0) { - // load file content - if (em4x50_load_file(filename, data, DUMP_FILESIZE, &bytes_read) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Read error"); - return PM3_EFILE; - } - - PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to davice", filename); - - // upload to device - if (IfPm3Flash()) { - sprintf((char *)destfn, "em4x50_sim.bin"); - status = flashmem_spiffs_load(destfn, data, DUMP_FILESIZE); - if (status != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "SPIFFS upload failed"); - return status; - } - } else { - em4x50_seteml(data, 0, DUMP_FILESIZE); - } - - PrintAndLogEx(INFO, "Simulating data from " _YELLOW_("%s"), filename); - } else { - PrintAndLogEx(INFO, "Simulating data from emulator memory"); - } + PrintAndLogEx(INFO, "Simulating data from emulator memory"); clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X50_SIM, destfn, sizeof(destfn)); + SendCommandNG(CMD_LF_EM4X50_SIM, NULL, 0); + PacketResponseNG resp; WaitForResponse(CMD_LF_EM4X50_SIM, &resp); - - status = resp.status; - if (status == PM3_SUCCESS) + if (resp.status == PM3_SUCCESS) PrintAndLogEx(INFO, "Done"); else PrintAndLogEx(FAILED, "No valid em4x50 data in memory."); @@ -1193,24 +1111,23 @@ int CmdEM4x50Sim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, + {"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, - {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, - {"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, - {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, - {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, {"login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, + {"rdbl", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, + {"wrbl", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, + {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, + {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, + {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, - {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, - {"chk", CmdEM4x50Chk, IfPm3EM4x50, "check passwords from dictionary"}, {NULL, NULL, NULL, NULL} }; - static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index c38758679..8e154e300 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -123,7 +123,7 @@ int CmdWiegandDecode(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_lit0("p", "parity", "ignore invalid parity"), - arg_strx1(NULL, "raw", "", "raw hex to be decoded"), + arg_strx1("r", "raw", "", "raw hex to be decoded"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false);