mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 10:37:23 -07:00
WIP adapt for cliparser and EM4x69
This commit is contained in:
parent
34a56fae9a
commit
0ea561f239
1 changed files with 285 additions and 168 deletions
|
@ -35,20 +35,7 @@
|
|||
#include "cmdhw.h"
|
||||
|
||||
//////////////// 4205 / 4305 commands
|
||||
static int usage_lf_em4x05_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [f <filename prefix>] <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " f <filename prefix> - overide filename prefix (optional). Default is based on UID");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump f card1 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_em4x05_wipe(void) {
|
||||
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -103,6 +90,48 @@ static int usage_lf_em4x05_info(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define EM_SERIAL_BLOCK 1
|
||||
#define EM_CONFIG_BLOCK 4
|
||||
#define EM4305_PROT1_BLOCK 14
|
||||
#define EM4305_PROT2_BLOCK 15
|
||||
#define EM4469_PROT_BLOCK 3
|
||||
|
||||
typedef enum {
|
||||
EM_UNKNOWN,
|
||||
EM_4205,
|
||||
EM_4305,
|
||||
EM_4X69,
|
||||
} em_tech_type_t;
|
||||
|
||||
// 1 = EM4x69
|
||||
// 2 = EM4x05
|
||||
static em_tech_type_t em_get_card_type(uint32_t config) {
|
||||
uint8_t t = (config >> 1) & 0xF;
|
||||
switch(t) {
|
||||
case 4:
|
||||
return EM_4X69;
|
||||
case 8:
|
||||
return EM_4205;
|
||||
case 9:
|
||||
return EM_4305;
|
||||
}
|
||||
return EM_UNKNOWN;
|
||||
}
|
||||
|
||||
static const char* em_get_card_str(uint32_t config) {
|
||||
switch (em_get_card_type(config)) {
|
||||
case EM_4305:
|
||||
return "EM4305";
|
||||
case EM_4X69:
|
||||
return "EM4469";
|
||||
case EM_4205:
|
||||
return "EM4205";
|
||||
case EM_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// even parity COLUMN
|
||||
static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
||||
if (rows * cols > size) return false;
|
||||
|
@ -366,37 +395,52 @@ int CmdEM4x05Demod(const char *Cmd) {
|
|||
}
|
||||
|
||||
int CmdEM4x05Dump(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em dump",
|
||||
"Dump EM4x05/EM4x69. Tag must be on antenna.",
|
||||
"lf em dump\n"
|
||||
"lf em dump -p 11223344\n"
|
||||
"lf em dump -f myfile -p 11223344"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0("p", "pwd", "<hex>", "password (0x00000000)"),
|
||||
arg_str0("f", "file", "<filename>", "overide filename prefix (optional). Default is based on UID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
uint64_t inputpwd = arg_get_u64_def(ctx, 1, 0xFFFFFFFFFFFFFFFF);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t addr = 0;
|
||||
uint32_t pwd = 0;
|
||||
bool usePwd = false;
|
||||
bool usePwd = false;
|
||||
if (inputpwd != 0xFFFFFFFFFFFFFFFF) {
|
||||
|
||||
if (inputpwd & 0xFFFFFFFF00000000) {
|
||||
PrintAndLogEx(FAILED, "Pwd too large");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
usePwd = true;
|
||||
pwd = (inputpwd & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
uint32_t block0 = 0;
|
||||
// read word 0 (chip info)
|
||||
// block 0 can be read even without a password.
|
||||
if (EM4x05IsBlock0(&block0) == false)
|
||||
return PM3_ESOFT;
|
||||
|
||||
bool needReadPwd = true;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t bytes[4] = {0};
|
||||
uint32_t data[16];
|
||||
char preferredName[FILE_PATH_SIZE] = {0};
|
||||
char optchk[10];
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_em4x05_dump();
|
||||
break;
|
||||
case 'f': // since f could match in password, lets confirm it is 1 character only for an option
|
||||
param_getstr(Cmd, cmdp, optchk, sizeof(optchk));
|
||||
if (strlen(optchk) == 1) { // Have a single character f so filename no password
|
||||
param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE);
|
||||
cmdp += 2;
|
||||
break;
|
||||
} // if not a single 'f' dont break and flow onto default as should be password
|
||||
|
||||
default : // for backwards-compatibility options should be > 'f' else assume its the hex password`
|
||||
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
|
||||
pwd = param_get32ex(Cmd, cmdp, 1, 16);
|
||||
if (pwd != 1)
|
||||
usePwd = true;
|
||||
cmdp++;
|
||||
};
|
||||
}
|
||||
|
||||
int success = PM3_SUCCESS;
|
||||
int status, status14, status15;
|
||||
|
@ -404,105 +448,187 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
bool gotLockBits = false;
|
||||
bool lockInPW2 = false;
|
||||
uint32_t word = 0;
|
||||
|
||||
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
|
||||
const char *info4x69 [] = {"Info", "UID", "Password", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(14, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info");
|
||||
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
|
||||
// EM4305 vs EM4469
|
||||
em_tech_type_t card_type = em_get_card_type(block0);
|
||||
|
||||
PrintAndLogEx(INFO, "Found a " _GREEN_("%s") " tag", em_get_card_str(block0));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
PrintAndLogEx(INFO, "Addr | data | ascii |lck| info");
|
||||
PrintAndLogEx(INFO, "-----+----------+-------+---+-----");
|
||||
|
||||
if ( card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
data[14] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
status15 = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
lockInPW2 = true;
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
}
|
||||
data[EM4305_PROT1_BLOCK] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
data[15] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
uint32_t lockbit;
|
||||
// Now read blocks 0 - 13 as we have 14 and 15
|
||||
for (; addr < 14; addr++) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
status15 = EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word);
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
lockInPW2 = true;
|
||||
}
|
||||
data[EM4305_PROT2_BLOCK] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
uint32_t lockbit;
|
||||
// Now read blocks 0 - 13 as we have 14 and 15
|
||||
for (; addr < 14; addr++) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
} else {
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
|
||||
if (status != PM3_SUCCESS)
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
data[addr] = BSWAP_32(word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
num_to_bytes(word, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
} else {
|
||||
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
|
||||
if (status != PM3_SUCCESS)
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
data[addr] = BSWAP_32(word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
num_to_bytes(word, 4, bytes);
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
}
|
||||
// Print blocks 14 and 15
|
||||
// Both lock bits are protected with bit idx 14 (special case)
|
||||
addr = 14;
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? "" : _GREEN_("active"));
|
||||
// Print blocks 14 and 15
|
||||
// Both lock bits are protected with bit idx 14 (special case)
|
||||
addr = 14;
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? "" : _GREEN_("active"));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
addr = 15;
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> 14) & 1; // beware lock bit of word15 is pr14
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
// Update endian for files
|
||||
data[14] = BSWAP_32(data[14]);
|
||||
data[15] = BSWAP_32(data[15]);
|
||||
|
||||
} else if (card_type == EM_4X69) {
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
}
|
||||
data[EM4469_PROT_BLOCK] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
|
||||
uint32_t lockbit;
|
||||
|
||||
for (; addr < 15; addr++) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||
}
|
||||
} else {
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||
}
|
||||
} else {
|
||||
|
||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
if (status != PM3_SUCCESS) {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
|
||||
data[addr] = BSWAP_32(word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
num_to_bytes(word, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info4x69[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
addr = 15;
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> 14) & 1; // beware lock bit of word15 is pr14
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
// Update endian for files
|
||||
data[14] = BSWAP_32(data[14]);
|
||||
data[15] = BSWAP_32(data[15]);
|
||||
|
||||
if (success == PM3_SUCCESS) { // all ok save dump to file
|
||||
// saveFileEML will add .eml extension to filename
|
||||
// saveFile (binary) passes in the .bin extension.
|
||||
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
|
||||
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||
if (strcmp(filename, "") == 0) {
|
||||
|
||||
if ( card_type == EM_4X69) {
|
||||
sprintf(filename, "lf-4x69-%08X-dump", BSWAP_32(data[1]));
|
||||
} else {
|
||||
sprintf(filename, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||
}
|
||||
|
||||
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
||||
saveFile(preferredName, ".bin", data, sizeof(data));
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
saveFileEML(filename, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
||||
saveFile(filename, ".bin", data, sizeof(data));
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -787,7 +913,7 @@ static void printEM4x05config(uint32_t wordData) {
|
|||
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ------------------------");
|
||||
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
|
||||
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
|
||||
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
|
||||
|
@ -810,11 +936,6 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
|||
uint8_t cap = (block0 >> 5) & 3;
|
||||
uint16_t custCode = (block0 >> 9) & 0x2FF;
|
||||
|
||||
PrintAndLogEx(INFO, " block0: %X", block0);
|
||||
PrintAndLogEx(INFO, " chiptype: %X", chipType);
|
||||
PrintAndLogEx(INFO, "capacitor: %X", cap);
|
||||
PrintAndLogEx(INFO, " custcode: %X", custCode);
|
||||
|
||||
/* bits
|
||||
// 0, rfu
|
||||
// 1,2,3,4 chip type
|
||||
|
@ -834,51 +955,35 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
|||
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
|
||||
char ctstr[50];
|
||||
snprintf(ctstr, sizeof(ctstr), " Chip Type: %u | ", chipType);
|
||||
switch (chipType) {
|
||||
case 9:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305");
|
||||
break;
|
||||
case 4:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
|
||||
break;
|
||||
case 8:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205");
|
||||
break;
|
||||
//add more here when known
|
||||
default:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
|
||||
break;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "%s", ctstr);
|
||||
PrintAndLogEx(SUCCESS, " Block0: " _GREEN_("%08x") " (Word 0)", block0);
|
||||
PrintAndLogEx(SUCCESS, " Chip Type: %3u | " _YELLOW_("%s"), chipType, em_get_card_str(block0));
|
||||
|
||||
switch (cap) {
|
||||
case 3:
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | 330pF", cap);
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 330pF", cap);
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | %spF", cap, (chipType == 2) ? "75" : "210");
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %3u | %spF", cap, (chipType == 4) ? "75" : "210");
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | 250pF", cap);
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 250pF", cap);
|
||||
break;
|
||||
case 0:
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | no resonant capacitor", cap);
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %3u | no resonant capacitor", cap);
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | unknown", cap);
|
||||
PrintAndLogEx(SUCCESS, " Cap Type: %3u | unknown", cap);
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
|
||||
PrintAndLogEx(SUCCESS, " Cust Code: 0x%x | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
|
||||
if (serial != 0)
|
||||
PrintAndLogEx(SUCCESS, " Serial #: " _YELLOW_("%08X"), serial);
|
||||
}
|
||||
|
||||
static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " --------------------------------");
|
||||
PrintAndLogEx(INFO, "ProtectionWord: %08X (Word %i)", word, addr);
|
||||
for (uint8_t i = 0; i < 15; i++) {
|
||||
PrintAndLogEx(INFO, " Word: %02u | %s", i, ((1 << i) & word) ? _RED_("write Locked") : "unlocked");
|
||||
|
@ -893,10 +998,6 @@ bool EM4x05IsBlock0(uint32_t *word) {
|
|||
}
|
||||
|
||||
int CmdEM4x05Info(const char *Cmd) {
|
||||
#define EM_SERIAL_BLOCK 1
|
||||
#define EM_CONFIG_BLOCK 4
|
||||
#define EM_PROT1_BLOCK 14
|
||||
#define EM_PROT2_BLOCK 15
|
||||
uint32_t pwd;
|
||||
uint32_t word = 0, block0 = 0, serial = 0;
|
||||
bool usePwd = false;
|
||||
|
@ -914,9 +1015,13 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
if (EM4x05IsBlock0(&block0) == false)
|
||||
return PM3_ESOFT;
|
||||
|
||||
// based on Block0 , decide type.
|
||||
int card_type = em_get_card_type(block0);
|
||||
|
||||
// read word 1 (serial #) doesn't need pwd
|
||||
// continue if failed, .. non blocking fail.
|
||||
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
|
||||
|
||||
printEM4x05info(block0, serial);
|
||||
|
||||
// read word 4 (config block)
|
||||
|
@ -925,21 +1030,33 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
|
||||
printEM4x05config(word);
|
||||
|
||||
// if 4469 read EM4469_PROT_BLOCK
|
||||
// if 4305 read 14,15
|
||||
if (card_type == EM_4205 || card_type == EM_4305) {
|
||||
|
||||
// read word 14 and 15 to see which is being used for the protection bits
|
||||
if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM_PROT1_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
} else { // if status bit says this is not the used protection word
|
||||
if (EM4x05ReadWord_ext(EM_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
// read word 14 and 15 to see which is being used for the protection bits
|
||||
if (EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM_PROT2_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
} else { // if status bit says this is not the used protection word
|
||||
if (EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
return PM3_ESOFT;
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
} else if (card_type == EM_4X69) {
|
||||
// read word 3 to see which is being used for the protection bits
|
||||
if (EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
|
||||
}
|
||||
//something went wrong
|
||||
return PM3_ESOFT;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue