mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
Merge branch 'master' into update_4x50
update 201130
This commit is contained in:
commit
efd6c04b7e
49 changed files with 5965 additions and 5685 deletions
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, "");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, "-------------------------------------------------------------");
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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--) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 :
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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
6
pm3
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue