added legic view command, and converted OLD -> NG comms

This commit is contained in:
iceman1001 2022-02-14 09:19:35 +01:00
parent 12695a984a
commit 63bc9b5eb2
7 changed files with 262 additions and 92 deletions

View file

@ -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...
## [unreleased][unreleased]
- Changed `hf legic *` - now uses NG instead (@iceman1001)
- Added `hf legic view` - view contents of LEGIC Prime dump files (@iceman1001)
- Changed `hf mfu restore` - now takes bin/json as dump files (@iceman1001)
- Added `hf mfu view` - view contents of MFU dump files (@iceman1001)
- Changed `hf_mf_uidbruteforce` - added support for S70, enhance UID length management (@cactuschibre)

View file

@ -1285,11 +1285,13 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_LEGIC_WRITER: {
LegicRfWriter(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
legic_packet_t *payload = (legic_packet_t*) packet->data.asBytes;
LegicRfWriter(payload->offset, payload->len, payload->iv, payload->data);
break;
}
case CMD_HF_LEGIC_READER: {
LegicRfReader(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]);
legic_packet_t *payload = (legic_packet_t*) packet->data.asBytes;
LegicRfReader(payload->offset, payload->len, payload->iv);
break;
}
case CMD_HF_LEGIC_INFO: {
@ -1302,10 +1304,9 @@ static void PacketReceived(PacketCommandNG *packet) {
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
//-----------------------------------------------------------------------------
// arg0 = offset
// arg1 = num of bytes
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]);
legic_packet_t *payload = (legic_packet_t*) packet->data.asBytes;
emlSet(payload->data, payload->offset, payload->len);
break;
}
#endif

View file

@ -422,7 +422,7 @@ void LegicRfInfo(void) {
// establish shared secret and detect card type
uint8_t card_type = setup_phase(0x01);
if (init_card(card_type, &card) != PM3_SUCCESS) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_INFO, PM3_EINIT, NULL, 0);
goto OUT;
}
@ -430,7 +430,7 @@ void LegicRfInfo(void) {
for (uint8_t i = 0; i < sizeof(card.uid); ++i) {
int16_t byte = read_byte(i, card.cmdsize);
if (byte == -1) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_INFO, PM3_EFAILED, NULL, 0);
goto OUT;
}
card.uid[i] = byte & 0xFF;
@ -440,12 +440,12 @@ void LegicRfInfo(void) {
int16_t mcc = read_byte(4, card.cmdsize);
int16_t calc_mcc = CRC8Legic(card.uid, 4);
if (mcc != calc_mcc) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_INFO, PM3_ESOFT, NULL, 0);
goto OUT;
}
// OK
reply_mix(CMD_ACK, 1, 0, 0, (uint8_t *)&card, sizeof(legic_card_select_t));
reply_ng(CMD_HF_LEGIC_INFO, PM3_SUCCESS, (uint8_t *)&card, sizeof(legic_card_select_t));
OUT:
switch_off();
@ -497,7 +497,7 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
// establish shared secret and detect card type
uint8_t card_type = setup_phase(iv);
if (init_card(card_type, &card) != PM3_SUCCESS) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_READER, PM3_EINIT, NULL, 0);
goto OUT;
}
@ -509,7 +509,7 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
for (uint16_t i = 0; i < len; ++i) {
int16_t byte = read_byte(offset + i, card.cmdsize);
if (byte == -1) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_READER, PM3_EFAILED, NULL, 0);
goto OUT;
}
legic_mem[i] = byte;
@ -520,7 +520,7 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
}
// OK
reply_mix(CMD_ACK, 1, len, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_READER, PM3_SUCCESS, (uint8_t*)&len, sizeof(len));
OUT:
switch_off();
@ -533,14 +533,14 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
// uid is not writeable
if (offset <= WRITE_LOWERLIMIT) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_WRITER, PM3_EINVARG, NULL, 0);
goto OUT;
}
// establish shared secret and detect card type
uint8_t card_type = setup_phase(iv);
if (init_card(card_type, &card) != PM3_SUCCESS) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_WRITER, PM3_EINIT, NULL, 0);
goto OUT;
}
@ -553,13 +553,13 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
while (len-- > 0 && BUTTON_PRESS() == false) {
if (write_byte(len + offset, data[len], card.addrsize) == false) {
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_WRITER, PM3_EFAILED, NULL, 0);
goto OUT;
}
}
// OK
reply_mix(CMD_ACK, 1, len, 0, 0, 0);
reply_ng(CMD_HF_LEGIC_WRITER, PM3_SUCCESS, (uint8_t*)&len, sizeof(len));
OUT:
switch_off();

View file

@ -170,14 +170,9 @@ end
-- read LEGIC data
local function readlegicdata(offset, length, iv)
-- Read data
local command = Command:newMIX{
cmd = cmds.CMD_HF_LEGIC_READER
, arg1 = offset
, arg2 = length
, arg3 = iv
, data = nil
}
local result, err = command:sendMIX()
local d0 = ('%04X%04X%02X'):format(offset, len, iv)
local c = Command:newNG{cmd = cmds.CMD_HF_LEGIC_READER, data = d0}
local result, err = c:sendNG()
if not result then return oops(err) end
-- result is a packed data structure, data starts at offset 33
return result

View file

@ -30,7 +30,7 @@
static int CmdHelp(const char *Cmd);
#define MAX_LENGTH 1024
#define LEGIC_PRIME_MAX_LENGTH 1024
static bool legic_xor(uint8_t *data, uint16_t cardsize) {
@ -393,33 +393,30 @@ static int CmdLegicRdbl(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic rdbl",
"Read data from a LEGIC Prime tag",
"hf legic rdbl -o 0 -l 16 -> reads from byte[0] 16 bytes(system header)\n"
"hf legic rdbl -o 0 -l 4 --iv 55 -> reads from byte[0] 4 bytes with IV 0x55\n"
"hf legic rdbl -o 0 -l 256 --iv 55 -> reads from byte[0] 256 bytes with IV 0x55");
"hf legic rdbl -o 0 -l 16 -> read 16 bytes from offset 0 (system header)\n"
"hf legic rdbl -o 0 -l 4 --iv 55 -> read 4 bytes from offset 0\n"
"hf legic rdbl -o 0 -l 256 --iv 55 -> read 256 bytes from offset 0");
void *argtable[] = {
arg_param_begin,
arg_int1("o", "offset", "<dec>", "offset in data array to start download from"),
arg_int1("l", "length", "<dec>", "number of bytes to read"),
arg_int0("o", "offset", "<dec>", "offset in data array to start download from"),
arg_int0("l", "length", "<dec>", "number of bytes to read"),
arg_str0(NULL, "iv", "<hex>", "Initialization vector to use. Must be odd and 7bits max"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int offset = arg_get_int_def(ctx, 1, 0);
int len = arg_get_int_def(ctx, 2, 0);
int len = arg_get_int_def(ctx, 2, 16);
int iv_len = 0;
uint8_t iv[1] = {0x01}; // formerly uidcrc
uint8_t iv[1] = {0x01};
CLIGetHexWithReturn(ctx, 3, iv, &iv_len);
CLIParserFree(ctx);
// sanity checks
if (len + offset >= MAX_LENGTH) {
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", MAX_LENGTH, len + offset);
if (len + offset >= LEGIC_PRIME_MAX_LENGTH) {
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", LEGIC_PRIME_MAX_LENGTH, len + offset);
return PM3_EOUTOFBOUND;
}
@ -435,9 +432,9 @@ static int CmdLegicRdbl(const char *Cmd) {
uint16_t datalen = 0;
int status = legic_read_mem(offset, len, iv[0], data, &datalen);
if (status == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, " ## | 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------------------------------------------------------");
print_hex_break(data, datalen, 32);
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
print_hex_break(data, datalen, 16);
}
free(data);
return status;
@ -513,15 +510,13 @@ static int CmdLegicWrbl(const char *Cmd) {
int offset = arg_get_int_def(ctx, 1, 0);
int dlen = 0;
uint8_t data[MAX_LENGTH] = {0};
uint8_t data[LEGIC_PRIME_MAX_LENGTH] = {0};
CLIGetHexWithReturn(ctx, 2, data, &dlen);
bool autoconfirm = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
uint32_t IV = 0x55;
// OUT-OF-BOUNDS checks
// UID 4+1 bytes can't be written to.
if (offset < 5) {
@ -558,16 +553,24 @@ static int CmdLegicWrbl(const char *Cmd) {
}
}
uint32_t IV = 0x55;
legic_chk_iv(&IV);
PrintAndLogEx(SUCCESS, "Writing to tag");
PrintAndLogEx(SUCCESS, "Writing to tag to offset %i", offset);
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + dlen);
payload->offset = (offset & 0xFFFF);
payload->iv = (IV & 0x7F);
payload->len = dlen;
memcpy(payload->data, data, dlen);
PacketResponseNG resp;
clearCommandBuffer();
SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, dlen, IV, data, dlen);
SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t*)payload, sizeof(legic_packet_t) + dlen);
free(payload);
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
++timeout;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 7) {
@ -576,9 +579,8 @@ static int CmdLegicWrbl(const char *Cmd) {
}
}
PrintAndLogEx(NORMAL, "");
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (!isOK) {
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed writing tag");
return PM3_ERFTRANS;
}
@ -633,12 +635,17 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin
legic_chk_iv(&iv);
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t));
payload->offset = (offset & 0xFFFF);
payload->iv = iv;
payload->len = len;
clearCommandBuffer();
SendCommandMIX(CMD_HF_LEGIC_READER, offset, len, iv, NULL, 0);
SendCommandNG(CMD_HF_LEGIC_READER, (uint8_t*)payload, sizeof(legic_packet_t));
PacketResponseNG resp;
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
while (WaitForResponseTimeout(CMD_HF_LEGIC_READER, &resp, 1000) == false) {
++timeout;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 14) {
@ -648,9 +655,9 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin
}
PrintAndLogEx(NORMAL, "");
uint8_t isOK = resp.oldarg[0] & 0xFF;
*outlen = resp.oldarg[1];
if (!isOK) {
*outlen = resp.data.asDwords[0];
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed reading tag");
return PM3_ESOFT;
}
@ -659,7 +666,7 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin
PrintAndLogEx(WARNING, "Fail, only managed to read %u bytes", *outlen);
// copy data from device
if (!GetFromDevice(BIG_BUF_EML, out, *outlen, 0, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF_EML, out, *outlen, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
return PM3_ETIMEOUT;
}
@ -683,21 +690,22 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces) {
}
int legic_get_type(legic_card_select_t *card) {
if (card == NULL) return PM3_EINVARG;
if (card == NULL)
return PM3_EINVARG;
clearCommandBuffer();
SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500))
if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false)
return PM3_ETIMEOUT;
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (!isOK)
if (resp.status != PM3_SUCCESS)
return PM3_ESOFT;
memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t));
return PM3_SUCCESS;
}
void legic_chk_iv(uint32_t *iv) {
if ((*iv & 0x7F) != *iv) {
*iv &= 0x7F;
@ -709,20 +717,30 @@ void legic_chk_iv(uint32_t *iv) {
PrintAndLogEx(INFO, "LSB of IV must be SET %u", *iv);
}
}
void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) {
// fast push mode
g_conn.block_after_ACK = true;
for (size_t i = offset; i < numofbytes; i += PM3_CMD_DATA_SIZE) {
for (size_t i = offset; i < numofbytes; i += (PM3_CMD_DATA_SIZE - sizeof(legic_packet_t))) {
size_t len = MIN((numofbytes - i), PM3_CMD_DATA_SIZE);
size_t len = MIN((numofbytes - i), (PM3_CMD_DATA_SIZE - sizeof(legic_packet_t)));
if (len == numofbytes - i) {
// Disable fast mode on last packet
g_conn.block_after_ACK = false;
}
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
payload->offset = i;
payload->len = len;
memcpy(payload->data, src + i, len);
clearCommandBuffer();
SendCommandOLD(CMD_HF_LEGIC_ESET, i, len, 0, src + i, len);
SendCommandNG(CMD_HF_LEGIC_ESET, (uint8_t*)payload, sizeof(legic_packet_t) + len);
free(payload);
}
}
static int CmdLegicReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic reader",
@ -780,12 +798,17 @@ static int CmdLegicDump(const char *Cmd) {
legic_print_type(dumplen, 0);
PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", dumplen);
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t));
payload->offset = 0;
payload->iv = 0x55;
payload->len = dumplen;
clearCommandBuffer();
SendCommandMIX(CMD_HF_LEGIC_READER, 0x00, dumplen, 0x55, NULL, 0);
SendCommandNG(CMD_HF_LEGIC_READER, (uint8_t*)payload, sizeof(legic_packet_t));
PacketResponseNG resp;
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_HF_LEGIC_READER, &resp, 2000) == false) {
++timeout;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 7) {
@ -795,13 +818,12 @@ static int CmdLegicDump(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "");
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (!isOK) {
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed dumping tag data");
return PM3_ERFTRANS;
}
uint16_t readlen = resp.oldarg[1];
uint16_t readlen = resp.data.asDwords[0];
uint8_t *data = calloc(readlen, sizeof(uint8_t));
if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
@ -812,7 +834,7 @@ static int CmdLegicDump(const char *Cmd) {
PrintAndLogEx(WARNING, "Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen);
// copy data from device
if (!GetFromDevice(BIG_BUF_EML, data, readlen, 0, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF_EML, data, readlen, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(data);
return PM3_ETIMEOUT;
@ -918,11 +940,19 @@ static int CmdLegicRestore(const char *Cmd) {
// Disable fast mode on last packet
g_conn.block_after_ACK = false;
}
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
payload->offset = i;
payload->iv = 0x55;
payload->len = len;
memcpy(payload->data, data + i, len);
clearCommandBuffer();
SendCommandOLD(CMD_HF_LEGIC_WRITER, i, len, 0x55, data + i, len);
SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t*)payload, sizeof(legic_packet_t) + len);
free(payload);
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
++timeout;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 7) {
@ -933,8 +963,7 @@ static int CmdLegicRestore(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "");
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (!isOK) {
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", (uint8_t)(resp.oldarg[1] & 0xFF));
free(data);
return PM3_ERFTRANS;
@ -952,7 +981,7 @@ static int CmdLegicELoad(const char *Cmd) {
CLIParserInit(&ctx, "hf legic eload",
"Loads a LEGIC binary dump into emulator memory",
"hf legic eload -f myfile -t 0 -> Simulate Type MIM22\n"
"hf legic eload -f myfile -t 1 -> Simulate Type MIM256 (default)\n"
"hf legic eload -f myfile -t 1 -> Simulate Type MIM256 (def)\n"
"hf legic eload -f myfile -t 2 -> Simulate Type MIM1024");
void *argtable[] = {
@ -1021,7 +1050,7 @@ static int CmdLegicESave(const char *Cmd) {
"Saves bin/eml/json dump file of emulator memory",
"hf legic esave --> uses UID as filename\n"
"hf legic esave -f myfile -t 0 --> Type MIM22\n"
"hf legic esave -f myfile -t 1 --> Type MIM256 (default)\n"
"hf legic esave -f myfile -t 1 --> Type MIM256 (def)\n"
"hf legic esave -f myfile -t 2 --> Type MIM1024");
void *argtable[] = {
@ -1061,14 +1090,14 @@ static int CmdLegicESave(const char *Cmd) {
// set up buffer
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
if (!data) {
if (data == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
// download emulator memory
PrintAndLogEx(SUCCESS, "Reading emulator memory...");
if (!GetFromDevice(BIG_BUF_EML, data, numofbytes, 0, NULL, 0, NULL, 2500, false)) {
if (GetFromDevice(BIG_BUF_EML, data, numofbytes, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(data);
return PM3_ETIMEOUT;
@ -1091,6 +1120,66 @@ static int CmdLegicESave(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdLegicEView(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic eview",
"It displays emulator memory",
"hf legic eview\n"
"hf legic eview -t 0 -> MIM22\n"
"hf legic eview -t 1 -> MIM256 (def)\n"
"hf legic eview -t 2 -> MIM1024"
);
void *argtable[] = {
arg_param_begin,
arg_int0("t", "type", "<dec>", "Tag type to simulate."),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
size_t bytes = 0;
switch (arg_get_int_def(ctx, 1, 1)) {
case 0:
bytes = 22;
break;
case 1:
bytes = 256;
break;
case 2:
bytes = LEGIC_PRIME_MAX_LENGTH;
break;
default:
PrintAndLogEx(ERR, "Unknown tag type");
CLIParserFree(ctx);
return PM3_EINVARG;
}
CLIParserFree(ctx);
// validations
uint8_t *dump = calloc(bytes, 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, bytes, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(dump);
return PM3_ETIMEOUT;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
print_hex_break(dump, bytes, 16);
free(dump);
return PM3_SUCCESS;
}
static int CmdLegicWipe(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic wipe",
@ -1136,11 +1225,19 @@ static int CmdLegicWipe(const char *Cmd) {
// Disable fast mode on last packet
g_conn.block_after_ACK = false;
}
legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
payload->offset = i;
payload->iv = 0x55;
payload->len = len;
memcpy(payload->data, data + i, len);
clearCommandBuffer();
SendCommandOLD(CMD_HF_LEGIC_WRITER, i, len, 0x55, data + i, len);
SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t*)payload, sizeof(legic_packet_t) + len);
free(payload);
uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
++timeout;
PrintAndLogEx(NORMAL, "." NOLF);
if (timeout > 7) {
@ -1151,14 +1248,13 @@ static int CmdLegicWipe(const char *Cmd) {
}
PrintAndLogEx(NORMAL, "");
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (!isOK) {
PrintAndLogEx(WARNING, "Failed writing tag [msg = %u]", (uint8_t)(resp.oldarg[1] & 0xFF));
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "failed writing tag");
free(data);
return PM3_ERFTRANS;
}
}
PrintAndLogEx(SUCCESS, "ok\n");
PrintAndLogEx(SUCCESS, "Done!\n");
free(data);
return PM3_SUCCESS;
}
@ -1167,20 +1263,85 @@ static int CmdLegicList(const char *Cmd) {
return CmdTraceListAlias(Cmd, "hf legic", "legic");
}
static int CmdLegicView(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic view",
"Print a LEGIC Prime dump file (bin/eml/json)",
"hf legic view -f hf-legic-01020304-dump.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "Filename of dump"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE];
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
// reserve memory
uint8_t *dump = NULL;
size_t bytes_read = 0;
int res = 0;
DumpFileType_t dftype = getfiletype(filename);
switch (dftype) {
case BIN: {
res = loadFile_safe(filename, ".bin", (void **)&dump, &bytes_read);
break;
}
case JSON: {
dump = calloc(LEGIC_PRIME_MAX_LENGTH, sizeof(uint8_t));
if (dump == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
res = loadFileJSON(filename, (void *)dump, LEGIC_PRIME_MAX_LENGTH, &bytes_read, NULL);
break;
}
case EML:
res = loadFileEML_safe(filename, (void **)&dump, &bytes_read);
break;
case DICTIONARY: {
PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed");
free(dump);
return PM3_EINVARG;
}
}
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
free(dump);
return PM3_EFILE;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
print_hex_break(dump, bytes_read, 16);
free(dump);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
{"reader", CmdLegicReader, IfPm3Legicrf, "LEGIC Prime Reader UID and tag info"},
{"info", CmdLegicInfo, IfPm3Legicrf, "Display deobfuscated and decoded LEGIC Prime tag data"},
{"dump", CmdLegicDump, IfPm3Legicrf, "Dump LEGIC Prime tag to binary file"},
{"restore", CmdLegicRestore, IfPm3Legicrf, "Restore a dump file onto a LEGIC Prime tag"},
{"info", CmdLegicInfo, IfPm3Legicrf, "Display deobfuscated and decoded LEGIC Prime tag data"},
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
{"rdbl", CmdLegicRdbl, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
{"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"},
{"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
{"eload", CmdLegicELoad, AlwaysAvailable, "Load binary dump to emulator memory"},
{"esave", CmdLegicESave, AlwaysAvailable, "Save emulator memory to binary file"},
{"reader", CmdLegicReader, IfPm3Legicrf, "LEGIC Prime Reader UID and tag info"},
{"restore", CmdLegicRestore, IfPm3Legicrf, "Restore a dump file onto a LEGIC Prime tag"},
{"wipe", CmdLegicWipe, IfPm3Legicrf, "Wipe a LEGIC Prime tag"},
{"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
{"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"},
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
{"eview", CmdLegicEView, IfPm3Legicrf, "View emulator memory"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
{"view", CmdLegicView, AlwaysAvailable, "Display content from tag dump file"},
{NULL, NULL, NULL, NULL}
};

View file

@ -1239,6 +1239,10 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
}
if (!strcmp(ctype, "legic")) {
JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
}
out:
if (callback != NULL) {

View file

@ -30,7 +30,14 @@ typedef struct {
uint8_t cmdsize;
uint8_t addrsize;
uint16_t cardsize;
} legic_card_select_t;
} PACKED legic_card_select_t;
typedef struct {
uint16_t offset;
uint16_t len;
uint8_t iv;
uint8_t data[];
} PACKED legic_packet_t;
// iceman: todo : this should be packed