mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 06:13:51 -07:00
hf mf ginfo -now supports decoding of a user supplied configuration block and improved textual output
This commit is contained in:
parent
39984c400a
commit
82a809887c
2 changed files with 99 additions and 60 deletions
|
@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Changed `hf mf *` - printing of keys if MFC EV1 added extra explaination (@iceman1001)
|
||||||
|
- Changed `hf mf ginfo - now supports decoding of user supplied configuration block (@iceman1001)
|
||||||
- Changed `data load` - now shows loaded number as comma printed. (@iceman1001)
|
- Changed `data load` - now shows loaded number as comma printed. (@iceman1001)
|
||||||
- Updated `/tools/hitag2crack/common/OpenCL-Headers/CL` with latest from KhronosGroup github page (@iceman1001)
|
- Updated `/tools/hitag2crack/common/OpenCL-Headers/CL` with latest from KhronosGroup github page (@iceman1001)
|
||||||
- Fixed `lf hitag list` - improved HITAG2 protocol annotation (@iceman1001)
|
- Fixed `lf hitag list` - improved HITAG2 protocol annotation (@iceman1001)
|
||||||
|
|
|
@ -7667,11 +7667,13 @@ static int CmdHF14AGen4Info(const char *cmd) {
|
||||||
"Read info about magic gen4 GTU card.",
|
"Read info about magic gen4 GTU card.",
|
||||||
"hf mf ginfo --> get info with default password 00000000\n"
|
"hf mf ginfo --> get info with default password 00000000\n"
|
||||||
"hf mf ginfo --pwd 01020304 --> get info with password\n"
|
"hf mf ginfo --pwd 01020304 --> get info with password\n"
|
||||||
|
"hf mf ginfo -d 00000000000002090978009102BDAC19131011121314151604001800FF0002FD -v --> decode config block"
|
||||||
);
|
);
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
|
||||||
|
arg_str0("d", "data", "<hex>", "config bytes 32 bytes"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, cmd, argtable, true);
|
CLIExecWithReturn(ctx, cmd, argtable, true);
|
||||||
|
@ -7680,6 +7682,10 @@ static int CmdHF14AGen4Info(const char *cmd) {
|
||||||
int pwd_len = 0;
|
int pwd_len = 0;
|
||||||
uint8_t pwd[4] = {0};
|
uint8_t pwd[4] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len);
|
CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len);
|
||||||
|
|
||||||
|
int dlen = 0;
|
||||||
|
uint8_t data[32] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 3, data, &dlen);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (pwd_len != 0 && pwd_len != 4) {
|
if (pwd_len != 0 && pwd_len != 4) {
|
||||||
|
@ -7689,7 +7695,10 @@ static int CmdHF14AGen4Info(const char *cmd) {
|
||||||
|
|
||||||
uint8_t resp[40] = {0};
|
uint8_t resp[40] = {0};
|
||||||
size_t resplen = 0;
|
size_t resplen = 0;
|
||||||
int res = mfG4GetConfig(pwd, resp, &resplen, verbose);
|
int res = 0;
|
||||||
|
|
||||||
|
if (dlen != 32) {
|
||||||
|
res = mfG4GetConfig(pwd, resp, &resplen, verbose);
|
||||||
if (res != PM3_SUCCESS || resplen == 0) {
|
if (res != PM3_SUCCESS || resplen == 0) {
|
||||||
if (res == PM3_ETIMEOUT)
|
if (res == PM3_ETIMEOUT)
|
||||||
PrintAndLogEx(ERR, "No card in the field or card command timeout.");
|
PrintAndLogEx(ERR, "No card in the field or card command timeout.");
|
||||||
|
@ -7697,141 +7706,168 @@ static int CmdHF14AGen4Info(const char *cmd) {
|
||||||
PrintAndLogEx(ERR, "Error get config. Maybe not a Gen4 card?. error=%d rlen=%zu", res, resplen);
|
PrintAndLogEx(ERR, "Error get config. Maybe not a Gen4 card?. error=%d rlen=%zu", res, resplen);
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(resp, data, dlen);
|
||||||
|
resplen = 32;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "---------- Gen4 configuration ----------");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "---------- " _CYAN_("GTU Gen4 configuration") " -------------------------------------");
|
||||||
if (resplen != 30 && resplen != 32) {
|
if (resplen != 30 && resplen != 32) {
|
||||||
PrintAndLogEx(INFO, "Raw config [%02zu] %s", resplen, sprint_hex_inrow(resp, resplen));
|
PrintAndLogEx(INFO, "Raw ( %zub )... %s", resplen, sprint_hex_inrow(resp, resplen));
|
||||||
PrintAndLogEx(WARNING, "Unknown config format");
|
PrintAndLogEx(WARNING, "Unknown config format");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
if (verbose)
|
|
||||||
PrintAndLogEx(INFO, "Raw config [%02zu]..... %s", resplen, sprint_hex_inrow(resp, resplen));
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "UL protocol......... %02x" NOLF, resp[0]);
|
PrintAndLogEx(INFO, "Raw... " _YELLOW_("%s"), sprint_hex_inrow(resp, resplen));
|
||||||
|
PrintAndLogEx(INFO, "Len... %u", resplen);
|
||||||
|
PrintAndLogEx(INFO, "");
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Config 1 - UID & modes"));
|
||||||
|
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(resp, 8));
|
||||||
|
PrintAndLogEx(INFO, "%02X.............. " NOLF, resp[0]);
|
||||||
|
bool is_ul_enabled = ( resp[0] == 1 );
|
||||||
switch (resp[0]) {
|
switch (resp[0]) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " (MIFARE Classic mode)");
|
PrintAndLogEx(NORMAL, "MIFARE Classic mode");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " (MIFARE Ultralight/NTAG mode)");
|
PrintAndLogEx(NORMAL, "MIFARE Ultralight/NTAG mode");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(NORMAL, " (unknown %02x)", resp[0]);
|
PrintAndLogEx(NORMAL, _RED_("unknown"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "..%02X............ UID " NOLF, resp[1]);
|
||||||
uint8_t uid_len = resp[1];
|
uint8_t uid_len = resp[1];
|
||||||
PrintAndLogEx(INFO, "UID length.......... %02x" NOLF, resp[1]);
|
|
||||||
switch (resp[1]) {
|
switch (resp[1]) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " (4 byte)");
|
PrintAndLogEx(NORMAL, _GREEN_("4") " byte");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " (7 byte)");
|
PrintAndLogEx(NORMAL, _GREEN_("7") " byte");
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " (10 byte)");
|
PrintAndLogEx(NORMAL, _GREEN_("10") " byte");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(NORMAL, " (unknown %02x)", resp[1]);
|
PrintAndLogEx(NORMAL, _RED_("unknown"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(INFO, "...." _YELLOW_("%s") ".... " _YELLOW_("Password"), sprint_hex_inrow(&resp[2], 4));
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Password............ %s", sprint_hex_inrow(&resp[2], 4));
|
PrintAndLogEx(INFO, "............%02X.. GTU mode " NOLF, resp[6]);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "GTU mode............ %02x" NOLF, resp[6]);
|
|
||||||
switch (resp[6]) {
|
switch (resp[6]) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " (pre-write, shadow data can be written)");
|
PrintAndLogEx(NORMAL, _GREEN_("pre-write") " - shadow data can be written");
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " (restore mode)");
|
PrintAndLogEx(NORMAL, _GREEN_("restore mode"));
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " (disabled)");
|
PrintAndLogEx(NORMAL, "disabled");
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
PrintAndLogEx(NORMAL, " (disabled, high speed R/W mode for Ultralight?)");
|
PrintAndLogEx(NORMAL, "disabled, high speed R/W mode for Ultralight ?");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(NORMAL, " (unknown %02x)", resp[6]);
|
PrintAndLogEx(NORMAL, _RED_("unknown"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "ATS [%02d]............ %s", resp[7], sprint_hex_inrow(&resp[8], resp[7]));
|
PrintAndLogEx(INFO, "..............%02X unknown", resp[7]);
|
||||||
PrintAndLogEx(INFO, "ATQA................ %02x%02x", resp[25], resp[24]);
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, "SAK................. %02x", resp[26]);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "UL mode............. %02x" NOLF, resp[27]);
|
// ATS seems to have 16 bytes reserved
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Config 2 - ATS"));
|
||||||
|
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(resp + 8, 16));
|
||||||
|
PrintAndLogEx(INFO, "%s.............. ATS ( %db )", sprint_hex_inrow(&resp[8], resp[7]), resp[7]);
|
||||||
|
PrintAndLogEx(INFO, "..................%s Reserved for ATS", sprint_hex_inrow(resp + 8 + resp[7], 16 - resp[7]));
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "");
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Config 3 - Limits"));
|
||||||
|
PrintAndLogEx(INFO, "%s", sprint_hex_inrow(resp + 24, (resplen - 24)));
|
||||||
|
PrintAndLogEx(INFO, "%02X%02X............ ATQA", resp[24], resp[25]);
|
||||||
|
PrintAndLogEx(INFO, "....%02X.......... SAK", resp[26]);
|
||||||
|
PrintAndLogEx(INFO, "......%02X........ " NOLF, resp[27]);
|
||||||
switch (resp[27]) {
|
switch (resp[27]) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " (UL EV1)");
|
PrintAndLogEx(NORMAL, "%s", (is_ul_enabled) ? _GREEN_("Ultralight EV1") : "Ultralight Ev1" );
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " (NTAG)");
|
PrintAndLogEx(NORMAL, "%s", (is_ul_enabled) ? _GREEN_("NTAG") : "NTAG" );
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " (UL-C)");
|
PrintAndLogEx(NORMAL, "%s", (is_ul_enabled) ? _GREEN_("Ultralight C") : "Ultralight C" );
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
PrintAndLogEx(NORMAL, " (UL)");
|
PrintAndLogEx(NORMAL, "%s", (is_ul_enabled) ? _GREEN_("Ultralight") : "Ultralight" );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(NORMAL, " (unknown %02x)", resp[27]);
|
PrintAndLogEx(NORMAL, _RED_("unknown"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "max rd/wr sectors... %02x", resp[28]);
|
PrintAndLogEx(INFO, "........%02X...... Max R/W sectors", resp[28]);
|
||||||
PrintAndLogEx(INFO, "block0 direct wr.... %02x" NOLF, resp[29]);
|
PrintAndLogEx(INFO, "..........%02X.... " NOLF, resp[29]);
|
||||||
switch (resp[29]) {
|
switch (resp[29]) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(NORMAL, " (Activate direct write to block 0 (Same behaviour of Gen2 cards. Some readers may identify the card as magic))");
|
PrintAndLogEx(NORMAL, _GREEN_("CUID enabled"));
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(NORMAL, " (Deactivate direct write to block 0 (Same behaviour of vanilla cards))");
|
PrintAndLogEx(NORMAL, "CUID disabled");
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(NORMAL, " (Default value. Same behaviour as 00?");
|
PrintAndLogEx(NORMAL, "Default value. Same behaviour as 00?");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(NORMAL, " (unknown %02x)", resp[29]);
|
PrintAndLogEx(NORMAL, _RED_("unknown"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(INFO, "............%s unknown", sprint_hex_inrow(resp + 30, resplen - 30));
|
||||||
|
PrintAndLogEx(INFO, "");
|
||||||
|
|
||||||
res = mfG4GetFactoryTest(pwd, resp, &resplen, false);
|
res = mfG4GetFactoryTest(pwd, resp, &resplen, false);
|
||||||
if (res == PM3_SUCCESS && resplen > 2) {
|
if (res == PM3_SUCCESS && resplen > 2) {
|
||||||
if (verbose) {
|
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, "Raw test [%02zu]....... %s", resplen, sprint_hex_inrow(resp, resplen));
|
PrintAndLogEx(INFO, _CYAN_("Factory test"));
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Raw......... %s", sprint_hex_inrow(resp, resplen));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp[resplen - 2] == 0x66 && resp[resplen - 1] == 0x66)
|
if (memcmp(resp + resplen - 2, "\x66\x66", 2) == 0) {
|
||||||
PrintAndLogEx(INFO, "Card type........... generic");
|
PrintAndLogEx(INFO, "Card type... Generic");
|
||||||
else if (resp[resplen - 2] == 0x02 && resp[resplen - 1] == 0xaa)
|
|
||||||
PrintAndLogEx(INFO, "Card type........... limited functionality");
|
} else if (memcmp(resp + resplen - 2, "\x02\xAA", 2) == 0) {
|
||||||
else if (resp[resplen - 2] == 0x03 && resp[resplen - 1] == 0xa0)
|
PrintAndLogEx(INFO, "Card type... " _RED_("Limited functionality"));
|
||||||
PrintAndLogEx(INFO, "Card type........... old card version");
|
|
||||||
else if (resp[resplen - 2] == 0x06 && resp[resplen - 1] == 0xa0)
|
} else if (memcmp(resp + resplen - 2, "\x03\xA0", 2) == 0) {
|
||||||
PrintAndLogEx(INFO, "Card type........... new card version");
|
PrintAndLogEx(INFO, "Card type... Old card version");
|
||||||
else
|
|
||||||
PrintAndLogEx(INFO, "Card type........... unknown %02x%02x", resp[resplen - 2], resp[resplen - 1]);
|
} else if (memcmp(resp + resplen - 2, "\x06\xA0", 2) == 0) {
|
||||||
|
PrintAndLogEx(INFO, "Card type... " _GREEN_("New card version"));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "Card type... " _RED_("unknown %02X%02X"), resp[resplen - 2], resp[resplen - 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read block 0
|
// read block 0
|
||||||
res = mfG4GetBlock(pwd, 0, resp, MAGIC_INIT | MAGIC_OFF);
|
res = mfG4GetBlock(pwd, 0, resp, MAGIC_INIT | MAGIC_OFF);
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(INFO, "");
|
PrintAndLogEx(INFO, "");
|
||||||
PrintAndLogEx(INFO, "Block 0............. %s", sprint_hex_inrow(resp, 16));
|
PrintAndLogEx(INFO, _CYAN_("Block 0 test"));
|
||||||
|
PrintAndLogEx(INFO, "Block 0..... %s", sprint_hex_inrow(resp, 16));
|
||||||
|
|
||||||
switch (uid_len) {
|
switch (uid_len) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
PrintAndLogEx(INFO, "UID [4]............. %s", sprint_hex(resp, 4));
|
PrintAndLogEx(INFO, "UID [4]..... %s", sprint_hex_inrow(resp, 4));
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
PrintAndLogEx(INFO, "UID [7]............. %s", sprint_hex(resp, 7));
|
PrintAndLogEx(INFO, "UID [7]..... %s", sprint_hex_inrow(resp, 7));
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
PrintAndLogEx(INFO, "UID [10]............ %s", sprint_hex(resp, 10));
|
PrintAndLogEx(INFO, "UID [10..... %s", sprint_hex_inrow(resp, 10));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -7839,6 +7875,7 @@ static int CmdHF14AGen4Info(const char *cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue