Merge branch 'master' into update_4x50

update 201130
This commit is contained in:
tharexde 2020-11-30 20:38:25 +01:00
commit efd6c04b7e
49 changed files with 5965 additions and 5685 deletions

View file

@ -251,7 +251,7 @@ print-%: ; @echo $* = $($*)
cliparser:
# Get list of all commands
cat doc/commands.md | grep -e ^\|\` | cut -f 2 -d "\`" | grep -v help | awk '{$$1=$$1};1' > cliparser_all_commands.tmp
cat doc/commands.md | grep -e ^\|\` | cut -f 2 -d "\`" | grep -v 'help\|list\|mem spiffs\|quit\|exit' | awk '{$$1=$$1};1' > cliparser_all_commands.tmp
# Get list of cliparserized commands
grep -r CLIParserInit ./client/src/ | cut -f 2 -d "\"" | awk '{$$1=$$1};1' > cliparser_done.tmp
# Determine commands that still need cliparser conversion

View file

@ -907,7 +907,13 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_LF_TI_WRITE: {
WriteTItag(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]);
struct p {
uint32_t high;
uint32_t low;
uint16_t crc;
} PACKED;
struct p *payload = (struct p *)packet->data.asBytes;
WriteTItag(payload->high, payload->low, packet->crc);
break;
}
case CMD_LF_SIMULATE: {

View file

@ -803,7 +803,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) {
AcquireTiType();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
DbpString("Now use `lf ti read` to check");
DbpString("Now use `lf ti reader` to check");
StopTicks();
}

View file

@ -4,8 +4,8 @@
typedef struct pm3_device pm3;
pm3 *pm3_open(char *port);
int pm3_console(pm3* dev, char *cmd);
const char *pm3_name_get(pm3* dev);
void pm3_close(pm3* dev);
int pm3_console(pm3 *dev, char *cmd);
const char *pm3_name_get(pm3 *dev);
void pm3_close(pm3 *dev);
pm3 *pm3_get_current_dev(void);
#endif // LIBPM3_H

View file

@ -3024,7 +3024,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
typedef struct {
uint8_t thread_idx;
uint8_t use_raw;
uint8_t use_raw;
uint8_t use_elite;
uint32_t keycnt;
uint8_t csn[8];
@ -3038,25 +3038,25 @@ typedef struct {
static size_t iclass_tc = 1;
static void* bf_generate_mac(void *thread_arg) {
static void *bf_generate_mac(void *thread_arg) {
iclass_thread_arg_t *targ = (iclass_thread_arg_t *)thread_arg;
const uint8_t idx = targ->thread_idx;
const uint8_t use_raw = targ->use_raw;
const uint8_t use_elite = targ->use_elite;
const uint32_t keycnt = targ->keycnt;
uint8_t *keys = targ->keys;
iclass_premac_t *list = targ->list.premac;
uint8_t csn[8];
uint8_t cc_nr[12];
memcpy(csn, targ->csn, sizeof(csn));
memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr));
uint8_t key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
for (uint32_t i = idx; i < keycnt; i += iclass_tc) {
memcpy(key, keys + 8 * i, 8);
@ -3080,14 +3080,14 @@ void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite,
// init thread arguments
for (uint8_t i = 0; i < iclass_tc; i++) {
args[i].thread_idx = i;
args[i].use_raw = use_raw;
args[i].use_raw = use_raw;
args[i].use_elite = use_elite;
args[i].keycnt = keycnt;
args[i].keys = keys;
args[i].list.premac = list;
memcpy(args[i].csn, CSN, sizeof(args[i].csn) );
memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr) );
memcpy(args[i].csn, CSN, sizeof(args[i].csn));
memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr));
}
for (int i = 0; i < iclass_tc; i++) {
@ -3103,22 +3103,22 @@ void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite,
pthread_join(threads[i], NULL);
}
static void* bf_generate_mackey(void *thread_arg) {
static void *bf_generate_mackey(void *thread_arg) {
iclass_thread_arg_t *targ = (iclass_thread_arg_t *)thread_arg;
const uint8_t idx = targ->thread_idx;
const uint8_t use_raw = targ->use_raw;
const uint8_t use_elite = targ->use_elite;
const uint32_t keycnt = targ->keycnt;
uint8_t *keys = targ->keys;
iclass_prekey_t *list = targ->list.prekey;
uint8_t csn[8];
uint8_t cc_nr[12];
memcpy(csn, targ->csn, sizeof(csn));
memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr));
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
for (uint32_t i = idx; i < keycnt; i += iclass_tc) {
@ -3143,14 +3143,14 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit
// init thread arguments
for (uint8_t i = 0; i < iclass_tc; i++) {
args[i].thread_idx = i;
args[i].use_raw = use_raw;
args[i].use_raw = use_raw;
args[i].use_elite = use_elite;
args[i].keycnt = keycnt;
args[i].keys = keys;
args[i].list.prekey = list;
memcpy(args[i].csn, CSN, sizeof(args[i].csn) );
memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr) );
memcpy(args[i].csn, CSN, sizeof(args[i].csn));
memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr));
}
for (int i = 0; i < iclass_tc; i++) {
@ -3164,7 +3164,7 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit
for (int i = 0; i < iclass_tc; i++)
pthread_join(threads[i], NULL);
PrintAndLogEx(NORMAL, "");
}

View file

@ -13,6 +13,7 @@
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "cliparser.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "cmdtrace.h"
@ -36,62 +37,6 @@
static int CmdHelp(const char *Cmd);
static int usage_lto_info(void) {
PrintAndLogEx(NORMAL, "Usage: hf lto info [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto info"));
return PM3_SUCCESS;
}
static int usage_lto_rdbl(void) {
PrintAndLogEx(NORMAL, "Usage: hf lto rdbl [h] s <start block> e <end block>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " s start block in decimal >= 0");
PrintAndLogEx(NORMAL, " e end block in decimal <= 254");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto rdbl s 0 e 254") " - Read data block from 0 to 254");
return PM3_SUCCESS;
}
static int usage_lto_wrbl(void) {
PrintAndLogEx(NORMAL, "Usage: hf lto wrbl [h] b <block> d <data>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " b block address (decimal, 0 - 254) ");
PrintAndLogEx(NORMAL, " d 32 bytes of data to write (64 hex characters, no space)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto wrbl b 128 d 0001020304050607080910111213141516171819202122232425262728293031") " - write 00..31 to block address 128");
return PM3_SUCCESS;
}
static int usage_lto_dump(void) {
PrintAndLogEx(NORMAL, "Usage: hf lto dump [h|p] f <filename>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " f file name");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto dump f myfile"));
return PM3_SUCCESS;
}
static int usage_lto_restore(void) {
PrintAndLogEx(NORMAL, "Usage: hf lto restore [h] f <filename>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " f file name [.bin|.eml]");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto restore f hf_lto_92C7842CFF.bin|.eml"));
return PM3_SUCCESS;
}
static void lto_switch_off_field(void) {
SendCommandMIX(CMD_HF_ISO14443A_READER, 0, 0, 0, NULL, 0);
}
@ -173,24 +118,16 @@ static int lto_select(uint8_t *id_response, uint8_t id_len, uint8_t *type_respon
}
static int CmdHfLTOInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto info",
"Get info from LTO tags",
"hf lto info");
uint8_t cmdp = 0;
bool errors = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lto_info();
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors) {
return usage_lto_info();
}
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
return infoLTO(true);
}
@ -304,48 +241,31 @@ int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose) {
}
static int CmdHfLTOReadBlock(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto rdbl",
"Reead blocks from LTO tag",
"hf lto rdbl --first 0 --last 254");
uint8_t cmdp = 0;
bool errors = false;
uint8_t st_blk = 0;
uint8_t end_blk = 254;
void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "first", "<dec>", "The first block number to read as an integer"),
arg_int0(NULL, "last", "<dec>", "The last block number to read as an integer"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lto_rdbl();
case 's':
st_blk = param_get8(Cmd, cmdp + 1);
if (end_blk < st_blk) {
errors = true;
break;
}
cmdp += 2;
break;
int startblock = arg_get_int_def(ctx, 1, 0);
int endblock = arg_get_int_def(ctx, 2, 254);
case 'e':
end_blk = param_get8(Cmd, cmdp + 1);
if (end_blk < st_blk) {
errors = true;
break;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
CLIParserFree(ctx);
//Validations
if (errors) {
usage_lto_rdbl();
if (endblock < startblock) {
PrintAndLogEx(ERR, "First block must be less than last block");
return PM3_EINVARG;
}
return rdblLTO(st_blk, end_blk, true);
return rdblLTO(startblock, endblock, true);
}
static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) {
@ -407,46 +327,33 @@ int wrblLTO(uint8_t blk, uint8_t *data, bool verbose) {
}
static int CmdHfLTOWriteBlock(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto wrbl",
"Write data to block on LTO tag",
"hf lto wrbl --block 128 -d 0001020304050607080910111213141516171819202122232425262728293031");
uint8_t cmdp = 0;
bool errors = false;
bool b_opt_selected = false;
bool d_opt_selected = false;
uint8_t blk = 128;
void *argtable[] = {
arg_param_begin,
arg_str1("d", "data", "<hex>", "32 bytes of data to write (64 hex symbols, no spaces)"),
arg_int1(NULL, "block", "<dec>", "The block number to write to as an integer"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int block_data_len = 0;
uint8_t block_data[32] = {0};
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lto_wrbl();
case 'b':
blk = param_get8(Cmd, cmdp + 1);
b_opt_selected = true;
cmdp += 2;
break;
case 'd':
if (param_gethex(Cmd, cmdp + 1, block_data, 64)) {
PrintAndLogEx(WARNING, "block data must include 64 HEX symbols");
errors = true;
break;
}
d_opt_selected = true;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
CLIGetHexWithReturn(ctx, 1, block_data, &block_data_len);
if (block_data_len != 32) {
PrintAndLogEx(ERR, "Block data is incorrect length");
CLIParserFree(ctx);
return PM3_EINVARG;
}
//Validations
if (errors) {
return usage_lto_wrbl();
} else if (b_opt_selected == false || d_opt_selected == false) {
PrintAndLogEx(WARNING, "Need to specify block address and data.");
return usage_lto_wrbl();
}
int blk = arg_get_int_def(ctx, 2, 0);
CLIParserFree(ctx);
int res = wrblLTO(blk, block_data, true);
if (res == PM3_SUCCESS)
@ -504,35 +411,25 @@ int dumpLTO(uint8_t *dump, bool verbose) {
}
static int CmdHfLTODump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto dump",
"Dump data from LTO tag",
"hf lto dump -f myfile");
uint8_t cmdp = 0;
bool errors = false;
uint32_t dump_len = CM_MEM_MAX_SIZE;
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<filename>", "specify a filename for dumpfile"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lto_dump();
case 'f':
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
PrintAndLogEx(FAILED, "filename too long");
errors = true;
break;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
CLIParserFree(ctx);
if (errors) {
usage_lto_dump();
return PM3_EINVARG;
}
uint32_t dump_len = CM_MEM_MAX_SIZE;
uint8_t *dump = calloc(dump_len, sizeof(uint8_t));
if (!dump) {
@ -596,32 +493,23 @@ int restoreLTO(uint8_t *dump, bool verbose) {
}
static int CmdHfLTRestore(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto restore",
"Restore data from dumpfile to LTO tag",
"hf lto restore -f hf-lto-92C7842CFF.bin|.eml");
uint8_t cmdp = 0;
bool errors = false;
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<filename>", "specify a filename for dumpfile"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lto_restore();
case 'f':
param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (strlen(filename) < 5)
errors = true;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors || strlen(Cmd) == 0) {
return usage_lto_restore();
}
CLIParserFree(ctx);
size_t dump_len = 0;
char *lowstr = str_dup(filename);

View file

@ -266,7 +266,17 @@ static int get_plus_version(uint8_t *version, int *version_len) {
}
static int CmdHFMFPInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp info",
"Get info from MIFARE Plus tags",
"hf mfp info");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");

View file

@ -10,97 +10,28 @@
// Low frequency AWID26/50 commands
// FSK2a, RF/50, 96 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfawid.h" // AWID function declarations
#include "cmdlfawid.h" // AWID function declarations
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
#include "graph.h"
#include "cmddata.h"
#include "ui.h" // PrintAndLog
#include "lfdemod.h" // parityTest
#include "cmdlf.h" // lf read
#include "protocols.h" // for T55xx config register definitions
#include "ui.h" // PrintAndLog
#include "lfdemod.h" // parityTest
#include "cmdlf.h" // lf read
#include "protocols.h" // for T55xx config register definitions
#include "util_posix.h"
#include "cmdlft55xx.h" // verifywrite
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd);
static int usage_lf_awid_watch(void) {
PrintAndLogEx(NORMAL, "Enables AWID compatible reader mode printing details of scanned AWID26 or AWID50 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 awid watch");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid watch"));
return PM3_SUCCESS;
}
static int usage_lf_awid_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of AWID card with specified facility-code and card number.");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf awid sim [h] <format> <facility-code> <card-number>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <format> : format length 26|34|37|50");
PrintAndLogEx(NORMAL, " <facility-code> : 8|16bit value facility code");
PrintAndLogEx(NORMAL, " <card number> : 16|32-bit value card number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid sim 26 224 1337"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid sim 50 2001 13371337"));
return PM3_SUCCESS;
}
static int usage_lf_awid_clone(void) {
PrintAndLogEx(NORMAL, "Enables cloning of AWID card with specified facility-code and card number onto T55x7 or Q5/T5555.");
PrintAndLogEx(NORMAL, "The T55x7 must be on the antenna when issuing this command. T55x7 blocks are calculated and printed in the process.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf awid clone [h] <format> <facility-code> <card-number> [Q5]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <format> : format length 26|34|37|50");
PrintAndLogEx(NORMAL, " <facility-code> : 8|16bit value facility code");
PrintAndLogEx(NORMAL, " <card number> : 16|32-bit value card number");
PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid clone 26 224 1337"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid clone 50 2001 13371337"));
return PM3_SUCCESS;
}
static int usage_lf_awid_brute(void) {
PrintAndLogEx(NORMAL, "Enables bruteforce of AWID reader with specified facility-code.");
PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step");
PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf awid brute [h] [v] a <format> f <facility-code> c <cardnumber> d <delay>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " a <format> : format length 26|50");
PrintAndLogEx(NORMAL, " f <facility-code> : 8|16bit value facility code");
PrintAndLogEx(NORMAL, " c <cardnumber> : (optional) cardnumber to start with, max 65535");
PrintAndLogEx(NORMAL, " d <delay> : delay betweens attempts in ms. Default 1000ms");
PrintAndLogEx(NORMAL, " v : verbose logging, show all tries");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute a 26 f 224"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute a 50 f 2001 d 2000"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute v a 50 f 2001 c 200 d 2000"));
return PM3_SUCCESS;
}
static int sendPing(void) {
SendCommandNG(CMD_PING, NULL, 0);
SendCommandNG(CMD_PING, NULL, 0);
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
SendCommandNG(CMD_PING, NULL, 0);
clearCommandBuffer();
PacketResponseNG resp;
@ -112,7 +43,7 @@ static int sendPing(void) {
static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose) {
if (verbose)
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn);
PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fc, cn);
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
@ -180,8 +111,19 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn) {
// this read loops on device side.
// uses the demod in lfops.c
static int CmdAWIDWatch(const char *Cmd) {
uint8_t c = tolower(param_getchar(Cmd, 0));
if (c == 'h') return usage_lf_awid_watch();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid watch",
"Enables AWID compatible reader mode printing details of scanned AWID26 or AWID50 tags.\n"
"Run until the button is pressed or another USB command is issued.",
"lf awid watch"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(SUCCESS, "Watching for AWID cards - place tag on antenna");
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
@ -339,31 +281,152 @@ int demodAWID(bool verbose) {
}
static int CmdAWIDDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid demod",
"Try to find AWID Prox preamble, if found decode / descramble data",
"lf awid demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodAWID(true);
}
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdAWIDRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 12000);
return demodAWID(true);
static int CmdAWIDReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid reader",
"read a AWID Prox tag",
"lf awid reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 12000);
demodAWID(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdAWIDClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid clone",
"clone a AWID Prox tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
"lf awid clone --fmt 26 --fc 123 --cn 1337\n"
"lf awid clone --fmt 50 --fc 2001 --cn 13371337\n"
"lf awid clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
"lf awid clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
);
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|34|37|50"),
arg_u64_1(NULL, "fc", "<dec>", "8|16bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "16|32-bit value card number"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
bool q5 = arg_get_lit(ctx, 4);
bool em = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
uint32_t blocks[4] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
char cardtype[16] = {"T55x7"};
// Q5
if (q5) {
//t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_AWID_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
verify_values(&fmtlen, &fc, &cn);
uint8_t *bits = calloc(96, sizeof(uint8_t));
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT;
}
blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 32);
blocks[3] = bytebits_to_byte(bits + 64, 32);
free(bits);
PrintAndLogEx(INFO, "Preparing to clone AWID %u to " _YELLOW_("%s") " with FC: " _GREEN_("%u") " CN: " _GREEN_("%u"), fmtlen, cardtype, fc, cn);
print_blocks(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid reader`") " to verify");
return res;
}
static int CmdAWIDSim(const char *Cmd) {
uint32_t fc = 0, cn = 0;
uint8_t fmtlen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid sim",
"Enables simulation of AWID card with specified facility-code and card number.\n"
"Simulation runs until the button is pressed or another USB command is issued.",
"lf awid sim --fmt 26 --fc 123 --cn 1337\n"
"lf awid sim --fmt 50 --fc 2001 --cn 13371337"
);
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
CLIParserFree(ctx);
uint8_t bs[96];
memset(bs, 0x00, sizeof(bs));
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_sim();
fmtlen = param_get8(Cmd, 0);
fc = param_get32ex(Cmd, 1, 0, 10);
cn = param_get32ex(Cmd, 2, 0, 10);
if (!fc || !cn) return usage_lf_awid_sim();
verify_values(&fmtlen, &fc, &cn);
if (getAWIDBits(fmtlen, fc, cn, bs) != PM3_SUCCESS) {
@ -371,7 +434,7 @@ static int CmdAWIDSim(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn);
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn);
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
// AWID uses: FSK2a fcHigh: 10, fcLow: 8, clk: 50, invert: 1
@ -398,97 +461,34 @@ static int CmdAWIDSim(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdAWIDClone(const char *Cmd) {
uint32_t fc = 0, cn = 0;
uint8_t fmtlen = 0;
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_clone();
fmtlen = param_get8(Cmd, 0);
fc = param_get32ex(Cmd, 1, 0, 10);
cn = param_get32ex(Cmd, 2, 0, 10);
if (!fc || !cn) return usage_lf_awid_clone();
uint32_t blocks[4] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
if (q5)
//t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
verify_values(&fmtlen, &fc, &cn);
uint8_t *bits = calloc(96, sizeof(uint8_t));
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT;
}
blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 32);
blocks[3] = bytebits_to_byte(bits + 64, 32);
free(bits);
PrintAndLogEx(INFO, "Preparing to clone AWID %u to " _YELLOW_("%s") " with FC: %u, CN: %u", fmtlen, (q5) ? "Q5/T5555" : "T55x7", fc, cn);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid read`") " to verify");
return res;
}
static int CmdAWIDBrute(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf awid brute",
"Enables bruteforce of AWID reader with specified facility-code.\n"
"This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step\n"
"if cardnumber is not given, it starts with 1 and goes up to 65535",
"lf awid brute --fmt 26 --fc 224\n"
"lf awid brute --fmt 50 --fc 2001 --delay 2000\n"
"lf awid brute --fmt 50 --fc 2001 --cn 200 --delay 2000 -v"
);
bool errors = false, verbose = false;
uint32_t fc = 0, cn = 0, delay = 1000;
uint8_t fmtlen = 0;
uint8_t bits[96];
size_t size = sizeof(bits);
memset(bits, 0x00, size);
uint8_t cmdp = 0;
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|50"),
arg_u64_1(NULL, "fc", "<dec>", "8|16bit value facility code"),
arg_u64_0(NULL, "cn", "<dec>", "optional - card number to start with, max 65535"),
arg_u64_0(NULL, "delay", "<dec>", "optional - delay betweens attempts in ms. Default 1000ms"),
arg_lit0("v", "verbose", "verbose logging, show all tries"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_awid_brute();
case 'f':
fc = param_get32ex(Cmd, cmdp + 1, 0, 10);
if (!fc)
errors = true;
cmdp += 2;
break;
case 'd':
// delay between attemps, defaults to 1000ms.
delay = param_get32ex(Cmd, cmdp + 1, 1000, 10);
cmdp += 2;
break;
case 'c':
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
// truncate cardnumber.
cn &= 0xFFFF;
cmdp += 2;
break;
case 'a':
fmtlen = param_get8(Cmd, cmdp + 1);
cmdp += 2;
break;
case 'v':
verbose = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (fc == 0) errors = true;
if (errors) return usage_lf_awid_brute();
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
uint32_t delay = arg_get_u32_def(ctx, 4, 1000);
bool verbose = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
// limit fc according to selected format
switch (fmtlen) {
@ -506,12 +506,23 @@ static int CmdAWIDBrute(const char *Cmd) {
break;
}
PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d Reader", fmtlen);
// truncate card number
if ((cn & 0xFFFF) != cn) {
cn &= 0xFFFF;
PrintAndLogEx(INFO, "Card number truncated to 16-bits : %u", cn);
}
PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d reader", fmtlen);
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or press Enter");
uint16_t up = cn;
uint16_t down = cn;
uint8_t bits[96];
size_t size = sizeof(bits);
memset(bits, 0x00, size);
// main loop
for (;;) {
@ -525,13 +536,20 @@ static int CmdAWIDBrute(const char *Cmd) {
}
// Do one up
if (up < 0xFFFF)
if (sendTry(fmtlen, fc, up++, delay, bits, size, verbose) != PM3_SUCCESS) return PM3_ESOFT;
if (up < 0xFFFF) {
if (sendTry(fmtlen, fc, up++, delay, bits, size, verbose) != PM3_SUCCESS) {
return PM3_ESOFT;
}
}
// Do one down (if cardnumber is given)
if (cn > 1)
if (down > 1)
if (sendTry(fmtlen, fc, --down, delay, bits, size, verbose) != PM3_SUCCESS) return PM3_ESOFT;
if (cn > 1) {
if (down > 1) {
if (sendTry(fmtlen, fc, --down, delay, bits, size, verbose) != PM3_SUCCESS) {
return PM3_ESOFT;
}
}
}
}
return PM3_SUCCESS;
}
@ -539,7 +557,7 @@ static int CmdAWIDBrute(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdAWIDDemod, AlwaysAvailable, "demodulate an AWID FSK tag from the GraphBuffer"},
{"read", CmdAWIDRead, IfPm3Lf, "attempt to read and extract tag data"},
{"reader", CmdAWIDReader, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7 or Q5/T5555"},
{"sim", CmdAWIDSim, IfPm3Lf, "simulate AWID tag"},
{"brute", CmdAWIDBrute, IfPm3Lf, "Bruteforce card number against reader"},

View file

@ -8,33 +8,18 @@
// Low frequency COTAG commands
//-----------------------------------------------------------------------------
#include "cmdlfcotag.h" // COTAG function declarations
#include <string.h>
#include <stdio.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "lfdemod.h"
#include "cmddata.h" // getSamples
#include "ui.h" // PrintAndLog
#include "ctype.h" // tolower
#include "cliparser.h"
static int CmdHelp(const char *Cmd);
static int usage_lf_cotag_read(void) {
PrintAndLogEx(NORMAL, "Usage: lf COTAG read [h] <signaldata>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <0|1|2> : 0 - HIGH/LOW signal; maxlength bigbuff");
PrintAndLogEx(NORMAL, " : 1 - translation of HI/LO into bytes with manchester 0,1");
PrintAndLogEx(NORMAL, " : 2 - raw signal; maxlength bigbuff");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " lf cotag read 0");
PrintAndLogEx(NORMAL, " lf cotag read 1");
return PM3_SUCCESS;
}
// COTAG demod should be able to use GraphBuffer,
// when data load samples
int demodCOTAG(bool verbose) {
@ -74,22 +59,63 @@ int demodCOTAG(bool verbose) {
}
static int CmdCOTAGDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf cotag demod",
"Try to find COTAG preamble, if found decode / descramble data",
"lf cotag demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodCOTAG(true);
}
// When reading a COTAG.
// 0 = HIGH/LOW signal - maxlength bigbuff
// 1 = translation for HI/LO into bytes with manchester 0,1 - length 300
// 2 = raw signal - maxlength bigbuff
static int CmdCOTAGRead(const char *Cmd) {
static int CmdCOTAGReader(const char *Cmd) {
if (tolower(Cmd[0]) == 'h')
return usage_lf_cotag_read();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf cotag reader",
"read a COTAG tag, the current support for COTAG is limited. ",
"lf cotag reader -2"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("1", NULL, "HIGH/LOW signal; maxlength bigbuff"),
arg_lit0("2", NULL, "translation of HIGH/LOW into bytes with manchester 0,1"),
arg_lit0("3", NULL, "raw signal; maxlength bigbuff"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool mode0 = arg_get_lit(ctx, 1);
bool mode1 = arg_get_lit(ctx, 2);
bool mode2 = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
if ((mode0 + mode1 + mode2) > 1) {
PrintAndLogEx(ERR, "You can only use one option at a time");
return PM3_EINVARG;
}
uint8_t mode = 0xFF;
if (mode0)
mode = 0;
if (mode1)
mode = 1;
if (mode2)
mode = 2;
struct p {
uint8_t mode;
} PACKED payload;
payload.mode = param_get8ex(Cmd, 0, 1, 10);
payload.mode = mode;
PacketResponseNG resp;
clearCommandBuffer();
@ -126,9 +152,9 @@ static int CmdCOTAGRead(const char *Cmd) {
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdCOTAGDemod, AlwaysAvailable, "Tries to decode a COTAG signal"},
{"read", CmdCOTAGRead, IfPm3Lf, "Attempt to read and extract tag data"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdCOTAGDemod, AlwaysAvailable, "Tries to decode a COTAG signal"},
{"reader", CmdCOTAGReader, IfPm3Lf, "Attempt to read and extract tag data"},
{NULL, NULL, NULL, NULL}
};
@ -144,5 +170,5 @@ int CmdLFCOTAG(const char *Cmd) {
}
int readCOTAGUid(void) {
return (CmdCOTAGRead("") == PM3_SUCCESS);
return (CmdCOTAGReader("") == PM3_SUCCESS);
}

View file

@ -7,22 +7,22 @@
// Low frequency FDX-A FECAVA Destron tag commands
//-----------------------------------------------------------------------------
#include "cmdlfdestron.h"
#include <ctype.h> //tolower
#include <string.h> // memcpy
#include "commonutil.h" // ARRAYLEN
#include <ctype.h> // tolower
#include <string.h> // memcpy
#include "commonutil.h" // ARRAYLEN
#include "common.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cmdlf.h" // cmdlfconfig
#include "cliparser.h" // cli parse input
#include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cmdlf.h" // cmdlfconfig
#include "parity.h"
#include "cliparser.h" // cli parse input
#include "cmdlfem4x05.h" // EM defines
#define DESTRON_FRAME_SIZE 96
#define DESTRON_PREAMBLE_SIZE 16
@ -36,6 +36,7 @@ int demodDestron(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: FSK Demod failed");
return PM3_ESOFT;
}
size_t size = DemodBufferLen;
int ans = detectDestron(DemodBuffer, &size);
if (ans < 0) {
@ -50,12 +51,13 @@ int demodDestron(bool verbose) {
return PM3_ESOFT;
}
setDemodBuff(DemodBuffer, DESTRON_FRAME_SIZE, ans);
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
uint8_t bits[DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE] = {0};
size_t bitlen = DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE;
memcpy(bits, DemodBuffer + 16, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
memcpy(bits, DemodBuffer + DESTRON_PREAMBLE_SIZE, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
uint8_t alignPos = 0;
uint16_t errCnt = manrawdecode(bits, &bitlen, 0, &alignPos);
@ -75,75 +77,155 @@ int demodDestron(bool verbose) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: parity errors: %d", parity_err);
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%02X%02X%02X%02X%02X"), data[0], data[1], data[2], data[3], data[4]);
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%s"), sprint_hex_inrow(data, 5));
return PM3_SUCCESS;
}
static int CmdDestronDemod(const char *Cmd) {
(void)Cmd;
return demodDestron(true);
}
static int CmdDestronRead(const char *Cmd) {
lf_read(false, 16000);
return demodDestron(true);
}
static int CmdDestronClone(const char *Cmd) {
uint32_t blocks[4] = {0};
uint8_t data[8];
int datalen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf destron clone",
"Enables cloning of Destron card with specified uid onto T55x7",
"lf destron clone 1A2B3C4D5E"
CLIParserInit(&ctx, "lf destron demod",
"Try to find Destron preamble, if found decode / descramble data",
"lf destron demod"
);
void *argtable[] = {
arg_param_begin,
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodDestron(true);
}
static int CmdDestronReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf destron reader",
"read a Destron tag",
"lf destron reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 16000);
demodDestron(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdDestronClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf destron clone",
"clone a Destron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf destron clone --uid 1A2B3C4D5E\n"
"lf destron clone --q5 --uid 1A2B3C4D5E -> encode for Q5/T5555 tag\n"
"lf destron clone --em --uid 1A2B3C4D5E -> encode for EM4305/4469"
);
void *argtable[] = {
arg_param_begin,
arg_strx1("u", "uid", "<hex>", "5 bytes max"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
//TODO add selection of chip for Q5 or T55x7
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t data[8];
int datalen = 0;
CLIGetHexWithReturn(ctx, 1, data, &datalen);
bool q5 = arg_get_lit(ctx, 2);
bool em = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
if (datalen > 5) {
PrintAndLogEx(FAILED, "Uid is max 5 bytes. (got %u)", datalen);
return PM3_EINVARG;
}
uint32_t blocks[4] = {0};
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
char cardtype[16] = {"T55x7"};
// Q5
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_DESTRON_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
uint8_t data_ex[12 + 24] = {0}; // ManchesterEncode need extra room
for (int i = 0; i < datalen; i++) {
data_ex[i + 1] = ~data [i] | (evenparity8(data[i]) << 7);
data_ex[i + 1] = ~(data [i] | (oddparity8(data[i]) << 7));
}
// manchester encode it
for (int i = 0; i < 3; i++) {
blocks[i + 1] = manchesterEncode2Bytes((data_ex[i * 2] << 8) + data_ex[i * 2 + 1]);
}
// inject preamble
blocks[1] = (blocks[1] & 0xFFFF) | 0xAAE20000;
PrintAndLogEx(INFO, "Preparing to clone Destron tag with ID: %s", sprint_hex(data, datalen));
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
PrintAndLogEx(INFO, "Preparing to clone Destron tag to " _YELLOW_("%s") " with ID: " _YELLOW_("%s")
, cardtype
, sprint_hex_inrow(data, datalen)
);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf Destron read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf destron reader`") " to verify");
return res;
}
static int CmdDestronSim(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf destron sim",
"Try to find Destron preamble, if found decode / descramble data",
"lf destron sim"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
{"read", CmdDestronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
{"reader", CmdDestronReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
{NULL, NULL, NULL, NULL}
};
@ -185,5 +267,5 @@ int detectDestron(uint8_t *dest, size_t *size) {
}
int readDestronUid(void) {
return (CmdDestronRead("") == PM3_SUCCESS);
return (CmdDestronReader("") == PM3_SUCCESS);
}

View file

@ -30,7 +30,9 @@
#define EM4305_NORALSY_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK, data rate 32, 3 data blocks
#define EM4305_PRESCO_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN, data rate 32, 4 data blocks
#define EM4305_SECURAKEY_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK/MAN, data rate 40, 3 data blocks
#define EM4305_GALLAGHER_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK/MAN, data rate 32, 3 data blocks
#define EM4305_DESTRON_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_HID_26_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_PARADOX_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_AWID_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
@ -47,6 +49,7 @@
#define EM4305_GUARDPROXII_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(3) ) // Biphase, data rate 64, Direct modulation, 3 data blocks
#define EM4305_NEDAP_64_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(2) ) // Biphase, data rate 64, 2 data blocks
#define EM4305_NEDAP_128_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // Biphase, data rate 64, 4 data blocks
#define EM4305_FDXB_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // Biphase, data rate 32, 4 data blocks
#define EM4305_PAC_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 32, 4 data blocks
#define EM4305_VERICHIP_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 40, 4 data blocks

View file

@ -9,23 +9,22 @@
//-----------------------------------------------------------------------------
#include "cmdlffdxb.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> // tolower
#include <ctype.h> // tolower
#include "cmdparser.h" // command_t
#include "comms.h"
#include "commonutil.h"
#include "ui.h" // PrintAndLog
#include "ui.h" // PrintAndLog
#include "cmddata.h"
#include "cmdlf.h" // lf read
#include "crc16.h" // for checksum crc-16_ccitt
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "cmdlf.h" // lf read
#include "crc16.h" // for checksum crc-16_ccitt
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
/*
FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits)
@ -48,55 +47,63 @@
static int CmdHelp(const char *Cmd);
static int usage_lf_fdxb_clone(void) {
PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag.");
PrintAndLogEx(NORMAL, "Usage: lf fdxb clone [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
PrintAndLogEx(NORMAL, " s : Set animal bit");
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 e 16a"));
return PM3_SUCCESS;
}
static int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint16_t extended, uint8_t *bits) {
static int usage_lf_fdxb_read(void) {
PrintAndLogEx(NORMAL, "Read FDX-B animal tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf fdxb read [h] [@]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)");
PrintAndLogEx(NORMAL, "Note that the continuous mode is less verbose");
return PM3_SUCCESS;
}
// add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10);
bits[10] = 1;
static int usage_lf_fdxb_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of FDX-B animal tag");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf fdxb sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
PrintAndLogEx(NORMAL, " s : Set animal bit");
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 e 16a"));
// 128bits
// every 9th bit is 0x01, but we can just fill the rest with 0x01 and overwrite
memset(bits, 0x01, 128);
// add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10);
// add reserved
num_to_bytebitsLSBF(0x00, 7, bits + 66);
num_to_bytebitsLSBF(0x00 >> 7, 7, bits + 74);
// add animal flag - OK
bits[81] = is_animal;
// add extended flag - OK
bits[65] = is_extended;
// add national code 40bits - OK
num_to_bytebitsLSBF(national_code >> 0, 8, bits + 11);
num_to_bytebitsLSBF(national_code >> 8, 8, bits + 20);
num_to_bytebitsLSBF(national_code >> 16, 8, bits + 29);
num_to_bytebitsLSBF(national_code >> 24, 8, bits + 38);
num_to_bytebitsLSBF(national_code >> 32, 6, bits + 47);
// add country code - OK
num_to_bytebitsLSBF(country_code >> 0, 2, bits + 53);
num_to_bytebitsLSBF(country_code >> 2, 8, bits + 56);
// add crc-16 - OK
uint8_t raw[8];
for (uint8_t i = 0; i < 8; ++i)
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
init_table(CRC_11784);
uint16_t crc = crc16_fdxb(raw, 8);
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);
// extended data - OK
num_to_bytebitsLSBF(extended >> 0, 8, bits + 101);
num_to_bytebitsLSBF(extended >> 8, 8, bits + 110);
num_to_bytebitsLSBF(extended >> 16, 8, bits + 119);
// 8 16 24 32 40 48 49
// A8 28 0C 92 EA 6F 00 01
// A8 28 0C 92 EA 6F 80 00
return PM3_SUCCESS;
}
// clearing the topbit needed for the preambl detection.
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *extended, uint8_t *is_animal) {
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint16_t *extended) {
if ((*animalid & 0x3FFFFFFFFF) != *animalid) {
*animalid &= 0x3FFFFFFFFF;
PrintAndLogEx(INFO, "Animal ID truncated to 38bits: " _YELLOW_("%"PRIx64), *animalid);
@ -109,8 +116,6 @@ static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *ext
*extended &= 0xFFF;
PrintAndLogEx(INFO, "Extended truncated to 24bits: " _YELLOW_("0x%03X"), *extended);
}
*is_animal &= 0x01;
}
static inline uint32_t bitcount(uint32_t a) {
@ -607,71 +612,75 @@ int demodFDXB(bool verbose) {
}
static int CmdFdxBDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf fdxb demod",
"Try to find FDX-B preamble, if found decode / descramble data",
"lf fdxb demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodFDXB(true);
}
static int CmdFdxBRead(const char *Cmd) {
static int CmdFdxBReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf fdxb reader",
"read a FDX-B animal tag\n"
"Note that the continuous mode is less verbose",
"lf fdxb reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
sample_config config;
memset(&config, 0, sizeof(sample_config));
int retval = lf_getconfig(&config);
if (retval != PM3_SUCCESS) {
int res = lf_getconfig(&config);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to get current device LF config");
return retval;
return res;
}
bool errors = false;
bool continuous = false;
uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdxb_read();
case '@':
continuous = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors) return usage_lf_fdxb_read();
int16_t tmp_div = config.divisor;
if (tmp_div != LF_DIVISOR_134) {
config.divisor = LF_DIVISOR_134;
config.verbose = false;
retval = lf_config(&config);
if (retval != PM3_SUCCESS) {
res = lf_config(&config);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to change LF configuration");
return retval;
return res;
}
}
if (continuous) {
PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit");
if (cm) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
}
int ret = PM3_SUCCESS;
do {
retval = lf_read(false, 10000);
if (retval != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to get LF read from device");
return retval;
}
ret = demodFDXB(!continuous); // be verbose only if not in continuous mode
if (kbd_enter_pressed()) {
break;
}
PrintAndLogEx(INPLACE, "");
} while (continuous);
lf_read(false, 10000);
ret = demodFDXB(!cm); // be verbose only if not in continuous mode
//PrintAndLogEx(INPLACE, "");
} while (cm && !kbd_enter_pressed());
if (tmp_div != LF_DIVISOR_134) {
config.divisor = tmp_div;
retval = lf_config(&config);
if (retval != PM3_SUCCESS) {
res = lf_config(&config);
if (res != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to restore LF configuration");
return retval;
return res;
}
}
return ret;
@ -679,145 +688,159 @@ static int CmdFdxBRead(const char *Cmd) {
static int CmdFdxBClone(const char *Cmd) {
uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0;
uint8_t is_animal = 0, cmdp = 0;
bool errors = false, has_extended = false, q5 = false;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf fdxb clone",
"clone a FDX-B tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf fdxb clone --country 999 --national 1337 --animal\n"
"lf fdxb clone --country 999 --national 1337 --extended 016A\n"
"lf fdxb clone --q5 --country 999 --national 1337 -> encode for Q5/T5555 tag\n"
"lf fdxb clone --em --country 999 --national 1337 -> encode for EM4305/4469"
);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdxb_clone();
case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
}
case 'n': {
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
}
case 'e': {
extended = param_get32ex(Cmd, cmdp + 1, 0, 16);
has_extended = true;
cmdp += 2;
break;
}
case 's': {
is_animal = 1;
cmdp++;
break;
}
case 'q': {
q5 = true;
cmdp++;
break;
}
default: {
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
void *argtable[] = {
arg_param_begin,
arg_u64_1("c", "country", "<dec>", "country code"),
arg_u64_1("n", "national", "<dec>", "national code"),
arg_str0(NULL, "extended", "<hex>", "extended data"),
arg_lit0("a", "animal", "optional - set animal bit"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint32_t country_code = arg_get_u32_def(ctx, 1, 0);
uint64_t national_code = arg_get_u64_def(ctx, 2, 0);
int extended_len = 0;
uint8_t edata[2] = {0};
CLIGetHexWithReturn(ctx, 3, edata, &extended_len);
bool is_animal = arg_get_lit(ctx, 4);
bool q5 = arg_get_lit(ctx, 5);
bool em = arg_get_lit(ctx, 6);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
if (errors || strlen(Cmd) == 0) return usage_lf_fdxb_clone();
verify_values(&national_code, &country_code, &extended, &is_animal);
uint16_t extended = 0;
bool has_extended = false;
if (extended_len) {
extended = bytes_to_num(edata, extended_len);
has_extended = true;
}
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
PrintAndLogEx(INFO, " RFU 0");
verify_values(&national_code, &country_code, &extended);
uint8_t *bits = calloc(128, sizeof(uint8_t));
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Country code........ %"PRIu32, country_code);
PrintAndLogEx(INFO, "National code....... %"PRIu64, national_code);
PrintAndLogEx(INFO, "Set animal bit...... %c", (is_animal) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Set data block bit.. %c", (has_extended) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Extended data....... 0x%"PRIX32, extended);
PrintAndLogEx(INFO, "RFU................. 0");
uint8_t *bs = calloc(128, sizeof(uint8_t));
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
free(bs);
return PM3_ESOFT;
}
uint32_t blocks[5] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0, 0};
char cardtype[16] = {"T55x7"};
//Q5
if (q5)
// Q5
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_FDXB_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
// convert from bit stream to block data
blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 32);
blocks[3] = bytebits_to_byte(bits + 64, 32);
blocks[4] = bytebits_to_byte(bits + 96, 32);
blocks[1] = bytebits_to_byte(bs, 32);
blocks[2] = bytebits_to_byte(bs + 32, 32);
blocks[3] = bytebits_to_byte(bs + 64, 32);
blocks[4] = bytebits_to_byte(bs + 96, 32);
free(bits);
free(bs);
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64), (q5) ? "Q5/T5555" : "T55x7", country_code, national_code);
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64)
, cardtype
, country_code
, national_code
);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb reader`") " to verify");
return res;
}
static int CmdFdxBSim(const char *Cmd) {
uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0;
uint8_t is_animal = 0, cmdp = 0;
bool errors = false, has_extended = false;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf fdxb sim",
"Enables simulation of FDX-B animal tag.\n"
"Simulation runs until the button is pressed or another USB command is issued.",
"lf fdxb sim --country 999 --national 1337 --animal\n"
"lf fdxb sim --country 999 --national 1337 --extended 016A\n"
);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdxb_sim();
case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
}
case 'n': {
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
}
case 'e': {
extended = param_get32ex(Cmd, cmdp + 1, 0, 10);
has_extended = true;
cmdp += 2;
break;
}
case 's': {
is_animal = 1;
cmdp++;
break;
}
default: {
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
void *argtable[] = {
arg_param_begin,
arg_u64_1("c", "country", "<dec>", "country code"),
arg_u64_1("n", "national", "<dec>", "national code"),
arg_str0(NULL, "extended", "<hex>", "extended data"),
arg_lit0("a", "animal", "optional - set animal bit"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint32_t country_code = arg_get_u32_def(ctx, 1, 0);
uint64_t national_code = arg_get_u64_def(ctx, 2, 0);
int extended_len = 0;
uint8_t edata[2] = {0};
CLIGetHexWithReturn(ctx, 3, edata, &extended_len);
bool is_animal = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
uint16_t extended = 0;
bool has_extended = false;
if (extended_len) {
extended = bytes_to_num(edata, extended_len);
has_extended = true;
}
if (errors) return usage_lf_fdxb_sim();
verify_values(&national_code, &country_code, &extended, &is_animal);
verify_values(&national_code, &country_code, &extended);
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
PrintAndLogEx(INFO, " RFU 0");
PrintAndLogEx(INFO, "Country code........ %"PRIu32, country_code);
PrintAndLogEx(INFO, "National code....... %"PRIu64, national_code);
PrintAndLogEx(INFO, "Set animal bit...... %c", (is_animal) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Set data block bit.. %c", (has_extended) ? 'Y' : 'N');
PrintAndLogEx(INFO, "Extended data....... 0x%"PRIX16, extended);
PrintAndLogEx(INFO, "RFU................. 0");
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _YELLOW_("%04u-%"PRIu64), country_code, national_code);
uint8_t *bits = calloc(128, sizeof(uint8_t));
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
uint8_t *bs = calloc(128, sizeof(uint8_t));
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
free(bs);
return PM3_ESOFT;
}
@ -827,12 +850,12 @@ static int CmdFdxBSim(const char *Cmd) {
payload->invert = 1;
payload->separator = 0;
payload->clock = 32;
memcpy(payload->data, bits, 128);
memcpy(payload->data, bs, 128);
clearCommandBuffer();
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + 128);
free(bits);
free(bs);
free(payload);
PacketResponseNG resp;
@ -846,11 +869,11 @@ static int CmdFdxBSim(const char *Cmd) {
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
{"read", CmdFdxBRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
{"reader", CmdFdxBReader, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
{NULL, NULL, NULL, NULL}
};
@ -878,59 +901,3 @@ int detectFDXB(uint8_t *dest, size_t *size) {
//return start position
return (int)startIdx;
}
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
// add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10);
bits[10] = 1;
// 128bits
// every 9th bit is 0x01, but we can just fill the rest with 0x01 and overwrite
memset(bits, 0x01, 128);
// add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10);
// add reserved
num_to_bytebitsLSBF(0x00, 7, bits + 66);
num_to_bytebitsLSBF(0x00 >> 7, 7, bits + 74);
// add animal flag - OK
bits[81] = is_animal;
// add extended flag - OK
bits[65] = is_extended;
// add national code 40bits - OK
num_to_bytebitsLSBF(national_code >> 0, 8, bits + 11);
num_to_bytebitsLSBF(national_code >> 8, 8, bits + 20);
num_to_bytebitsLSBF(national_code >> 16, 8, bits + 29);
num_to_bytebitsLSBF(national_code >> 24, 8, bits + 38);
num_to_bytebitsLSBF(national_code >> 32, 6, bits + 47);
// add country code - OK
num_to_bytebitsLSBF(country_code >> 0, 2, bits + 53);
num_to_bytebitsLSBF(country_code >> 2, 8, bits + 56);
// add crc-16 - OK
uint8_t raw[8];
for (uint8_t i = 0; i < 8; ++i)
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
init_table(CRC_11784);
uint16_t crc = crc16_fdxb(raw, 8);
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);
// extended data - OK
num_to_bytebitsLSBF(extended >> 0, 8, bits + 101);
num_to_bytebitsLSBF(extended >> 8, 8, bits + 110);
num_to_bytebitsLSBF(extended >> 16, 8, bits + 119);
// 8 16 24 32 40 48 49
// A8 28 0C 92 EA 6F 00 01
// A8 28 0C 92 EA 6F 80 00
return PM3_SUCCESS;
}

View file

@ -19,7 +19,7 @@ typedef struct {
int CmdLFFdxB(const char *Cmd);
int detectFDXB(uint8_t *dest, size_t *size);
int demodFDXB(bool verbose);
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
//int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint16_t extended, uint8_t *bits);
#endif

View file

@ -10,36 +10,25 @@
// sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006)
//-----------------------------------------------------------------------------
#include "cmdlfgallagher.h"
#include <ctype.h> //tolower
#include <string.h> // memcpy
#include <ctype.h> // tolower
#include <stdio.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "common.h"
#include "cmdparser.h" // command_t
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "crc.h" // CRC8/Cardx
#include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "crc.h" // CRC8/Cardx
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd);
static int usage_lf_gallagher_clone(void) {
PrintAndLogEx(NORMAL, "clone a GALLAGHER tag to a T55x7 tag.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf gallagher clone [h] [b <raw hex>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf gallagher clone b 0FFD5461A9DA1346B2D1AC32"));
return PM3_SUCCESS;
}
static void descramble(uint8_t *arr, uint8_t len) {
uint8_t lut[] = {
@ -134,73 +123,165 @@ int demodGallagher(bool verbose) {
}
static int CmdGallagherDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gallagher demod",
"Try to find GALLAGHER preamble, if found decode / descramble data",
"lf gallagher demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodGallagher(true);
}
static int CmdGallagherRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 4096 * 2 + 20);
return demodGallagher(true);
static int CmdGallagherReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gallagher reader",
"read a GALLAGHER tag",
"lf gallagher reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 4096 * 2 + 20);
demodGallagher(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdGallagherClone(const char *Cmd) {
uint32_t blocks[4];
bool errors = false;
uint8_t cmdp = 0;
int datalen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gallagher clone",
"clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf gallagher clone --raw 0FFD5461A9DA1346B2D1AC32\n"
"lf gallagher clone --q5 --raw 0FFD5461A9DA1346B2D1AC32 -> encode for Q5/T5555 tag\n"
"lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469"
);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_gallagher_clone();
case 'b': {
// skip first block, 3*4 = 12 bytes left
uint8_t rawhex[12] = {0};
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
if (res != 0)
errors = true;
void *argtable[] = {
arg_param_begin,
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
}
cmdp += 2;
break;
}
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
int raw_len = 0;
// skip first block, 3*4 = 12 bytes left
uint8_t raw[12] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
bool q5 = arg_get_lit(ctx, 2);
bool em = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
if (errors || cmdp == 0) return usage_lf_gallagher_clone();
uint32_t blocks[4];
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
//Pac - compat mode, NRZ, data rate 40, 3 data blocks
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
char cardtype[16] = {"T55x7"};
// Q5
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 3 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
PrintAndLogEx(INFO, "Preparing to clone Gallagher to T55x7 with raw hex");
// EM4305
if (em) {
blocks[0] = EM4305_GALLAGHER_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " with raw hex", cardtype);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher reader`") " to verify");
return res;
}
static int CmdGallagherSim(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gallagher sim",
"Enables simulation of GALLAGHER card with specified card number.\n"
"Simulation runs until the button is pressed or another USB command is issued.\n",
"lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32"
);
void *argtable[] = {
arg_param_begin,
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int raw_len = 0;
// skip first block, 3*4 = 12 bytes left
uint8_t raw[12] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
CLIParserFree(ctx);
// ASK/MAN sim.
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
PrintAndLogEx(SUCCESS, "Simulating Gallagher - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
uint8_t bs[sizeof(raw) * 8];
bytes_to_bytebits(raw, sizeof(raw), bs);
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
payload->encoding = 1;
payload->invert = 0;
payload->separator = 0;
payload->clock = 32;
memcpy(payload->data, bs, sizeof(bs));
clearCommandBuffer();
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
free(payload);
PacketResponseNG resp;
WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
PrintAndLogEx(INFO, "Done");
if (resp.status != PM3_EOPABORTED)
return resp.status;
return PM3_SUCCESS;
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdGallagherDemod, AlwaysAvailable, "Demodulate an GALLAGHER tag from the GraphBuffer"},
{"read", CmdGallagherRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdGallagherClone, IfPm3Lf, "clone GALLAGHER tag to T55x7"},
{"sim", CmdGallagherSim, IfPm3Lf, "simulate GALLAGHER tag"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdGallagherDemod, AlwaysAvailable, "Demodulate an GALLAGHER tag from the GraphBuffer"},
{"reader", CmdGallagherReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdGallagherClone, IfPm3Lf, "clone GALLAGHER tag to T55x7"},
{"sim", CmdGallagherSim, IfPm3Lf, "simulate GALLAGHER tag"},
{NULL, NULL, NULL, NULL}
};

View file

@ -1,4 +1,5 @@
//-----------------------------------------------------------------------------
// Marshmellow
//
// 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
@ -8,63 +9,28 @@
// Biphase, rf/ , 96 bits (unknown key calc + some bits)
//-----------------------------------------------------------------------------
#include "cmdlfguard.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd);
static int usage_lf_guard_clone(void) {
PrintAndLogEx(NORMAL, "clone a Guardall tag to a T55x7 or Q5/T5555 tag.");
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. ");
PrintAndLogEx(NORMAL, "Currently work only on 26bit");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf gprox clone [h] <format> <Facility-Code> <Card-Number> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " <format> : format length 26|32|36|40");
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf gprox clone 26 123 11223"));
return PM3_SUCCESS;
}
static int usage_lf_guard_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of Guardall card with specified card number.");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.");
PrintAndLogEx(NORMAL, "Currently work only on 26bit");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf gprox sim [h] <format> <Facility-Code> <Card-Number>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " <format> : format length 26|32|36|40");
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf gprox sim 26 123 11223"));
return PM3_SUCCESS;
}
//by marshmellow
//attempts to demodulate and identify a G_Prox_II verex/chubb card
//WARNING: if it fails during some points it will destroy the DemodBuffer data
// attempts to demodulate and identify a G_Prox_II verex/chubb card
// WARNING: if it fails during some points it will destroy the DemodBuffer data
// but will leave the GraphBuffer intact.
//if successful it will push askraw data back to demod buffer ready for emulation
// if successful it will push askraw data back to demod buffer ready for emulation
int demodGuard(bool verbose) {
(void) verbose; // unused so far
//Differential Biphase
@ -150,43 +116,104 @@ int demodGuard(bool verbose) {
}
static int CmdGuardDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gproxii demod",
"Try to find Guardall Prox-II preamble, if found decode / descramble data",
"lf gproxii demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodGuard(true);
}
static int CmdGuardRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 10000);
return demodGuard(true);
static int CmdGuardReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gproxii reader",
"read a Guardall tag",
"lf gproxii reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 10000);
demodGuard(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdGuardClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gproxii clone",
"clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
"Currently work only on 26bit",
"lf gproxii clone --fmt 26 --fc 123 --cn 1337\n"
"lf gproxii clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
"lf gproxii clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
);
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_guard_clone();
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0, fmtlen = 0;
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
bool q5 = arg_get_lit(ctx, 4);
bool em = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (sscanf(Cmd, "%u %u %u", &fmtlen, &fc, &cn) != 3) return usage_lf_guard_clone();
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
fmtlen &= 0x7f;
facilitycode = (fc & 0x000000FF);
cardnumber = (cn & 0x0000FFFF);
uint32_t facilitycode = (fc & 0x000000FF);
uint32_t cardnumber = (cn & 0x0000FFFF);
//GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks
uint32_t blocks[4] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
uint8_t *bs = calloc(96, sizeof(uint8_t));
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bs);
return PM3_ESOFT;
}
uint32_t blocks[4] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
char cardtype[16] = {"T55x7"};
// Q5
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
if (q5)
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_GUARDPROXII_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
blocks[1] = bytebits_to_byte(bs, 32);
blocks[2] = bytebits_to_byte(bs + 32, 32);
@ -194,37 +221,65 @@ static int CmdGuardClone(const char *Cmd) {
free(bs);
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber);
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u")
, cardtype
, facilitycode
, cardnumber
);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gprox read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gproxii reader`") " to verify");
return res;
}
static int CmdGuardSim(const char *Cmd) {
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0, fmtlen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf gproxii sim",
"Enables simulation of Guardall card with specified card number.\n"
"Simulation runs until the button is pressed or another USB command is issued.\n"
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
"Currently work only on 26bit",
"lf gproxii sim --fmt 26 --fc 123 --cn 1337\n"
);
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_guard_sim();
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "16-bit value card number"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
if (sscanf(Cmd, "%u %u %u", &fmtlen, &fc, &cn) != 3) return usage_lf_guard_sim();
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
CLIParserFree(ctx);
fmtlen &= 0x7F;
uint32_t facilitycode = (fc & 0x000000FF);
uint32_t cardnumber = (cn & 0x0000FFFF);
uint8_t bs[96];
memset(bs, 0x00, sizeof(bs));
fmtlen &= 0x7F;
facilitycode = (fc & 0x000000FF);
cardnumber = (cn & 0x0000FFFF);
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
, facilitycode
, cardnumber
);
// Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase)
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
@ -250,7 +305,7 @@ static int CmdGuardSim(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdGuardDemod, AlwaysAvailable, "demodulate a G Prox II tag from the GraphBuffer"},
{"read", CmdGuardRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
{"reader", CmdGuardReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
{"clone", CmdGuardClone, IfPm3Lf, "clone Guardall tag to T55x7 or Q5/T5555"},
{"sim", CmdGuardSim, IfPm3Lf, "simulate Guardall tag"},
{NULL, NULL, NULL, NULL}
@ -267,7 +322,6 @@ int CmdLFGuard(const char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
// by marshmellow
// demod gProxIIDemod
// error returns as -x
// success returns start position in bitstream

View file

@ -19,13 +19,10 @@
//-----------------------------------------------------------------------------
#include "cmdlfhid.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "commonutil.h" // ARRAYLEN
@ -38,6 +35,7 @@
#include "lfdemod.h"
#include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#include "cmdlfem4x05.h" // EM defines
#ifndef BITS
# define BITS 96
@ -153,15 +151,44 @@ int demodHID(bool verbose) {
}
static int CmdHIDDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid demod",
"Try to find HID Prox preamble, if found decode / descramble data",
"lf hid demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodHID(true);
}
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdHIDRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 16000);
return demodHID(true);
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid reader",
"read a HID Prox tag",
"lf hid reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 16000);
demodHID(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
// this read loops on device side.
@ -212,7 +239,6 @@ static int CmdHIDSim(const char *Cmd) {
arg_int0("i", NULL, "<dec>", "issue level"),
arg_int0("o", "oem", "<dec>", "OEM code"),
arg_strx0("r", "raw", "<hex>", "raw bytes"),
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -231,8 +257,6 @@ static int CmdHIDSim(const char *Cmd) {
int raw_len = 0;
char raw[40] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
//bool q5 = arg_get_lit(ctx, 7);
CLIParserFree(ctx);
wiegand_message_t packed;

View file

@ -9,13 +9,10 @@
// PSK
//-----------------------------------------------------------------------------
#include "cmdlfidteck.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "common.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
@ -23,6 +20,8 @@
#include "cmdlf.h"
#include "lfdemod.h"
#include "commonutil.h" // num_to_bytes
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd);
@ -87,20 +86,49 @@ int demodIdteck(bool verbose) {
}
static int CmdIdteckDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf idteck demod",
"Try to find Idteck preamble, if found decode / descramble data",
"lf idteck demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodIdteck(true);
}
static int CmdIdteckRead(const char *Cmd) {
(void)Cmd;
lf_read(false, 5000);
return demodIdteck(true);
static int CmdIdteckReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf idteck reader",
"read a Idteck tag",
"lf idteck reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 5000);
demodIdteck(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdIdteckDemod, AlwaysAvailable, "Demodulate an Idteck tag from the GraphBuffer"},
{"read", CmdIdteckRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdIdteckDemod, AlwaysAvailable, "Demodulate an Idteck tag from the GraphBuffer"},
{"reader", CmdIdteckReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
{NULL, NULL, NULL, NULL}
};

View file

@ -9,13 +9,10 @@
//-----------------------------------------------------------------------------
#include "cmdlfindala.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "graph.h"
@ -28,6 +25,8 @@
#include "cmdlf.h" // lf_read
#include "protocols.h" // t55 defines
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
#define INDALA_ARR_LEN 64
@ -499,16 +498,33 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
}
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdIndalaRead(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_lf_indala_demod();
static int CmdIndalaReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf indala reader",
"read a Indala Prox tag",
"lf indala reader -@ -> continuous reader mode"
);
int clk = 32, invert = 0, maxErr = 100;
if (strlen(Cmd) > 0) {
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
}
lf_read(false, 30000);
return demodIndalaEx(clk, invert, maxErr, true);
void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "clock", "<dec>", "optional - set clock (as integer), if not set, autodetect."),
arg_int0(NULL, "maxerr", "<dec>", "optional - set maximum allowed errors, default = 100"),
arg_lit0("i", "invert", "optional - invert output"),
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t clk = arg_get_u32_def(ctx, 1, 32);
uint32_t max_err = arg_get_u32_def(ctx, 2, 100);
bool invert = arg_get_lit(ctx, 3);
bool cm = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
do {
lf_read(false, 30000);
demodIndalaEx(clk, invert, max_err, !cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdIndalaSim(const char *Cmd) {
@ -699,7 +715,7 @@ static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdIndalaDemod, AlwaysAvailable, "demodulate an indala tag (PSK1) from GraphBuffer"},
{"altdemod", CmdIndalaDemodAlt, AlwaysAvailable, "alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
{"read", CmdIndalaRead, IfPm3Lf, "read an Indala Prox tag from the antenna"},
{"reader", CmdIndalaReader, IfPm3Lf, "read an Indala Prox tag from the antenna"},
{"clone", CmdIndalaClone, IfPm3Lf, "clone Indala tag to T55x7 or Q5/T5555"},
{"sim", CmdIndalaSim, IfPm3Lf, "simulate Indala tag"},
{NULL, NULL, NULL, NULL}

View file

@ -9,23 +9,22 @@
//-----------------------------------------------------------------------------
#include "cmdlfio.h"
#include <stdio.h> // sscanf
#include <stdio.h> // sscanf
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "commonutil.h" //ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
#include "graph.h"
#include "cmdlf.h"
#include "ui.h" // PrintAndLog
#include "lfdemod.h" // parityTest, bitbytes_to_byte
#include "protocols.h" // for T55xx config register definitions
#include "ui.h" // PrintAndLog
#include "lfdemod.h" // parityTest, bitbytes_to_byte
#include "protocols.h" // for T55xx config register definitions
#include "cmddata.h"
#include "cmdlft55xx.h" // verifywrite
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd);
@ -192,14 +191,43 @@ int demodIOProx(bool verbose) {
}
static int CmdIOProxDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf io demod",
"Try to find IO Prox preamble, if found decode / descramble data",
"lf io demod\n"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodIOProx(true);
}
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdIOProxRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 12000);
return demodIOProx(true);
static int CmdIOProxReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf io reader",
"read a IO Prox tag",
"lf io reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 12000);
demodIOProx(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdIOProxSim(const char *Cmd) {
uint16_t cn = 0;
@ -297,12 +325,12 @@ static int CmdIOProxClone(const char *Cmd) {
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdIOProxDemod, AlwaysAvailable, "demodulate an IOProx tag from the GraphBuffer"},
{"read", CmdIOProxRead, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdIOProxClone, IfPm3Lf, "clone IOProx tag to T55x7 or Q5/T5555"},
{"sim", CmdIOProxSim, IfPm3Lf, "simulate IOProx tag"},
{"watch", CmdIOProxWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdIOProxDemod, AlwaysAvailable, "demodulate an IOProx tag from the GraphBuffer"},
{"reader", CmdIOProxReader, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdIOProxClone, IfPm3Lf, "clone IOProx tag to T55x7 or Q5/T5555"},
{"sim", CmdIOProxSim, IfPm3Lf, "simulate IOProx tag"},
{"watch", CmdIOProxWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
{NULL, NULL, NULL, NULL}
};

View file

@ -9,40 +9,26 @@
//-----------------------------------------------------------------------------
#include "cmdlfjablotron.h"
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
#define JABLOTRON_ARR_LEN 64
static int CmdHelp(const char *Cmd);
static int usage_lf_jablotron_clone(void) {
PrintAndLogEx(NORMAL, "clone a Jablotron tag to a T55x7 or Q5/T5555 tag.");
PrintAndLogEx(NORMAL, "Usage: lf jablotron clone [h] <card ID> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card ID> : jablotron card ID");
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf jablotron clone 112233"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int usage_lf_jablotron_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of jablotron card with specified card number.");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
@ -134,30 +120,93 @@ int demodJablotron(bool verbose) {
//see ASKDemod for what args are accepted
static int CmdJablotronDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf jablotron demod",
"Try to find Jablotron preamble, if found decode / descramble data",
"lf jablotron demod\n"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodJablotron(true);
}
static int CmdJablotronRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 16000);
return demodJablotron(true);
static int CmdJablotronReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf jablotron reader",
"read a jablotron tag",
"lf jablotron reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 16000);
demodJablotron(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdJablotronClone(const char *Cmd) {
uint64_t fullcode = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf jablotron clone",
"clone a Jablotron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf jablotron clone --cn 01b669\n"
"lf jablotron clone --q5 --cn 01b669 -> encode for Q5/T5555 tag\n"
"lf jablotron clone --em --cn 01b669 -> encode for EM4305/4469"
);
void *argtable[] = {
arg_param_begin,
arg_str1(NULL, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int raw_len = 0;
uint8_t raw[5] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
bool q5 = arg_get_lit(ctx, 2);
bool em = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
uint32_t blocks[3] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
fullcode = param_get64ex(Cmd, 0, 0, 16);
//Q5
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
if (q5)
char cardtype[16] = {"T55x7"};
// Q5
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_JABLOTRON_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
uint64_t fullcode = bytes_to_num(raw, raw_len);
// clearing the topbit needed for the preambl detection.
if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
@ -181,10 +230,20 @@ static int CmdJablotronClone(const char *Cmd) {
free(bits);
PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: %"PRIx64, (q5) ? "Q5/T5555" : "T55x7", fullcode);
print_blocks(blocks, ARRAYLEN(blocks));
uint64_t id = getJablontronCardId(fullcode);
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: " _GREEN_("%"PRIx64)" id: " _GREEN_("%"PRIx64), cardtype, fullcode, id);
print_blocks(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf jablotron reader`") " to verify");
return res;
}
static int CmdJablotronSim(const char *Cmd) {
@ -201,7 +260,7 @@ static int CmdJablotronSim(const char *Cmd) {
PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
}
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode);
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: " _YELLOW_("%"PRIx64), fullcode);
uint8_t *bs = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
if (bs == NULL) {
@ -236,7 +295,7 @@ static int CmdJablotronSim(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdJablotronDemod, AlwaysAvailable, "Demodulate an Jablotron tag from the GraphBuffer"},
{"read", CmdJablotronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"reader", CmdJablotronReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdJablotronClone, IfPm3Lf, "clone jablotron tag to T55x7 or Q5/T5555"},
{"sim", CmdJablotronSim, IfPm3Lf, "simulate jablotron tag"},
{NULL, NULL, NULL, NULL}

View file

@ -175,7 +175,18 @@ int demodKeri(bool verbose) {
}
static int CmdKeriDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf keri demod",
"Try to find KERI preamble, if found decode / descramble data",
"lf keri demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodKeri(true);
}

View file

@ -116,9 +116,19 @@ int demodMotorola(bool verbose) {
return PM3_SUCCESS;
}
//see PSKDemod for what args are accepted
static int CmdMotorolaDemod(const char *Cmd) {
(void)Cmd;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf motorola demod",
"Try to find Motorola preamble, if found decode / descramble data",
"lf motorola demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodMotorola(true);
}
@ -218,9 +228,9 @@ static int CmdMotorolaClone(const char *Cmd) {
// config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s")
, cardtype
, sprint_hex_inrow(raw, sizeof(raw))
);
, cardtype
, sprint_hex_inrow(raw, sizeof(raw))
);
print_blocks(blocks, ARRAYLEN(blocks));
int res;
@ -235,7 +245,20 @@ static int CmdMotorolaClone(const char *Cmd) {
}
static int CmdMotorolaSim(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf motorola sim",
"Enables simulation of Motorola card with specified card number.\n"
"Simulation runs until the button is pressed or another USB command is issued.",
"lf motorola sim"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
// PSK sim.
PrintAndLogEx(INFO, " PSK1 at 66 kHz... Interesting.");
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");

View file

@ -11,10 +11,8 @@
#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "crc16.h"
@ -24,6 +22,8 @@
#include "cmdlf.h"
#include "lfdemod.h"
#include "protocols.h"
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
#define FIXED_71 0x71
#define FIXED_40 0x40
@ -262,7 +262,18 @@ int demodNedap(bool verbose) {
}
static int CmdLFNedapDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf nedap demod",
"Try to find Nedap preamble, if found decode / descramble data",
"lf nedap demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodNedap(true);
}
/* Index map E E

View file

@ -217,14 +217,25 @@ int demodNexWatch(bool verbose) {
}
static int CmdNexWatchDemod(const char *Cmd) {
(void)Cmd;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf nexwatch demod",
"Try to find Nexwatch preamble, if found decode / descramble data",
"lf nexwatch demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodNexWatch(true);
}
static int CmdNexWatchReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf nexwatch reader",
"read a nexwatch tag",
"read a Nexwatch tag",
"lf nexwatch reader -@ -> continuous reader mode"
);
@ -385,7 +396,7 @@ static int CmdNexWatchSim(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int raw_len = 0;
int raw_len = 0;
// skip first block, 3*4 = 12 bytes left
uint8_t raw[12] = {0x56, 0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
@ -438,7 +449,7 @@ static int CmdNexWatchSim(const char *Cmd) {
uint8_t bs[96];
memset(bs, 0, sizeof(bs));
// hex to bits. (3 * 32 == 96)
// hex to bits. (3 * 32 == 96)
for (size_t i = 0; i < 3; i++) {
uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));

View file

@ -103,14 +103,25 @@ int demodNoralsy(bool verbose) {
}
static int CmdNoralsyDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf noralsy demod",
"Try to find Noralsy preamble, if found decode / descramble data",
"lf noralsy demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodNoralsy(true);
}
static int CmdNoralsyReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf noralsy reader",
"read a noralsy tag",
"read a Noralsy tag",
"lf noralsy reader -@ -> continuous reader mode"
);
@ -133,7 +144,7 @@ static int CmdNoralsyReader(const char *Cmd) {
static int CmdNoralsyClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf noralsy clone",
"clone a noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"clone a Noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf noralsy clone --cn 112233\n"
"lf noralsy clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
"lf noralsy clone --cn 112233 --em -> encode for EM4305/4469"

View file

@ -69,7 +69,7 @@ static int pac_buf_to_cardid(uint8_t *src, const size_t src_size, uint8_t *dst,
// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID
// performs no parity or checksum validation
static void pac_raw_to_cardid(const uint8_t* src, uint8_t *dst) {
static void pac_raw_to_cardid(const uint8_t *src, uint8_t *dst) {
for (int i = 4; i < 12; i++) {
uint8_t shift = 7 - (i + 3) % 4 * 2;
size_t index = i + (i - 1) / 4;
@ -157,15 +157,26 @@ int demodPac(bool verbose) {
}
static int CmdPacDemod(const char *Cmd) {
(void)Cmd;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf pac demod",
"Try to find PAC/Stanley preamble, if found decode / descramble data",
"lf pac demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodPac(true);
}
static int CmdPacReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf pac reader",
"read a pac tag",
"read a PAC/Stanley tag",
"lf pac reader -@ -> continuous reader mode"
);
@ -208,7 +219,7 @@ static int CmdPacClone(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t cnstr[9];
int cnlen = 9;
int cnlen = 9;
memset(cnstr, 0x00, sizeof(cnstr));
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
@ -236,7 +247,7 @@ static int CmdPacClone(const char *Cmd) {
}
if (cnlen == 8 || cnlen == 9) {
pac_cardid_to_raw((char*)cnstr, raw);
pac_cardid_to_raw((char *)cnstr, raw);
} else {
pac_raw_to_cardid(raw, cnstr);
}
@ -262,10 +273,10 @@ static int CmdPacClone(const char *Cmd) {
}
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to " _YELLOW_("%s") " with ID " _GREEN_("%s") " raw " _GREEN_("%s")
, cardtype
, cnstr
, sprint_hex_inrow(raw, sizeof(raw))
);
, cardtype
, cnstr
, sprint_hex_inrow(raw, sizeof(raw))
);
print_blocks(blocks, ARRAYLEN(blocks));
@ -300,7 +311,7 @@ static int CmdPacSim(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t cnstr[10];
int cnlen = 9;
int cnlen = 9;
memset(cnstr, 0x00, sizeof(cnstr));
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
@ -321,7 +332,7 @@ static int CmdPacSim(const char *Cmd) {
}
if (cnlen == 8 || cnlen == 9) {
pac_cardid_to_raw((char*)cnstr, raw);
pac_cardid_to_raw((char *)cnstr, raw);
} else {
pac_raw_to_cardid(raw, cnstr);
}
@ -333,9 +344,9 @@ static int CmdPacSim(const char *Cmd) {
}
PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw " _YELLOW_("%s")
, cnstr
, sprint_hex_inrow(raw, sizeof(raw))
);
, cnstr
, sprint_hex_inrow(raw, sizeof(raw))
);
// NRZ sim.
lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs));

View file

@ -170,7 +170,18 @@ int demodParadox(bool verbose) {
}
static int CmdParadoxDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf paradox demod",
"Try to find Paradox preamble, if found decode / descramble data",
"lf paradox demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodParadox(true);
}
@ -240,7 +251,7 @@ static int CmdParadoxClone(const char *Cmd) {
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
// Paradox - FSK2a, data rate 50, 3 data blocks
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT;
char cardtype[16] = {"T55x7"};
@ -255,7 +266,7 @@ static int CmdParadoxClone(const char *Cmd) {
blocks[0] = EM4305_PARADOX_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
PrintAndLogEx(INFO, "Preparing to clone Paradox to " _YELLOW_("%s") " with raw hex", cardtype);
print_blocks(blocks, ARRAYLEN(blocks));
@ -323,7 +334,8 @@ static int CmdParadoxSim(const char *Cmd) {
if (resp.status != PM3_EOPABORTED)
return resp.status;
return PM3_SUCCESS;}
return PM3_SUCCESS;
}
/*
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();

View file

@ -40,7 +40,7 @@ static int detectPresco(uint8_t *dest, size_t *size) {
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) {
char *s = (char*)arr;
char *s = (char *)arr;
uint8_t val = 0;
for (int i = 0; i < strlen(s); ++i) {
// Get value from number string.
@ -103,16 +103,27 @@ int demodPresco(bool verbose) {
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
, sitecode
, usercode
, fullcode
, raw1, raw2, raw3, raw4
);
, sitecode
, usercode
, fullcode
, raw1, raw2, raw3, raw4
);
return PM3_SUCCESS;
}
static int CmdPrescoDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf presco demod",
"Try to find presco preamble, if found decode / descramble data",
"lf presco demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodPresco(true);
}
@ -120,8 +131,8 @@ static int CmdPrescoDemod(const char *Cmd) {
static int CmdPrescoReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf presco reader",
"read a presco tag",
"lf presco reader -@ -> continuous reader mode"
"read a presco tag",
"lf presco reader -@ -> continuous reader mode"
);
void *argtable[] = {
@ -162,11 +173,11 @@ static int CmdPrescoClone(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
int hex_len = 0;
uint8_t hex[4] = {0,0,0,0};
uint8_t hex[4] = {0, 0, 0, 0};
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
uint8_t idstr[11];
int slen = 9;
int slen = 9;
memset(idstr, 0x00, sizeof(idstr));
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
@ -227,11 +238,11 @@ static int CmdPrescoClone(const char *Cmd) {
blocks[4] = fullcode;
PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x")
, cardtype
, sitecode
, usercode
, fullcode
);
, cardtype
, sitecode
, usercode
, fullcode
);
print_blocks(blocks, ARRAYLEN(blocks));
int res;
@ -265,11 +276,11 @@ static int CmdPrescoSim(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
int hex_len = 0;
uint8_t hex[4] = {0,0,0,0};
uint8_t hex[4] = {0, 0, 0, 0};
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
uint8_t idstr[11];
int slen = 9;
int slen = 9;
memset(idstr, 0x00, sizeof(idstr));
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
CLIParserFree(ctx);
@ -300,10 +311,10 @@ static int CmdPrescoSim(const char *Cmd) {
}
PrintAndLogEx(SUCCESS, "Simulating Presco - Site Code: " _GREEN_("%u") " User Code: " _GREEN_("%u") " Full Code: " _GREEN_("%08X")
, sitecode
, usercode
, fullcode)
;
, sitecode
, usercode
, fullcode)
;
uint8_t bs[128];
getPrescoBits(fullcode, bs);

View file

@ -178,7 +178,18 @@ int demodPyramid(bool verbose) {
}
static int CmdPyramidDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf pyramid demod",
"Try to find Farpoint/Pyramid preamble, if found decode / descramble data",
"lf pyramid demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodPyramid(true);
}

View file

@ -8,18 +8,18 @@
// ASK/Manchester, RF/40, 96 bits long (unknown cs)
//-----------------------------------------------------------------------------
#include "cmdlfsecurakey.h"
#include <string.h> // memcpy
#include <ctype.h> // tolower
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include <string.h> // memcpy
#include <ctype.h> // tolower
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h" // preamble test
#include "parity.h" // for wiegand parity test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "lfdemod.h" // preamble test
#include "parity.h" // for wiegand parity test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
@ -114,7 +114,18 @@ int demodSecurakey(bool verbose) {
}
static int CmdSecurakeyDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf securakey demod",
"Try to find Securakey preamble, if found decode / descramble data",
"lf securakey demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodSecurakey(true);
}
@ -240,7 +251,7 @@ static int CmdSecurakeySim(const char *Cmd) {
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "Simulating SecuraKey - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
PrintAndLogEx(SUCCESS, "Simulating SecuraKey - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
uint8_t bs[sizeof(raw) * 8];
bytes_to_bytebits(raw, sizeof(raw), bs);

View file

@ -272,7 +272,18 @@ out:
}
static int CmdTIDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf ti demod",
"Try to find TI preamble, if found decode / descramble data",
"lf ti demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodTI(true);
}
@ -303,19 +314,43 @@ static int CmdTIReader(const char *Cmd) {
// write new data to a r/w TI tag
static int CmdTIWrite(const char *Cmd) {
int res = 0;
uint64_t arg0, arg1, arg2;
res = sscanf(Cmd, "%012" SCNx64 " %012" SCNx64 " %012" SCNx64 "", &arg0, &arg1, &arg2);
if (res == 2)
arg2 = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf ti write",
"write to a r/w TI tag.",
"lf ti write --raw 1122334455667788\n"
"lf ti write --raw 1122334455667788 --crc 1122\n"
);
void *argtable[] = {
arg_param_begin,
arg_str1("r", "raw", "<hex>", "raw hex data. 8 bytes max"),
arg_str0(NULL, "crc", "<hex>", "optional - crc"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int raw_len = 0;
uint8_t raw[8] = {0};
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
int crc_len = 0;
uint8_t crc[2] = {0};
CLIGetHexWithReturn(ctx, 2, crc, &crc_len);
CLIParserFree(ctx);
struct {
uint32_t high;
uint32_t low;
uint16_t crc;
} PACKED payload;
payload.high = bytes_to_num(raw, 4);
payload.low = bytes_to_num(raw + 4, 4);
payload.crc = bytes_to_num(crc, crc_len);
if (res < 2) {
PrintAndLogEx(WARNING, "Please specify the data as two hex strings, optionally the CRC as a third");
return PM3_EINVARG;
}
clearCommandBuffer();
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
SendCommandNG(CMD_LF_TI_WRITE, (uint8_t*)&payload, sizeof(payload));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti reader`") " to verify");
return PM3_SUCCESS;
@ -323,7 +358,7 @@ static int CmdTIWrite(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"},
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI LF tag from the GraphBuffer"},
{"reader", CmdTIReader, IfPm3Lf, "Read and decode a TI 134 kHz tag"},
{"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
{NULL, NULL, NULL, NULL}

View file

@ -54,7 +54,18 @@ int demodViking(bool verbose) {
}
static int CmdVikingDemod(const char *Cmd) {
(void)Cmd;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf viking demod",
"Try to find Viking AM preamble, if found decode / descramble data",
"lf viking demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodViking(true);
}

View file

@ -133,7 +133,18 @@ int demodVisa2k(bool verbose) {
}
static int CmdVisa2kDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf visa2000 demod",
"Try to find visa2000 preamble, if found decode / descramble data",
"lf visa2000 demod"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return demodVisa2k(true);
}

View file

@ -32,12 +32,12 @@
#include "fileutils.h"
#ifdef HAVE_LUA_SWIG
extern int luaopen_pm3(lua_State* L);
extern int luaopen_pm3(lua_State *L);
#endif
#ifdef HAVE_PYTHON
#ifdef HAVE_PYTHON_SWIG
extern PyObject* PyInit__pm3(void);
extern PyObject *PyInit__pm3(void);
#endif // HAVE_PYTHON_SWIG
// Partly ripped from PyRun_SimpleFileExFlags

View file

@ -232,7 +232,7 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
if (g_debugMode > 0) {
PrintAndLogEx(DEBUG, "High security custom key (Kcus):");
PrintAndLogEx(DEBUG, "z0 %s", sprint_hex(z[0],8));
PrintAndLogEx(DEBUG, "z0 %s", sprint_hex(z[0], 8));
}
uint8_t y[8][8] = {{0}, {0}};
@ -308,7 +308,7 @@ typedef struct {
static size_t loclass_tc = 1;
static int loclass_found = 0;
static void* bf_thread(void* thread_arg) {
static void *bf_thread(void *thread_arg) {
loclass_thread_arg_t *targ = (loclass_thread_arg_t *)thread_arg;
const uint32_t endmask = targ->endmask;
@ -332,7 +332,7 @@ static void* bf_thread(void* thread_arg) {
int found;
while (!(brute & endmask)) {
found = __atomic_load_n (&loclass_found, __ATOMIC_SEQ_CST);
found = __atomic_load_n(&loclass_found, __ATOMIC_SEQ_CST);
if (found != 0xFF) return NULL;
@ -370,13 +370,13 @@ static void* bf_thread(void* thread_arg) {
// success
if (memcmp(calculated_MAC, mac, 4) == 0) {
loclass_thread_ret_t *r = (loclass_thread_ret_t*)malloc(sizeof(loclass_thread_ret_t));
loclass_thread_ret_t *r = (loclass_thread_ret_t *)malloc(sizeof(loclass_thread_ret_t));
for (uint8_t i = 0 ; i < numbytes_to_recover; i++) {
r->values[i] = keytable[bytes_to_recover[i]] & 0xFF;
}
__atomic_store_n(&loclass_found, targ->thread_idx, __ATOMIC_SEQ_CST);
pthread_exit ((void*)r);
pthread_exit((void *)r);
}
brute += loclass_tc;
@ -385,19 +385,19 @@ static void* bf_thread(void* thread_arg) {
if (numbytes_to_recover == 3) {
if ((brute > 0) && ((brute & 0xFFFF) == 0)) {
PrintAndLogEx(INPLACE, "[ %02x %02x %02x ] %8u / %u", bytes_to_recover[0], bytes_to_recover[1], bytes_to_recover[2] , brute, 0xFFFFFF);
PrintAndLogEx(INPLACE, "[ %02x %02x %02x ] %8u / %u", bytes_to_recover[0], bytes_to_recover[1], bytes_to_recover[2], brute, 0xFFFFFF);
}
} else if (numbytes_to_recover == 2) {
if ((brute > 0) && ((brute & 0x3F) == 0))
PrintAndLogEx(INPLACE, "[ %02x %02x ] %5u / %u" _CLR_ , bytes_to_recover[0], bytes_to_recover[1], brute, 0xFFFF);
PrintAndLogEx(INPLACE, "[ %02x %02x ] %5u / %u" _CLR_, bytes_to_recover[0], bytes_to_recover[1], brute, 0xFFFF);
} else {
if ((brute > 0) && ((brute & 0x1F) == 0))
PrintAndLogEx(INPLACE, "[ %02x ] %3u / %u" _CLR_, bytes_to_recover[0], brute, 0xFF);
}
}
pthread_exit(NULL);
void* dummyptr = NULL;
void *dummyptr = NULL;
return dummyptr;
}
@ -455,9 +455,9 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
args[i].numbytes_to_recover = numbytes_to_recover;
args[i].endmask = 1 << 8 * numbytes_to_recover;
memcpy((void*)&args[i].item, (void*)&item, sizeof(loclass_dumpdata_t));
memcpy(args[i].bytes_to_recover, bytes_to_recover, sizeof(args[i].bytes_to_recover) );
memcpy(args[i].key_index, key_index, sizeof(args[i].key_index) );
memcpy((void *)&args[i].item, (void *)&item, sizeof(loclass_dumpdata_t));
memcpy(args[i].bytes_to_recover, bytes_to_recover, sizeof(args[i].bytes_to_recover));
memcpy(args[i].key_index, key_index, sizeof(args[i].key_index));
memcpy(args[i].keytable, keytable, sizeof(args[i].keytable));
}
@ -472,7 +472,7 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
}
}
// wait for threads to terminate:
void* ptrs[loclass_tc];
void *ptrs[loclass_tc];
for (int i = 0; i < loclass_tc; i++)
pthread_join(threads[i], &ptrs[i]);
@ -526,18 +526,18 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
uint8_t key_index[8] = {0};
hash1(item.csn, key_index);
*/
/*
* Determine which bytes to retrieve. A hash is typically
* 01010000454501
* We go through that hash, and in the corresponding keytable, we put markers
* on what state that particular index is:
* - CRACKED (this has already been cracked)
* - BEING_CRACKED (this is being bruteforced now)
* - CRACK_FAILED (self-explaining...)
*
* The markers are placed in the high area of the 16 bit key-table.
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
**/
/*
* Determine which bytes to retrieve. A hash is typically
* 01010000454501
* We go through that hash, and in the corresponding keytable, we put markers
* on what state that particular index is:
* - CRACKED (this has already been cracked)
* - BEING_CRACKED (this is being bruteforced now)
* - CRACK_FAILED (self-explaining...)
*
* The markers are placed in the high area of the 16 bit key-table.
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
**/
/*
@ -571,13 +571,13 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
//A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
uint32_t brute = 0;
*/
/*
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
(when brute reaches 0x100). And so on...
bytes_to_recover = 1 --> endmask = 0x000000100
bytes_to_recover = 2 --> endmask = 0x000010000
bytes_to_recover = 3 --> endmask = 0x001000000
*/
/*
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
(when brute reaches 0x100). And so on...
bytes_to_recover = 1 --> endmask = 0x000000100
bytes_to_recover = 2 --> endmask = 0x000010000
bytes_to_recover = 3 --> endmask = 0x001000000
*/
/*
uint32_t endmask = 1 << 8 * numbytes_to_recover;
PrintAndLogEx(NORMAL, "----------------------------");
@ -903,11 +903,11 @@ int testElite(bool slowtests) {
int res = PM3_SUCCESS;
PrintAndLogEx(INFO, "Testing hash1...");
res += _testHash1();
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " hash1 (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail") );
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " hash1 (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(INFO, "Testing key diversification...");
res += _test_iclass_key_permutation();
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " key diversification (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail") );
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " key diversification (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
if (slowtests)
res += _testBruteforce();

View file

@ -210,12 +210,12 @@ static void permute(BitstreamIn *p_in, uint64_t z, int l, int r, BitstreamOut *o
return;
bool pn = tailBit(p_in);
if (pn) {
if (pn) {
// pn = 1
uint8_t zl = getSixBitByte(z, l);
push6bits(out, zl + 1);
permute(p_in, z, l + 1, r, out);
} else {
} else {
// otherwise
uint8_t zr = getSixBitByte(z, r);
push6bits(out, zr);
@ -256,8 +256,8 @@ void hash0(uint64_t c, uint8_t k[8]) {
c = swapZvalues(c);
if (g_debugMode > 0) {
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
printState("origin", c);
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
printState("origin", c);
}
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
// x = 8 bits
@ -421,7 +421,7 @@ static int testDES(uint8_t *key, testcase_t testcase) {
uint8_t des_encrypted_csn[8] = {0};
uint8_t decrypted[8] = {0};
uint8_t div_key[8] = {0};
mbedtls_des_context ctx_enc;
mbedtls_des_context ctx_dec;
@ -466,12 +466,12 @@ static int testDES(uint8_t *key, testcase_t testcase) {
static bool des_getParityBitFromKey(uint8_t key) {
// The top 7 bits is used
bool parity = ((key & 0x80) >> 7)
^ ((key & 0x40) >> 6)
^ ((key & 0x20) >> 5)
^ ((key & 0x10) >> 4)
^ ((key & 0x08) >> 3)
^ ((key & 0x04) >> 2)
^ ((key & 0x02) >> 1);
^ ((key & 0x40) >> 6)
^ ((key & 0x20) >> 5)
^ ((key & 0x10) >> 4)
^ ((key & 0x08) >> 3)
^ ((key & 0x04) >> 2)
^ ((key & 0x02) >> 1);
return !parity;
}
@ -613,7 +613,7 @@ static int testDES2(uint8_t *key, uint64_t csn, uint64_t expected) {
uint64_t crypt_csn = x_bytes_to_num(result, 8);
PrintAndLogEx(DEBUG, " {csn} %"PRIx64, crypt_csn);
PrintAndLogEx(DEBUG, " expected %"PRIx64 " (%s)", expected, (expected == crypt_csn) ? _GREEN_("ok") : _RED_("fail") );
PrintAndLogEx(DEBUG, " expected %"PRIx64 " (%s)", expected, (expected == crypt_csn) ? _GREEN_("ok") : _RED_("fail"));
if (expected != crypt_csn)
return PM3_ESOFT;

View file

@ -13,7 +13,7 @@
#include "util_posix.h"
#include "comms.h"
pm3_device* pm3_open(char *port) {
pm3_device *pm3_open(char *port) {
pm3_init();
OpenProxmark(&session.current_device, port, false, 20, false, USART_BAUD_RATE);
if (session.pm3_present && (TestProxmark(session.current_device) != PM3_SUCCESS)) {
@ -30,7 +30,7 @@ pm3_device* pm3_open(char *port) {
return session.current_device;
}
void pm3_close(pm3_device* dev) {
void pm3_close(pm3_device *dev) {
// Clean up the port
if (session.pm3_present) {
clearCommandBuffer();
@ -40,16 +40,16 @@ void pm3_close(pm3_device* dev) {
}
}
int pm3_console(pm3_device* dev, char *Cmd) {
int pm3_console(pm3_device *dev, char *Cmd) {
// For now, there is no real device context:
(void) dev;
return CommandReceived(Cmd);
}
const char *pm3_name_get(pm3_device* dev) {
const char *pm3_name_get(pm3_device *dev) {
return dev->conn->serial_port_name;
}
pm3_device* pm3_get_current_dev(void) {
pm3_device *pm3_get_current_dev(void) {
return session.current_device;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -446,10 +446,10 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
}
}
void bytes_to_bytebits(void* src, size_t srclen, void* dest) {
void bytes_to_bytebits(void *src, size_t srclen, void *dest) {
uint8_t *s = (uint8_t*)src;
uint8_t *d = (uint8_t*)dest;
uint8_t *s = (uint8_t *)src;
uint8_t *d = (uint8_t *)dest;
uint32_t i = srclen * 8;
while (srclen--) {

View file

@ -56,7 +56,7 @@ void print_blocks(uint32_t *data, size_t len);
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
void bytes_to_bytebits(void* src, size_t srclen, void* dest);
void bytes_to_bytebits(void *src, size_t srclen, void *dest);
// Swap endian on arrays up to 64bytes.
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);

View file

@ -143,9 +143,10 @@ PLATFORM_DEFS+=$(STANDALONE_PLATFORM_DEFS)
$(info $(findstring WITH_STANDALONE_*,$(PLATFORM_DEFS)))
# Misc
#PLATFORM_DEFS += -DWITH_LCD
# Misc (LCD support)
ifneq (,$(findstring WITH_LCD,$(PLATFORM_DEFS)))
#PLATFORM_DEFS += -DWITH_LCD
endif
# Add flags dependencies :

View file

@ -1,8 +1,6 @@
clear
pref
rem
quit
exit
analyse lcr
analyse crc
analyse chksum
@ -13,6 +11,7 @@ analyse a
analyse nuid
analyse demodbuff
analyse freq
analyse foo
data biphaserawdecode
data detectclock
data fsktonrz
@ -44,20 +43,15 @@ data print
data samples
data setdebugmode
data tune
emv list
hf list
hf tune
hf search
hf sniff
hf 14a list
hf 14a reader
hf 14a cuids
hf 14a sim
hf 14a sniff
hf 14a config
hf 14b list
hf 14b sriwrite
hf 15 list
hf 15 dump
hf 15 info
hf 15 raw
@ -69,7 +63,6 @@ hf 15 writeafi
hf 15 writedsfid
hf epa cnonces
hf epa preplay
hf felica list
hf felica reader
hf felica sniff
hf felica raw
@ -85,11 +78,9 @@ hf felica rqspecver
hf felica resetmode
hf felica litesim
hf felica litedump
hf fido list
hf fido info
hf iclass info
hf iclass list
hf legic list
hf iclass permutekey
hf legic reader
hf legic info
hf legic dump
@ -101,13 +92,6 @@ hf legic crc
hf legic eload
hf legic esave
hf legic wipe
hf lto dump
hf lto restore
hf lto info
hf lto rdbl
hf lto wrbl
hf lto list
hf mf list
hf mf darkside
hf mf nested
hf mf hardnested
@ -144,7 +128,6 @@ hf mf gen3uid
hf mf gen3blk
hf mf gen3freeze
hf mf ice
hf mfp info
hf mfu info
hf mfu dump
hf mfu restore
@ -161,12 +144,8 @@ hf mfu otptear
hf mfdes enum
hf mfdes getuid
hf mfdes info
hf mfdes list
hf st list
hf thinfilm info
hf thinfilm list
hf thinfilm sim
hf topaz list
hf topaz info
hf topaz reader
hf topaz sim
@ -199,17 +178,6 @@ lf simpsk
lf simbidir
lf sniff
lf tune
lf awid demod
lf awid read
lf awid clone
lf awid sim
lf awid brute
lf awid watch
lf cotag demod
lf cotag read
lf destron demod
lf destron read
lf destron sim
lf em 410x_demod
lf em 410x_read
lf em 410x_sim
@ -229,21 +197,7 @@ lf em 4x50_write
lf em 4x50_write_password
lf em 4x50_read
lf em 4x50_wipe
lf fdxb demod
lf fdxb read
lf fdxb clone
lf fdxb sim
lf gallagher demod
lf gallagher read
lf gallagher clone
lf gallagher sim
lf gproxii demod
lf gproxii read
lf gproxii clone
lf gproxii sim
lf hid demod
lf hid read
lf hitag list
lf hitag info
lf hitag reader
lf hitag sim
@ -251,41 +205,20 @@ lf hitag sniff
lf hitag writer
lf hitag dump
lf hitag cc
lf idteck demod
lf idteck read
lf indala demod
lf indala altdemod
lf indala read
lf indala sim
lf io demod
lf io read
lf io clone
lf io sim
lf io watch
lf jablotron demod
lf jablotron read
lf jablotron clone
lf jablotron sim
lf keri demod
lf motorola demod
lf motorola sim
lf nedap demod
lf nedap generate
lf nedap read
lf nedap clone
lf nedap sim
lf nexwatch demod
lf noralsy demod
lf pac demod
lf paradox demod
lf pcf7931 read
lf pcf7931 write
lf pcf7931 config
lf presco demod
lf pyramid demod
lf securakey demod
lf ti demod
lf ti write
lf t55xx config
lf t55xx dangerraw
lf t55xx detect
@ -306,17 +239,12 @@ lf t55xx recoverpw
lf t55xx sniff
lf t55xx special
lf t55xx wipe
lf viking demod
lf visa2000 demod
mem spiffs
smart list
smart info
smart reader
smart raw
smart upgrade
smart setclock
smart brute
script list
script run
usart btpin
usart btfactory
@ -326,4 +254,3 @@ usart txrx
usart txhex
usart rxhex
usart config
wiegand list

View file

@ -1,82 +1,82 @@
# Notes on Cloner guns
This document is based mostly on information posted on http://www.proxmark.org/forum/viewtopic.php?pid=39903#p39903
- [Notes on Cloner guns](#notes-on-cloner-guns)
- [Blue and black cloners](#blue-and-black-cloners)
- [White cloner (pre 2015)](#white-cloner-pre-2015)
- [White cloner (after 2016)](#white-cloner-after-2016)
- [White cloner (after 2016 D Quality)](#white-cloner-after-2016-d-quality)
- [Restore page1 data](#restore-page1-data)
- [Sniffing the comms](#sniffing-the-comms)
# Blue and black cloners
3 variants:
1. EM cloner
2. HID cloner
3. EM/HID cloner
Quality varies my manufacturer (Quality A (Good) until D (Bad))
They set a password on block 7 of the chip and set the password enable bit in block 0
```
Standard password is normally: 51243648
```
**Be sure to purchase the EM/HID version**
# White cloner (pre 2015)
Multifrequency
Buttons light up BLUE
Reads data correctly
Coil performance acceptable
```
Standard password is normally (for T55xx): AA55BBBB
Standard password 13,56mHz: individual per white cloner
```
# White cloner (after 2016)
Multifrequency
Buttons light up WHITE
Data scrambled (variable per individual cloner, possibly due to prevent legal issues)
Coil performance good
```
Standard password is normally (for T55xx): AA55BBBB
Standard password 13,56mHz: individual per white cloner
```
# White cloner (after 2016 D Quality)
Multifrequency (it says so but it doesn't)
Only works for EM/HID card (125kHz)
High frequency not working
```
Standard password is normally (for T55xx): AA55BBBB
```
**Note: Sets the HID card in TEST MODE**
# Restore page1 data
```
lf t55xx write b 1 d E0150A48 1
If t55xx write b 2 d 2D782308 1
```
# Sniffing the comms
The T55x7 protocol uses a pwm based protocol for writing to tags. In order to make decoding easier try the new command as seen below instead. It will try to extract the data written.
```
-- after threshold limit 20 is triggered, skip 10000 samples before collecting samples.
lf config s 10000 t 20
lf t55xx sniff
-- if you have a save trace from before, try
data load -f xxxxxxx.pm3
lf t55xx sniff 1
```
It uses the existing `lf sniff` command to collect the data, so setting that first as per normal sniffing is recommended. Once you have a sniff, you can "re-sniff" from the stored sniffed data and try different settings, if you think the data is not clean.
# Notes on Cloner guns
This document is based mostly on information posted on http://www.proxmark.org/forum/viewtopic.php?pid=39903#p39903
- [Notes on Cloner guns](#notes-on-cloner-guns)
- [Blue and black cloners](#blue-and-black-cloners)
- [White cloner (pre 2015)](#white-cloner-pre-2015)
- [White cloner (after 2016)](#white-cloner-after-2016)
- [White cloner (after 2016 D Quality)](#white-cloner-after-2016-d-quality)
- [Restore page1 data](#restore-page1-data)
- [Sniffing the comms](#sniffing-the-comms)
# Blue and black cloners
3 variants:
1. EM cloner
2. HID cloner
3. EM/HID cloner
Quality varies my manufacturer (Quality A (Good) until D (Bad))
They set a password on block 7 of the chip and set the password enable bit in block 0
```
Standard password is normally: 51243648
```
**Be sure to purchase the EM/HID version**
# White cloner (pre 2015)
Multifrequency
Buttons light up BLUE
Reads data correctly
Coil performance acceptable
```
Standard password is normally (for T55xx): AA55BBBB
Standard password 13,56mHz: individual per white cloner
```
# White cloner (after 2016)
Multifrequency
Buttons light up WHITE
Data scrambled (variable per individual cloner, possibly due to prevent legal issues)
Coil performance good
```
Standard password is normally (for T55xx): AA55BBBB
Standard password 13,56mHz: individual per white cloner
```
# White cloner (after 2016 D Quality)
Multifrequency (it says so but it doesn't)
Only works for EM/HID card (125kHz)
High frequency not working
```
Standard password is normally (for T55xx): AA55BBBB
```
**Note: Sets the HID card in TEST MODE**
# Restore page1 data
```
lf t55xx write b 1 d E0150A48 1
If t55xx write b 2 d 2D782308 1
```
# Sniffing the comms
The T55x7 protocol uses a pwm based protocol for writing to tags. In order to make decoding easier try the new command as seen below instead. It will try to extract the data written.
```
-- after threshold limit 20 is triggered, skip 10000 samples before collecting samples.
lf config s 10000 t 20
lf t55xx sniff
-- if you have a save trace from before, try
data load -f xxxxxxx.pm3
lf t55xx sniff 1
```
It uses the existing `lf sniff` command to collect the data, so setting that first as per normal sniffing is recommended. Once you have a sniff, you can "re-sniff" from the stored sniffed data and try different settings, if you think the data is not clean.
As normal, the cloner may write data past the end of the 40K sample buffer. So using the `lf config s <x bytes>` then re-run the sniff to see if there is more data.

View file

@ -1,50 +1,50 @@
<a id="Top"></a>
# Notes on Color usage.
## Table of Contents
* [style/color](#style_color)
* [Proxspace](#proxspace)
* [](#)
The client should autodetect color support when starting.
You can also use the command `pref show` to see and set your personal setting.
Why use colors in the Proxmark client? When everything is white it is hard to extract the important information fast. You also need new-lines for extra space to be easier to read.
We have gradually been introducing this color scheme into the client since we got decent color support on all systems: OSX, Linux, WSL, Proxspace.
## style/color
^[Top](#top)
The following definition has be crystallized out from these experiments. Its not set in stone yet so take this document as a guideline for how to create unified system scheme.
### Definition
^[Top](#top)
- blue - system related headers, banner
- white - normal
- cyan - headers
- red - warning, error, catastrophic failures
- yellow - informative (to make things stick out from white blob)
- green - successful, (to make things stick out from white blob)
- magenta - device side messages
### Styled header
^[Top](#top)
```
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
```
For more examples, see also all **-h** helptext now in the LUA scripts.
For the command help texts using _YELLOW_ for the example makes it very easy to see what is the command vs the description.
### non styled header
^[Top](#top)
Most commands doesn't use a header yet. We added it to make it standout (ie: yellow, green) of the informative tidbits in the output of a command.
## Proxspace
^[Top](#top)
Proxspace has support for colors.
<a id="Top"></a>
# Notes on Color usage.
## Table of Contents
* [style/color](#style_color)
* [Proxspace](#proxspace)
* [](#)
The client should autodetect color support when starting.
You can also use the command `pref show` to see and set your personal setting.
Why use colors in the Proxmark client? When everything is white it is hard to extract the important information fast. You also need new-lines for extra space to be easier to read.
We have gradually been introducing this color scheme into the client since we got decent color support on all systems: OSX, Linux, WSL, Proxspace.
## style/color
^[Top](#top)
The following definition has be crystallized out from these experiments. Its not set in stone yet so take this document as a guideline for how to create unified system scheme.
### Definition
^[Top](#top)
- blue - system related headers, banner
- white - normal
- cyan - headers
- red - warning, error, catastrophic failures
- yellow - informative (to make things stick out from white blob)
- green - successful, (to make things stick out from white blob)
- magenta - device side messages
### Styled header
^[Top](#top)
```
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
```
For more examples, see also all **-h** helptext now in the LUA scripts.
For the command help texts using _YELLOW_ for the example makes it very easy to see what is the command vs the description.
### non styled header
^[Top](#top)
Most commands doesn't use a header yet. We added it to make it standout (ie: yellow, green) of the informative tidbits in the output of a command.
## Proxspace
^[Top](#top)
Proxspace has support for colors.

View file

@ -38,6 +38,7 @@ Check column "offline" for their availability.
|`analyse nuid `|Y |`create NUID from 7byte UID`
|`analyse demodbuff `|Y |`Load binary string to demodbuffer`
|`analyse freq `|Y |`Calc wave lengths`
|`analyse foo `|Y |`muxer`
### data
@ -267,7 +268,7 @@ Check column "offline" for their availability.
|`hf iclass encrypt `|Y |`[options..] Encrypt given block data`
|`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file`
|`hf iclass managekeys `|Y |`[options..] Manage keys to use with iclass commands`
|`hf iclass permute `|N |` Permute function from 'heart of darkness' paper`
|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper`
|`hf iclass view `|Y |`[options..] Display content from tag dump file`
@ -538,7 +539,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf awid help `|Y |`this help`
|`lf awid demod `|Y |`demodulate an AWID FSK tag from the GraphBuffer`
|`lf awid read `|N |`attempt to read and extract tag data`
|`lf awid reader `|N |`attempt to read and extract tag data`
|`lf awid clone `|N |`clone AWID tag to T55x7 or Q5/T5555`
|`lf awid sim `|N |`simulate AWID tag`
|`lf awid brute `|N |`Bruteforce card number against reader`
@ -553,7 +554,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf cotag help `|Y |`This help`
|`lf cotag demod `|Y |`Tries to decode a COTAG signal`
|`lf cotag read `|N |`Attempt to read and extract tag data`
|`lf cotag reader `|N |`Attempt to read and extract tag data`
### lf destron
@ -564,7 +565,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf destron help `|Y |`This help`
|`lf destron demod `|Y |`Demodulate an Destron tag from the GraphBuffer`
|`lf destron read `|N |`Attempt to read and extract tag data from the antenna`
|`lf destron reader `|N |`Attempt to read and extract tag data from the antenna`
|`lf destron clone `|N |`Clone Destron tag to T55x7`
|`lf destron sim `|N |`Simulate Destron tag`
@ -609,7 +610,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf fdxb help `|Y |`this help`
|`lf fdxb demod `|Y |`demodulate a FDX-B ISO11784/85 tag from the GraphBuffer`
|`lf fdxb read `|N |`attempt to read at 134kHz and extract tag data`
|`lf fdxb reader `|N |`attempt to read at 134kHz and extract tag data`
|`lf fdxb clone `|N |`clone animal ID tag to T55x7 or Q5/T5555`
|`lf fdxb sim `|N |`simulate Animal ID tag`
@ -622,7 +623,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf gallagher help `|Y |`This help`
|`lf gallagher demod `|Y |`Demodulate an GALLAGHER tag from the GraphBuffer`
|`lf gallagher read `|N |`Attempt to read and extract tag data from the antenna`
|`lf gallagher reader `|N |`Attempt to read and extract tag data from the antenna`
|`lf gallagher clone `|N |`clone GALLAGHER tag to T55x7`
|`lf gallagher sim `|N |`simulate GALLAGHER tag`
@ -635,7 +636,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf gproxii help `|Y |`this help`
|`lf gproxii demod `|Y |`demodulate a G Prox II tag from the GraphBuffer`
|`lf gproxii read `|N |`attempt to read and extract tag data from the antenna`
|`lf gproxii reader `|N |`attempt to read and extract tag data from the antenna`
|`lf gproxii clone `|N |`clone Guardall tag to T55x7 or Q5/T5555`
|`lf gproxii sim `|N |`simulate Guardall tag`
@ -680,7 +681,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf idteck help `|Y |`This help`
|`lf idteck demod `|Y |`Demodulate an Idteck tag from the GraphBuffer`
|`lf idteck read `|N |`Attempt to read and Extract tag data from the antenna`
|`lf idteck reader `|N |`Attempt to read and Extract tag data from the antenna`
### lf indala
@ -692,7 +693,7 @@ Check column "offline" for their availability.
|`lf indala help `|Y |`this help`
|`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer`
|`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)`
|`lf indala read `|N |`read an Indala Prox tag from the antenna`
|`lf indala reader `|N |`read an Indala Prox tag from the antenna`
|`lf indala clone `|N |`clone Indala tag to T55x7 or Q5/T5555`
|`lf indala sim `|N |`simulate Indala tag`
@ -705,7 +706,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf io help `|Y |`this help`
|`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer`
|`lf io read `|N |`attempt to read and extract tag data`
|`lf io reader `|N |`attempt to read and extract tag data`
|`lf io clone `|N |`clone IOProx tag to T55x7 or Q5/T5555`
|`lf io sim `|N |`simulate IOProx tag`
|`lf io watch `|N |`continuously watch for cards. Reader mode`
@ -719,7 +720,7 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`lf jablotron help `|Y |`This help`
|`lf jablotron demod `|Y |`Demodulate an Jablotron tag from the GraphBuffer`
|`lf jablotron read `|N |`Attempt to read and extract tag data from the antenna`
|`lf jablotron reader `|N |`Attempt to read and extract tag data from the antenna`
|`lf jablotron clone `|N |`clone jablotron tag to T55x7 or Q5/T5555`
|`lf jablotron sim `|N |`simulate jablotron tag`
@ -874,7 +875,7 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`lf ti help `|Y |`This help`
|`lf ti demod `|Y |`Demodulate raw bits for TI-type LF tag from the GraphBuffer`
|`lf ti demod `|Y |`Demodulate raw bits for TI LF tag from the GraphBuffer`
|`lf ti reader `|N |`Read and decode a TI 134 kHz tag`
|`lf ti write `|N |`Write new data to a r/w TI 134 kHz tag`

View file

@ -1,249 +1,249 @@
# Notes on ARM & FPGA comms
https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/original_proxmark3/proxmark3.pdf
INTERFACE FROM THE ARM TO THE FPGA
==================================
The FPGA and the ARM can communicate in two main ways: using the ARM's
general-purpose synchronous serial port (the SSP), or using the ARM's
SPI port. The SPI port is used to configure the FPGA. The ARM writes a
configuration word to the FPGA, which determines what operation will
be performed (e.g. read 13.56 MHz vs. read 125 kHz vs. read 134 kHz
vs...). The SPI is used exclusively for configuration.
The SSP is used for actual data sent over the air. The ARM's SSP can
work in slave mode, which means that we can send the data using clocks
generated by the FPGA (either from the PCK0 clock, which the ARM itself
supplies, or from the 13.56 MHz clock, which is certainly not going to
be synchronous to anything in the ARM), which saves synchronizing logic
in the FPGA. The SSP is bi-directional and full-duplex.
The FPGA communicates with the ARM through either
1) SPI port (the ARM is the master)
2) SSC synchronous serial port (the ARM is the master).
opamps, (*note, this affects source code in ARM, calculating actual voltage from antenna. Manufacturers never report what they use to much frustration)
comparators
coil drivers
LF analog path (MCP6294 opamp. This has a GBW of 10 MHz), all 'slow' signals. Used for low frequency signals. Follows the peak detector. Signal centered around generated voltage Vmid.
## FPGA
Since the SPARTAN II is a old outdated FPGA, thus is very limited resource there was a need to split LF and HF functionality into two separate FPGA images. Which are stored in ARM flash memory as bitstreams.
We swap between these images by flashing fpga from ARM on the go. It takes about 1sec. Hence its usually a bad idea to program your device to continuously execute LF alt HF commands.
The FPGA images is precompiled and located inside the /fpga folder.
- fpga_hf.bit
- fpga_lf.bit
There is very rarely changes to the images so there is no need to setup a fpga tool chain to compile it yourself.
Since the FPGA is very old, the Xilinx WebPack ISE 10.1 is the last working tool chain. You can download this legacy development on Xilinx and register for a free product installation id.
Or use mine `11LTAJ5ZJK3PXTUBMF0C0J6C4` The package to download is about 7Gb and linux based. Though I recently managed to install it on WSL for Windows 10.
In order to save space, these fpga images are LZ4 compressed and included in the fullimage.elf file when compiling the ARM SRC. `make armsrc`
This means we save some precious space on the ARM but its a bit more complex when flashing to fpga since it has to decompress on the fly.
### FPGA modes.
- Major modes
- Minor modes
## ARM FPGA communications.
The ARM talks with FPGA over the Synchronous Serial Port (SSC) rx an tx.
ARM, send a 16bit configuration with fits the select major mode.
## ARM GPIO setup
```
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
GPIO_SSC_DIN |
GPIO_SSC_DOUT |
GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
// Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts on Transmit Start,
// data and frame signal is sampled on falling edge of RK
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
if ((FPGA_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// TX clock comes from TK pin, no clock output, outputs change on rising edge of TK,
// TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;
```
## FPGA Setup
// Set up DMA to receive samples from the FPGA. We will use the PDC, with
// a single buffer as a circular buffer (so that we just chain back to
# HARDWARE OVERVIEW
## ADC (ANALOG TO DIGITAL CONVERTER)
The analogue signal that comes from the antenna circuit is fed into an 8-bit Analogue to Digital Converter
(ADC). This delivers 8 output bits in parallel which represent the current voltage retrieved from the field.
## FIELD PROGRAMMABLE GATE ARRAY, FPGA
The 8 output pins from the ADC are connected to 8 pins of the Field Programmable Gate Array (FPGA). An
FPGA has a great advantage over a normal microcontroller in the sense that it emulates hardware. A
hardware description can be compiled and flashed into an FPGA.
Because basic arithmetic functions can be performed fast and in parallel by an FPGA it is faster than an
implementation on a normal microcontroller. Only a real hardware implementation would be faster but
this lacks the flexibility of an FPGA.
The FPGA can therefore be seen as dynamic hardware. It is possible to make a hardware design and flash
it into the memory of the FPGA. This gives some major advantages:
- "Hardware" errors can be corrected; the FPGA can be flashed with a new hardware design.
- Although not as fast as a real hardware implementation, an FPGA is faster than its equivalent on microprocessor. That is, it is specialized for one job.
The FPGA has two main tasks. The first task is to demodulate the signal received from the ADC and relay
this as a digital encoded signal to the ARM. Depending on the task this might be the demodulation of a
100% Amplitude Shift Keying (ASK) signal from the reader or the load modulation of a card. The encoding
schemes used to communicate the signal to the ARM are Modified Miller for the reader and Manchester
encoding for the card signal.
The second task is to modulate an encoded signal that is received from the ARM into the field of the
antenna. This can be both the encoding of reader messages or card messages. For reader messages the
FPGA generates an electromagnetic field on power hi and drops the amplitude for short periods.
## MICROCONTROLLER
The microcontroller is responsible for the protocol management. It receives the digital encoded signals
from the FPGA and decodes them. The decoded signals can just be copied to a buffer in the EEPROM
memory. Additionally, an answer to the received message can be send by encoding a reply and
communicating this to the FPGA.
The microcontroller (ARM) implements the transport layer. First it decodes the samples received from
the FPGA. These samples are stored in a Direct Memory Access (DMA) buffer. The samples are binary
sequences that represent whether the signal was high or low. The software on the ARM tries to decode
these samples. When the Proxmark is in sniffing mode this is done for both the Manchester and Modified
Miller at the same time. Whenever one of the decoding procedures returns a valid message, this message
is stored in another buffer (BigBuf) and both decoding procedures are set to an un-synced state. The
BigBuf is limited to the available memory on the ARM. The current firmware has 2 KB of memory
reserved for traces (Besides the trace, the buffer also stores some temporary data that is needed in the
processing). When the BigBuf buffer is full the function normally returns. A new function call from the
client is needed to download the BigBuf contents to the computer. The BigBuf is especially useful for
protocol investigation. Every single message is stored in this buffer. When a card is emulated or when the
Proxmark is used as a reader the BigBuf can be used to store status messages or protocol exceptions.
```
HF PATH
-- ANTENNA -> rectifying -> lowpass filter -> ADC -> FPGA -> ARM -> USB/CDC | FPC -> CLIENT
| | | |
induct peak detect (8bit) -- modes:
via circuit HF - peak-detected
HF - RAW
HF -
```
```
LF PATH
-- ANTENNA -> rectifying -> lowpass filter -> ADC -> FPGA -> ARM -> USB/CDC | FPC -> CLIENT
| | | |
induct peak detect (8bit) -- modes:
via circuit LF - peak-detected
LF - RAW
```
Problems:
1. dynamic range of signal. Ie: High Carrier signal (reader) and low
##
## To behave like a READER.
By driving all of the buffers LOW, it is possible to make the antenna
look to the receive path like a parallel LC circuit; this provides a
high-voltage output signal. This is typically what will be done when we
are not actively transmitting a carrier (i.e., behaving as a reader).
## To behave like a TAG
On the receive side, there are two possibilities, which are selected by
RLY1. A mechanical relay is used, because the signal from the antenna is
likely to be more positive or negative than the highest or lowest supply
voltages on-board. In the usual case (PEAK-DETECTED mode), the received
signal is peak-detected by an analog circuit, then filtered slightly,
and then digitized by the ADC. This is the case for both the low- and
high-frequency paths, although the details of the circuits for the
two cases are somewhat different. This receive path would typically
be selected when the device is behaving as a reader, or when it is
eavesdropping at close range.
It is also possible to digitize the signal from the antenna directly (RAW
mode), after passing it through a gain stage. This is more likely to be
useful in reading signals at long range, but the available dynamic range
will be poor, since it is limited by the 8-bit A/D.
In either case, an analog signal is digitized by the ADC, and
from there goes in to the FPGA. The FPGA is big enough that it
can perform DSP operations itself. For some high-frequency standards,
the subcarriers are fast enough that it would be inconvenient to do all
the math on a general-purpose CPU. The FPGA can therefore correlate for
the desired signal itself, and simply report the total to the ARM. For
low-frequency tags, it probably makes sense just to pass data straight
through to the ARM.
The FPGA communicates with the ARM through either its SPI port (the ARM
is the master) or its generic synchronous serial port (again, the ARM
is the master). The ARM connects to the outside world over USB.
## To sniff traffic
## FPGA purpose
Digital signal processing.
In short, apply low pass / hi pass filtering, peak detect, correlate signal meaning IQ pair collecting.
IQ means measure at In-phase and 90 phase shift later Quadrature-phase, with IQ samples you can plot the signal on a vector plan.
```
IQ1 = 1,1 : 1, -1 (rising)
IQ2 = -1,1 : 1, 1 (falling)
-1,1 | 1,1
| (q2)
(i2) | (i1)
|
----------0------------>
|
| (q1)
-1,-1 | 1, -1
```
# Notes on ARM & FPGA comms
https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/original_proxmark3/proxmark3.pdf
INTERFACE FROM THE ARM TO THE FPGA
==================================
The FPGA and the ARM can communicate in two main ways: using the ARM's
general-purpose synchronous serial port (the SSP), or using the ARM's
SPI port. The SPI port is used to configure the FPGA. The ARM writes a
configuration word to the FPGA, which determines what operation will
be performed (e.g. read 13.56 MHz vs. read 125 kHz vs. read 134 kHz
vs...). The SPI is used exclusively for configuration.
The SSP is used for actual data sent over the air. The ARM's SSP can
work in slave mode, which means that we can send the data using clocks
generated by the FPGA (either from the PCK0 clock, which the ARM itself
supplies, or from the 13.56 MHz clock, which is certainly not going to
be synchronous to anything in the ARM), which saves synchronizing logic
in the FPGA. The SSP is bi-directional and full-duplex.
The FPGA communicates with the ARM through either
1) SPI port (the ARM is the master)
2) SSC synchronous serial port (the ARM is the master).
opamps, (*note, this affects source code in ARM, calculating actual voltage from antenna. Manufacturers never report what they use to much frustration)
comparators
coil drivers
LF analog path (MCP6294 opamp. This has a GBW of 10 MHz), all 'slow' signals. Used for low frequency signals. Follows the peak detector. Signal centered around generated voltage Vmid.
## FPGA
Since the SPARTAN II is a old outdated FPGA, thus is very limited resource there was a need to split LF and HF functionality into two separate FPGA images. Which are stored in ARM flash memory as bitstreams.
We swap between these images by flashing fpga from ARM on the go. It takes about 1sec. Hence its usually a bad idea to program your device to continuously execute LF alt HF commands.
The FPGA images is precompiled and located inside the /fpga folder.
- fpga_hf.bit
- fpga_lf.bit
There is very rarely changes to the images so there is no need to setup a fpga tool chain to compile it yourself.
Since the FPGA is very old, the Xilinx WebPack ISE 10.1 is the last working tool chain. You can download this legacy development on Xilinx and register for a free product installation id.
Or use mine `11LTAJ5ZJK3PXTUBMF0C0J6C4` The package to download is about 7Gb and linux based. Though I recently managed to install it on WSL for Windows 10.
In order to save space, these fpga images are LZ4 compressed and included in the fullimage.elf file when compiling the ARM SRC. `make armsrc`
This means we save some precious space on the ARM but its a bit more complex when flashing to fpga since it has to decompress on the fly.
### FPGA modes.
- Major modes
- Minor modes
## ARM FPGA communications.
The ARM talks with FPGA over the Synchronous Serial Port (SSC) rx an tx.
ARM, send a 16bit configuration with fits the select major mode.
## ARM GPIO setup
```
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
GPIO_SSC_DIN |
GPIO_SSC_DOUT |
GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
// Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts on Transmit Start,
// data and frame signal is sampled on falling edge of RK
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
if ((FPGA_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// TX clock comes from TK pin, no clock output, outputs change on rising edge of TK,
// TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;
```
## FPGA Setup
// Set up DMA to receive samples from the FPGA. We will use the PDC, with
// a single buffer as a circular buffer (so that we just chain back to
# HARDWARE OVERVIEW
## ADC (ANALOG TO DIGITAL CONVERTER)
The analogue signal that comes from the antenna circuit is fed into an 8-bit Analogue to Digital Converter
(ADC). This delivers 8 output bits in parallel which represent the current voltage retrieved from the field.
## FIELD PROGRAMMABLE GATE ARRAY, FPGA
The 8 output pins from the ADC are connected to 8 pins of the Field Programmable Gate Array (FPGA). An
FPGA has a great advantage over a normal microcontroller in the sense that it emulates hardware. A
hardware description can be compiled and flashed into an FPGA.
Because basic arithmetic functions can be performed fast and in parallel by an FPGA it is faster than an
implementation on a normal microcontroller. Only a real hardware implementation would be faster but
this lacks the flexibility of an FPGA.
The FPGA can therefore be seen as dynamic hardware. It is possible to make a hardware design and flash
it into the memory of the FPGA. This gives some major advantages:
- "Hardware" errors can be corrected; the FPGA can be flashed with a new hardware design.
- Although not as fast as a real hardware implementation, an FPGA is faster than its equivalent on microprocessor. That is, it is specialized for one job.
The FPGA has two main tasks. The first task is to demodulate the signal received from the ADC and relay
this as a digital encoded signal to the ARM. Depending on the task this might be the demodulation of a
100% Amplitude Shift Keying (ASK) signal from the reader or the load modulation of a card. The encoding
schemes used to communicate the signal to the ARM are Modified Miller for the reader and Manchester
encoding for the card signal.
The second task is to modulate an encoded signal that is received from the ARM into the field of the
antenna. This can be both the encoding of reader messages or card messages. For reader messages the
FPGA generates an electromagnetic field on power hi and drops the amplitude for short periods.
## MICROCONTROLLER
The microcontroller is responsible for the protocol management. It receives the digital encoded signals
from the FPGA and decodes them. The decoded signals can just be copied to a buffer in the EEPROM
memory. Additionally, an answer to the received message can be send by encoding a reply and
communicating this to the FPGA.
The microcontroller (ARM) implements the transport layer. First it decodes the samples received from
the FPGA. These samples are stored in a Direct Memory Access (DMA) buffer. The samples are binary
sequences that represent whether the signal was high or low. The software on the ARM tries to decode
these samples. When the Proxmark is in sniffing mode this is done for both the Manchester and Modified
Miller at the same time. Whenever one of the decoding procedures returns a valid message, this message
is stored in another buffer (BigBuf) and both decoding procedures are set to an un-synced state. The
BigBuf is limited to the available memory on the ARM. The current firmware has 2 KB of memory
reserved for traces (Besides the trace, the buffer also stores some temporary data that is needed in the
processing). When the BigBuf buffer is full the function normally returns. A new function call from the
client is needed to download the BigBuf contents to the computer. The BigBuf is especially useful for
protocol investigation. Every single message is stored in this buffer. When a card is emulated or when the
Proxmark is used as a reader the BigBuf can be used to store status messages or protocol exceptions.
```
HF PATH
-- ANTENNA -> rectifying -> lowpass filter -> ADC -> FPGA -> ARM -> USB/CDC | FPC -> CLIENT
| | | |
induct peak detect (8bit) -- modes:
via circuit HF - peak-detected
HF - RAW
HF -
```
```
LF PATH
-- ANTENNA -> rectifying -> lowpass filter -> ADC -> FPGA -> ARM -> USB/CDC | FPC -> CLIENT
| | | |
induct peak detect (8bit) -- modes:
via circuit LF - peak-detected
LF - RAW
```
Problems:
1. dynamic range of signal. Ie: High Carrier signal (reader) and low
##
## To behave like a READER.
By driving all of the buffers LOW, it is possible to make the antenna
look to the receive path like a parallel LC circuit; this provides a
high-voltage output signal. This is typically what will be done when we
are not actively transmitting a carrier (i.e., behaving as a reader).
## To behave like a TAG
On the receive side, there are two possibilities, which are selected by
RLY1. A mechanical relay is used, because the signal from the antenna is
likely to be more positive or negative than the highest or lowest supply
voltages on-board. In the usual case (PEAK-DETECTED mode), the received
signal is peak-detected by an analog circuit, then filtered slightly,
and then digitized by the ADC. This is the case for both the low- and
high-frequency paths, although the details of the circuits for the
two cases are somewhat different. This receive path would typically
be selected when the device is behaving as a reader, or when it is
eavesdropping at close range.
It is also possible to digitize the signal from the antenna directly (RAW
mode), after passing it through a gain stage. This is more likely to be
useful in reading signals at long range, but the available dynamic range
will be poor, since it is limited by the 8-bit A/D.
In either case, an analog signal is digitized by the ADC, and
from there goes in to the FPGA. The FPGA is big enough that it
can perform DSP operations itself. For some high-frequency standards,
the subcarriers are fast enough that it would be inconvenient to do all
the math on a general-purpose CPU. The FPGA can therefore correlate for
the desired signal itself, and simply report the total to the ARM. For
low-frequency tags, it probably makes sense just to pass data straight
through to the ARM.
The FPGA communicates with the ARM through either its SPI port (the ARM
is the master) or its generic synchronous serial port (again, the ARM
is the master). The ARM connects to the outside world over USB.
## To sniff traffic
## FPGA purpose
Digital signal processing.
In short, apply low pass / hi pass filtering, peak detect, correlate signal meaning IQ pair collecting.
IQ means measure at In-phase and 90 phase shift later Quadrature-phase, with IQ samples you can plot the signal on a vector plan.
```
IQ1 = 1,1 : 1, -1 (rising)
IQ2 = -1,1 : 1, 1 (falling)
-1,1 | 1,1
| (q2)
(i2) | (i1)
|
----------0------------>
|
| (q1)
-1,-1 | 1, -1
```

View file

@ -1,101 +1,101 @@
# Notes on MFU binary formats
- new mfu format
- old mfu format
- plain mfu format
- future mfu format
## New mfu format
The new mfu binary format was created to compensate for different manufactures tag functions.
Like UL-Ev1 has three counter and tearing bytes, while NTAG only has one counter and tearing byte.
PACK was removed from header, since its just normally part of the tag memory, unreadable, but when
a proxmark3 dumps a tag and we have pwd/pack, we add those to their normal location in memory.
This makes memory not a exact memory dump from a tag, but a "what it should have looked like" if we could read all memory
```
// New Ultralight/NTAG dump file format
// Length must be aligned to 4 bytes (UL/NTAG page)
#define MFU_DUMP_PREFIX_LENGTH 56
typedef struct {
uint8_t version[8];
uint8_t tbo[2];
uint8_t tbo1[1];
uint8_t pages; // max page number in dump
uint8_t signature[32];
uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag
uint8_t data[1024];
} PACKED mfu_dump_t;
```
## Old mfu format
The old binary format saved the extra data on tag in order for the Proxmark3 to able to simulate a real tag.
```
// Old Ultralight/NTAG dump file format
#define OLD_MFU_DUMP_PREFIX_LENGTH 48
typedef struct {
uint8_t version[8];
uint8_t tbo[2];
uint8_t tearing[3];
uint8_t pack[2];
uint8_t tbo1[1];
uint8_t signature[32];
uint8_t data[1024];
} old_mfu_dump_t;
```
## Plain mfu format
The first binary format for MFU was just a memory dump from the tag block 0 to end.
No extra data was saved.
```
uint8_t data[1024];
```
## future mfu format
For developers of apps and other tools, like libnfc, we don't recommend using binary formats.
We decided to adopt a JSON based format, which is much more flexible to changes of new tag functionality.
Example
```
{
"Created": "proxmark3",
"FileType": "mfu",
"Card": {
"UID": "04F654CAFC388",
"Version": "0004030101000B0",
"TBO_0": "000",
"TBO_1": "0",
"Signature": "BC9BFD4B550C16B2B5A5ABA10B644A027B4CB03DDB46F94D992DC0FB02E0C3F",
"Counter0": "00000",
"Tearing0": "BD",
"Counter1": "00000",
"Tearing1": "BD",
"Counter2": "00000",
"Tearing2": "BD"
},
"blocks": {
"0": "04F6542",
"1": "CAFC388",
"2": "8E48000",
"3": "E110120",
"4": "0103A00",
"5": "340300F",
"6": "0000000",
"7": "0000000",
"8": "0000000",
"9": "0000000",
"10": "0000000",
"11": "0000000",
"12": "1122334",
"13": "0000000",
"14": "0000000",
"15": "0000000",
"16": "000000F",
"17": "0005000",
"18": "0000000",
"19": "0000000"
}
}
```
# Notes on MFU binary formats
- new mfu format
- old mfu format
- plain mfu format
- future mfu format
## New mfu format
The new mfu binary format was created to compensate for different manufactures tag functions.
Like UL-Ev1 has three counter and tearing bytes, while NTAG only has one counter and tearing byte.
PACK was removed from header, since its just normally part of the tag memory, unreadable, but when
a proxmark3 dumps a tag and we have pwd/pack, we add those to their normal location in memory.
This makes memory not a exact memory dump from a tag, but a "what it should have looked like" if we could read all memory
```
// New Ultralight/NTAG dump file format
// Length must be aligned to 4 bytes (UL/NTAG page)
#define MFU_DUMP_PREFIX_LENGTH 56
typedef struct {
uint8_t version[8];
uint8_t tbo[2];
uint8_t tbo1[1];
uint8_t pages; // max page number in dump
uint8_t signature[32];
uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag
uint8_t data[1024];
} PACKED mfu_dump_t;
```
## Old mfu format
The old binary format saved the extra data on tag in order for the Proxmark3 to able to simulate a real tag.
```
// Old Ultralight/NTAG dump file format
#define OLD_MFU_DUMP_PREFIX_LENGTH 48
typedef struct {
uint8_t version[8];
uint8_t tbo[2];
uint8_t tearing[3];
uint8_t pack[2];
uint8_t tbo1[1];
uint8_t signature[32];
uint8_t data[1024];
} old_mfu_dump_t;
```
## Plain mfu format
The first binary format for MFU was just a memory dump from the tag block 0 to end.
No extra data was saved.
```
uint8_t data[1024];
```
## future mfu format
For developers of apps and other tools, like libnfc, we don't recommend using binary formats.
We decided to adopt a JSON based format, which is much more flexible to changes of new tag functionality.
Example
```
{
"Created": "proxmark3",
"FileType": "mfu",
"Card": {
"UID": "04F654CAFC388",
"Version": "0004030101000B0",
"TBO_0": "000",
"TBO_1": "0",
"Signature": "BC9BFD4B550C16B2B5A5ABA10B644A027B4CB03DDB46F94D992DC0FB02E0C3F",
"Counter0": "00000",
"Tearing0": "BD",
"Counter1": "00000",
"Tearing1": "BD",
"Counter2": "00000",
"Tearing2": "BD"
},
"blocks": {
"0": "04F6542",
"1": "CAFC388",
"2": "8E48000",
"3": "E110120",
"4": "0103A00",
"5": "340300F",
"6": "0000000",
"7": "0000000",
"8": "0000000",
"9": "0000000",
"10": "0000000",
"11": "0000000",
"12": "1122334",
"13": "0000000",
"14": "0000000",
"15": "0000000",
"16": "000000F",
"17": "0005000",
"18": "0000000",
"19": "0000000"
}
}
```

6
pm3
View file

@ -133,7 +133,7 @@ function get_pm3_list_Windows {
# Need to look for this first, the call to Win32_serialport "crashes" then native bt serial port. Don't ask why.
#BT direct SERIAL PORTS (COM)
if $FINDBTRFCOMM; then
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2> /dev/null | awk 'match($0,/COM([0-9]+)/,m){print m[1]}'); do
for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do
DEV=${DEV/ */}
PM3LIST+=("$DEV")
if [ ${#PM3LIST[*]} -ge "$N" ]; then
@ -143,7 +143,7 @@ function get_pm3_list_Windows {
fi
# Normal SERIAL PORTS (COM)
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_9AC4&PID_4B8F*' | Select DeviceID" 2>/dev/null | awk '/^COM/{print $1}'); do
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
DEV=${DEV/ */}
PM3LIST+=("$DEV")
if [ ${#PM3LIST[*]} -ge "$N" ]; then
@ -153,7 +153,7 @@ function get_pm3_list_Windows {
#white BT dongle SERIAL PORTS (COM)
if $FINDBTDONGLE; then
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select DeviceID" 2>/dev/null | awk '/^COM/{print $1}'); do
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
DEV=${DEV/ */}
PM3LIST+=("$DEV")
if [ ${#PM3LIST[*]} -ge "$N" ]; then