mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #1943 from 0xdeb/legic_info
Legic info command for other sources, out of bounds memory
This commit is contained in:
commit
48d9503a5b
2 changed files with 127 additions and 40 deletions
|
@ -33,6 +33,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
|
- Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
|
||||||
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
|
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
|
||||||
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
|
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
|
||||||
|
- Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb)
|
||||||
-
|
-
|
||||||
|
|
||||||
## [Nitride.4.16191][2023-01-29]
|
## [Nitride.4.16191][2023-01-29]
|
||||||
|
|
|
@ -57,54 +57,28 @@ static bool legic_xor(uint8_t *data, uint16_t cardsize) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int decode_and_print_memory(uint16_t card_size, const uint8_t *input_buffer) {
|
||||||
* Output BigBuf and deobfuscate LEGIC RF tag data.
|
|
||||||
* This is based on information given in the talk held
|
|
||||||
* by Henryk Ploetz and Karsten Nohl at 26c3
|
|
||||||
*/
|
|
||||||
static int CmdLegicInfo(const char *Cmd) {
|
|
||||||
CLIParserContext *ctx;
|
|
||||||
CLIParserInit(&ctx, "hf legic info",
|
|
||||||
"Gets information from a LEGIC Prime tag like systemarea, user areas, etc",
|
|
||||||
"hf legic info");
|
|
||||||
|
|
||||||
void *argtable[] = {
|
|
||||||
arg_param_begin,
|
|
||||||
arg_param_end
|
|
||||||
};
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
|
int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
|
||||||
int crc = 0, wrp = 0, wrc = 0;
|
int crc = 0, wrp = 0, wrc = 0;
|
||||||
uint8_t stamp_len = 0;
|
uint8_t stamp_len = 0;
|
||||||
uint16_t datalen = 0;
|
|
||||||
char token_type[6] = {0, 0, 0, 0, 0, 0};
|
char token_type[6] = {0, 0, 0, 0, 0, 0};
|
||||||
int dcf = 0;
|
int dcf = 0;
|
||||||
int bIsSegmented = 0;
|
int bIsSegmented = 0;
|
||||||
|
int return_value = PM3_SUCCESS;
|
||||||
|
|
||||||
// tagtype
|
if (!(card_size == LEGIC_PRIME_MIM22 || card_size == LEGIC_PRIME_MIM256 || card_size == LEGIC_PRIME_MIM1024)) {
|
||||||
legic_card_select_t card;
|
PrintAndLogEx(FAILED, "Bytebuffer is not any known legic card size! (MIM22, MIM256, MIM1024)");
|
||||||
if (legic_get_type(&card) != PM3_SUCCESS) {
|
return_value = PM3_EFAILED;
|
||||||
PrintAndLogEx(WARNING, "Failed to identify tagtype");
|
return PM3_EFAILED;
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Reading full tag memory of " _YELLOW_("%d") " bytes...", card.cardsize);
|
// copy input buffer into newly allocated buffer, because the existing code mutates the data inside.
|
||||||
|
uint8_t *data = calloc(card_size, sizeof(uint8_t));
|
||||||
// allocate receiver buffer
|
|
||||||
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
PrintAndLogEx(WARNING, "Cannot allocate memory");
|
PrintAndLogEx(WARNING, "Cannot allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
memcpy(data, input_buffer, card_size);
|
||||||
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
|
|
||||||
if (status != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(WARNING, "Failed reading memory");
|
|
||||||
free(data);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output CDF System area (9 bytes) plus remaining header area (12 bytes)
|
// Output CDF System area (9 bytes) plus remaining header area (12 bytes)
|
||||||
crc = data[4];
|
crc = data[4];
|
||||||
|
@ -217,9 +191,10 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
uint32_t segCalcCRC = 0;
|
uint32_t segCalcCRC = 0;
|
||||||
uint32_t segCRC = 0;
|
uint32_t segCRC = 0;
|
||||||
|
|
||||||
// Not Data card?
|
// Not a data card by dcf or too small to contain data (MIM22)?
|
||||||
if (dcf > 60000)
|
if (dcf > 60000 || card_size == LEGIC_PRIME_MIM22) {
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, _CYAN_("ADF: User Area"));
|
PrintAndLogEx(SUCCESS, _CYAN_("ADF: User Area"));
|
||||||
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "------------------------------------------------------");
|
||||||
|
@ -231,6 +206,13 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
|
|
||||||
// decode segments
|
// decode segments
|
||||||
for (segmentNum = 1; segmentNum < 128; segmentNum++) {
|
for (segmentNum = 1; segmentNum < 128; segmentNum++) {
|
||||||
|
// for decoding the segment header we need at least 4 bytes left in buffer
|
||||||
|
if ((i + 4) > card_size) {
|
||||||
|
PrintAndLogEx(FAILED, "Cannot read segment header, because the input buffer is too small. "
|
||||||
|
"Please check that the data is correct and properly aligned. ");
|
||||||
|
return_value = PM3_EOUTOFBOUND;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
segment_len = ((data[i + 1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
|
segment_len = ((data[i + 1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
|
||||||
segment_flag = ((data[i + 1] ^ crc) & 0xf0) >> 4;
|
segment_flag = ((data[i + 1] ^ crc) & 0xf0) >> 4;
|
||||||
wrp = (data[i + 2] ^ crc);
|
wrp = (data[i + 2] ^ crc);
|
||||||
|
@ -277,6 +259,14 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
|
|
||||||
i += 5;
|
i += 5;
|
||||||
|
|
||||||
|
// for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
|
||||||
|
if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
|
||||||
|
PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
|
||||||
|
"Please check that the data is correct and properly aligned. ");
|
||||||
|
return_value = PM3_EOUTOFBOUND;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasWRC) {
|
if (hasWRC) {
|
||||||
PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
|
@ -330,7 +320,6 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
} // end for loop
|
} // end for loop
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Data start point on unsegmented cards
|
// Data start point on unsegmented cards
|
||||||
i = 8;
|
i = 8;
|
||||||
|
|
||||||
|
@ -340,7 +329,7 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
bool hasWRC = (wrc > 0);
|
bool hasWRC = (wrc > 0);
|
||||||
bool hasWRP = (wrp > wrc);
|
bool hasWRP = (wrp > wrc);
|
||||||
int wrp_len = (wrp - wrc);
|
int wrp_len = (wrp - wrc);
|
||||||
int remain_seg_payload_len = (card.cardsize - 22 - wrp);
|
int remain_seg_payload_len = (card_size - 22 - wrp);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
|
PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
|
||||||
wrp,
|
wrp,
|
||||||
|
@ -348,6 +337,14 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
(data[7] & 0x80) >> 7
|
(data[7] & 0x80) >> 7
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
|
||||||
|
if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
|
||||||
|
PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
|
||||||
|
"Please check that the data is correct and properly aligned. ");
|
||||||
|
return_value = PM3_EOUTOFBOUND;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasWRC) {
|
if (hasWRC) {
|
||||||
PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc);
|
PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc);
|
||||||
PrintAndLogEx(NORMAL, "\nrow | data");
|
PrintAndLogEx(NORMAL, "\nrow | data");
|
||||||
|
@ -386,6 +383,55 @@ static int CmdLegicInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
free(data);
|
||||||
|
return (return_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output BigBuf and deobfuscate LEGIC RF tag data.
|
||||||
|
* This is based on information given in the talk held
|
||||||
|
* by Henryk Ploetz and Karsten Nohl at 26c3
|
||||||
|
*/
|
||||||
|
static int CmdLegicInfo(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf legic info",
|
||||||
|
"Gets information from a LEGIC Prime tag like systemarea, user areas, etc",
|
||||||
|
"hf legic info");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
uint16_t datalen = 0;
|
||||||
|
|
||||||
|
// tagtype
|
||||||
|
legic_card_select_t card;
|
||||||
|
if (legic_get_type(&card) != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(WARNING, "Failed to identify tagtype");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Reading full tag memory of " _YELLOW_("%d") " bytes...", card.cardsize);
|
||||||
|
|
||||||
|
// allocate receiver buffer
|
||||||
|
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
|
||||||
|
if (!data) {
|
||||||
|
PrintAndLogEx(WARNING, "Cannot allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
|
||||||
|
if (status != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(WARNING, "Failed reading memory");
|
||||||
|
free(data);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_and_print_memory(card.cardsize, data);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1174,6 +1220,41 @@ static int CmdLegicEView(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdLegicEInfo(const char *Cmd) {
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf legic einfo",
|
||||||
|
"It decodes and displays emulator memory",
|
||||||
|
"hf legic einfo\n"
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
size_t card_size = LEGIC_PRIME_MIM256;
|
||||||
|
|
||||||
|
uint8_t *dump = calloc(card_size, sizeof(uint8_t));
|
||||||
|
if (dump == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "downloading emulator memory");
|
||||||
|
if (GetFromDevice(BIG_BUF_EML, dump, card_size, 0, NULL, 0, NULL, 2500, false) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
|
||||||
|
free(dump);
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_and_print_memory(card_size, dump);
|
||||||
|
|
||||||
|
free(dump);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdLegicWipe(const char *Cmd) {
|
static int CmdLegicWipe(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf legic wipe",
|
CLIParserInit(&ctx, "hf legic wipe",
|
||||||
|
@ -1286,6 +1367,10 @@ static int CmdLegicView(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
|
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
|
||||||
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
|
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
|
||||||
print_hex_break(dump, bytes_read, 16);
|
print_hex_break(dump, bytes_read, 16);
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
decode_and_print_memory(bytes_read, dump);
|
||||||
|
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1306,9 +1391,10 @@ static command_t CommandTable[] = {
|
||||||
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
|
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
|
||||||
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
|
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
|
||||||
{"eview", CmdLegicEView, IfPm3Legicrf, "View emulator memory"},
|
{"eview", CmdLegicEView, IfPm3Legicrf, "View emulator memory"},
|
||||||
|
{"einfo", CmdLegicEInfo, IfPm3Legicrf, "Display deobfuscated and decoded emulator memory"},
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
|
||||||
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
|
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
|
||||||
{"view", CmdLegicView, AlwaysAvailable, "Display content from tag dump file"},
|
{"view", CmdLegicView, AlwaysAvailable, "Display deobfuscated and decoded content from tag dump file"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue