From 00f91b2a00c16b1cb500de9a700c169b683c51da Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 4 Dec 2020 00:11:57 +0100 Subject: [PATCH] re-order the 'lf em' commands --- client/CMakeLists.txt | 3 +- client/Makefile | 3 +- client/src/cmddata.c | 2 +- client/src/cmdlf.c | 13 +- client/src/cmdlfem.c | 41 ++ client/src/{cmdlfem4x.h => cmdlfem.h} | 13 +- client/src/cmdlfem4x.c | 673 -------------------------- client/src/cmdlfem4x05.c | 447 +++++++++-------- client/src/cmdlfem4x50.c | 27 ++ client/src/cmdlfem4x50.h | 2 + doc/cliparser_todo.txt | 25 +- doc/commands.md | 28 +- 12 files changed, 347 insertions(+), 930 deletions(-) create mode 100644 client/src/cmdlfem.c rename client/src/{cmdlfem4x.h => cmdlfem.h} (54%) delete mode 100644 client/src/cmdlfem4x.c diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 92888a0fa..b630bf5de 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -248,7 +248,8 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlfawid.c ${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfdestron.c - ${PM3_ROOT}/client/src/cmdlfem4x.c + ${PM3_ROOT}/client/src/cmdlfem.c + ${PM3_ROOT}/client/src/cmdlfem410x.c ${PM3_ROOT}/client/src/cmdlfem4x05.c ${PM3_ROOT}/client/src/cmdlfem4x50.c ${PM3_ROOT}/client/src/cmdlffdxb.c diff --git a/client/Makefile b/client/Makefile index 2f0899bc8..d577b0d25 100644 --- a/client/Makefile +++ b/client/Makefile @@ -489,7 +489,8 @@ SRCS = aiddesfire.c \ cmdlfawid.c \ cmdlfcotag.c \ cmdlfdestron.c \ - cmdlfem4x.c \ + cmdlfem.c \ + cmdlfem410x.c \ cmdlfem4x05.c \ cmdlfem4x50.c \ cmdlffdxb.c \ diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 3aa7b07fd..d1855aaff 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -23,7 +23,7 @@ #include "comms.h" #include "lfdemod.h" // for demod code #include "loclass/cipherutils.h" // for decimating samples in getsamples -#include "cmdlfem4x.h" // askem410xdecode +#include "cmdlfem410x.h" // askem410xdecode #include "fileutils.h" // searchFile #include "mifare/ndef.h" #include "cliparser.h" diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 7cd9d801e..cbecb8f87 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -12,24 +12,23 @@ // Low frequency commands //----------------------------------------------------------------------------- #include "cmdlf.h" - #include #include #include #include #include - -#include "cmdparser.h" // command_t +#include "cmdparser.h" // command_t #include "comms.h" -#include "commonutil.h" // ARRAYLEN - +#include "commonutil.h" // ARRAYLEN #include "lfdemod.h" // device/client demods of LF signals #include "ui.h" // for show graph controls #include "proxgui.h" +#include "cliparser.h" // args parsing #include "graph.h" // for graph data #include "cmddata.h" // for `lf search` #include "cmdlfawid.h" // for awid menu -#include "cmdlfem4x.h" // for em4x menu +#include "cmdlfem.h" // for em menu +#include "cmdlfem410x.h" // for em4x menu #include "cmdlfem4x05.h" // for em4x05 / 4x69 #include "cmdlfem4x50.h" // for em4x50 #include "cmdlfhid.h" // for hid menu @@ -1530,7 +1529,7 @@ static command_t CommandTable[] = { {"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"}, {"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"}, {"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"}, - {"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"}, + {"em", CmdLFEM, AlwaysAvailable, "{ EM CHIPs & RFIDs... }"}, {"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"}, {"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"}, {"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"}, diff --git a/client/src/cmdlfem.c b/client/src/cmdlfem.c new file mode 100644 index 000000000..fbc7ac476 --- /dev/null +++ b/client/src/cmdlfem.c @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 iceman +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// Low frequency EM4x commands +//----------------------------------------------------------------------------- + +#include "cmdlfem.h" +#include "cmdlfem410x.h" +#include "cmdlfem4x05.h" +#include "cmdlfem4x50.h" + +#include +#include +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer +#include "cmdlf.h" + +static int CmdHelp(const char *Cmd); + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"410x", CmdLFEM410X, AlwaysAvailable, "EM 410x commands..."}, + {"4x05", CmdLFEM4X05, AlwaysAvailable, "EM 4x05 commands..."}, + {"4x50", CmdLFEM4X50, AlwaysAvailable, "EM 4x50 commands..."}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdLFEM(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdlfem4x.h b/client/src/cmdlfem.h similarity index 54% rename from client/src/cmdlfem4x.h rename to client/src/cmdlfem.h index 34801000e..c4f987b0e 100644 --- a/client/src/cmdlfem4x.h +++ b/client/src/cmdlfem.h @@ -1,11 +1,10 @@ //----------------------------------------------------------------------------- -// Copyright (C) 2010 iZsh -// 2016, 2017 marshmellow, iceman +// Copyright (C) 2020 iceman // 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 // the license. //----------------------------------------------------------------------------- -// Low frequency EM4x commands +// Low frequency EM commands //----------------------------------------------------------------------------- #ifndef CMDLFEM4X_H__ @@ -13,12 +12,6 @@ #include "common.h" -int CmdLFEM4X(const char *Cmd); - -int demodEM410x(bool verbose); -void printEM410x(uint32_t hi, uint64_t id); - -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); +int CmdLFEM(const char *Cmd); #endif diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c deleted file mode 100644 index 9c1c7e0a6..000000000 --- a/client/src/cmdlfem4x.c +++ /dev/null @@ -1,673 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2010 iZsh -// -// 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 -// the license. -//----------------------------------------------------------------------------- -// Low frequency EM4x commands -//----------------------------------------------------------------------------- - -#include "cmdlfem4x.h" -#include "cmdlfem4x05.h" -#include "cmdlfem4x50.h" - -#include -#include -#include -#include -#include - -#include "fileutils.h" -#include "cmdparser.h" // command_t -#include "comms.h" -#include "commonutil.h" -#include "common.h" -#include "util_posix.h" -#include "protocols.h" -#include "ui.h" -#include "proxgui.h" -#include "graph.h" -#include "cmddata.h" -#include "cmdlf.h" -#include "lfdemod.h" -#include "generator.h" -#include "cliparser.h" -#include "cmdhw.h" - -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 - * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID - * .... - * CCCC <-- each bit here is parity for the 10 bits above in corresponding column - * 0 <-- stop bit, end of tag - */ - -// Construct the graph for emulating an EM410X tag -static void ConstructEM410xEmulGraph(const char *uid, const uint8_t clock) { - - int i, j, binary[4], parity[4]; - uint32_t n; - /* clear our graph */ - ClearGraph(true); - - /* write 16 zero bit sledge */ - for (i = 0; i < 20; i++) - AppendGraph(false, clock, 0); - - /* write 9 start bits */ - for (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; - - /* append each bit */ - AppendGraph(false, clock, binary[0]); - AppendGraph(false, clock, binary[1]); - AppendGraph(false, clock, binary[2]); - AppendGraph(false, clock, binary[3]); - - /* append parity bit */ - AppendGraph(false, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); - - /* keep track of column parity */ - parity[0] ^= binary[0]; - parity[1] ^= binary[1]; - parity[2] ^= binary[2]; - parity[3] ^= binary[3]; - } - - /* parity columns */ - AppendGraph(false, clock, parity[0]); - AppendGraph(false, clock, parity[1]); - AppendGraph(false, clock, parity[2]); - AppendGraph(false, clock, parity[3]); - - /* stop bit */ - AppendGraph(true, clock, 0); -} - -//by marshmellow -//print 64 bit EM410x ID in multiple formats -void printEM410x(uint32_t hi, uint64_t id) { - - if (!id && !hi) return; - - PrintAndLogEx(SUCCESS, "EM410x%s pattern found", (hi) ? " XL" : ""); - - uint64_t n = 1; - uint64_t id2lo = 0; - uint8_t m, i; - for (m = 5; m > 0; m--) { - for (i = 0; i < 8; i++) { - id2lo = (id2lo << 1LL) | ((id & (n << (i + ((m - 1) * 8)))) >> (i + ((m - 1) * 8))); - } - } - - 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); - } 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, - (id2lo & 0xf000000000) >> 36, - (id2lo & 0x0f00000000) >> 32, - (id2lo & 0x00f0000000) >> 28, - (id2lo & 0x000f000000) >> 24, - (id2lo & 0x0000f00000) >> 20, - (id2lo & 0x00000f0000) >> 16, - (id2lo & 0x000000f000) >> 12, - (id2lo & 0x0000000f00) >> 8, - (id2lo & 0x00000000f0) >> 4, - (id2lo & 0x000000000f) - ); - 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); - - uint32_t p1id = (id & 0xFFFFFF); - uint8_t arr[32] = {0x00}; - int j = 23; - for (int k = 0 ; k < 24; ++k, --j) { - arr[k] = (p1id >> k) & 1; - } - - uint32_t p1 = 0; - - p1 |= arr[23] << 21; - p1 |= arr[22] << 23; - p1 |= arr[21] << 20; - p1 |= arr[20] << 22; - - p1 |= arr[19] << 18; - p1 |= arr[18] << 16; - p1 |= arr[17] << 19; - p1 |= arr[16] << 17; - - p1 |= arr[15] << 13; - p1 |= arr[14] << 15; - p1 |= arr[13] << 12; - p1 |= arr[12] << 14; - - p1 |= arr[11] << 6; - p1 |= arr[10] << 2; - p1 |= arr[9] << 7; - p1 |= arr[8] << 1; - - p1 |= arr[7] << 0; - p1 |= arr[6] << 8; - p1 |= arr[5] << 11; - p1 |= arr[4] << 3; - - p1 |= arr[3] << 10; - p1 |= arr[2] << 4; - p1 |= arr[1] << 5; - p1 |= arr[0] << 9; - PrintAndLogEx(NORMAL, "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); - } -} -/* Read the ID of an EM410x tag. - * Format: - * 1111 1111 1 <-- standard non-repeatable header - * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID - * .... - * CCCC <-- each bit here is parity for the 10 bits above in corresponding column - * 0 <-- stop bit, end of tag - */ -int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) { - size_t idx = 0; - uint8_t bits[512] = {0}; - size_t size = sizeof(bits); - if (!getDemodBuff(bits, &size)) { - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x problem during copy from ASK demod"); - return PM3_ESOFT; - } - - int ans = Em410xDecode(bits, &size, &idx, hi, lo); - if (ans < 0) { - - if (ans == -2) - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not enough samples after demod"); - else if (ans == -4) - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x preamble not found"); - else if (ans == -5) - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x Size not correct: %zu", size); - else if (ans == -6) - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x parity failed"); - - return PM3_ESOFT; - } - if (!lo && !hi) { - PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x decoded to all zeros"); - return PM3_ESOFT; - } - - //set GraphBuffer for clone or sim command - setDemodBuff(DemodBuffer, (size == 40) ? 64 : 128, idx + 1); - setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx + 1)*g_DemodClock)); - - PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %zu, Len: %zu, Printing Demod Buffer:", idx, size); - if (g_debugMode) { - printDemodBuff(0, false, false, true); - } - - if (verbose) - printEM410x(*hi, *lo); - - return PM3_SUCCESS; -} - -int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose) { - bool st = true; - - // em410x simulation etc uses 0/1 as signal data. This must be converted in order to demod it back again - if (isGraphBitstream()) { - convertGraphFromBitstream(); - } - if (ASKDemod_ext(clk, invert, maxErr, maxLen, amplify, false, false, 1, &st) != PM3_SUCCESS) - return PM3_ESOFT; - return AskEm410xDecode(verbose, hi, lo); -} - -// 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(); - - PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna"); - PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM410X_WATCH, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_EM410X_WATCH, &resp); - PrintAndLogEx(INFO, "Done"); - return resp.status; -} - -//by marshmellow -//takes 3 arguments - clock, invert and maxErr as integers -//attempts to demodulate ask while decoding manchester -//prints binary found and saves in graphbuffer for further commands -int demodEM410x(bool verbose) { - (void) verbose; // unused so far - uint32_t hi = 0; - uint64_t lo = 0; - return AskEm410xDemod(0, 0, 100, 0, false, &hi, &lo, true); -} - -static int CmdEM410xDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod(); - - 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) - 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(); - - 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); -} - -// 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(); - - uint8_t uid[5] = {0x00}; - - /* clock is 64 in EM410x tags */ - uint8_t clk = 64; - - if (param_gethex(Cmd, 0, uid, 10)) { - PrintAndLogEx(FAILED, "UID must include 10 HEX symbols"); - 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, "Press pm3-button to abort simulation"); - - ConstructEM410xEmulGraph(Cmd, clk); - - CmdLFSim("0"); //240 start_gap. - return PM3_SUCCESS; -} - -static int CmdEM410xBrute(const char *Cmd) { - 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; - - 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) { - PrintAndLogEx(ERR, "Error: Please specify a filename"); - return PM3_EINVARG; - } - - 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) { - fclose(f); - return PM3_ESOFT; - } - - while (fgets(buf, sizeof(buf), f)) { - if (strlen(buf) < 10 || buf[9] == '\n') continue; - while (fgetc(f) != '\n' && !feof(f)); //goto next line - - //The line start with # is comment, skip - if (buf[0] == '#') continue; - - if (param_gethex(buf, 0, uid, 10)) { - PrintAndLogEx(FAILED, "UIDs must include 10 HEX symbols"); - free(uidBlock); - fclose(f); - return PM3_ESOFT; - } - - buf[10] = 0; - - if (stUidBlock - uidcnt < 2) { - p = realloc(uidBlock, 5 * (stUidBlock += 10)); - if (!p) { - PrintAndLogEx(WARNING, "Cannot allocate memory for UIDs"); - free(uidBlock); - fclose(f); - return PM3_ESOFT; - } - uidBlock = p; - } - 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); - return PM3_ESOFT; - } - - PrintAndLogEx(SUCCESS, "Loaded "_YELLOW_("%d")" UIDs from "_YELLOW_("%s")", pause delay:"_YELLOW_("%d")" ms", uidcnt, filename, delay); - - // loop - 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); - 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); - - ConstructEM410xEmulGraph(testuid, clock1); - - CmdLFSim("0"); //240 start_gap. - - msleep(delay); - } - - free(uidBlock); - return PM3_SUCCESS; -} - -//currently only supports manchester modulations -static int CmdEM410xWatchnSpoof(const char *Cmd) { - - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_em410x_ws(); - - // loops if the captured ID was in XL-format. - CmdEM410xWatch(Cmd); - 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(); - - 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); - - // 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; - } - - // 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; - - // 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(); - return PM3_EINVARG; - } - - PrintAndLogEx(SUCCESS, "Writing " _YELLOW_("%s") " tag with UID 0x%010" PRIx64 " (clock rate: %d)", (card == 1) ? "T55x7" : "Q5/T5555", id, clock1); - // 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 - // the clock rate in bits 8-15 of the card value - - struct { - uint8_t card; - uint8_t clock; - uint32_t high; - uint32_t low; - } PACKED params; - - params.card = card; - params.clock = clock1; - params.high = (uint32_t)(id >> 32); - params.low = (uint32_t)id; - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM410X_WRITE, (uint8_t *)¶ms, sizeof(params)); - - PacketResponseNG resp; - WaitForResponse(CMD_LF_EM410X_WRITE, &resp); - switch (resp.status) { - case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") " to verify"); - break; - } - default: { - PrintAndLogEx(WARNING, "Something went wrong"); - break; - } - } - return resp.status; -} - -static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 410x") " -----------------------"}, - //{"410x_demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"}, - {"410x_demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"}, - {"410x_read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"410x_sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"}, - {"410x_brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, - {"410x_watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, - {"410x_spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"410x_clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, - {"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"}, - {"4x05_chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"}, - {"4x05_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"}, - {"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"}, - {"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"}, - {"4x05_info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"}, - {"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"}, - {"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"}, - {"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"}, - {"4x05_sniff", CmdEM4x05Sniff, AlwaysAvailable, "Attempt to recover em4x05 commands from sample buffer"}, - {"4x05_brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"}, - {"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"}, - {"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, - {"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, - {"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"}, - {"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, - {"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, - {NULL, NULL, NULL, NULL} -}; - -static int CmdHelp(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdsHelp(CommandTable); - return PM3_SUCCESS; -} - -int CmdLFEM4X(const char *Cmd) { - clearCommandBuffer(); - return CmdsParse(CommandTable, Cmd); -} diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 3b260ed2e..0f968d23d 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -38,59 +38,7 @@ #define EM_PREAMBLE_LEN 8 -static int usage_lf_em4x05_wipe(void) { - PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_wipe [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " c - chip type : 0 em4205"); - PrintAndLogEx(NORMAL, " 1 em4305 (default)"); - PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf em 4x05_wipe"); - PrintAndLogEx(NORMAL, " lf em 4x05_wipe 11223344"); - return PM3_SUCCESS; -} -static int usage_lf_em4x05_read(void) { - PrintAndLogEx(NORMAL, "Read EM4x05/EM4x69. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_read [h]
"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)"); - PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf em 4x05_read 1"); - PrintAndLogEx(NORMAL, " lf em 4x05_read 1 11223344"); - return PM3_SUCCESS; -} -static int usage_lf_em4x05_write(void) { - PrintAndLogEx(NORMAL, "Write EM4x05/4x69. Tag must be on antenna. "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_write [h]
"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " address - memory address to write to. (0-13, 99 for Protection Words)"); - PrintAndLogEx(NORMAL, " data - data to write (hex)"); - PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de"); - PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de 11223344"); - return PM3_SUCCESS; -} -static int usage_lf_em4x05_info(void) { - PrintAndLogEx(NORMAL, "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_info [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf em 4x05_info"); - PrintAndLogEx(NORMAL, " lf em 4x05_info deadc0de"); - return PM3_SUCCESS; -} +static int CmdHelp(const char *Cmd); // 1 = EM4x69 // 2 = EM4x05 @@ -140,7 +88,6 @@ static bool em4x05_col_parity_test(uint8_t *bs, size_t size, uint8_t rows, uint8 return true; } - // download samples from device and copy to Graphbuffer static bool em4x05_download_samples(void) { @@ -387,6 +334,7 @@ static bool em4x05_verify_write(uint8_t addr, uint32_t pwd, bool use_pwd, uint32 uint32_t r = 0; int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r); if (res == PM3_SUCCESS) { + PrintAndLogEx(INFO, "%08x == %08x", r, data); return (r == data); } return false; @@ -506,7 +454,40 @@ int em4x05_write_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t dat return PM3_SUCCESS; } +static int em4x05_protect(uint32_t pwd, bool use_pwd, uint32_t data) { + struct { + uint32_t password; + uint32_t data; + uint8_t usepwd; + } PACKED payload; + + payload.password = pwd; + payload.data = data; + payload.usepwd = use_pwd; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000)) { + PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); + return PM3_ETIMEOUT; + } + return PM3_SUCCESS; +} + int CmdEM4x05Demod(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05 demod", + "Try to find EM 4x05 preamble, if found decode / descramble data", + "lf em 4x05 demod" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); uint32_t dummy = 0; return em4x05_demod_resp(&dummy, false); } @@ -514,11 +495,11 @@ int CmdEM4x05Demod(const char *Cmd) { int CmdEM4x05Dump(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em dump", + CLIParserInit(&ctx, "lf em 4x05 dump", "Dump EM4x05/EM4x69. Tag must be on antenna.", - "lf em dump\n" - "lf em dump -p 11223344\n" - "lf em dump -f myfile -p 11223344" + "lf em 4x05 dump\n" + "lf em 4x05 dump -p 11223344\n" + "lf em 4x05 dump -f myfile -p 11223344" ); void *argtable[] = { @@ -734,29 +715,43 @@ int CmdEM4x05Dump(const char *Cmd) { } int CmdEM4x05Read(const char *Cmd) { - uint8_t addr; - uint32_t pwd; - bool usePwd = false; - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_read(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05 read", + "Read EM4x05/EM4x69. Tag must be on antenna.", + "lf em 4x05 read -a 1\n" + "lf em 4x05 read --addr 1 --pwd 11223344" + ); - addr = param_get8ex(Cmd, 0, 50, 10); - pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16); + void *argtable[] = { + arg_param_begin, + arg_int1("a", "addr", "", "memory address to read. (0-15)"), + arg_str0("p", "pwd", "", "optional - password, 4 bytes hex"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t addr = (uint8_t)arg_get_int_def(ctx, 1, 50); + uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 2, 0xFFFFFFFFFFFFFFFF); + CLIParserFree(ctx); + + uint32_t pwd = 0; + bool use_pwd = false; if (addr > 15) { - PrintAndLogEx(WARNING, "Address must be between 0 and 15"); - return PM3_ESOFT; + PrintAndLogEx(ERR, "Address must be between 0 and 15"); + return PM3_EINVARG; } - if (pwd == 0xFFFFFFFF) { + + if (inputpwd == 0xFFFFFFFFFFFFFFFF) { PrintAndLogEx(INFO, "Reading address %02u", addr); } else { - usePwd = true; + pwd = (inputpwd & 0xFFFFFFFF); + use_pwd = true; PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd); } uint32_t word = 0; - int status = em4x05_read_word_ext(addr, pwd, usePwd, &word); + int status = em4x05_read_word_ext(addr, pwd, use_pwd, &word); if (status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : ""); else if (status == PM3_EFAILED) @@ -767,55 +762,61 @@ int CmdEM4x05Read(const char *Cmd) { } int CmdEM4x05Write(const char *Cmd) { - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_write(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05 write", + "Write EM4x05/EM4x69. Tag must be on antenna.", + "lf em 4x05 write -a 1 -d deadc0de\n" + "lf em 4x05 write --addr 1 --pwd 11223344 --data deadc0de\n" + "lf em 4x05 write --po --pwd 11223344 --data deadc0de\n" + ); - bool usePwd = false; - uint8_t addr; - uint32_t data, pwd; - - addr = param_get8ex(Cmd, 0, 50, 10); - data = param_get32ex(Cmd, 1, 0, 16); - pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16); - bool protectOperation = addr == 99; // will do better with cliparser... - - if ((addr > 13) && (!protectOperation)) { + 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_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); + bool protect_operation = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if ((addr > 13) && (protect_operation == false)) { PrintAndLogEx(WARNING, "Address must be between 0 and 13"); return PM3_EINVARG; } + + bool use_pwd = false; + uint32_t pwd = ( inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0; if (pwd == 0xFFFFFFFF) { - if (protectOperation) + if (protect_operation) PrintAndLogEx(INFO, "Writing protection words data %08X", data); else PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data); } else { - usePwd = true; - if (protectOperation) + use_pwd = true; + 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); } - if (protectOperation) { // set Protect Words - struct { - uint32_t password; - uint32_t data; - uint8_t usepwd; - } PACKED payload; - - payload.password = pwd; - payload.data = data; - payload.usepwd = usePwd; - - clearCommandBuffer(); - SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000)) { - PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); - return PM3_ETIMEOUT; + int res = PM3_SUCCESS; + // set Protect Words + if (protect_operation) { + res = em4x05_protect(pwd, use_pwd, data); + if ( res != PM3_SUCCESS) { + return res; } } else { - em4x05_write_word_ext(addr, pwd, usePwd, data); + res = em4x05_write_word_ext(addr, pwd, use_pwd, data); + if ( res != PM3_SUCCESS) { + return res; + } } if (em4x05_download_samples() == false) @@ -826,86 +827,111 @@ int CmdEM4x05Write(const char *Cmd) { if (status == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Data written and verified"); else if (status == PM3_EFAILED) - PrintAndLogEx(ERR, "Tag denied %s operation", protectOperation ? "Protect" : "Write"); + PrintAndLogEx(ERR, "Tag denied %s operation", protect_operation ? "Protect" : "Write"); else PrintAndLogEx(DEBUG, "No answer from tag"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05 read`") " to verify"); return status; } int CmdEM4x05Wipe(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05 wipe", + "Wipe EM4x05/EM4x69. Tag must be on antenna.", + "lf em 4x05 wipe --4305 -p 11223344 -> wipe EM 4305 w pwd\n" + "lf em 4x05 wipe --4205 -> wipe EM 4205\n" + "lf em 4x05 wipe --4369 -> wipe EM 4369" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0(NULL, "4205", "target chip type EM 4205"), + arg_lit0(NULL, "4305", "target chip type EM 4305 (default)"), + arg_lit0(NULL, "4369", "target chip type EM 4369"), + arg_lit0(NULL, "4369", "target chip type EM 4469"), + arg_str0("p", "pwd", "", "optional - password, 4 bytes hex"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool target_4205 = arg_get_lit(ctx, 1); + bool target_4305 = arg_get_lit(ctx, 2); + bool target_4369 = arg_get_lit(ctx, 3); + bool target_4469 = arg_get_lit(ctx, 4); + uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 5, 0xFFFFFFFFFFFFFFFF); + CLIParserFree(ctx); + + uint8_t foo = target_4205 + target_4305 + target_4369 + target_4469; + + if (foo > 1) { + PrintAndLogEx(ERR, "Can't target multiple chip types at the same time"); + return PM3_EINVARG; + } + uint8_t addr = 0; + uint32_t chip_info = 0x00040072; // Chip info/User Block normal 4305 Chip Type + uint32_t chip_UID = 0x614739AE; // UID normally readonly, but just in case + uint32_t block_data = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1 + uint32_t config = 0x0001805F; // Default config (no password) + + if (target_4205) { + chip_info = 0x00040070; + } + if (target_4369) { + chip_info = 0x00020078; // found on HID Prox + } + if (target_4469) { +// chip_info = 0x00020078; // need to get a normal 4469 chip info block + } + + bool use_pwd = false; uint32_t pwd = 0; - uint8_t cmdp = 0; - uint8_t chipType = 1; // em4305 - uint32_t chipInfo = 0x00040072; // Chip info/User Block normal 4305 Chip Type - uint32_t chipUID = 0x614739AE; // UID normally readonly, but just in case - uint32_t blockData = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1 - uint32_t config = 0x0001805F; // Default config (no password) - int success = PM3_SUCCESS; - char cmdStr [100]; - char optchk[10]; - - while (param_getchar(Cmd, cmdp) != 0x00) { - // check if cmd is a 1 byte option - param_getstr(Cmd, cmdp, optchk, sizeof(optchk)); - if (strlen(optchk) == 1) { // Have a single character so option not part of password - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'c': // chip type - if (param_getchar(Cmd, cmdp) != 0x00) - chipType = param_get8ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'h': // return usage_lf_em4x05_wipe(); - default : // Unknown or 'h' send help - return usage_lf_em4x05_wipe(); - break; - }; - } else { // Not a single character so assume password - pwd = param_get32ex(Cmd, cmdp, 1, 16); - cmdp++; - } + if ( inputpwd != 0xFFFFFFFFFFFFFFFF) { + pwd = (inputpwd & 0xFFFFFFFF); + use_pwd = true; } - - switch (chipType) { - case 0 : // em4205 - chipInfo = 0x00040070; - config = 0x0001805F; - break; - case 1 : // em4305 - chipInfo = 0x00040072; - config = 0x0001805F; - break; - default : // Type 0/Default : EM4305 - chipInfo = 0x00040072; - config = 0x0001805F; - } - // block 0 : User Data or Chip Info - sprintf(cmdStr, "%d %08X %08X", 0, chipInfo, pwd); - CmdEM4x05Write(cmdStr); + int res = em4x05_write_word_ext(0, pwd, use_pwd, chip_info); + if ( res != PM3_SUCCESS) { + return res; + } + // block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others - sprintf(cmdStr, "%d %08X %08X", 1, chipUID, pwd); - CmdEM4x05Write(cmdStr); + res = em4x05_write_word_ext(1, pwd, use_pwd, chip_UID); + if ( res != PM3_SUCCESS) { + PrintAndLogEx(INFO, "UID block write failed"); + } + // block 2 : password - sprintf(cmdStr, "%d %08X %08X", 2, blockData, pwd); - CmdEM4x05Write(cmdStr); - pwd = blockData; // Password should now have changed, so use new password + res = em4x05_write_word_ext(2, pwd, use_pwd, block_data); + if ( res != PM3_SUCCESS) { + return res; + } + + // Password should now have changed, so use new password + pwd = block_data; // block 3 : user data - sprintf(cmdStr, "%d %08X %08X", 3, blockData, pwd); - CmdEM4x05Write(cmdStr); + res = em4x05_write_word_ext(3, pwd, use_pwd, block_data); + if ( res != PM3_SUCCESS) { + return res; + } + // block 4 : config - sprintf(cmdStr, "%d %08X %08X", 4, config, pwd); - CmdEM4x05Write(cmdStr); + res = em4x05_write_word_ext(4, pwd, use_pwd, config); + if ( res != PM3_SUCCESS) { + return res; + } // Remainder of user/data blocks for (addr = 5; addr < 14; addr++) {// Clear user data blocks - sprintf(cmdStr, "%d %08X %08X", addr, blockData, pwd); - CmdEM4x05Write(cmdStr); + res = em4x05_write_word_ext(addr, pwd, use_pwd, block_data); + if ( res != PM3_SUCCESS) { + return res; + } } - - return success; + return PM3_SUCCESS; } static const char *printEM4x05_known(uint32_t word) { @@ -1174,24 +1200,37 @@ static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) { } } - //quick test for EM4x05/EM4x69 tag bool em4x05_isblock0(uint32_t *word) { return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS); } int CmdEM4x05Info(const char *Cmd) { - uint32_t pwd; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05 info", + "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.", + "lf em 4x05 info\n" + "lf em 4x05 info -p 11223344" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("p", "pwd", "", "optional - password, 4 hex bytes"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 1, 0xFFFFFFFFFFFFFFFF); + CLIParserFree(ctx); + + bool use_pwd = false; + uint32_t pwd = 0; + if (inputpwd != 0xFFFFFFFFFFFFFFFF) { + pwd = inputpwd & 0xFFFFFFFF; + use_pwd = true; + } + uint32_t word = 0, block0 = 0, serial = 0; - bool usePwd = false; - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (ctmp == 'h') return usage_lf_em4x05_info(); - - // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) - pwd = param_get32ex(Cmd, 0, 0xFFFFFFFF, 16); - - if (pwd != 0xFFFFFFFF) - usePwd = true; // read word 0 (chip info) // block 0 can be read even without a password. @@ -1209,7 +1248,7 @@ int CmdEM4x05Info(const char *Cmd) { // read word 4 (config block) // needs password if one is set - if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) { + if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) { PrintAndLogEx(DEBUG, "(CmdEM4x05Info) failed to read CONFIG BLOCK"); return PM3_ESOFT; } @@ -1221,7 +1260,7 @@ int CmdEM4x05Info(const char *Cmd) { if (card_type == EM_4205 || card_type == EM_4305) { // read word 14 and 15 to see which is being used for the protection bits - if (em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) { + if (em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) { return PM3_ESOFT; } @@ -1229,7 +1268,7 @@ int CmdEM4x05Info(const char *Cmd) { printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK); return PM3_SUCCESS; } else { // if status bit says this is not the used protection word - if (em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) + if (em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) return PM3_ESOFT; if (word & 0x8000) { printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK); @@ -1238,7 +1277,7 @@ int CmdEM4x05Info(const char *Cmd) { } } else if (card_type == EM_4369 || card_type == EM_4469) { // read word 3 to see which is being used for the protection bits - if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) { + if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) { return PM3_ESOFT; } printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK); @@ -1259,11 +1298,11 @@ static bool is_cancelled(void) { int CmdEM4x05Chk(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x05_chk", + 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 000022B8 -> remember to use 0x for hex\n" - "lf em 4x05_chk -f t55xx_default_pwds -> use T55xx default dictionary" + "lf em 4x05 chk\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[] = { @@ -1360,12 +1399,12 @@ int CmdEM4x05Chk(const char *Cmd) { int CmdEM4x05Brute(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x05_brute", + CLIParserInit(&ctx, "lf em 4x05 brute", "This command tries to bruteforce the password of a EM4205/4305/4469/4569\n", "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 000022B8 -> remember to use 0x for hex" + "lf em 4x05 brute\n" + "lf em 4x05 brute -n 1 -> stop after first candidate found\n" + "lf em 4x05 brute -s 000022B8 -> remember to use 0x for hex" ); void *argtable[] = { @@ -1464,11 +1503,11 @@ static void unlock_add_item(em4x05_unlock_item_t *array, uint8_t len, uint32_t v int CmdEM4x05Unlock(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x05_unlock", + CLIParserInit(&ctx, "lf em 4x05 unlock", "execute tear off against EM4205/4305/4469/4569", - "lf em 4x05_unlock\n" - "lf em 4x05_unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n" - "lf em 4x05_unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us" + "lf em 4x05 unlock\n" + "lf em 4x05 unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n" + "lf em 4x05 unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us" ); void *argtable[] = { @@ -2082,3 +2121,29 @@ int CmdEM4x05Sniff(const char *Cmd) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"}, + {"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"}, + {"demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"}, + {"dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"}, + {"info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"}, + {"read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"}, + {"sniff", CmdEM4x05Sniff, AlwaysAvailable, "Attempt to recover em4x05 commands from sample buffer"}, + {"unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"}, + {"wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"}, + {"write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdLFEM4X05(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} \ No newline at end of file diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 2f768c62b..be0b17bb1 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1,6 +1,8 @@ //----------------------------------------------------------------------------- // Copyright (C) 2020 tharexde // +// 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 // the license. @@ -10,11 +12,14 @@ #include "cmdlfem4x50.h" #include +#include "cmdparser.h" // command_t #include "fileutils.h" #include "comms.h" #include "commonutil.h" #include "em4x50.h" +static int CmdHelp(const char *Cmd); + static int usage_lf_em4x50_info(void) { PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna."); PrintAndLogEx(NORMAL, ""); @@ -749,3 +754,25 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_SUCCESS; } + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, + {"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, + {"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, + {"write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"}, + {"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, + {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdLFEM4X50(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 01417aa1e..36e87ce70 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -14,6 +14,8 @@ #include"common.h" #include "em4x50.h" +int CmdLFEM4X50(const char *Cmd); + int read_em4x50_uid(void); bool detect_4x50_block(void); int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 4d85a78fd..4e1dc76cd 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -174,30 +174,11 @@ lf simfsk lf simpsk lf simbidir lf sniff -lf tune -lf em 410x_demod -lf em 410x_read -lf em 410x_sim -lf em 410x_brute -lf em 410x_watch -lf em 410x_spoof -lf em 410x_clone -lf em 4x05_demod -lf em 4x05_dump -lf em 4x05_wipe -lf em 4x05_info -lf em 4x05_read -lf em 4x05_write -lf em 4x50_dump -lf em 4x50_info -lf em 4x50_write -lf em 4x50_write_password -lf em 4x50_read -lf em 4x50_wipe -lf hitag info +lf em 410x +lf em 4x05 +lf em 4x50 lf hitag reader lf hitag sim -lf hitag sniff lf hitag writer lf hitag dump lf hitag cc diff --git a/doc/commands.md b/doc/commands.md index 6a9b61b40..f496ef3fe 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -572,34 +572,14 @@ Check column "offline" for their availability. ### lf em - { EM4X CHIPs & RFIDs... } + { EM CHIPs & RFIDs... } |command |offline |description |------- |------- |----------- |`lf em help `|Y |`This help` -|`lf em 410x_demod `|Y |`demodulate a EM410x tag from the GraphBuffer` -|`lf em 410x_read `|N |`attempt to read and extract tag data` -|`lf em 410x_sim `|N |`simulate EM410x tag` -|`lf em 410x_brute `|N |`reader bruteforce attack by simulating EM410x tags` -|`lf em 410x_watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)` -|`lf em 410x_spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)` -|`lf em 410x_clone `|N |`write EM410x UID to T55x7 or Q5/T5555 tag` -|`lf em 4x05_chk `|N |`Check passwords from dictionary` -|`lf em 4x05_demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer` -|`lf em 4x05_dump `|N |`dump EM4x05/EM4x69 tag` -|`lf em 4x05_wipe `|N |`wipe EM4x05/EM4x69 tag` -|`lf em 4x05_info `|N |`tag information EM4x05/EM4x69` -|`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69` -|`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69` -|`lf em 4x05_unlock `|N |`execute tear off against EM4x05/EM4x69` -|`lf em 4x05_sniff `|Y |`Attempt to recover em4x05 commands from sample buffer` -|`lf em 4x05_brute `|N |`Bruteforce password` -|`lf em 4x50_dump `|N |`dump EM4x50 tag` -|`lf em 4x50_info `|N |`tag information EM4x50` -|`lf em 4x50_write `|N |`write word data to EM4x50` -|`lf em 4x50_write_password`|N |`change password of EM4x50 tag` -|`lf em 4x50_read `|N |`read word data from EM4x50` -|`lf em 4x50_wipe `|N |`wipe data from EM4x50` +|`lf em 410x `|Y |`EM 410x commands...` +|`lf em 4x05 `|Y |`EM 4x05 commands...` +|`lf em 4x50 `|Y |`EM 4x50 commands...` ### lf fdxb