re-order the 'lf em' commands

This commit is contained in:
iceman1001 2020-12-04 00:11:57 +01:00
commit 00f91b2a00
12 changed files with 347 additions and 930 deletions

View file

@ -248,7 +248,8 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdlfawid.c ${PM3_ROOT}/client/src/cmdlfawid.c
${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfcotag.c
${PM3_ROOT}/client/src/cmdlfdestron.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/cmdlfem4x05.c
${PM3_ROOT}/client/src/cmdlfem4x50.c ${PM3_ROOT}/client/src/cmdlfem4x50.c
${PM3_ROOT}/client/src/cmdlffdxb.c ${PM3_ROOT}/client/src/cmdlffdxb.c

View file

@ -489,7 +489,8 @@ SRCS = aiddesfire.c \
cmdlfawid.c \ cmdlfawid.c \
cmdlfcotag.c \ cmdlfcotag.c \
cmdlfdestron.c \ cmdlfdestron.c \
cmdlfem4x.c \ cmdlfem.c \
cmdlfem410x.c \
cmdlfem4x05.c \ cmdlfem4x05.c \
cmdlfem4x50.c \ cmdlfem4x50.c \
cmdlffdxb.c \ cmdlffdxb.c \

View file

@ -23,7 +23,7 @@
#include "comms.h" #include "comms.h"
#include "lfdemod.h" // for demod code #include "lfdemod.h" // for demod code
#include "loclass/cipherutils.h" // for decimating samples in getsamples #include "loclass/cipherutils.h" // for decimating samples in getsamples
#include "cmdlfem4x.h" // askem410xdecode #include "cmdlfem410x.h" // askem410xdecode
#include "fileutils.h" // searchFile #include "fileutils.h" // searchFile
#include "mifare/ndef.h" #include "mifare/ndef.h"
#include "cliparser.h" #include "cliparser.h"

View file

@ -12,24 +12,23 @@
// Low frequency commands // Low frequency commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlf.h" #include "cmdlf.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "lfdemod.h" // device/client demods of LF signals #include "lfdemod.h" // device/client demods of LF signals
#include "ui.h" // for show graph controls #include "ui.h" // for show graph controls
#include "proxgui.h" #include "proxgui.h"
#include "cliparser.h" // args parsing
#include "graph.h" // for graph data #include "graph.h" // for graph data
#include "cmddata.h" // for `lf search` #include "cmddata.h" // for `lf search`
#include "cmdlfawid.h" // for awid menu #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 "cmdlfem4x05.h" // for em4x05 / 4x69
#include "cmdlfem4x50.h" // for em4x50 #include "cmdlfem4x50.h" // for em4x50
#include "cmdlfhid.h" // for hid menu #include "cmdlfhid.h" // for hid menu
@ -1530,7 +1529,7 @@ static command_t CommandTable[] = {
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"}, {"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"}, {"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"}, {"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... }"}, {"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"}, {"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"}, {"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},

41
client/src/cmdlfem.c Normal file
View file

@ -0,0 +1,41 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2020 iceman <iceman at icesql.net>
//
// 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 <inttypes.h>
#include <stdlib.h>
#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);
}

View file

@ -1,11 +1,10 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com> // Copyright (C) 2020 iceman <iceman at icesql.net>
// 2016, 2017 marshmellow, iceman
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Low frequency EM4x commands // Low frequency EM commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifndef CMDLFEM4X_H__ #ifndef CMDLFEM4X_H__
@ -13,12 +12,6 @@
#include "common.h" #include "common.h"
int CmdLFEM4X(const char *Cmd); int CmdLFEM(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);
#endif #endif

View file

@ -1,673 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
//
// 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 <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <stdlib.h>
#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] <id> <card> [clock]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " <id> - ID number");
PrintAndLogEx(NORMAL, " <card> - 0|1 0 = Q5/T5555, 1 = T55x7");
PrintAndLogEx(NORMAL, " <clock> - 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] <uid> <clock>");
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, &amp);
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, &amp);
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 *)&params, 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);
}

View file

@ -38,59 +38,7 @@
#define EM_PREAMBLE_LEN 8 #define EM_PREAMBLE_LEN 8
static int usage_lf_em4x05_wipe(void) { static int CmdHelp(const char *Cmd);
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_wipe [h] <pwd>");
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] <address> <pwd>");
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] <address> <data> <pwd>");
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] <pwd>");
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;
}
// 1 = EM4x69 // 1 = EM4x69
// 2 = EM4x05 // 2 = EM4x05
@ -140,7 +88,6 @@ static bool em4x05_col_parity_test(uint8_t *bs, size_t size, uint8_t rows, uint8
return true; return true;
} }
// download samples from device and copy to Graphbuffer // download samples from device and copy to Graphbuffer
static bool em4x05_download_samples(void) { 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; uint32_t r = 0;
int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r); int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "%08x == %08x", r, data);
return (r == data); return (r == data);
} }
return false; 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; 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) { 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; uint32_t dummy = 0;
return em4x05_demod_resp(&dummy, false); return em4x05_demod_resp(&dummy, false);
} }
@ -514,11 +495,11 @@ int CmdEM4x05Demod(const char *Cmd) {
int CmdEM4x05Dump(const char *Cmd) { int CmdEM4x05Dump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em dump", CLIParserInit(&ctx, "lf em 4x05 dump",
"Dump EM4x05/EM4x69. Tag must be on antenna.", "Dump EM4x05/EM4x69. Tag must be on antenna.",
"lf em dump\n" "lf em 4x05 dump\n"
"lf em dump -p 11223344\n" "lf em 4x05 dump -p 11223344\n"
"lf em dump -f myfile -p 11223344" "lf em 4x05 dump -f myfile -p 11223344"
); );
void *argtable[] = { void *argtable[] = {
@ -734,29 +715,43 @@ int CmdEM4x05Dump(const char *Cmd) {
} }
int CmdEM4x05Read(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)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_read(); 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); void *argtable[] = {
pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16); arg_param_begin,
arg_int1("a", "addr", "<dec>", "memory address to read. (0-15)"),
arg_str0("p", "pwd", "<hex>", "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) { if (addr > 15) {
PrintAndLogEx(WARNING, "Address must be between 0 and 15"); PrintAndLogEx(ERR, "Address must be between 0 and 15");
return PM3_ESOFT; return PM3_EINVARG;
} }
if (pwd == 0xFFFFFFFF) {
if (inputpwd == 0xFFFFFFFFFFFFFFFF) {
PrintAndLogEx(INFO, "Reading address %02u", addr); PrintAndLogEx(INFO, "Reading address %02u", addr);
} else { } else {
usePwd = true; pwd = (inputpwd & 0xFFFFFFFF);
use_pwd = true;
PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd); PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd);
} }
uint32_t word = 0; 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) if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : ""); PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
else if (status == PM3_EFAILED) else if (status == PM3_EFAILED)
@ -767,55 +762,61 @@ int CmdEM4x05Read(const char *Cmd) {
} }
int CmdEM4x05Write(const char *Cmd) { int CmdEM4x05Write(const char *Cmd) {
uint8_t ctmp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_write(); 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; void *argtable[] = {
uint8_t addr; arg_param_begin,
uint32_t data, pwd; arg_int0("a", "addr", "<dec>", "memory address to write to. (0-13)"),
arg_str1("d", "data", "<hex>", "data to write, 4 bytes hex"),
arg_str0("p", "pwd", "<hex>", "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);
addr = param_get8ex(Cmd, 0, 50, 10); if ((addr > 13) && (protect_operation == false)) {
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)) {
PrintAndLogEx(WARNING, "Address must be between 0 and 13"); PrintAndLogEx(WARNING, "Address must be between 0 and 13");
return PM3_EINVARG; return PM3_EINVARG;
} }
bool use_pwd = false;
uint32_t pwd = ( inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0;
if (pwd == 0xFFFFFFFF) { if (pwd == 0xFFFFFFFF) {
if (protectOperation) if (protect_operation)
PrintAndLogEx(INFO, "Writing protection words data %08X", data); PrintAndLogEx(INFO, "Writing protection words data %08X", data);
else else
PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data); PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data);
} else { } else {
usePwd = true; use_pwd = true;
if (protectOperation) if (protect_operation)
PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd); PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd);
else else
PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd); PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd);
} }
if (protectOperation) { // set Protect Words int res = PM3_SUCCESS;
struct { // set Protect Words
uint32_t password; if (protect_operation) {
uint32_t data; res = em4x05_protect(pwd, use_pwd, data);
uint8_t usepwd; if ( res != PM3_SUCCESS) {
} PACKED payload; return res;
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;
} }
} else { } 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) if (em4x05_download_samples() == false)
@ -826,86 +827,111 @@ int CmdEM4x05Write(const char *Cmd) {
if (status == PM3_SUCCESS) if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Data written and verified"); PrintAndLogEx(SUCCESS, "Data written and verified");
else if (status == PM3_EFAILED) 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 else
PrintAndLogEx(DEBUG, "No answer from tag"); 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; return status;
} }
int CmdEM4x05Wipe(const char *Cmd) { int CmdEM4x05Wipe(const char *Cmd) {
uint8_t addr = 0;
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) { CLIParserContext *ctx;
// check if cmd is a 1 byte option CLIParserInit(&ctx, "lf em 4x05 wipe",
param_getstr(Cmd, cmdp, optchk, sizeof(optchk)); "Wipe EM4x05/EM4x69. Tag must be on antenna.",
if (strlen(optchk) == 1) { // Have a single character so option not part of password "lf em 4x05 wipe --4305 -p 11223344 -> wipe EM 4305 w pwd\n"
switch (tolower(param_getchar(Cmd, cmdp))) { "lf em 4x05 wipe --4205 -> wipe EM 4205\n"
case 'c': // chip type "lf em 4x05 wipe --4369 -> wipe EM 4369"
if (param_getchar(Cmd, cmdp) != 0x00) );
chipType = param_get8ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2; void *argtable[] = {
break; arg_param_begin,
case 'h': // return usage_lf_em4x05_wipe(); arg_lit0(NULL, "4205", "target chip type EM 4205"),
default : // Unknown or 'h' send help arg_lit0(NULL, "4305", "target chip type EM 4305 (default)"),
return usage_lf_em4x05_wipe(); arg_lit0(NULL, "4369", "target chip type EM 4369"),
break; arg_lit0(NULL, "4369", "target chip type EM 4469"),
arg_str0("p", "pwd", "<hex>", "optional - password, 4 bytes hex"),
arg_param_end
}; };
} else { // Not a single character so assume password CLIExecWithReturn(ctx, Cmd, argtable, false);
pwd = param_get32ex(Cmd, cmdp, 1, 16);
cmdp++; 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;
} }
switch (chipType) { uint8_t addr = 0;
case 0 : // em4205 uint32_t chip_info = 0x00040072; // Chip info/User Block normal 4305 Chip Type
chipInfo = 0x00040070; uint32_t chip_UID = 0x614739AE; // UID normally readonly, but just in case
config = 0x0001805F; uint32_t block_data = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1
break; uint32_t config = 0x0001805F; // Default config (no password)
case 1 : // em4305
chipInfo = 0x00040072; if (target_4205) {
config = 0x0001805F; chip_info = 0x00040070;
break; }
default : // Type 0/Default : EM4305 if (target_4369) {
chipInfo = 0x00040072; chip_info = 0x00020078; // found on HID Prox
config = 0x0001805F; }
if (target_4469) {
// chip_info = 0x00020078; // need to get a normal 4469 chip info block
} }
bool use_pwd = false;
uint32_t pwd = 0;
if ( inputpwd != 0xFFFFFFFFFFFFFFFF) {
pwd = (inputpwd & 0xFFFFFFFF);
use_pwd = true;
}
// block 0 : User Data or Chip Info // block 0 : User Data or Chip Info
sprintf(cmdStr, "%d %08X %08X", 0, chipInfo, pwd); int res = em4x05_write_word_ext(0, pwd, use_pwd, chip_info);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
return res;
}
// block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others // block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others
sprintf(cmdStr, "%d %08X %08X", 1, chipUID, pwd); res = em4x05_write_word_ext(1, pwd, use_pwd, chip_UID);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "UID block write failed");
}
// block 2 : password // block 2 : password
sprintf(cmdStr, "%d %08X %08X", 2, blockData, pwd); res = em4x05_write_word_ext(2, pwd, use_pwd, block_data);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
pwd = blockData; // Password should now have changed, so use new password return res;
}
// Password should now have changed, so use new password
pwd = block_data;
// block 3 : user data // block 3 : user data
sprintf(cmdStr, "%d %08X %08X", 3, blockData, pwd); res = em4x05_write_word_ext(3, pwd, use_pwd, block_data);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
return res;
}
// block 4 : config // block 4 : config
sprintf(cmdStr, "%d %08X %08X", 4, config, pwd); res = em4x05_write_word_ext(4, pwd, use_pwd, config);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
return res;
}
// Remainder of user/data blocks // Remainder of user/data blocks
for (addr = 5; addr < 14; addr++) {// Clear user data blocks for (addr = 5; addr < 14; addr++) {// Clear user data blocks
sprintf(cmdStr, "%d %08X %08X", addr, blockData, pwd); res = em4x05_write_word_ext(addr, pwd, use_pwd, block_data);
CmdEM4x05Write(cmdStr); if ( res != PM3_SUCCESS) {
return res;
} }
}
return success; return PM3_SUCCESS;
} }
static const char *printEM4x05_known(uint32_t word) { 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 //quick test for EM4x05/EM4x69 tag
bool em4x05_isblock0(uint32_t *word) { bool em4x05_isblock0(uint32_t *word) {
return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS); return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS);
} }
int CmdEM4x05Info(const char *Cmd) { 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", "<hex>", "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; 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) // read word 0 (chip info)
// block 0 can be read even without a password. // block 0 can be read even without a password.
@ -1209,7 +1248,7 @@ int CmdEM4x05Info(const char *Cmd) {
// read word 4 (config block) // read word 4 (config block)
// needs password if one is set // 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"); PrintAndLogEx(DEBUG, "(CmdEM4x05Info) failed to read CONFIG BLOCK");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -1221,7 +1260,7 @@ int CmdEM4x05Info(const char *Cmd) {
if (card_type == EM_4205 || card_type == EM_4305) { if (card_type == EM_4205 || card_type == EM_4305) {
// read word 14 and 15 to see which is being used for the protection bits // 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; return PM3_ESOFT;
} }
@ -1229,7 +1268,7 @@ int CmdEM4x05Info(const char *Cmd) {
printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK); printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK);
return PM3_SUCCESS; return PM3_SUCCESS;
} else { // if status bit says this is not the used protection word } 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; return PM3_ESOFT;
if (word & 0x8000) { if (word & 0x8000) {
printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK); printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK);
@ -1238,7 +1277,7 @@ int CmdEM4x05Info(const char *Cmd) {
} }
} else if (card_type == EM_4369 || card_type == EM_4469) { } else if (card_type == EM_4369 || card_type == EM_4469) {
// read word 3 to see which is being used for the protection bits // 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; return PM3_ESOFT;
} }
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK); printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
@ -1259,11 +1298,11 @@ static bool is_cancelled(void) {
int CmdEM4x05Chk(const char *Cmd) { int CmdEM4x05Chk(const char *Cmd) {
CLIParserContext *ctx; 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", "This command uses a dictionary attack against EM4205/4305/4469/4569",
"lf em 4x05_chk\n" "lf em 4x05 chk\n"
"lf em 4x05_chk -e 000022B8 -> remember to use 0x for hex\n" "lf em 4x05 chk -e 000022B8 -> remember to use 0x for hex\n"
"lf em 4x05_chk -f t55xx_default_pwds -> use T55xx default dictionary" "lf em 4x05 chk -f t55xx_default_pwds -> use T55xx default dictionary"
); );
void *argtable[] = { void *argtable[] = {
@ -1360,12 +1399,12 @@ int CmdEM4x05Chk(const char *Cmd) {
int CmdEM4x05Brute(const char *Cmd) { int CmdEM4x05Brute(const char *Cmd) {
CLIParserContext *ctx; 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", "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" "Note: if you get many false positives, change position on the antenna"
"lf em 4x05_brute\n" "lf em 4x05 brute\n"
"lf em 4x05_brute -n 1 -> stop after first candidate found\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 -s 000022B8 -> remember to use 0x for hex"
); );
void *argtable[] = { 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) { int CmdEM4x05Unlock(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x05_unlock", CLIParserInit(&ctx, "lf em 4x05 unlock",
"execute tear off against EM4205/4305/4469/4569", "execute tear off against EM4205/4305/4469/4569",
"lf em 4x05_unlock\n" "lf em 4x05 unlock\n"
"lf em 4x05_unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\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 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us"
); );
void *argtable[] = { void *argtable[] = {
@ -2082,3 +2121,29 @@ int CmdEM4x05Sniff(const char *Cmd) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; 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);
}

View file

@ -1,6 +1,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020 tharexde // Copyright (C) 2020 tharexde
// //
// modified iceman, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
@ -10,11 +12,14 @@
#include "cmdlfem4x50.h" #include "cmdlfem4x50.h"
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t
#include "fileutils.h" #include "fileutils.h"
#include "comms.h" #include "comms.h"
#include "commonutil.h" #include "commonutil.h"
#include "em4x50.h" #include "em4x50.h"
static int CmdHelp(const char *Cmd);
static int usage_lf_em4x50_info(void) { static int usage_lf_em4x50_info(void) {
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna."); PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -749,3 +754,25 @@ int CmdEM4x50Wipe(const char *Cmd) {
return PM3_SUCCESS; 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);
}

View file

@ -14,6 +14,8 @@
#include"common.h" #include"common.h"
#include "em4x50.h" #include "em4x50.h"
int CmdLFEM4X50(const char *Cmd);
int read_em4x50_uid(void); int read_em4x50_uid(void);
bool detect_4x50_block(void); bool detect_4x50_block(void);
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose); int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose);

View file

@ -174,30 +174,11 @@ lf simfsk
lf simpsk lf simpsk
lf simbidir lf simbidir
lf sniff lf sniff
lf tune lf em 410x
lf em 410x_demod lf em 4x05
lf em 410x_read lf em 4x50
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 hitag reader lf hitag reader
lf hitag sim lf hitag sim
lf hitag sniff
lf hitag writer lf hitag writer
lf hitag dump lf hitag dump
lf hitag cc lf hitag cc

View file

@ -572,34 +572,14 @@ Check column "offline" for their availability.
### lf em ### lf em
{ EM4X CHIPs & RFIDs... } { EM CHIPs & RFIDs... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`lf em help `|Y |`This help` |`lf em help `|Y |`This help`
|`lf em 410x_demod `|Y |`demodulate a EM410x tag from the GraphBuffer` |`lf em 410x `|Y |`EM 410x commands...`
|`lf em 410x_read `|N |`attempt to read and extract tag data` |`lf em 4x05 `|Y |`EM 4x05 commands...`
|`lf em 410x_sim `|N |`simulate EM410x tag` |`lf em 4x50 `|Y |`EM 4x50 commands...`
|`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 fdxb ### lf fdxb