Merge pull request #1128 from tcprst/legic_cliparser

hf legic crc, rdbl, wrbl, sim, info, reader - now use cliparser
This commit is contained in:
Iceman 2020-12-21 10:37:22 +01:00 committed by GitHub
commit 4ac50615a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 289 deletions

View file

@ -582,14 +582,14 @@ function writeToTag(tag)
-- write pm3-buffer to Tag -- write pm3-buffer to Tag
for i=1, WriteBytes do for i=1, WriteBytes do
if (i > 7) then if (i > 7) then
cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i])) cmd = ("hf legic wrbl -o %d -d %s "):format(i-1, padString(bytes[i]))
print(acgreen..cmd..acoff) print(acgreen..cmd..acoff)
core.console(cmd) core.console(cmd)
core.clearCommandBuffer() core.clearCommandBuffer()
elseif (i == 7) then elseif (i == 7) then
if (writeDCF) then if (writeDCF) then
-- write DCF in reverse order (requires 'mosci-patch') -- write DCF in reverse order (requires 'mosci-patch')
cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) cmd = ('hf legic wrbl -o 5 -d %s%s'):format(padString(bytes[i-1]), padString(bytes[i]))
print(acgreen..cmd..acoff) print(acgreen..cmd..acoff)
core.console(cmd) core.console(cmd)
core.clearCommandBuffer() core.clearCommandBuffer()

View file

@ -536,7 +536,7 @@ local function main(args)
res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3, Segment-Header0..3" res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3, Segment-Header0..3"
res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):"
res = res .."\n" res = res .."\n"
res = res ..ansicolors.yellow.."hf legic crc d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." u "..newcrc.." c 8"..ansicolors.reset res = res ..ansicolors.yellow.."hf legic crc -d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." --mcc "..newcrc.." -t 8"..ansicolors.reset
-- this can not be calculated without knowing the new MCD, MSN0..2 -- this can not be calculated without knowing the new MCD, MSN0..2
print(res) print(res)
end end

View file

@ -109,7 +109,7 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, " Searching for LEGIC tag..."); PrintAndLogEx(INPLACE, " Searching for LEGIC tag...");
if (IfPm3Legicrf()) { if (IfPm3Legicrf()) {
if (readLegicUid(false) == PM3_SUCCESS) { if (readLegicUid(false, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC Prime tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC Prime tag") " found\n");
res = PM3_SUCCESS; res = PM3_SUCCESS;
} }

View file

@ -16,6 +16,7 @@
#include <readline/readline.h> #include <readline/readline.h>
#endif #endif
#include "cliparser.h"
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" // clearCommandBuffer #include "comms.h" // clearCommandBuffer
#include "cmdtrace.h" #include "cmdtrace.h"
@ -27,84 +28,6 @@ static int CmdHelp(const char *Cmd);
#define MAX_LENGTH 1024 #define MAX_LENGTH 1024
static int usage_legic_calccrc(void) {
PrintAndLogEx(NORMAL, "Calculates the legic crc8/crc16 on the given data.");
PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.\n");
PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d <data> u <uidcrc> c <8|16>\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to calculate crc over");
PrintAndLogEx(NORMAL, " u <uidcrc> : MCC hexbyte");
PrintAndLogEx(NORMAL, " c <8|16> : Crc type");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122 u 9A c 16"));
return PM3_SUCCESS;
}
static int usage_legic_rdbl(void) {
PrintAndLogEx(NORMAL, "Read data from a LEGIC Prime tag\n");
PrintAndLogEx(NORMAL, "Usage: hf legic rdbl [h] [o <offset>] [l <length>] [iv <IV>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start download from");
PrintAndLogEx(NORMAL, " l <length> : (hex) number of bytes to read");
PrintAndLogEx(NORMAL, " i <IV> : (hex) (optional) Initialization vector to use. Must be odd and 7bits max");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 16 - reads from byte[0] 0x16 bytes(system header)"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 4 iv 55 - reads from byte[0] 0x4 bytes with IV 0x55"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 100 iv 55 - reads 0x100 bytes with IV 0x55"));
return PM3_SUCCESS;
}
static int usage_legic_sim(void) {
PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated");
PrintAndLogEx(NORMAL, "Use " _YELLOW_("`hf legic eload`") " to upload a dump into emulator memory\n");
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <tagtype> : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic sim 2"));
return PM3_SUCCESS;
}
static int usage_legic_wrbl(void) {
PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size\n");
PrintAndLogEx(NORMAL, "Usage: hf legic wrbl [h] [o <offset>] [d <data (hex symbols)>] [y]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start writing");
//PrintAndLogEx(NORMAL, " <IV> : (optional) Initialization vector to use (ODD and 7bits)");
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to write ");
PrintAndLogEx(NORMAL, " y : Auto-confirm dangerous operations ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wrbl o 10 d 11223344 - Write 0x11223344 starting from offset 0x10"));
return PM3_SUCCESS;
}
static int usage_legic_reader(void) {
PrintAndLogEx(NORMAL, "Read UID and type information from a LEGIC Prime tag\n");
PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic reader"));
return PM3_SUCCESS;
}
static int usage_legic_info(void) {
PrintAndLogEx(NORMAL, "Reads information from a LEGIC Prime tag like systemarea, user areas etc\n");
PrintAndLogEx(NORMAL, "Usage: hf legic info [h]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic info"));
return PM3_SUCCESS;
}
static int usage_legic_dump(void) { static int usage_legic_dump(void) {
PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024"); PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024");
PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file"); PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file");
@ -203,9 +126,17 @@ static bool legic_xor(uint8_t *data, uint16_t cardsize) {
* by Henryk Ploetz and Karsten Nohl at 26c3 * by Henryk Ploetz and Karsten Nohl at 26c3
*/ */
static int CmdLegicInfo(const char *Cmd) { 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");
char cmdp = tolower(param_getchar(Cmd, 0)); void *argtable[] = {
if (cmdp == 'h') return usage_legic_info(); 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;
@ -526,34 +457,32 @@ out:
// offset in data memory // offset in data memory
// number of bytes to read // number of bytes to read
static int CmdLegicRdbl(const char *Cmd) { 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");
uint32_t offset = 0, len = 0, iv = 1; void *argtable[] = {
bool errors = false; arg_param_begin,
uint8_t cmdp = 0; arg_int1("o", "offset", "<dec>", "offset in data array to start download from"),
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { arg_int1("l", "length", "<dec>", "number of bytes to read"),
switch (tolower(param_getchar(Cmd, cmdp))) { arg_str0(NULL, "iv", "<hex>", "Initialization vector to use. Must be odd and 7bits max"),
case 'h' : arg_param_end
return usage_legic_rdbl(); };
case 'o' : CLIExecWithReturn(ctx, Cmd, argtable, false);
offset = param_get32ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2; int offset = arg_get_int_def(ctx, 1, 0);
break;
case 'l' : int len = arg_get_int_def(ctx, 2, 0);
len = param_get32ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2; int iv_len = 0;
break; uint8_t iv[1] = {0x01}; // formerly uidcrc
case 'i' :
iv = param_get32ex(Cmd, cmdp + 1, 1, 16); CLIGetHexWithReturn(ctx, 3, iv, &iv_len);
cmdp += 2;
break; CLIParserFree(ctx);
default :
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || strlen(Cmd) == 0) return usage_legic_rdbl();
// sanity checks // sanity checks
if (len + offset >= MAX_LENGTH) { if (len + offset >= MAX_LENGTH) {
@ -571,9 +500,9 @@ static int CmdLegicRdbl(const char *Cmd) {
} }
uint16_t datalen = 0; uint16_t datalen = 0;
int status = legic_read_mem(offset, len, iv, data, &datalen); int status = legic_read_mem(offset, len, iv[0], data, &datalen);
if (status == PM3_SUCCESS) { if (status == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, "\n ## | 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, " ## | 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, "-----+------------------------------------------------------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------------------------------------------------------");
print_hex_break(data, datalen, 32); print_hex_break(data, datalen, 32);
} }
@ -582,9 +511,19 @@ static int CmdLegicRdbl(const char *Cmd) {
} }
static int CmdLegicSim(const char *Cmd) { static int CmdLegicSim(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic sim",
"Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated",
"hf legic sim -t 0 <- Simulate Type MIM22\n"
"hf legic sim -t 1 <- Simulate Type MIM256 (default)\n"
"hf legic sim -t 2 <- Simulate Type MIM1024");
char cmdp = tolower(param_getchar(Cmd, 0)); void *argtable[] = {
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_legic_sim(); arg_param_begin,
arg_int0("t", "type", "<dec>", "Tag type to simulate."),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
struct { struct {
uint8_t tagtype; uint8_t tagtype;
@ -592,9 +531,13 @@ static int CmdLegicSim(const char *Cmd) {
} PACKED payload; } PACKED payload;
payload.send_reply = true; payload.send_reply = true;
payload.tagtype = param_get8ex(Cmd, 0, 1, 10); payload.tagtype = arg_get_int_def(ctx, 1, 1);
CLIParserFree(ctx);
if (payload.tagtype > 2) { if (payload.tagtype > 2) {
return usage_legic_sim(); PrintAndLogEx(ERR, "Invalid tag type selected.");
return PM3_EINVARG;
} }
clearCommandBuffer(); clearCommandBuffer();
@ -619,94 +562,37 @@ static int CmdLegicSim(const char *Cmd) {
} }
static int CmdLegicWrbl(const char *Cmd) { static int CmdLegicWrbl(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic wrbl",
"Write data to a LEGIC Prime tag. It autodetects tagsize to ensure proper write",
"hf legic wrbl -o 0 -d 11223344 <- Write 0x11223344 starting from offset 0)\n"
"hf legic wrbl -o 10 -d DEADBEEF <- Write 0xdeadbeef starting from offset 10");
uint8_t *data = NULL; void *argtable[] = {
uint8_t cmdp = 0; arg_param_begin,
bool errors = false; arg_int1("o", "offset", "<dec>", "offset in data array to start writing"),
bool autoconfirm = false; arg_str1("d", "data", "<hex>", "data to write"),
int len = 0, bg, en; arg_lit0(NULL, "danger", "Auto-confirm dangerous operations"),
uint32_t offset = 0, IV = 0x55; arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { int offset = arg_get_int_def(ctx, 1, 0);
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': {
errors = true;
break;
}
case 'd': {
// peek at length of the input string so we can
// figure out how many elements to malloc in "data"
bg = en = 0;
if (param_getptr(Cmd, &bg, &en, cmdp + 1)) {
errors = true;
break;
}
len = (en - bg + 1);
// check that user entered even number of characters int data_len = 0;
// for hex data string uint8_t data[MAX_LENGTH] = {0};
if (len & 1) {
errors = true;
break;
}
// limit number of bytes to write. This is not a 'restore' command. CLIGetHexWithReturn(ctx, 2, data, &data_len);
if ((len >> 1) > 100) {
PrintAndLogEx(WARNING, "Max bound on 100bytes to write a one time.");
PrintAndLogEx(WARNING, "Use the 'hf legic restore' command if you want to write the whole tag at once");
errors = true;
}
// it's possible for user to accidentally enter "b" parameter bool autoconfirm = arg_get_lit(ctx, 3);
// more than once - we have to clean previous malloc
if (data)
free(data);
data = calloc(len >> 1, sizeof(uint8_t)); CLIParserFree(ctx);
if (data == NULL) {
PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
errors = true;
break;
}
if (param_gethex(Cmd, cmdp + 1, data, len)) { uint32_t IV = 0x55;
errors = true;
break;
}
len >>= 1;
cmdp += 2;
break;
}
case 'o': {
offset = param_get32ex(Cmd, cmdp + 1, 4, 16);
cmdp += 2;
break;
}
case 'y': {
autoconfirm = true;
break;
}
default: {
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
}
//Validations
if (errors || cmdp == 0) {
if (data)
free(data);
return usage_legic_wrbl();
}
// OUT-OF-BOUNDS checks // OUT-OF-BOUNDS checks
// UID 4+1 bytes can't be written to. // UID 4+1 bytes can't be written to.
if (offset < 5) { if (offset < 5) {
if (data)
free(data);
PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset); PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
return PM3_EOUTOFBOUND; return PM3_EOUTOFBOUND;
} }
@ -720,8 +606,8 @@ static int CmdLegicWrbl(const char *Cmd) {
legic_print_type(card.cardsize, 0); legic_print_type(card.cardsize, 0);
if (len + offset > card.cardsize) { if (data_len + offset > card.cardsize) {
PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset); PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, data_len + offset);
return PM3_EOUTOFBOUND; return PM3_EOUTOFBOUND;
} }
@ -756,7 +642,7 @@ static int CmdLegicWrbl(const char *Cmd) {
PacketResponseNG resp; PacketResponseNG resp;
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, len, IV, data, len); SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, data_len, IV, data, data_len);
uint8_t timeout = 0; uint8_t timeout = 0;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
@ -779,84 +665,45 @@ static int CmdLegicWrbl(const char *Cmd) {
} }
static int CmdLegicCalcCrc(const char *Cmd) { static int CmdLegicCalcCrc(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic crc",
"Calculates the legic crc8/crc16 on the given data",
"hf legic crc -d deadbeef1122\n"
"hf legic crc -d deadbeef1122 --mcc 9A -t 16 <- CRC Type 16");
uint8_t *data = NULL; void *argtable[] = {
uint8_t cmdp = 0, uidcrc = 0, type = 0; arg_param_begin,
bool errors = false; arg_str1("d", "data", "<hex>", "bytes to calculate crc over"),
int len = 0; arg_str0(NULL, "mcc", "<hex>", "MCC hex byte (UID CRC)"),
int bg, en; arg_int0("t", "type", "<dec>", "CRC Type (default: 8)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { int data_len = 0;
switch (tolower(param_getchar(Cmd, cmdp))) { uint8_t data[4096] = {0};
case 'd':
// peek at length of the input string so we can
// figure out how many elements to malloc in "data"
bg = en = 0;
if (param_getptr(Cmd, &bg, &en, cmdp + 1)) {
errors = true;
break;
}
len = (en - bg + 1);
// check that user entered even number of characters CLIGetHexWithReturn(ctx, 1, data, &data_len);
// for hex data string
if (len & 1) {
errors = true;
break;
}
// it's possible for user to accidentally enter "b" parameter int mcc_len = 0;
// more than once - we have to clean previous malloc uint8_t mcc[1] = {0}; // formerly uidcrc
if (data) free(data);
data = calloc(len >> 1, sizeof(uint8_t));
if (data == NULL) {
PrintAndLogEx(WARNING, "Can't allocate memory. exiting");
errors = true;
break;
}
if (param_gethex(Cmd, cmdp + 1, data, len)) { CLIGetHexWithReturn(ctx, 2, mcc, &mcc_len);
errors = true;
break;
}
len >>= 1; int type = arg_get_int_def(ctx, 3, 0);
cmdp += 2;
break; CLIParserFree(ctx);
case 'u':
uidcrc = param_get8ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2;
break;
case 'c':
type = param_get8ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'h':
errors = true;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || cmdp == 0) {
if (data) free(data);
return usage_legic_calccrc();
}
switch (type) { switch (type) {
case 16: case 16:
init_table(CRC_LEGIC); init_table(CRC_LEGIC);
PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, len, uidcrc)); PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0]));
break; break;
default: default:
PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, len)); PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, data_len));
break; break;
} }
if (data) free(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -954,12 +801,26 @@ void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) {
SendCommandOLD(CMD_HF_LEGIC_ESET, i, len, 0, src + i, len); SendCommandOLD(CMD_HF_LEGIC_ESET, i, len, 0, src + i, len);
} }
} }
static int CmdLegicReader(const char *Cmd) { static int CmdLegicReader(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (cmdp == 'h') return usage_legic_reader(); CLIParserInit(&ctx, "hf legic reader",
"Read UID and type information from a LEGIC Prime tag",
"hf legic reader");
return readLegicUid(true); void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
if (cm) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
}
return readLegicUid(cm, true);
} }
static int CmdLegicDump(const char *Cmd) { static int CmdLegicDump(const char *Cmd) {
@ -1438,24 +1299,38 @@ int CmdHFLegic(const char *Cmd) {
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
int readLegicUid(bool verbose) { int readLegicUid(bool loop, bool verbose) {
do {
legic_card_select_t card;
int resp = legic_get_type(&card);
if (loop) {
if (resp != PM3_SUCCESS) {
continue;
}
} else {
switch (resp) {
case PM3_EINVARG:
return PM3_EINVARG;
case PM3_ETIMEOUT:
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
case PM3_ESOFT:
if (verbose) PrintAndLogEx(WARNING, "legic card select failed");
return PM3_ESOFT;
default:
break;
}
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " MCD: " _GREEN_("%02X"), card.uid[0]);
PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
legic_print_type(card.cardsize, 0);
} while (loop && kbd_enter_pressed() == false);
legic_card_select_t card;
switch (legic_get_type(&card)) {
case PM3_EINVARG:
return PM3_EINVARG;
case PM3_ETIMEOUT:
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
case PM3_ESOFT:
if (verbose) PrintAndLogEx(WARNING, "legic card select failed");
return PM3_ESOFT;
default:
break;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " MCD: " _GREEN_("%02X"), card.uid[0]);
PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
legic_print_type(card.cardsize, 0);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -17,7 +17,7 @@
int CmdHFLegic(const char *Cmd); int CmdHFLegic(const char *Cmd);
int readLegicUid(bool verbose); int readLegicUid(bool loop, bool verbose);
int legic_print_type(uint32_t tagtype, uint8_t spaces); int legic_print_type(uint32_t tagtype, uint8_t spaces);
int legic_get_type(legic_card_select_t *card); int legic_get_type(legic_card_select_t *card);
void legic_chk_iv(uint32_t *iv); void legic_chk_iv(uint32_t *iv);

View file

@ -74,14 +74,8 @@ hf felica resetmode
hf felica litesim hf felica litesim
hf felica litedump hf felica litedump
hf fido info hf fido info
hf legic reader
hf legic info
hf legic dump hf legic dump
hf legic restore hf legic restore
hf legic rdbl
hf legic sim
hf legic wrbl
hf legic crc
hf legic eload hf legic eload
hf legic esave hf legic esave
hf legic wipe hf legic wipe