mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
chg: lf em 4x50_read / info - remake output
This commit is contained in:
parent
4529d0a891
commit
86bfdcf260
3 changed files with 181 additions and 326 deletions
|
@ -1207,6 +1207,14 @@ static bool CheckChipType(bool getDeviceData) {
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for em4x50 chips
|
||||||
|
if (detect_4x50_block()) {
|
||||||
|
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x50"));
|
||||||
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x50`") " commands");
|
||||||
|
retval = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
save_restoreGB(GRAPH_RESTORE);
|
save_restoreGB(GRAPH_RESTORE);
|
||||||
save_restoreDB(GRAPH_RESTORE);
|
save_restoreDB(GRAPH_RESTORE);
|
||||||
|
@ -1252,7 +1260,7 @@ int CmdLFfind(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IfPm3EM4x50()) {
|
if (IfPm3EM4x50()) {
|
||||||
if (EM4x50Read("", false) == PM3_SUCCESS) {
|
if (read_em4x50_uid() == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM4x50 ID") " found!");
|
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM4x50 ID") " found!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,47 +24,51 @@ int usage_lf_em4x50_info(void) {
|
||||||
PrintAndLogEx(NORMAL, " v - verbose output");
|
PrintAndLogEx(NORMAL, " v - verbose output");
|
||||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_info");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info"));
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_info p fa225de1\n");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info p fa225de1"));
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_info v p fa225de1\n");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_info v p fa225de1"));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
int usage_lf_em4x50_write(void) {
|
int usage_lf_em4x50_write(void) {
|
||||||
PrintAndLogEx(NORMAL, "Write EM4x50 word. Tag must be on antenna. ");
|
PrintAndLogEx(NORMAL, "Write EM4x50 word. Tag must be on antenna. ");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] a <address> w <data>");
|
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] [a <address>] [w <data>]");
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
PrintAndLogEx(NORMAL, " h - this help");
|
PrintAndLogEx(NORMAL, " h - this help");
|
||||||
PrintAndLogEx(NORMAL, " a <addr> - memory address to write to (dec)");
|
PrintAndLogEx(NORMAL, " a <addr> - memory address to write to (dec)");
|
||||||
PrintAndLogEx(NORMAL, " w <word> - word to write (hex)");
|
PrintAndLogEx(NORMAL, " w <word> - word to write (hex)");
|
||||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_write a 3 w deadc0de");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write a 3 w deadc0de"));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
int usage_lf_em4x50_write_password(void) {
|
int usage_lf_em4x50_write_password(void) {
|
||||||
PrintAndLogEx(NORMAL, "Write EM4x50 password. Tag must be on antenna. ");
|
PrintAndLogEx(NORMAL, "Write EM4x50 password. Tag must be on antenna. ");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] p <pwd> n <pwd>");
|
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write_password [h] [p <pwd>] [n <pwd>]");
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
PrintAndLogEx(NORMAL, " h - this help");
|
PrintAndLogEx(NORMAL, " h - this help");
|
||||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex)");
|
PrintAndLogEx(NORMAL, " p <pwd> - password (hex)");
|
||||||
PrintAndLogEx(NORMAL, " n <pwd> - new password (hex)");
|
PrintAndLogEx(NORMAL, " n <pwd> - new password (hex)");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_write_password p 11223344 n 01020304");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_write_password p 11223344 n 01020304"));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
int usage_lf_em4x50_read(void) {
|
int usage_lf_em4x50_read(void) {
|
||||||
PrintAndLogEx(NORMAL, "Read EM4x50 word(s). Tag must be on antenna. ");
|
PrintAndLogEx(NORMAL, "Read EM4x50 word(s). Tag must be on antenna. ");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] a <address> p <pwd>");
|
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] [a <address>] [p <pwd>]");
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
PrintAndLogEx(NORMAL, " h - this help");
|
PrintAndLogEx(NORMAL, " h - this help");
|
||||||
PrintAndLogEx(NORMAL, " a <addr> - memory address to read (dec) (optional)");
|
PrintAndLogEx(NORMAL, " a <addr> - memory address to read (dec) (optional)");
|
||||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_read");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read"));
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x50_read a 2 p 00000000");
|
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_read a 2 p 00000000"));
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,75 +125,9 @@ static void prepare_result(const uint8_t *byte, int fwr, int lwr, em4x50_word_t
|
||||||
|
|
||||||
if (words[i].stopbit == 1)
|
if (words[i].stopbit == 1)
|
||||||
words[i].stopparity = false;
|
words[i].stopparity = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_bit_table(const em4x50_word_t word) {
|
|
||||||
|
|
||||||
// generate output in table form for each word including parities, stop
|
|
||||||
// bit, result of parity checks and hex notation of each row in msb/lsb
|
|
||||||
// notation
|
|
||||||
// individual parity errors will be highlighted in red
|
|
||||||
|
|
||||||
int bit = 0;
|
|
||||||
char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0};
|
|
||||||
|
|
||||||
// print binary data
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
|
|
||||||
strcat(string, " ");
|
|
||||||
|
|
||||||
// lsb notation
|
|
||||||
for (int k = 0; k < 8; k++) {
|
|
||||||
sprintf(pstring, "%i", (word.byte[j] >> (7-k)) & 1);
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat(string, " | ");
|
|
||||||
|
|
||||||
// binary row parities + hex bytes of word
|
|
||||||
sprintf(pstring, (word.rparity[j]) ? "%i" : _RED_("%i"), word.row_parity[j]);
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
if (j == 0)
|
|
||||||
sprintf(pstring, " msb: 0x%02x lsb: 0x%02x", word.byte[j], reflect8(word.byte[j]));
|
|
||||||
else
|
|
||||||
sprintf(pstring, " 0x%02x 0x%02x", word.byte[j], reflect8(word.byte[j]));
|
|
||||||
|
|
||||||
strcat(string, pstring);
|
|
||||||
PrintAndLogEx(NORMAL,string);
|
|
||||||
|
|
||||||
string[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat(string, " ------------ --------------------\n ");
|
|
||||||
|
|
||||||
// binary column parities
|
|
||||||
for (int k = 0; k < 8; k++) {
|
|
||||||
|
|
||||||
bit = (word.col_parity >> (7-k)) & 1;
|
|
||||||
|
|
||||||
// if column parity is false -> highlight bit in red
|
|
||||||
sprintf(pstring, (word.cparity[k]) ? "%i" : _RED_("%i"), bit);
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
// binary stop bit
|
|
||||||
strcat(string, " | ");
|
|
||||||
sprintf(pstring, (word.stopparity) ? "%i" : _RED_("%i"), word.stopbit);
|
|
||||||
strcat(pstring, " parities ");
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
// parities passed/failed
|
|
||||||
sprintf(pstring, (word.parity) ? _GREEN_("ok") : _RED_("failed"));
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL,string);
|
|
||||||
|
|
||||||
string[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_result(const em4x50_word_t *words, int fwr, int lwr, bool verbose) {
|
static void print_result(const em4x50_word_t *words, int fwr, int lwr, bool verbose) {
|
||||||
|
|
||||||
// print available information for given word from fwr to lwr, i.e.
|
// print available information for given word from fwr to lwr, i.e.
|
||||||
|
@ -201,12 +139,6 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr, bool verb
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
||||||
// blank line before each bit table
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
|
|
||||||
// print bit table
|
|
||||||
print_bit_table(words[i]);
|
|
||||||
|
|
||||||
// final result
|
// final result
|
||||||
string[0] = '\0';
|
string[0] = '\0';
|
||||||
sprintf(pstring, "\n word[%i] msb: " _GREEN_("0x"), i);
|
sprintf(pstring, "\n word[%i] msb: " _GREEN_("0x"), i);
|
||||||
|
@ -236,25 +168,19 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr, bool verb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL,string);
|
PrintAndLogEx(INFO, string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd, bool verbose) {
|
static void print_info_result(uint8_t *data, bool verbose) {
|
||||||
|
|
||||||
// display all information of info result in structured format
|
// display all information of info result in structured format
|
||||||
|
|
||||||
uint8_t *data = resp->data.asBytes;
|
|
||||||
em4x50_word_t words[EM4X50_NO_WORDS];
|
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||||
char pstring[NO_CHARS_MAX] = {0}, string[NO_CHARS_MAX] = {0};
|
|
||||||
|
|
||||||
bool bpwd_given = etd->pwd_given;
|
|
||||||
bool blogin = resp->status & STATUS_LOGIN;
|
|
||||||
|
|
||||||
prepare_result(data, 0, EM4X50_NO_WORDS - 1, words);
|
prepare_result(data, 0, EM4X50_NO_WORDS - 1, words);
|
||||||
|
|
||||||
bool bpwc = words[EM4X50_CONTROL].byte[CONFIG_BLOCK] & PASSWORD_CHECK;
|
bool bpwc = words[EM4X50_CONTROL].byte[CONFIG_BLOCK] & PASSWORD_CHECK;
|
||||||
bool braw = words[EM4X50_CONTROL].byte[CONFIG_BLOCK] & READ_AFTER_WRITE;
|
bool braw = words[EM4X50_CONTROL].byte[CONFIG_BLOCK] & READ_AFTER_WRITE;
|
||||||
|
|
||||||
int fwr = reflect8(words[EM4X50_CONTROL].byte[FIRST_WORD_READ]);
|
int fwr = reflect8(words[EM4X50_CONTROL].byte[FIRST_WORD_READ]);
|
||||||
int lwr = reflect8(words[EM4X50_CONTROL].byte[LAST_WORD_READ]);
|
int lwr = reflect8(words[EM4X50_CONTROL].byte[LAST_WORD_READ]);
|
||||||
int fwrp = reflect8(words[EM4X50_PROTECTION].byte[FIRST_WORD_READ_PROTECTED]);
|
int fwrp = reflect8(words[EM4X50_PROTECTION].byte[FIRST_WORD_READ_PROTECTED]);
|
||||||
|
@ -262,8 +188,14 @@ static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd,
|
||||||
int fwwi = reflect8(words[EM4X50_PROTECTION].byte[FIRST_WORD_WRITE_INHIBITED]);
|
int fwwi = reflect8(words[EM4X50_PROTECTION].byte[FIRST_WORD_WRITE_INHIBITED]);
|
||||||
int lwwi = reflect8(words[EM4X50_PROTECTION].byte[LAST_WORD_WRITE_INHIBITED]);
|
int lwwi = reflect8(words[EM4X50_PROTECTION].byte[LAST_WORD_WRITE_INHIBITED]);
|
||||||
|
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||||
|
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||||
|
|
||||||
// data section
|
// data section
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\n em4x50 data:"));
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:"));
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
||||||
|
@ -272,117 +204,82 @@ static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd,
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "idx | word | desc");
|
||||||
|
PrintAndLogEx(INFO, "----+-------------+----------------------------------");
|
||||||
|
|
||||||
// condensed data section
|
// condensed data section
|
||||||
for (int i = 0; i < EM4X50_NO_WORDS; i++) {
|
for (int i = 0; i < EM4X50_NO_WORDS; i++) {
|
||||||
|
|
||||||
sprintf(pstring, " word[%2i]: ", i);
|
char s[50] = {0};
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
sprintf(pstring, "%02x", words[i].byte[j]);
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case EM4X50_DEVICE_PASSWORD:
|
case EM4X50_DEVICE_PASSWORD:
|
||||||
sprintf(pstring, _YELLOW_(" password, write only"));
|
sprintf(s, _YELLOW_("password, write only"));
|
||||||
break;
|
break;
|
||||||
case EM4X50_PROTECTION:
|
case EM4X50_PROTECTION:
|
||||||
sprintf(pstring, _YELLOW_(" protection word, write inhibited"));
|
sprintf(s, _YELLOW_("protection cfg (locked)"));
|
||||||
break;
|
break;
|
||||||
case EM4X50_CONTROL:
|
case EM4X50_CONTROL:
|
||||||
sprintf(pstring, _YELLOW_(" control word, write inhibited"));
|
sprintf(s, _YELLOW_("control cfg (locked)"));
|
||||||
break;
|
break;
|
||||||
case EM4X50_DEVICE_SERIAL:
|
case EM4X50_DEVICE_SERIAL:
|
||||||
sprintf(pstring, _YELLOW_(" device serial number, read only"));
|
sprintf(s, _YELLOW_("device serial number (read only)"));
|
||||||
break;
|
break;
|
||||||
case EM4X50_DEVICE_ID:
|
case EM4X50_DEVICE_ID:
|
||||||
sprintf(pstring, _YELLOW_(" device identification, read only"));
|
sprintf(s, _YELLOW_("device identification (read only)"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(pstring, " user data");
|
sprintf(s, "user data");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(INFO, " %2i | %s| %s", i, sprint_hex(words[i].byte, 4), s);
|
||||||
strcat(string, pstring);
|
|
||||||
PrintAndLogEx(NORMAL,"%s", string);
|
|
||||||
string[0] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(INFO, "----+-------------+----------------------------------");
|
||||||
|
|
||||||
|
|
||||||
// configuration section
|
// configuration section
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\n em4x50 configuration"));
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL," control: | protection:");
|
PrintAndLogEx(INFO, "---- " _CYAN_("Configuration") " ----");
|
||||||
|
|
||||||
sprintf(pstring, " first word read: %3i |", fwr);
|
PrintAndLogEx(INFO, "first word read %3i", fwr);
|
||||||
strcat(string, pstring);
|
PrintAndLogEx(INFO, "last word read %3i", lwr);
|
||||||
sprintf(pstring, " first word read protected: %3i", fwrp);
|
PrintAndLogEx(INFO, "password check %3s", (bpwc) ? _RED_("on"): _GREEN_("off"));
|
||||||
strcat(string, pstring);
|
PrintAndLogEx(INFO, "read after write %3s", (braw) ? "on" : "off");
|
||||||
PrintAndLogEx(NORMAL,"%s", string);
|
PrintAndLogEx(NORMAL, "");
|
||||||
string[0] = '\0';
|
PrintAndLogEx(INFO, "--------- " _CYAN_("Protection") " ---------");
|
||||||
|
PrintAndLogEx(INFO, "first word read protected %3i", fwrp);
|
||||||
|
PrintAndLogEx(INFO, "last word read protected %3i", lwrp);
|
||||||
|
PrintAndLogEx(INFO, "first word write inhibited %3i", fwwi);
|
||||||
|
PrintAndLogEx(INFO, "last word write inhibited %3i", lwwi);
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "zero values may indicate read protection");
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(pstring, " last word read: %3i |", lwr);
|
//quick test for EM4x50 tag
|
||||||
strcat(string, pstring);
|
bool detect_4x50_block(void) {
|
||||||
sprintf(pstring, " last word read protected: %3i", lwrp);
|
em4x50_data_t etd = {
|
||||||
strcat(string, pstring);
|
.pwd_given = false,
|
||||||
PrintAndLogEx(NORMAL,"%s", string);
|
.addr_given = true,
|
||||||
string[0] = '\0';
|
.address = EM4X50_DEVICE_ID,
|
||||||
|
};
|
||||||
|
em4x50_word_t words[EM4X50_NO_WORDS] = {0};
|
||||||
|
return (em4x50_read(&etd, words, false) == PM3_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(pstring, " password check: %3s |", (bpwc) ? "on" : "off");
|
|
||||||
strcat(string, pstring);
|
|
||||||
sprintf(pstring, " first word write inhibited: %3i", fwwi);
|
|
||||||
strcat(string, pstring);
|
|
||||||
PrintAndLogEx(NORMAL,"%s", string);
|
|
||||||
string[0] = '\0';
|
|
||||||
|
|
||||||
sprintf(pstring, " read after write: %3s |", (braw) ? "on" : "off");
|
int read_em4x50_uid(void) {
|
||||||
strcat(string, pstring);
|
em4x50_data_t etd = {
|
||||||
sprintf(pstring, " last word write inhibited: %3i", lwwi);
|
.pwd_given = false,
|
||||||
strcat(string, pstring);
|
.addr_given = true,
|
||||||
PrintAndLogEx(NORMAL,"%s", string);
|
.address = EM4X50_DEVICE_SERIAL,
|
||||||
string[0] = '\0';
|
};
|
||||||
|
em4x50_word_t words[EM4X50_NO_WORDS] = {0};
|
||||||
PrintAndLogEx(NORMAL, "\n zero values may indicate read protection!");
|
int res = em4x50_read(&etd, words, false);
|
||||||
|
if (res == PM3_SUCCESS)
|
||||||
// status line
|
PrintAndLogEx(INFO, " Serial: " _GREEN_("%s"), sprint_hex(words[EM4X50_DEVICE_SERIAL].byte, 4));
|
||||||
sprintf(pstring, " reading ");
|
return res;
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
sprintf(pstring, _GREEN_("ok "));
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
if (blogin) {
|
|
||||||
|
|
||||||
if (bpwd_given) {
|
|
||||||
|
|
||||||
sprintf(pstring, "(login with password 0x%02x%02x%02x%02x)",
|
|
||||||
etd->password[0], etd->password[1],
|
|
||||||
etd->password[2], etd->password[3]);
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
sprintf(pstring, "(login with default password 0x00000000)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (bpwd_given) {
|
|
||||||
|
|
||||||
sprintf(pstring, "(login failed)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
sprintf(pstring, "(no login)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x50Info(const char *Cmd) {
|
int CmdEM4x50Info(const char *Cmd) {
|
||||||
|
@ -390,12 +287,9 @@ int CmdEM4x50Info(const char *Cmd) {
|
||||||
// envoke reading of a EM4x50 tag which has to be on the antenna because
|
// envoke reading of a EM4x50 tag which has to be on the antenna because
|
||||||
// decoding is done by the device (not on client side)
|
// decoding is done by the device (not on client side)
|
||||||
|
|
||||||
bool errors = false, verbose = false, success = false;
|
bool errors = false, verbose = false;
|
||||||
uint8_t cmdp = 0;
|
uint8_t cmdp = 0;
|
||||||
em4x50_data_t etd;
|
em4x50_data_t etd;
|
||||||
PacketResponseNG resp;
|
|
||||||
|
|
||||||
// init
|
|
||||||
etd.pwd_given = false;
|
etd.pwd_given = false;
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
|
@ -429,26 +323,23 @@ int CmdEM4x50Info(const char *Cmd) {
|
||||||
if (errors)
|
if (errors)
|
||||||
return usage_lf_em4x50_info();
|
return usage_lf_em4x50_info();
|
||||||
|
|
||||||
// call info command
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
// get result
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = (resp.status & STATUS_SUCCESS) >> 1;
|
bool success = (resp.status & STATUS_SUCCESS) >> 1;
|
||||||
|
if (success) {
|
||||||
|
print_info_result(resp.data.asBytes, verbose);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// print result
|
PrintAndLogEx(FAILED, "reading tag " _RED_("failed"));
|
||||||
if (success)
|
return PM3_ESOFT;
|
||||||
print_info_result(&resp, &etd, verbose);
|
|
||||||
else
|
|
||||||
PrintAndLogEx(NORMAL,"\nreading " _RED_("failed") "\n");
|
|
||||||
|
|
||||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_write_result(PacketResponseNG *resp, const em4x50_data_t *etd) {
|
static void print_write_result(PacketResponseNG *resp, const em4x50_data_t *etd) {
|
||||||
|
@ -644,156 +535,109 @@ int CmdEM4x50WritePassword(const char *Cmd) {
|
||||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_read_result(PacketResponseNG *resp, const em4x50_data_t *etd, bool verbose) {
|
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) {
|
||||||
|
|
||||||
// display result of writing operation in structured format
|
|
||||||
|
|
||||||
bool addr_given = etd->addr_given;
|
|
||||||
bool pwd_given = etd->pwd_given;
|
|
||||||
bool login = resp->status & STATUS_LOGIN;
|
|
||||||
int now = (resp->status & STATUS_NO_WORDS) >> 2;
|
|
||||||
char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0};
|
|
||||||
uint8_t *data = resp->data.asBytes;
|
|
||||||
em4x50_word_t words[EM4X50_NO_WORDS];
|
|
||||||
|
|
||||||
if (addr_given) {
|
|
||||||
|
|
||||||
// selective read mode
|
|
||||||
|
|
||||||
prepare_result(data, etd->address, etd->address, words);
|
|
||||||
print_result(words, etd->address, etd->address, true);
|
|
||||||
|
|
||||||
string[0] = '\0';
|
|
||||||
sprintf(pstring, "\n reading " _GREEN_("ok "));
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
if (pwd_given) {
|
|
||||||
if (login) {
|
|
||||||
sprintf(pstring, "(login with password 0x%02x%02x%02x%02x)",
|
|
||||||
etd->password[0], etd->password[1],
|
|
||||||
etd->password[2], etd->password[3]);
|
|
||||||
strcat(string, pstring);
|
|
||||||
} else {
|
|
||||||
sprintf(pstring, "(login failed)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sprintf(pstring, "(no login)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
//standard read mode
|
|
||||||
|
|
||||||
prepare_result(data, 0, now - 1, words);
|
|
||||||
print_result(words, 0, now - 1, verbose);
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
|
|
||||||
string[0] = '\0';
|
|
||||||
sprintf(pstring, "\n reading " _GREEN_("ok "));
|
|
||||||
strcat(string, pstring);
|
|
||||||
|
|
||||||
if (pwd_given) {
|
|
||||||
sprintf(pstring, "(standard read mode, password ignored)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
} else {
|
|
||||||
sprintf(pstring, "(standard read mode)");
|
|
||||||
strcat(string, pstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int EM4x50Read(const char *Cmd, bool verbose) {
|
|
||||||
|
|
||||||
// envoke reading
|
// envoke reading
|
||||||
// - without option -> standard read mode
|
// - without option -> standard read mode
|
||||||
// - with given address (option a) (and optional password if address is
|
// - with given address (option a) (and optional password if address is
|
||||||
// read protected) -> selective read mode
|
// read protected) -> selective read mode
|
||||||
|
|
||||||
bool errors = false, success = false;
|
em4x50_data_t edata;
|
||||||
uint8_t cmdp = 0;
|
edata.pwd_given = false;
|
||||||
em4x50_data_t etd;
|
edata.addr_given = false;
|
||||||
PacketResponseNG resp;
|
|
||||||
|
|
||||||
// init
|
|
||||||
etd.pwd_given = false;
|
|
||||||
etd.addr_given = false;
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_lf_em4x50_read();
|
|
||||||
|
|
||||||
case 'p':
|
|
||||||
if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) {
|
|
||||||
PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
etd.pwd_given = true;
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
param_getdec(Cmd, cmdp + 1, &etd.address);
|
|
||||||
|
|
||||||
// validation
|
|
||||||
if (etd.address <= 0 || etd.address >= EM4X50_NO_WORDS) {
|
|
||||||
PrintAndLogEx(FAILED, "\n error, address has to be in range [1-33]\n");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
etd.addr_given = true;
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errors)
|
|
||||||
return usage_lf_em4x50_read();
|
|
||||||
|
|
||||||
|
if (etd != NULL) {
|
||||||
|
edata = *etd;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata));
|
||||||
|
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = (resp.status & STATUS_SUCCESS) >> 1;
|
bool isOK = (resp.status & STATUS_SUCCESS) >> 1;
|
||||||
|
if (isOK == false) {
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(FAILED, "reading " _RED_("failed"));
|
||||||
|
|
||||||
// get, prepare and print response
|
return PM3_ESOFT;
|
||||||
if (success)
|
}
|
||||||
print_read_result(&resp, &etd, verbose);
|
|
||||||
else if (verbose)
|
|
||||||
PrintAndLogEx(NORMAL,"\nreading " _RED_("failed") "\n");
|
|
||||||
|
|
||||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
if (edata.pwd_given) {
|
||||||
|
bool login = resp.status & STATUS_LOGIN;
|
||||||
|
if (login == false) {
|
||||||
|
PrintAndLogEx(FAILED, "login failed");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "login with password " _YELLOW_("%s"), sprint_hex_inrow(etd->password, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||||
|
if (edata.addr_given) {
|
||||||
|
prepare_result(data, etd->address, etd->address, words);
|
||||||
|
} else {
|
||||||
|
int now = (resp.status & STATUS_NO_WORDS) >> 2;
|
||||||
|
prepare_result(data, 0, now - 1, words);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out != NULL) {
|
||||||
|
memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
print_result(words, etd->address, etd->address, true);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x50Read(const char *Cmd) {
|
int CmdEM4x50Read(const char *Cmd) {
|
||||||
|
|
||||||
// envoke reading function
|
em4x50_data_t etd;
|
||||||
// verbose = true for manual call
|
etd.pwd_given = false;
|
||||||
// verbose = false for automatic call (e.g. lf search)
|
etd.addr_given = false;
|
||||||
|
|
||||||
bool verbose = true;
|
bool errors = false;
|
||||||
|
uint8_t cmdp = 0;
|
||||||
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
|
|
||||||
return EM4x50Read(Cmd, verbose);
|
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||||
|
case 'h':
|
||||||
|
return usage_lf_em4x50_read();
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) {
|
||||||
|
PrintAndLogEx(FAILED, "\n password has to be 8 hex symbols\n");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
etd.pwd_given = true;
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
param_getdec(Cmd, cmdp + 1, &etd.address);
|
||||||
|
|
||||||
|
// validation
|
||||||
|
if (etd.address <= 0 || etd.address >= EM4X50_NO_WORDS) {
|
||||||
|
PrintAndLogEx(FAILED, "\n error, address has to be in range [1-33]\n");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
etd.addr_given = true;
|
||||||
|
cmdp += 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLogEx(WARNING, "\n Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors)
|
||||||
|
return usage_lf_em4x50_read();
|
||||||
|
|
||||||
|
return em4x50_read(&etd, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,16 @@
|
||||||
#define CMDLFEM4X50_H__
|
#define CMDLFEM4X50_H__
|
||||||
|
|
||||||
#include"common.h"
|
#include"common.h"
|
||||||
|
#include "em4x50.h"
|
||||||
|
|
||||||
int usage_lf_em4x50_info(void);
|
int usage_lf_em4x50_info(void);
|
||||||
int usage_lf_em4x50_write(void);
|
int usage_lf_em4x50_write(void);
|
||||||
int usage_lf_em4x50_write_password(void);
|
int usage_lf_em4x50_write_password(void);
|
||||||
int usage_lf_em4x50_read(void);
|
int usage_lf_em4x50_read(void);
|
||||||
|
|
||||||
int EM4x50Read(const char *Cmd, bool verbose);
|
int read_em4x50_uid(void);
|
||||||
|
bool detect_4x50_block(void);
|
||||||
|
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose);
|
||||||
|
|
||||||
int CmdEM4x50Info(const char *Cmd);
|
int CmdEM4x50Info(const char *Cmd);
|
||||||
int CmdEM4x50Write(const char *Cmd);
|
int CmdEM4x50Write(const char *Cmd);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue