From fdcc4b741c0f6debb621fe7d981a8336dff8a50f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 27 Jan 2021 22:52:08 +0100 Subject: [PATCH] fix lf em 4x05 write - pwd/data. t55xx chk - now uses cliparser, and color to cliparser empty message --- client/deps/cliparser/cliparser.c | 54 +++++++-- client/deps/cliparser/cliparser.h | 9 +- client/src/cmdanalyse.c | 18 ++- client/src/cmdlfem4x05.c | 48 +++++--- client/src/cmdlft55xx.c | 192 +++++++++++++++--------------- 5 files changed, 197 insertions(+), 124 deletions(-) diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 6c249e9cb..f3f3c581e 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -118,7 +118,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta if (nerrors > 0) { /* Display the error details contained in the arg_end struct.*/ arg_print_errors(stdout, ((struct arg_end *)(ctx->argtable)[vargtableLen - 1]), ctx->programName); - PrintAndLogEx(WARNING, "Try '%s --help' for more information.\n", ctx->programName); + PrintAndLogEx(WARNING, "Try " _YELLOW_("'%s --help'") " for more information.\n", ctx->programName); fflush(stdout); return 3; } @@ -269,15 +269,19 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } +// hexstr -> u64, w optional len input and default value fallback. +// 0 = failed +// 1 = OK +// 3 = optional param - not set 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 && datalen > 0) { - for (uint8_t i = 0; i < datalen; i++) { + uint8_t d[8]; + int dlen = 0; + int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &dlen); + if (res == 0 && dlen > 0) { + for (uint8_t i = 0; i < dlen; i++) { rv <<= 8; - rv |= data[i]; + rv |= d[i]; } } else { rv = def; @@ -285,11 +289,38 @@ uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_ return rv; } -int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out) { - return arg_get_u32_hexstr_def_nlen(ctx, paramnum, def, out, 4); +// hexstr -> u64, w optional len input and default value fallback. +// 0 = failed +// 1 = OK +// 2 = wrong len param, use default +// 3 = optional param, if fail, use default. +int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional) { + int n = 0; + uint8_t d[nlen]; + int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &n); + if (res == 0 && n == nlen) { + uint64_t rv = 0; + for (uint8_t i = 0; i < n; i++) { + rv <<= 8; + rv |= d[i]; + } + *out = rv; + return 1; + } else if (res == 0 && n) { + *out = def; + return 2; + } else if (res == 0 && n == 0 && optional) { + *out = def; + return 3; + } + return 0; } -int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen) { +int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out) { + return arg_get_u32_hexstr_def_nlen(ctx, paramnum, def, out, 4, false); +} + +int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen, bool optional) { int n = 0; uint8_t d[nlen]; int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &n); @@ -304,6 +335,9 @@ int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_ } else if (res == 0 && n) { *out = def; return 2; + } else if (res == 0 && n == 0 && optional) { + *out = def; + return 3; } return 0; } diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 40fd5c2f7..78bb59f32 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -68,6 +68,13 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int 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); +int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional); int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out); -int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen); +int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen, bool optional); + +#define CP_SUCCESS_OPTIONAL 1 +#define CP_SUCCESS 0 +#define CP_ENOPARAM -1 +#define CP_WRONGLEN -2 + #endif diff --git a/client/src/cmdanalyse.c b/client/src/cmdanalyse.c index 02ad3fcd0..4cdd35e68 100644 --- a/client/src/cmdanalyse.c +++ b/client/src/cmdanalyse.c @@ -170,6 +170,14 @@ static uint16_t calcBSDchecksum4(uint8_t *bytes, uint8_t len, uint32_t mask) { return sum; } +// 0xFF - ( n1 ^ n... ) +static uint16_t calcXORchecksum(uint8_t *bytes, uint8_t len, uint32_t mask) { + return 0xFF - calcSumByteXor(bytes, len, mask); +} + + +//2148050707DB0A0E000001C4000000 + // measuring LFSR maximum length static int CmdAnalyseLfsr(const char *Cmd) { CLIParserContext *ctx; @@ -421,11 +429,12 @@ static int CmdAnalyseCHKSUM(const char *Cmd) { PrintAndLogEx(INFO, "Mask value 0x%x", mask); if (verbose) { - PrintAndLogEx(INFO, " add | sub | add 1's compl | sub 1's compl | xor"); - PrintAndLogEx(INFO, "byte nibble crumb | byte nibble | byte nibble cumb | byte nibble | byte nibble cumb | BSD |"); - PrintAndLogEx(INFO, "------------------+-------------+------------------+-----------------+--------------------"); + PrintAndLogEx(INFO, "------------------+-------------+------------------+-----------------+------------------+-----------+-------------"); + PrintAndLogEx(INFO, " add | sub | add 1's compl | sub 1's compl | xor | |"); + PrintAndLogEx(INFO, "byte nibble crumb | byte nibble | byte nibble cumb | byte nibble | byte nibble cumb | BSD | 0xFF - (n^n)"); + PrintAndLogEx(INFO, "------------------+-------------+------------------+-----------------+------------------+-----------+-------------"); } - PrintAndLogEx(INFO, "0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X |\n", + PrintAndLogEx(INFO, "0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X\n", calcSumByteAdd(data, dlen, mask) , calcSumNibbleAdd(data, dlen, mask) , calcSumCrumbAdd(data, dlen, mask) @@ -441,6 +450,7 @@ static int CmdAnalyseCHKSUM(const char *Cmd) { , calcSumCrumbXor(data, dlen, mask) , calcBSDchecksum8(data, dlen, mask) , calcBSDchecksum4(data, dlen, mask) + , calcXORchecksum(data, dlen, mask) ); return PM3_SUCCESS; } diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index c0dc8c2ee..87303124b 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -773,15 +773,38 @@ int CmdEM4x05Write(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_int0("a", "addr", "", "memory address to write to. (0-13)"), - arg_str1("d", "data", "", "data to write, 4 bytes hex"), - arg_str0("p", "pwd", "", "optional - password, 4 bytes hex"), + arg_str1("d", "data", "", "data to write (4 hex bytes)"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), arg_lit0(NULL, "po", "protect operation"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); uint8_t addr = (uint8_t)arg_get_int_def(ctx, 1, 50); - uint32_t data = arg_get_u32(ctx, 2); - uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 3, 0xFFFFFFFFFFFFFFFF); + uint32_t data = 0; + int res = arg_get_u32_hexstr_def(ctx, 2, 0, &data); + if (res == 2) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "Data must be 4 hex bytes"); + return PM3_EINVARG; + } else if (res == 0) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "Data must be 4 hex bytes"); + return PM3_EINVARG; + } + + bool use_pwd = false; + uint32_t pwd = 0; + res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &pwd, 4, true); + if (res == 2) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "Password must be 4 hex bytes"); + return PM3_EINVARG; + } else if (res == 3) { + use_pwd = false; + } else if (res == 1) { + use_pwd = true; + } + bool protect_operation = arg_get_lit(ctx, 4); CLIParserFree(ctx); @@ -790,22 +813,19 @@ int CmdEM4x05Write(const char *Cmd) { return PM3_EINVARG; } - bool use_pwd = false; - uint32_t pwd = (inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0; - if (pwd == 0xFFFFFFFF) { - if (protect_operation) - PrintAndLogEx(INFO, "Writing protection words data %08X", data); - else - PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data); - } else { - use_pwd = true; + if (use_pwd) { if (protect_operation) PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd); else PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd); + } else { + if (protect_operation) + PrintAndLogEx(INFO, "Writing protection words data %08X", data); + else + PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data); } - int res = PM3_SUCCESS; + res = PM3_SUCCESS; // set Protect Words if (protect_operation) { res = em4x05_protect(pwd, use_pwd, data); diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index cd4947b4d..d98347342 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -262,26 +262,7 @@ static int usage_t55xx_wakup(void) { PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wakeup p 11223344") " - send wakeup password"); return PM3_SUCCESS; } -static int usage_t55xx_chk(void) { - PrintAndLogEx(NORMAL, "This command uses a dictionary attack"); - PrintAndLogEx(NORMAL, "press " _YELLOW_("'enter'") " to cancel the command"); - PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may brick non-password protected chips!"); - PrintAndLogEx(NORMAL, "Try to reading block 7 before\n"); - PrintAndLogEx(NORMAL, "Usage: lf t55xx chk [h] [m] [r ] [f <*.dic>] [e ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " m - use dictionary from flashmemory\n"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_ALL, T55XX_DLMODE_ALL); - PrintAndLogEx(NORMAL, " f <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLogEx(NORMAL, " e - will try the calculated password from some cloners based on EM4100 ID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk m")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk f t55xx_default_pwds")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk e aa11223344")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} + static int usage_t55xx_dangerraw(void) { PrintAndLogEx(NORMAL, "This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration."); PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may lock definitively the tag in an unusable state!"); @@ -2974,68 +2955,83 @@ static bool IsCancelled(void) { // load a default pwd file. static int CmdT55xxChkPwds(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx chk", + "This command uses a dictionary attack.\n" + "For some cloners, try '--em' for known pwdgen algo.\n" + "Try to reading Page 0 block 7 before.\n" + _RED_("WARNING:") _CYAN_(" this may brick non-password protected chips!"), + "lf t55xx chk -m -> use dictionary from flash memory (RDV4)\n" + "lf t55xx chk -f my_dictionary_pwds -> loads a default keys dictionary file\n" + "lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on EM4100 ID" + ); + // 4 + (5 or 6) + void *argtable[9] = { + arg_param_begin, + arg_lit0("m", "fm", "use dictionary from flash memory (RDV4)"), + arg_str0("f", "file", "", "file name"), + arg_str0(NULL, "em", "", "EM4100 ID (5 hex bytes)"), + }; + uint8_t idx = 4; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, T55XX_DLMODE_ALL); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool from_flash = arg_get_lit(ctx, 1); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - bool found = false; - uint8_t timeout = 0; - uint8_t *keyBlock = NULL; - bool from_flash = false; - bool try_all_dl_modes = false; - uint8_t downlink_mode = 0; - bool use_pwd_file = false; - int dl_mode; // to try each downlink mode for each password - uint8_t cmdp = 0; - bool errors = false; - bool useCardPassword = false; - uint32_t cardPassword = 0x00; - uint64_t cardID = 0x00; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, sizeof(filename), &fnlen); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_chk(); - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode >= 4) { - try_all_dl_modes = true; - downlink_mode = 0; - } - cmdp += 2; - break; - case 'm': - from_flash = true; - cmdp++; - break; - case 'f': - if (param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)) == 0) { - PrintAndLogEx(ERR, "Error, no filename after 'f' was found"); - errors = true; - } - use_pwd_file = true; - cmdp += 2; - break; - case 'e': // White cloner password based on EM4100 ID - useCardPassword = true; - cardID = param_get64ex(Cmd, cmdp + 1, 0, 16); - uint32_t card32Bit = cardID & 0xFFFFFFFF; - cardPassword = lf_t55xx_white_pwdgen(card32Bit); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + bool use_calc_password = false; + uint32_t card_password = 0x00; + uint64_t cardid = 0; + int res = arg_get_u64_hexstr_def_nlen(ctx, 3, 0x00, &cardid, 5, true); + if (res == 1) { + use_calc_password = true; + uint32_t calc = cardid & 0xFFFFFFFF; + card_password = lf_t55xx_white_pwdgen(calc); + } + if (res == 2) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "EM4100 ID must be 5 hex bytes"); + return PM3_EINVARG; + } + if (res == 0) { + CLIParserFree(ctx); + return PM3_EINVARG; } - if (errors) return usage_t55xx_chk(); + bool r0 = arg_get_lit(ctx, 4); + bool r1 = arg_get_lit(ctx, 5); + bool r2 = arg_get_lit(ctx, 6); + bool r3 = arg_get_lit(ctx, 7); + bool ra = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + if ((r0 + r1 + r2 + r3 + ra) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + bool use_pwd_file = false; if (strlen(filename) == 0) { snprintf(filename, sizeof(filename), "t55xx_default_pwds"); use_pwd_file = true; } + PrintAndLogEx(INFO, "press " _GREEN_("'enter'") " to cancel the command"); PrintAndLogEx(NORMAL, ""); /* // block 7, page1 = false, usepwd = false, override = false, pwd = 00000000 @@ -3047,6 +3043,8 @@ static int CmdT55xxChkPwds(const char *Cmd) { } */ + bool found = false; + uint64_t t1 = msclock(); uint8_t flags = downlink_mode << 3; @@ -3055,6 +3053,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { SendCommandNG(CMD_LF_T55XX_CHK_PWDS, &flags, sizeof(flags)); PacketResponseNG resp; + uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) { timeout++; PrintAndLogEx(NORMAL, "." NOLF); @@ -3090,55 +3089,59 @@ static int CmdT55xxChkPwds(const char *Cmd) { goto out; } - // try calculated password - if (useCardPassword) { + // to try each downlink mode for each password + int dl_mode; - PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", cardPassword); + // try calculated password + if (use_calc_password) { + + PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", card_password); for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) { - if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, cardPassword, dl_mode)) { + if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, card_password, dl_mode)) { continue; } - found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword); + found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, card_password); if (found) { - PrintAndLogEx(SUCCESS, "found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword); - dl_mode = 4; // Exit other downlink mode checks + PrintAndLogEx(SUCCESS, "found valid password : [ " _GREEN_("%08"PRIX32) " ]", card_password); + break; } - if (!try_all_dl_modes) // Exit loop if not trying all downlink modes - dl_mode = 4; + if (ra == false) + break; } } if ((found == false) && use_pwd_file) { uint32_t keycount = 0; + uint8_t *keyblock = NULL; - int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount); - if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) { + res = loadFileDICTIONARY_safe(filename, (void **) &keyblock, 4, &keycount); + if (res != PM3_SUCCESS || keycount == 0 || keyblock == NULL) { PrintAndLogEx(WARNING, "no keys found in file"); - if (keyBlock != NULL) - free(keyBlock); + if (keyblock != NULL) + free(keyblock); return PM3_ESOFT; } - PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command"); + PrintAndLogEx(INFO, "press " _GREEN_("'enter'") " to cancel the command"); - for (uint32_t c = 0; c < keycount; ++c) { + for (uint32_t c = 0; c < keycount && found == false; ++c) { if (!session.pm3_present) { PrintAndLogEx(WARNING, "device offline\n"); - free(keyBlock); + free(keyblock); return PM3_ENODATA; } if (IsCancelled()) { - free(keyBlock); + free(keyblock); return PM3_EOPABORTED; } - uint32_t curr_password = bytes_to_num(keyBlock + 4 * c, 4); + uint32_t curr_password = bytes_to_num(keyblock + 4 * c, 4); PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password); for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) { @@ -3150,20 +3153,19 @@ static int CmdT55xxChkPwds(const char *Cmd) { found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password); if (found) { PrintAndLogEx(SUCCESS, "found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password); - dl_mode = 4; // Exit other downlink mode checks - c = keycount; // Exit loop + break; } - if (!try_all_dl_modes) // Exit loop if not trying all downlink modes - dl_mode = 4; + if (ra == false) // Exit loop if not trying all downlink modes + break; } } + + free(keyblock); } if (found == false) - PrintAndLogEx(WARNING, "check pwd failed"); - - free(keyBlock); + PrintAndLogEx(WARNING, "failed to find password"); out: t1 = msclock() - t1;