diff --git a/client/src/cmddata.c b/client/src/cmddata.c index d1855aaff..daff73722 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -709,7 +709,7 @@ static int Cmdmandecoderaw(const char *Cmd) { if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) { //need to adjust to set bitstream back to manchester encoded data //setDemodBuff(bits, size, idx); - printEM410x(hi, id); + printEM410x(hi, id, false); } } return PM3_SUCCESS; diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index ef35e95a0..790e3e070 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -1,5 +1,8 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh + +// modified marshmellow +// modified Iceman, 2020 // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -10,13 +13,11 @@ #include "cmdlfem410x.h" #include "cmdlfem4x50.h" - #include #include #include #include #include - #include "fileutils.h" #include "cmdparser.h" // command_t #include "comms.h" @@ -37,88 +38,6 @@ static uint64_t g_em410xid = 0; static int CmdHelp(const char *Cmd); - -//////////////// 410x commands -static int usage_lf_em410x_demod(void) { - PrintAndLogEx(NORMAL, "Usage: lf em 410x_demod [h] [clock] <0|1> [maxError]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " clock - set clock as integer, optional, if not set, autodetect."); - PrintAndLogEx(NORMAL, " <0|1> - 0 normal output, 1 for invert output"); - PrintAndLogEx(NORMAL, " maxerror - set maximum allowed errors, default = 100."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod") " = demod an EM410x Tag ID from GraphBuffer"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32 1") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 1") " = demod an EM410x Tag ID from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 64 1 0") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors"); - return PM3_SUCCESS; -} -static int usage_lf_em410x_watch(void) { - PrintAndLogEx(NORMAL, "Enables IOProx compatible reader mode printing details of scanned tags."); - PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_watch"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_watch")); - return PM3_SUCCESS; -} - -static int usage_lf_em410x_clone(void) { - PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 or Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_clone [h] [clock]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " - ID number"); - PrintAndLogEx(NORMAL, " - 0|1 0 = Q5/T5555, 1 = T55x7"); - PrintAndLogEx(NORMAL, " - 16|32|40|64, optional, set R/F clock rate, defaults to 64"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_clone 0F0368568B 1") " = write ID to t55x7 card"); - return PM3_SUCCESS; -} -static int usage_lf_em410x_ws(void) { - PrintAndLogEx(NORMAL, "Watch 'nd Spoof, activates reader, waits until a EM410x tag gets presented then it starts simulating the found UID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_spoof [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_spoof")); - return PM3_SUCCESS; -} -static int usage_lf_em410x_sim(void) { - PrintAndLogEx(NORMAL, "Simulating EM410x tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " uid - uid (10 HEX symbols)"); - PrintAndLogEx(NORMAL, " clock - clock (32|64) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B 32")); - return PM3_SUCCESS; -} -static int usage_lf_em410x_brute(void) { - PrintAndLogEx(NORMAL, "Bruteforcing by emulating EM410x tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 410x_brute [h] ids.txt [d 2000] [c clock]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " ids.txt - file with UIDs in HEX format, one per line"); - PrintAndLogEx(NORMAL, " d (2000) - pause delay in milliseconds between UIDs simulation, default 1000 ms (optional)"); - PrintAndLogEx(NORMAL, " c (32) - clock (32|64), default 64 (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt c 32")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000 c 32")); - return PM3_SUCCESS; -} - /* Read the ID of an EM410x tag. * Format: * 1111 1111 1 <-- standard non-repeatable header @@ -129,63 +48,62 @@ static int usage_lf_em410x_brute(void) { */ // Construct the graph for emulating an EM410X tag -static void ConstructEM410xEmulGraph(const char *uid, const uint8_t clock) { +static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock) { - int i, j, binary[4], parity[4]; - uint32_t n; - /* clear our graph */ + // clear our graph ClearGraph(true); - /* write 16 zero bit sledge */ - for (i = 0; i < 20; i++) + // write 16 zero bit sledge + for (uint8_t i = 0; i < 20; i++) AppendGraph(false, clock, 0); - /* write 9 start bits */ - for (i = 0; i < 9; i++) + // write 9 start bits + for (uint8_t i = 0; i < 9; i++) AppendGraph(false, clock, 1); - /* for each hex char */ - parity[0] = parity[1] = parity[2] = parity[3] = 0; - for (i = 0; i < 10; i++) { - /* read each hex char */ - sscanf(&uid[i], "%1x", &n); - for (j = 3; j >= 0; j--, n /= 2) - binary[j] = n % 2; + uint8_t bs[8], parity[8]; + memset(parity, 0, sizeof(parity)); - /* append each bit */ - AppendGraph(false, clock, binary[0]); - AppendGraph(false, clock, binary[1]); - AppendGraph(false, clock, binary[2]); - AppendGraph(false, clock, binary[3]); + for (uint8_t i = 0; i < 5; i++) { - /* append parity bit */ - AppendGraph(false, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); + for (uint8_t j = 0; j < 8; j++) { + bs[j] = (uid[i] >> (7 - j) & 1); + } + PrintAndLogEx(DEBUG, "uid[%d] 0x%02x (%s)", i, uid[i], sprint_bin(bs, 4)); - /* keep track of column parity */ - parity[0] ^= binary[0]; - parity[1] ^= binary[1]; - parity[2] ^= binary[2]; - parity[3] ^= binary[3]; + for (uint8_t j = 0; j < 2; j++) { + // append each bit + AppendGraph(false, clock, bs[0 + (4 * j)]); + AppendGraph(false, clock, bs[1 + (4 * j)]); + AppendGraph(false, clock, bs[2 + (4 * j)]); + AppendGraph(false, clock, bs[3 + (4 * j)]); + + // append parity bit + AppendGraph(false, clock, bs[0 + (4 * j)] ^ bs[1 + (4 * j)] ^ bs[2 + (4 * j)] ^ bs[3 + (4 * j)]); + + // keep track of column parity + parity[0] ^= bs[0 + (4 * j)]; + parity[1] ^= bs[1 + (4 * j)]; + parity[2] ^= bs[2 + (4 * j)]; + parity[3] ^= bs[3 + (4 * j)]; + } } - /* parity columns */ + // parity columns AppendGraph(false, clock, parity[0]); AppendGraph(false, clock, parity[1]); AppendGraph(false, clock, parity[2]); AppendGraph(false, clock, parity[3]); - /* stop bit */ + // stop bit AppendGraph(true, clock, 0); } -//by marshmellow //print 64 bit EM410x ID in multiple formats -void printEM410x(uint32_t hi, uint64_t id) { +void printEM410x(uint32_t hi, uint64_t id, bool verbose) { if (!id && !hi) return; - PrintAndLogEx(SUCCESS, "EM410x%s pattern found", (hi) ? " XL" : ""); - uint64_t n = 1; uint64_t id2lo = 0; uint8_t m, i; @@ -195,26 +113,36 @@ void printEM410x(uint32_t hi, uint64_t id) { } } + if (verbose == false) { + + if (hi) { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); + } else { + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); + } + return; + } + if (hi) { //output 88 bit em id - PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%06X%016" PRIX64), hi, id); - PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock); + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); + PrintAndLogEx(SUCCESS, "EM410x XL ( RF/%d )", g_DemodClock); } else { //output 40 bit em id - PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%010" PRIX64), id); - PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock); - PrintAndLogEx(NORMAL, "\nPossible de-scramble patterns\n"); - PrintAndLogEx(NORMAL, "Unique TAG ID : %010" PRIX64, id2lo); - PrintAndLogEx(NORMAL, "HoneyWell IdentKey {"); - PrintAndLogEx(NORMAL, "DEZ 8 : %08" PRIu64, id & 0xFFFFFF); - PrintAndLogEx(NORMAL, "DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF); - PrintAndLogEx(NORMAL, "DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF)); - PrintAndLogEx(NORMAL, "DEZ 14/IK2 : %014" PRIu64, id); - PrintAndLogEx(NORMAL, "DEZ 15/IK3 : %015" PRIu64, id2lo); - PrintAndLogEx(NORMAL, "DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64, + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); + PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock); + PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); + PrintAndLogEx(SUCCESS, "Unique TAG ID : %010" PRIX64, id2lo); + PrintAndLogEx(INFO, "HoneyWell IdentKey"); + PrintAndLogEx(SUCCESS, " DEZ 8 : %08" PRIu64, id & 0xFFFFFF); + PrintAndLogEx(SUCCESS, " DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF); + PrintAndLogEx(SUCCESS, " DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF)); + PrintAndLogEx(SUCCESS, " DEZ 14/IK2 : %014" PRIu64, id); + PrintAndLogEx(SUCCESS, " DEZ 15/IK3 : %015" PRIu64, id2lo); + PrintAndLogEx(SUCCESS, " DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64, (id2lo & 0xf000000000) >> 36, (id2lo & 0x0f00000000) >> 32, (id2lo & 0x00f0000000) >> 28, @@ -226,9 +154,11 @@ void printEM410x(uint32_t hi, uint64_t id) { (id2lo & 0x00000000f0) >> 4, (id2lo & 0x000000000f) ); + PrintAndLogEx(INFO, ""); + uint64_t paxton = (((id >> 32) << 24) | (id & 0xffffff)) + 0x143e00; - PrintAndLogEx(NORMAL, "}\nOther : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF)); - PrintAndLogEx(NORMAL, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton); + PrintAndLogEx(SUCCESS, "Other : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF)); + PrintAndLogEx(SUCCESS, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton); uint32_t p1id = (id & 0xFFFFFF); uint8_t arr[32] = {0x00}; @@ -268,12 +198,13 @@ void printEM410x(uint32_t hi, uint64_t id) { p1 |= arr[2] << 4; p1 |= arr[1] << 5; p1 |= arr[0] << 9; - PrintAndLogEx(NORMAL, "Pattern 1 : %d [0x%X]", p1, p1); + PrintAndLogEx(SUCCESS, "Pattern 1 : %d [0x%X]", p1, p1); uint16_t sebury1 = id & 0xFFFF; uint8_t sebury2 = (id >> 16) & 0x7F; uint32_t sebury3 = id & 0x7FFFFF; - PrintAndLogEx(NORMAL, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3); + PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3); + PrintAndLogEx(INFO, "------------------------------------------------"); } } /* Read the ID of an EM410x tag. @@ -321,9 +252,8 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) { printDemodBuff(0, false, false, true); } - if (verbose) - printEM410x(*hi, *lo); - + printEM410x(*hi, *lo, verbose); + g_em410xid = *lo; return PM3_SUCCESS; } @@ -342,8 +272,19 @@ int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, // this read loops on device side. // uses the demod in lfops.c static int CmdEM410xWatch(const char *Cmd) { - uint8_t c = tolower(param_getchar(Cmd, 0)); - if (c == 'h') return usage_lf_em410x_watch(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x watch", + "Enables Electro Marine (EM) compatible reader mode printing details of scanned tags.\n" + "Run until the button is pressed or another USB command is issued.", + "lf em 410x watch" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna"); PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); @@ -367,111 +308,189 @@ int demodEM410x(bool verbose) { } static int CmdEM410xDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x demod", + "Try to find EM 410x preamble, if found decode / descramble data", + "lf em 410x demod -> demod an EM410x Tag ID from GraphBuffer\n" + "lf em 410x demod --clk 32 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32\n" + "lf em 410x demod --clk 32 -i -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data\n" + "lf em 410x demod -i -> demod an EM410x Tag ID from GraphBuffer while inverting data\n" + "lf em 410x demod --clk 64 -i --err 0 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "optional - maximum length"), + arg_lit0("i", "invert", "optional - invert output"), + arg_lit0("a", "amp", "optional - amplify signal"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int clk = arg_get_u32_def(ctx, 1, 0); + int max_err = arg_get_u32_def(ctx, 2, 100); + size_t max_len = arg_get_u32_def(ctx, 3, 0); + bool invert = arg_get_lit(ctx, 4); + bool amplify = arg_get_lit(ctx, 5); + CLIParserFree(ctx); uint32_t hi = 0; uint64_t lo = 0; - int clk = 0; - int invert = 0; - int maxErr = 100; - size_t maxLen = 0; - char amp = tolower(param_getchar(Cmd, 0)); - sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - bool amplify = amp == 'a'; - if (AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true) != PM3_SUCCESS) + if (AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, true) != PM3_SUCCESS) return PM3_ESOFT; - g_em410xid = lo; return PM3_SUCCESS; } // this read is the "normal" read, which download lf signal and tries to demod here. -static int CmdEM410xRead(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod(); +static int CmdEM410xReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x reader", + "read EM 410x tag", + "lf em 410x reader -> reader\n" + "lf em 410x reader -@ -> continuous reader mode\n" + "lf em 410x reader --clk 32 -> reader using a clock of RF/32\n" + "lf em 410x reader --clk 32 -i -> reader using a clock of RF/32 and inverting data\n" + "lf em 410x reader -i -> reader while inverting data\n" + "lf em 410x reader --clk 64 -i --err 0 -> reader using a clock of RF/64 and inverting data and allowing 0 demod errors" + ); - uint32_t hi = 0; - uint64_t lo = 0; - int clk = 0; - int invert = 0; - int maxErr = 100; - size_t maxLen = 0; - char amp = tolower(param_getchar(Cmd, 0)); - sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - bool amplify = amp == 'a'; - lf_read(false, 12288); - return AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true); + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "optional - maximum length"), + arg_lit0("i", "invert", "optional - invert output"), + arg_lit0("a", "amp", "optional - amplify signal"), + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int clk = arg_get_u32_def(ctx, 1, 0); + int max_err = arg_get_u32_def(ctx, 2, 100); + size_t max_len = arg_get_u32_def(ctx, 3, 0); + bool invert = arg_get_lit(ctx, 4); + bool amplify = arg_get_lit(ctx, 5); + bool cm = arg_get_lit(ctx, 6); + bool verbose = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + } + + do { + uint32_t hi = 0; + uint64_t lo = 0; + lf_read(false, 12288); + AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } // emulate an EM410X tag static int CmdEM410xSim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_sim(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x sim", + "Enables simulation of EM 410x card.\n" + "Simulation runs until the button is pressed or another USB command is issued.", + "lf em 410x sim --id 0F0368568B\n" + "lf em 410x sim --id 0F0368568B --clk 32" + ); - uint8_t uid[5] = {0x00}; + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock [32|64] (default 64)"), + arg_str1("i", "id", "", "ID number (5 hex bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - /* clock is 64 in EM410x tags */ - uint8_t clk = 64; + // clock is 64 in EM410x tags + int clk = arg_get_u32_def(ctx, 1, 64); + int uid_len = 0; + uint8_t uid[5] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + CLIParserFree(ctx); - if (param_gethex(Cmd, 0, uid, 10)) { - PrintAndLogEx(FAILED, "UID must include 10 HEX symbols"); + if (uid_len != 5) { + PrintAndLogEx(FAILED, "UID must include 5 hex bytes (%u)", uid_len); return PM3_EINVARG; } - param_getdec(Cmd, 1, &clk); - - PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%02X%02X%02X%02X%02X")" clock: "_YELLOW_("%d"), uid[0], uid[1], uid[2], uid[3], uid[4], clk); + PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation"); - ConstructEM410xEmulGraph(Cmd, clk); + em410x_construct_emul_graph(uid, clk); - CmdLFSim("0"); //240 start_gap. + CmdLFSim("0"); // 240 start_gap. return PM3_SUCCESS; } -static int CmdEM410xBrute(const char *Cmd) { +static int CmdEM410xBrute(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x brute", + "bruteforcing by emulating EM 410x tag", + "lf em 410x brute -f ids.txt\n" + "lf em 410x brute -f ids.txt --clk 32\n" + "lf em 410x brute -f ids.txt --delay 3000\n" + "lf em 410x brute -f ids.txt --delay 3000 --clk 32\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "clk", "", "optional - clock [32|64] (default 64)"), + arg_u64_1(NULL, "delay", "", "optional - pause delay in milliseconds between UIDs simulation (default 1000ms)"), + arg_str1("f", "file", "", "file with UIDs in HEX format, one per line"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + // clock default 64 in EM410x + uint32_t clk = arg_get_u32_def(ctx, 1, 64); + + // default pause time: 1 second + uint32_t delay = arg_get_u32_def(ctx, 2, 1000); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - FILE *f = NULL; - char buf[11]; - uint32_t uidcnt = 0; - uint8_t stUidBlock = 20; - uint8_t *uidBlock = NULL, *p = NULL; - uint8_t uid[5] = {0x00}; - /* clock is 64 in EM410x tags */ - uint8_t clock1 = 64; - /* default pause time: 1 second */ - uint32_t delay = 1000; + CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_brute(); - - cmdp = tolower(param_getchar(Cmd, 1)); - if (cmdp == 'd') { - delay = param_get32ex(Cmd, 2, 1000, 10); - param_getdec(Cmd, 4, &clock1); - } else if (cmdp == 'c') { - param_getdec(Cmd, 2, &clock1); - delay = param_get32ex(Cmd, 4, 1000, 10); - } - - int filelen = param_getstr(Cmd, 0, filename, FILE_PATH_SIZE); - if (filelen == 0) { + if (fnlen == 0) { PrintAndLogEx(ERR, "Error: Please specify a filename"); return PM3_EINVARG; } + + uint32_t uidcnt = 0; + uint8_t stUidBlock = 20; + uint8_t *p = NULL; + uint8_t uid[5] = {0x00}; + // open file + FILE *f = NULL; if ((f = fopen(filename, "r")) == NULL) { PrintAndLogEx(ERR, "Error: Could not open UIDs file ["_YELLOW_("%s")"]", filename); return PM3_EFILE; } - uidBlock = calloc(stUidBlock, 5); - if (uidBlock == NULL) { + // allocate mem for file contents + uint8_t *uidblock = calloc(stUidBlock, 5); + if (uidblock == NULL) { fclose(f); - return PM3_ESOFT; + PrintAndLogEx(ERR, "Error: can't allocate memory"); + return PM3_EMALLOC; } + // read file into memory + char buf[11]; + while (fgets(buf, sizeof(buf), f)) { if (strlen(buf) < 10 || buf[9] == '\n') continue; while (fgetc(f) != '\n' && !feof(f)); //goto next line @@ -481,7 +500,7 @@ static int CmdEM410xBrute(const char *Cmd) { if (param_gethex(buf, 0, uid, 10)) { PrintAndLogEx(FAILED, "UIDs must include 10 HEX symbols"); - free(uidBlock); + free(uidblock); fclose(f); return PM3_ESOFT; } @@ -489,109 +508,118 @@ static int CmdEM410xBrute(const char *Cmd) { buf[10] = 0; if (stUidBlock - uidcnt < 2) { - p = realloc(uidBlock, 5 * (stUidBlock += 10)); + p = realloc(uidblock, 5 * (stUidBlock += 10)); if (!p) { PrintAndLogEx(WARNING, "Cannot allocate memory for UIDs"); - free(uidBlock); + free(uidblock); fclose(f); return PM3_ESOFT; } - uidBlock = p; + uidblock = p; } - memset(uidBlock + 5 * uidcnt, 0, 5); - num_to_bytes(strtoll(buf, NULL, 16), 5, uidBlock + 5 * uidcnt); + memset(uidblock + 5 * uidcnt, 0, 5); + num_to_bytes(strtoll(buf, NULL, 16), 5, uidblock + 5 * uidcnt); uidcnt++; memset(buf, 0, sizeof(buf)); } - fclose(f); if (uidcnt == 0) { PrintAndLogEx(FAILED, "No UIDs found in file"); - free(uidBlock); + free(uidblock); return PM3_ESOFT; } PrintAndLogEx(SUCCESS, "Loaded "_YELLOW_("%d")" UIDs from "_YELLOW_("%s")", pause delay:"_YELLOW_("%d")" ms", uidcnt, filename, delay); // loop + uint8_t testuid[5]; for (uint32_t c = 0; c < uidcnt; ++c) { - char testuid[11]; - testuid[10] = 0; - if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); - free(uidBlock); + free(uidblock); return PM3_EOPABORTED; } - sprintf(testuid, "%010" PRIX64, bytes_to_num(uidBlock + 5 * c, 5)); - PrintAndLogEx(NORMAL, "Bruteforce %d / %d: simulating UID %s, clock %d", c + 1, uidcnt, testuid, clock1); + memcpy(testuid, uidblock + 5 * c, 5); + PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s") + , c + 1 + , uidcnt + , sprint_hex_inrow(testuid, sizeof(testuid)) + ); - ConstructEM410xEmulGraph(testuid, clock1); + em410x_construct_emul_graph(testuid, clk); CmdLFSim("0"); //240 start_gap. msleep(delay); } - - free(uidBlock); + free(uidblock); return PM3_SUCCESS; } //currently only supports manchester modulations -static int CmdEM410xWatchnSpoof(const char *Cmd) { +static int CmdEM410xSpoof(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x spoof", + "Watch 'nd Spoof, activates reader\n" + "Waits until a EM 410x tag gets presented then Proxmark3 starts simulating the found UID", + "lf em 410x spoof" + ); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_ws(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // loops if the captured ID was in XL-format. - CmdEM410xWatch(Cmd); + CmdEM410xReader("-@"); PrintAndLogEx(SUCCESS, "# Replaying captured ID: "_YELLOW_("%010" PRIx64), g_em410xid); CmdLFaskSim(""); return PM3_SUCCESS; } static int CmdEM410xClone(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 0x00 || cmdp == 'h') return usage_lf_em410x_clone(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 410x clone", + "Writes EM410x ID to a T55x7 or Q5/T5555 tag", + "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" + "lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag" + ); - uint64_t id = param_get64ex(Cmd, 0, -1, 16); - uint8_t card = param_get8ex(Cmd, 1, 0xFF, 10); - uint8_t clock1 = param_get8ex(Cmd, 2, 0, 10); + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "clk", "", "optional - clock <16|32|40|64> (default 64)"), + arg_str1("u", "uid", "", "ID number (5 hex bytes)"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - // Check ID - if (id == 0xFFFFFFFFFFFFFFFF) { - PrintAndLogEx(ERR, "error, ID is required\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } - if (id >= 0x10000000000) { - PrintAndLogEx(ERR, "error, given EM410x ID is longer than 40 bits\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } + // clock default 64 in EM410x + uint32_t clk = arg_get_u32_def(ctx, 1, 64); + int uid_len = 0; + uint8_t uid[5] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + bool q5 = arg_get_lit(ctx, 3); + CLIParserFree(ctx); - // Check Card - if (card > 1) { - PrintAndLogEx(FAILED, "error, bad card type selected\n"); - usage_lf_em410x_clone(); - return PM3_EINVARG; - } - - // Check Clock - if (clock1 == 0) - clock1 = 64; + uint64_t id = bytes_to_num(uid, uid_len); // Allowed clock rates: 16, 32, 40 and 64 - if ((clock1 != 16) && (clock1 != 32) && (clock1 != 64) && (clock1 != 40)) { - PrintAndLogEx(FAILED, "error, clock rate" _RED_("%d")" not valid", clock1); - PrintAndLogEx(INFO, "supported clock rates: " _YELLOW_("16, 32, 40, 60") "\n"); - usage_lf_em410x_clone(); + if ((clk != 16) && (clk != 32) && (clk != 64) && (clk != 40)) { + PrintAndLogEx(FAILED, "supported clock rates are " _YELLOW_("16, 32, 40, 64") " got " _RED_("%d") "\n", clk); return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Writing " _YELLOW_("%s") " tag with UID 0x%010" PRIx64 " (clock rate: %d)", (card == 1) ? "T55x7" : "Q5/T5555", id, clock1); + char cardtype[16] = {"T55x7"}; + if (q5) { + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with ID " _GREEN_("%010" PRIX64) " (RF/%d)", cardtype, id, clk); // NOTE: We really should pass the clock in as a separate argument, but to // provide for backwards-compatibility for older firmware, and to avoid // having to add another argument to CMD_LF_EM410X_WRITE, we just store @@ -604,8 +632,8 @@ static int CmdEM410xClone(const char *Cmd) { uint32_t low; } PACKED params; - params.card = card; - params.clock = clock1; + params.card = (q5) ? 0 : 1; + params.clock = clk; params.high = (uint32_t)(id >> 32); params.low = (uint32_t)id; @@ -617,7 +645,7 @@ static int CmdEM410xClone(const char *Cmd) { switch (resp.status) { case PM3_SUCCESS: { PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x reader`") " to verify"); break; } default: { @@ -629,15 +657,15 @@ static int CmdEM410xClone(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - //{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"}, - {"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"}, - {"read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"}, - {"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, - {"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + //{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"}, + {"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"}, + {"reader", CmdEM410xReader, IfPm3Lf, "attempt to read and extract tag data"}, + {"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"}, + {"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, + {"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, + {"spoof", CmdEM410xSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, + {"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem410x.h b/client/src/cmdlfem410x.h index 62d35cf55..d31812b56 100644 --- a/client/src/cmdlfem410x.h +++ b/client/src/cmdlfem410x.h @@ -16,7 +16,7 @@ int CmdLFEM410X(const char *Cmd); int demodEM410x(bool verbose); -void printEM410x(uint32_t hi, uint64_t id); +void printEM410x(uint32_t hi, uint64_t id, bool verbose); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo); int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);