From be8d2fbd255d8ce5be252f186b5c942506ba291b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 21 Oct 2020 08:42:33 +0200 Subject: [PATCH] add u64_from_hex, no need to use 0x, thanks @mwalker33!\n reverse blocks when cloning for em4305/4469 --- client/deps/cliparser/cliparser.c | 23 ++++++++++++++-- client/deps/cliparser/cliparser.h | 2 ++ client/src/cmdlfem4x05.c | 46 ++++++++++++++----------------- client/src/cmdlfkeri.c | 11 +++++--- client/src/cmdlfvisa2000.c | 42 +++++++++++++++++++++------- include/protocols.h | 8 +++--- 6 files changed, 85 insertions(+), 47 deletions(-) diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 258346c00..ca119ac14 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -11,8 +11,10 @@ #include "cliparser.h" #include #include -#include // Get color constants -#include // get PrintAndLogEx +#include // Get color constants +#include // get PrintAndLogEx +#include // tolower +#include // PRIu64 #ifndef ARRAYLEN # define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) @@ -125,7 +127,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta return 0; } - enum ParserState { PS_FIRST, PS_ARGUMENT, @@ -272,4 +273,20 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def) { + uint64_t rv = 0; + uint8_t data[8]; + int datalen = 0; + int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen); + if (res == 0) { + for (uint8_t i = 0; i < datalen; i++) { + rv <<= 8; + rv |= data[i]; + } + } else { + rv = def; + } + return rv; +} + diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 89c9e00ca..996ad81ef 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -66,4 +66,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); + +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); #endif diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index fed515b37..24a16d8e5 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -374,19 +374,17 @@ int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool // fast push mode conn.block_after_ACK = true; - - int res = em4x05_write_word_ext(EM_CONFIG_BLOCK, pwd, use_pwd, blockdata[0]); - if (res != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "(em4x05_clone_tag) Time out writing to tag"); - return res; - } - - for (int8_t i = 1; i < numblocks; i++) { + int res = 0; + for (int8_t i = 0; i < numblocks; i++) { // Disable fast mode on last packet if (i == numblocks - 1) { conn.block_after_ACK = false; } + + if (i != 0) { + blockdata[i] = reflect(blockdata[i], 32); + } res = em4x05_write_word_ext(4 + i, pwd, use_pwd, blockdata[i]); if (res != PM3_SUCCESS) { @@ -396,19 +394,14 @@ int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool } res = 0; - if (em4x05_verify_write(EM_CONFIG_BLOCK, use_pwd, pwd, blockdata[0]) == false) { - res++; - } - - for (int8_t i = 1; i < numblocks; i++) { + for (int8_t i = 0; i < numblocks; i++) { if (em4x05_verify_write(4 + i, use_pwd, pwd, blockdata[i]) == false) { res++; } } - if (res == 0) { + if (res == 0) PrintAndLogEx(SUCCESS, "Success writing to tag"); - } return PM3_SUCCESS; } @@ -496,19 +489,19 @@ int CmdEM4x05Dump(const char *Cmd) { CLIParserInit(&ctx, "lf em dump", "Dump EM4x05/EM4x69. Tag must be on antenna.", "lf em dump\n" - "lf em dump -p 0x11223344\n" - "lf em dump -f myfile -p 0x11223344" + "lf em dump -p 11223344\n" + "lf em dump -f myfile -p 11223344" ); void *argtable[] = { arg_param_begin, - arg_u64_0("p", "pwd", "", "password (0x00000000)"), + arg_str0("p", "pwd", "", "password (00000000)"), arg_str0("f", "file", "", "override 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); + uint64_t inputpwd = arg_get_u64_hexstr_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); @@ -1139,21 +1132,22 @@ int CmdEM4x05Chk(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x05_chk", "This command uses a dictionary attack against EM4205/4305/4469/4569", "lf em 4x05_chk\n" - "lf em 4x05_chk -e 0x00000022B8 -> remember to use 0x for hex\n" + "lf em 4x05_chk -e 000022B8 -> remember to use 0x for hex\n" "lf em 4x05_chk -f t55xx_default_pwds -> use T55xx default dictionary" ); void *argtable[] = { arg_param_begin, arg_strx0("f", "file", "<*.dic>", "loads a default keys dictionary file <*.dic>"), - arg_u64_0("e", "em", "", "try the calculated password from some cloners based on EM4100 ID"), + arg_str0("e", "em", "", "try the calculated password from some cloners based on EM4100 ID"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - uint64_t card_id = arg_get_u64_def(ctx, 2, 0); + + uint64_t card_id = arg_get_u64_hexstr_def(ctx, 2, 0); CLIParserFree(ctx); if (strlen(filename) == 0) { @@ -1241,7 +1235,7 @@ int CmdEM4x05Brute(const char *Cmd) { "Note: if you get many false positives, change position on the antenna" "lf em 4x05_brute\n" "lf em 4x05_brute -n 1 -> stop after first candidate found\n" - "lf em 4x05_brute -s 0x000022B8 -> remember to use 0x for hex" + "lf em 4x05_brute -s 000022B8 -> remember to use 0x for hex" ); void *argtable[] = { @@ -1251,7 +1245,7 @@ int CmdEM4x05Brute(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint32_t start_pwd = arg_get_u64_def(ctx, 1, 0); + uint32_t start_pwd = arg_get_u64_hexstr_def(ctx, 1, 0); uint32_t n = arg_get_int_def(ctx, 2, 0); CLIParserFree(ctx); @@ -1352,7 +1346,7 @@ int CmdEM4x05Unlock(const char *Cmd) { arg_int0("n", NULL, NULL, "steps to skip"), arg_int0("s", "start", "", "start scan from delay (us)"), arg_int0("e", "end", "", "end scan at delay (us)"), - arg_u64_0("p", "pwd", "", "password (0x00000000)"), + arg_str0("p", "pwd", "", "password (00000000)"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; @@ -1360,7 +1354,7 @@ int CmdEM4x05Unlock(const char *Cmd) { double n = (double)arg_get_int_def(ctx, 1, 0); double start = (double)arg_get_int_def(ctx, 2, 2000); double end = (double)arg_get_int_def(ctx, 3, 6000); - uint64_t inputpwd = arg_get_u64_def(ctx, 4, 0xFFFFFFFFFFFFFFFF); + uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 4, 0xFFFFFFFFFFFFFFFF); bool verbose = arg_get_lit(ctx, 5); CLIParserFree(ctx); diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c index 7260bc494..a35ad4c81 100644 --- a/client/src/cmdlfkeri.c +++ b/client/src/cmdlfkeri.c @@ -205,7 +205,7 @@ static int CmdKeriClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf keri clone", - "clone a KERI tag to a T55x7, Q5/T5555 or EM4305 tag", + "clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag", "lf keri clone -t i --id 12345\n" "lf keri clone -t m --fc 6 --id 12345\n"); @@ -215,17 +215,20 @@ static int CmdKeriClone(const char *Cmd) { arg_str0("t", "type", "", "Type m - MS, i - Internal ID"), arg_int0(NULL, "fc", "", "Facility Code"), arg_int1(NULL, "id", "", "Keri ID"), - arg_lit0(NULL, "em4305", "specify writing to EM5405 tag"), + arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); + char cardtype[16] = {"T55x7"}; if (arg_get_lit(ctx, 1)) { blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555"); q5 = true; } if (arg_get_lit(ctx, 5)) { - blocks[0] = EM4305_KERI_CONFIG_BLOCK; + blocks[0] = EM4305_KERI_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469"); em4305 = true; } @@ -258,7 +261,7 @@ static int CmdKeriClone(const char *Cmd) { // Prepare and write to card // 3 LSB is ONE uint64_t data = ((uint64_t)internalid << 3) + 7; - PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), (q5) ? "Q5/T5555" : "T55x7", internalid); + PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), cardtype, internalid); blocks[1] = data >> 32; blocks[2] = data & 0xFFFFFFFF; diff --git a/client/src/cmdlfvisa2000.c b/client/src/cmdlfvisa2000.c index 97f5dc48e..84abc6177 100644 --- a/client/src/cmdlfvisa2000.c +++ b/client/src/cmdlfvisa2000.c @@ -10,23 +10,23 @@ //----------------------------------------------------------------------------- #include "cmdlfvisa2000.h" - #include #include #include #include - -#include "commonutil.h" // ARRAYLEN +#include +#include "commonutil.h" // ARRAYLEN #include "common.h" -#include "cmdparser.h" // command_t +#include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" #include "graph.h" #include "cmddata.h" #include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest #include "cmdlft55xx.h" // write verify +#include "cmdlfem4x05.h" // #define BL0CK1 0x56495332 @@ -39,10 +39,12 @@ static int usage_lf_visa2k_clone(void) { PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : Visa2k card ID"); PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); + PrintAndLogEx(NORMAL, " : specify writing to EM4305/4469 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233")); PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 q5") " -- encode for Q5/T5555"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 em4305") " -- encode for EM4305/4469"); return PM3_SUCCESS; } @@ -180,18 +182,38 @@ static int CmdVisa2kClone(const char *Cmd) { id = param_get32ex(Cmd, 0, 0, 10); - //Q5 + char cardtype[16] = {"T55x7"}; + // Q5 bool q5 = tolower(param_getchar(Cmd, 1)) == 'q'; - if (q5) + if (q5) { blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555"); + } + // EM4305 + bool em4305 = tolower(param_getchar(Cmd, 1)) == 'e'; + if (em4305) { + blocks[0] = EM4305_VISA2000_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469"); + } + + if (q5 && em4305) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + blocks[2] = id; blocks[3] = (visa_parity(id) << 4) | visa_chksum(id); - PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, (q5) ? "Q5/T5555" : "T55x7", id); + PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em4305) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") " to verify"); return res; diff --git a/include/protocols.h b/include/protocols.h index bb520a71f..6a079f354 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -541,8 +541,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define T55XX_WRITE_TIMEOUT 1500 // em4x05 & em4x69 chip configuration register definitions -#define EM4x05_GET_BITRATE(x) (((x & 0x3F)*2)+2) -#define EM4x05_SET_BITRATE(x) ((x-2)/2) +#define EM4x05_GET_BITRATE(x) ((((x) & 0x3F) * 2) + 2) +#define EM4x05_SET_BITRATE(x) (((x) - 2) / 2) #define EM4x05_MODULATION_NRZ 0x00000000 #define EM4x05_MODULATION_MANCHESTER 0x00000040 #define EM4x05_MODULATION_BIPHASE 0x00000080 @@ -557,8 +557,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define EM4x05_PSK_RF_8 0x00000800 #define EM4x05_MAXBLOCK_SHIFT 14 #define EM4x05_FIRST_USER_BLOCK 5 -#define EM4x05_SET_NUM_BLOCKS(x) ((x+5-1)<<14) //# of blocks sent during default read mode -#define EM4x05_GET_NUM_BLOCKS(x) (((x>>14) & 0xF)-5+1) +#define EM4x05_SET_NUM_BLOCKS(x) (( (x) + 4) << 14) //# of blocks sent during default read mode +#define EM4x05_GET_NUM_BLOCKS(x) ((( (x) >> 14) & 0xF) - 4) #define EM4x05_READ_LOGIN_REQ (1 << 18) #define EM4x05_READ_HK_LOGIN_REQ (1 << 19) #define EM4x05_WRITE_LOGIN_REQ (1 << 20)