mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-15 06:50:00 +00:00
Merge branch 'RfidResearchGroup:master' into master
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
|
||||
- Added `lf trovan` commands to support Trovan Animal ID (@iceman1001)
|
||||
- Added `hf mf gdmgetblk/gdmgethidblk/gdmsethidblk/gdmsetuid/gdmwipe/gdmsetsig` (@0x6r1an0y)
|
||||
- Changed `hf mf gdmparsecfg/gdmsetblk` (@0x6r1an0y)
|
||||
- Renamed `hf mf gdmcfg` (@0x6r1an0y)
|
||||
|
||||
@@ -461,6 +461,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/cmdlfsecurakey.c
|
||||
${PM3_ROOT}/client/src/cmdlft55xx.c
|
||||
${PM3_ROOT}/client/src/cmdlfti.c
|
||||
${PM3_ROOT}/client/src/cmdlftrovan.c
|
||||
${PM3_ROOT}/client/src/cmdlfviking.c
|
||||
${PM3_ROOT}/client/src/cmdlfvisa2000.c
|
||||
${PM3_ROOT}/client/src/cmdlfzx8211.c
|
||||
@@ -491,6 +492,9 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/pm3.c
|
||||
${PM3_ROOT}/client/src/pm3_binlib.c
|
||||
${PM3_ROOT}/client/src/pm3_bitlib.c
|
||||
${PM3_ROOT}/client/src/pm3_dsp.c
|
||||
|
||||
${PM3_ROOT}/client/src/pm3_fit.c
|
||||
${PM3_ROOT}/client/src/pm3line.c
|
||||
${PM3_ROOT}/client/src/scandir.c
|
||||
${PM3_ROOT}/client/src/scripting.c
|
||||
|
||||
@@ -802,6 +802,7 @@ SRCS = mifare/aiddesfire.c \
|
||||
cmdlfsecurakey.c \
|
||||
cmdlft55xx.c \
|
||||
cmdlfti.c \
|
||||
cmdlftrovan.c \
|
||||
cmdlfviking.c \
|
||||
cmdlfvisa2000.c \
|
||||
cmdlfzx8211.c \
|
||||
@@ -888,6 +889,8 @@ SRCS = mifare/aiddesfire.c \
|
||||
pm3.c \
|
||||
pm3_binlib.c \
|
||||
pm3_bitlib.c \
|
||||
pm3_dsp.c \
|
||||
pm3_fit.c \
|
||||
preferences.c \
|
||||
pm3line.c \
|
||||
proxmark3.c \
|
||||
|
||||
+1733
-112
File diff suppressed because it is too large
Load Diff
@@ -512,11 +512,11 @@ static int CmdFlashMemSpiFFSUpload(const char *Cmd) {
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, FILE_PATH_SIZE, &slen);
|
||||
|
||||
int dlen = 0;
|
||||
char dest[32] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, 32, &dlen);
|
||||
char dst[32] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dst, 32, &dlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(DEBUG, "Upload `" _YELLOW_("%s") "` -> `" _YELLOW_("%s") "`", src, dest);
|
||||
PrintAndLogEx(DEBUG, "Upload `" _YELLOW_("%s") "` -> `" _YELLOW_("%s") "`", src, dst);
|
||||
|
||||
size_t datalen = 0;
|
||||
uint8_t *data = NULL;
|
||||
@@ -527,11 +527,12 @@ static int CmdFlashMemSpiFFSUpload(const char *Cmd) {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
res = flashmem_spiffs_load(dest, data, datalen);
|
||||
res = flashmem_spiffs_load(dst, data, datalen);
|
||||
free(data);
|
||||
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") " bytes to file "_GREEN_("%s"), datalen, dest);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") " bytes to file "_GREEN_("%s"), datalen, dst);
|
||||
}
|
||||
|
||||
PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("mem spiffs tree") "` to verify");
|
||||
return res;
|
||||
|
||||
+1
-1
@@ -395,7 +395,7 @@ int CmdHFTune(const char *Cmd) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark HF shutdown, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30);
|
||||
PrintAndLogEx(NORMAL, _CLR_LINE_ "\r");
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Min....... %u mV", v_min);
|
||||
|
||||
@@ -3132,7 +3132,7 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
||||
arg_lit0("t", "tlv", "executes TLV decoder if it possible"),
|
||||
arg_lit0(NULL, "decode", "decode apdu request if it possible"),
|
||||
arg_str0("m", "make", "<hex>", "make apdu with head from this field and data from data field.\n"
|
||||
" must be 4 bytes: <CLA INS P1 P2>"),
|
||||
" must be 4 bytes: <CLA INS P1 P2>"),
|
||||
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
|
||||
arg_int0("l", "le", "<int>", "Le apdu parameter if `m` parameter included"),
|
||||
arg_str1("d", "data", "<hex>", "<APDU | data> if `m` parameter included"),
|
||||
|
||||
+18
-18
@@ -1383,22 +1383,22 @@ static void iso15_render_presence_table(const iso15_seen_tag_t *seen, int n,
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (seen[i].present) {
|
||||
PrintAndLogEx(INFO, "%3d %-25s %02X %spresent%s"
|
||||
, i + 1
|
||||
, iso15693_sprintUID(NULL, (uint8_t *)seen[i].uid)
|
||||
, seen[i].dsfid
|
||||
, c_grn
|
||||
, c_off
|
||||
);
|
||||
, i + 1
|
||||
, iso15693_sprintUID(NULL, (uint8_t *)seen[i].uid)
|
||||
, seen[i].dsfid
|
||||
, c_grn
|
||||
, c_off
|
||||
);
|
||||
} else {
|
||||
uint32_t secs = (uint32_t)((now - seen[i].last_seen_ms) / 1000);
|
||||
PrintAndLogEx(INFO, "%3d %-25s %02X %sgone%s (%us ago)"
|
||||
, i + 1
|
||||
, iso15693_sprintUID(NULL, (uint8_t *)seen[i].uid)
|
||||
, seen[i].dsfid
|
||||
, c_yel
|
||||
, c_off
|
||||
, secs
|
||||
);
|
||||
, i + 1
|
||||
, iso15693_sprintUID(NULL, (uint8_t *)seen[i].uid)
|
||||
, seen[i].dsfid
|
||||
, c_yel
|
||||
, c_off
|
||||
, secs
|
||||
);
|
||||
}
|
||||
lines++;
|
||||
}
|
||||
@@ -3791,12 +3791,12 @@ static int CmdHF15SlixProtectPage(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(INFO, "Trying to set page protection pointer to " _YELLOW_("%d"), payload.divide_ptr);
|
||||
PrintAndLogEx(INFO, _YELLOW_("LO") " page access %s%s"
|
||||
, (payload.prot_status & 0x01) ? _RED_("r") : _GREEN_("r")
|
||||
, (payload.prot_status & 0x02) ? _RED_("w") : _GREEN_("w")
|
||||
);
|
||||
, (payload.prot_status & 0x01) ? _RED_("r") : _GREEN_("r")
|
||||
, (payload.prot_status & 0x02) ? _RED_("w") : _GREEN_("w")
|
||||
);
|
||||
PrintAndLogEx(INFO, _YELLOW_("HI") " page access %s%s"
|
||||
, (payload.prot_status & 0x10) ? _RED_("r") : _GREEN_("r")
|
||||
, (payload.prot_status & 0x20) ? _RED_("w") : _GREEN_("w"));
|
||||
, (payload.prot_status & 0x10) ? _RED_("r") : _GREEN_("r")
|
||||
, (payload.prot_status & 0x20) ? _RED_("w") : _GREEN_("w"));
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
||||
+12
-12
@@ -201,11 +201,11 @@ static int legic_write_dump_to_tag(uint8_t *dump, size_t bytes_read) {
|
||||
static int CmdLegicMigrate(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf legic migrate",
|
||||
"Clone a LEGIC Prime dump to the currently attached tag.\n"
|
||||
"Optionally apply a DCF update after cloning, but only when explicitly requested.",
|
||||
"hf legic migrate -f src.bin\n"
|
||||
"hf legic migrate -f src.bin --kgh\n"
|
||||
"hf legic migrate -f src.bin --dcf 60EA --danger");
|
||||
"Clone a LEGIC Prime dump to the currently attached tag.\n"
|
||||
"Optionally apply a DCF update after cloning, but only when explicitly requested.",
|
||||
"hf legic migrate -f src.bin\n"
|
||||
"hf legic migrate -f src.bin --kgh\n"
|
||||
"hf legic migrate -f src.bin --dcf 60EA --danger");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
@@ -1352,13 +1352,13 @@ static int CmdLegicRestore(const char *Cmd) {
|
||||
static int CmdLegicClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf legic clone",
|
||||
"Rewrite a LEGIC dump for a new target tag or MCC.\n"
|
||||
"Use --mcc to rewrite only the dump obfuscation, or --write to clone to the current tag.\n"
|
||||
"Use --kgh with --write to recalculate UID-bound KGH payload CRCs.",
|
||||
"hf legic clone -f src.bin -c 39 -o clone.bin\n"
|
||||
"hf legic clone -f src.bin --write\n"
|
||||
"hf legic clone -f src.bin --write --kgh\n"
|
||||
"hf legic clone -f src.bin --write --kgh -o clone.bin");
|
||||
"Rewrite a LEGIC dump for a new target tag or MCC.\n"
|
||||
"Use --mcc to rewrite only the dump obfuscation, or --write to clone to the current tag.\n"
|
||||
"Use --kgh with --write to recalculate UID-bound KGH payload CRCs.",
|
||||
"hf legic clone -f src.bin -c 39 -o clone.bin\n"
|
||||
"hf legic clone -f src.bin --write\n"
|
||||
"hf legic clone -f src.bin --write --kgh\n"
|
||||
"hf legic clone -f src.bin --write --kgh -o clone.bin");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
||||
+33
-1
@@ -49,6 +49,7 @@
|
||||
#include "cmdlfidteck.h" // for idteck menu
|
||||
#include "cmdlfio.h" // for ioprox menu
|
||||
#include "cmdlfcotag.h" // for COTAG menu
|
||||
#include "pm3_dsp.h" // pm3_extract, pm3_is_switched_carrier
|
||||
#include "cmdlfdestron.h" // for FDX-A FECAVA Destron menu
|
||||
#include "cmdlffdxb.h" // for FDX-B menu
|
||||
#include "cmdlfgallagher.h" // for GALLAGHER menu
|
||||
@@ -68,6 +69,7 @@
|
||||
#include "cmdlfsecurakey.h" // for securakey menu
|
||||
#include "cmdlft55xx.h" // for t55xx menu
|
||||
#include "cmdlfti.h" // for ti menu
|
||||
#include "cmdlftrovan.h" // for trovan menu
|
||||
#include "cmdlfviking.h" // for viking menu
|
||||
#include "cmdlfvisa2000.h" // for VISA2000 menu
|
||||
#include "cmdlfzx8211.h" // for ZX8211 menu
|
||||
@@ -239,7 +241,7 @@ static int CmdLFTune(const char *Cmd) {
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30);
|
||||
PrintAndLogEx(NORMAL, _CLR_LINE_ "\r");
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Min....... %u mV", v_min);
|
||||
PrintAndLogEx(INFO, "Max....... %u mV", v_max);
|
||||
@@ -2211,6 +2213,35 @@ int CmdLFfind(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (demodTrovan(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Trovan ID") " found!");
|
||||
if (search_cont) {
|
||||
found++;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// COTAG last, and only when the capture actually looks like one.
|
||||
if (found == 0) {
|
||||
|
||||
double *sig = pm3_extract(g_GraphBuffer, g_GraphTraceLen, 0, g_GraphTraceLen);
|
||||
if (sig != NULL) {
|
||||
|
||||
const bool switched = pm3_is_switched_carrier(sig, g_GraphTraceLen);
|
||||
free(sig);
|
||||
|
||||
if (switched && demodCOTAG(false, -1, -1) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("COTAG ID") " found!");
|
||||
if (search_cont) {
|
||||
found++;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
PrintAndLogEx(FAILED, _RED_("No known 125/134 kHz tags found!"));
|
||||
}
|
||||
@@ -2351,6 +2382,7 @@ static command_t CommandTable[] = {
|
||||
{"securakey", CmdLFSecurakey, AlwaysAvailable, "{ Securakey RFIDs... }"},
|
||||
{"ti", CmdLFTI, AlwaysAvailable, "{ TI CHIPs... }"},
|
||||
{"t55xx", CmdLFT55XX, AlwaysAvailable, "{ T55xx CHIPs... }"},
|
||||
{"trovan", CmdLFTrovan, AlwaysAvailable, "{ Trovan animal IDs... }"},
|
||||
{"viking", CmdLFViking, AlwaysAvailable, "{ Viking RFIDs... }"},
|
||||
{"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"},
|
||||
// {"zx", CmdLFZx8211, AlwaysAvailable, "{ ZX8211 RFIDs... }"},
|
||||
|
||||
+160
-242
@@ -54,75 +54,6 @@ static void find_avg_high_low(const int32_t *samples, int num_samples,
|
||||
double *out_high_level, double *out_low_level);
|
||||
static double trimmed_mean_abs(const int32_t *samples, int start, int count);
|
||||
|
||||
#if 0
|
||||
// TODO: With the new cotag implementation shall we remove this old version
|
||||
// or is there anything we could use from it?
|
||||
// COTAG demod should be able to use g_GraphBuffer,
|
||||
// when data load samples
|
||||
int demodCOTAG(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
|
||||
uint8_t bits[COTAG_BITS] = {0};
|
||||
size_t bitlen = COTAG_BITS;
|
||||
memcpy(bits, g_DemodBuffer, COTAG_BITS);
|
||||
|
||||
uint8_t inv_bits[COTAG_BITS] = {0};
|
||||
memcpy(inv_bits, g_DemodBuffer, COTAG_BITS);
|
||||
|
||||
uint8_t alignPos = 0;
|
||||
uint16_t err = manrawdecode(bits, &bitlen, 1, &alignPos);
|
||||
if (err > 50) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - COTAG too many errors: %d", err);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
setDemodBuff(bits, bitlen, 0);
|
||||
|
||||
//got a good demod
|
||||
uint16_t cn = bytebits_to_byteLSBF(bits + 1, 16);
|
||||
uint32_t fc = bytebits_to_byteLSBF(bits + 1 + 16, 8);
|
||||
|
||||
uint32_t raw1 = bytebits_to_byteLSBF(bits, 32);
|
||||
uint32_t raw2 = bytebits_to_byteLSBF(bits + 32, 32);
|
||||
uint32_t raw3 = bytebits_to_byteLSBF(bits + 64, 32);
|
||||
uint32_t raw4 = bytebits_to_byteLSBF(bits + 96, 32);
|
||||
|
||||
|
||||
/*
|
||||
fc 161: 1010 0001 -> LSB 1000 0101
|
||||
cn 33593 1000 0011 0011 1001 -> LSB 1001 1100 1100 0001
|
||||
cccc cccc cccc cccc ffffffff
|
||||
0 1001 1100 1100 0001 1000 0101 0000 0000 100001010000000001111011100000011010000010000000000000000000000000000000000000000000000000000000100111001100000110000101000
|
||||
1001 1100 1100 0001 10000101
|
||||
|
||||
COTAG FC/272
|
||||
1 7 7 D E 2 0 0 8 0 0 0 3 9 2 0 D 0 4 0000000000000
|
||||
0001 0111 0111 1101 1110 0010 0000 0000 1000 0000 0000 0000 0011 1001 0010 0000 1101 0000 0100 0000000000000000000000000000000000000000000000000000000
|
||||
0001 0111 0111 1101 1110 001 0010 1001 0011 1000 0110 0100
|
||||
|
||||
*/
|
||||
PrintAndLogEx(SUCCESS, "COTAG Found: FC " _GREEN_("%u")", CN: " _GREEN_("%u")" Raw: %08X%08X%08X%08X", fc, cn, raw1, raw2, raw3, raw4);
|
||||
|
||||
bitlen = COTAG_BITS;
|
||||
err = manrawdecode(inv_bits, &bitlen, 0, &alignPos);
|
||||
if (err < 50) {
|
||||
uint32_t cn_large = bytebits_to_byte(inv_bits + 1, 23);
|
||||
cn_large = reflect32(cn_large) >> 9;
|
||||
uint8_t a = bytebits_to_byte(inv_bits + 48, 4);
|
||||
uint8_t b = bytebits_to_byte(inv_bits + 52, 4);
|
||||
uint8_t c = bytebits_to_byte(inv_bits + 56, 4);
|
||||
uint16_t fc_large = NIBBLE_LOW(c) << 8 | NIBBLE_LOW(b) << 4 | NIBBLE_LOW(a);
|
||||
|
||||
raw1 = bytebits_to_byte(inv_bits, 32);
|
||||
raw2 = bytebits_to_byte(inv_bits + 32, 32);
|
||||
raw3 = bytebits_to_byte(inv_bits + 64, 32);
|
||||
raw4 = bytebits_to_byte(inv_bits + 96, 32);
|
||||
PrintAndLogEx(SUCCESS, " FC " _GREEN_("%u")", CN: " _GREEN_("%u")" Raw: %08X%08X%08X%08X", fc_large, cn_large, raw1, raw2, raw3, raw4);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Demodulate COTAG samples.
|
||||
*
|
||||
@@ -141,64 +72,80 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
uint8_t *manchester_demod = NULL;
|
||||
uint8_t *manchester_demod_reversed = NULL;
|
||||
|
||||
/* Calculate min, max, average */
|
||||
int manchester_count = 0;
|
||||
const char *fail = NULL;
|
||||
|
||||
int64_t sum = 0;
|
||||
min = max = samples[0];
|
||||
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
sum += samples[i];
|
||||
if (samples[i] < min) min = samples[i];
|
||||
if (samples[i] > max) max = samples[i];
|
||||
if (samples[i] < min) {
|
||||
min = samples[i];
|
||||
}
|
||||
|
||||
if (samples[i] > max) {
|
||||
max = samples[i];
|
||||
}
|
||||
}
|
||||
|
||||
avg = (double)sum / (double)num_samples;
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Clock: %d", clock);
|
||||
if (threshold < 0)
|
||||
if (threshold < 0) {
|
||||
PrintAndLogEx(INFO, " Threshold: auto");
|
||||
else
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " Threshold: %.2f", threshold);
|
||||
}
|
||||
PrintAndLogEx(INFO, " Min : %" PRId32, min);
|
||||
PrintAndLogEx(INFO, " Max : %" PRId32, max);
|
||||
PrintAndLogEx(INFO, " Avg : %.2f\n", avg);
|
||||
printf("\n");
|
||||
PrintAndLogEx(INFO, " Avg : %.2f", avg);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
/* DC offset removal: subtract average from every sample */
|
||||
// DC offset removal: subtract average from every sample
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
double v = round((double)samples[i] - avg);
|
||||
samples[i] = (int32_t)v;
|
||||
}
|
||||
|
||||
/* Auto threshold estimation: */
|
||||
// Auto threshold estimation
|
||||
if (threshold < 0) {
|
||||
double high_level, low_level;
|
||||
find_avg_high_low(samples, num_samples, clock, &high_level, &low_level);
|
||||
threshold = (low_level + high_level) * 0.5;
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " Auto threshold: low_level=%.2f, high_level=%.2f --> threshold=%.2f", low_level, high_level, threshold);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Auto threshold: low_level = %.2f, high_level = %.2f --> threshold = %.2f", low_level, high_level, threshold);
|
||||
}
|
||||
}
|
||||
|
||||
/* Auto clock-start detection (first edge detection) */
|
||||
// Auto clock-start detection (first edge detection)
|
||||
if (clock_start == -1) {
|
||||
clock_start = detect_edge(samples, num_samples, 0, threshold);
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Detected clock start candidate: sample #%d", clock_start);
|
||||
}
|
||||
}
|
||||
|
||||
/* High/low raw demodulation of clock-half cycles */
|
||||
// High/low raw demodulation of clock-half cycles
|
||||
int high_low_demod_01_len = (num_samples - clock_start) / clock_half + 16;
|
||||
|
||||
high_low_demod_01 = calloc(high_low_demod_01_len, sizeof(uint8_t));
|
||||
if (!high_low_demod_01) {
|
||||
if (high_low_demod_01 == NULL) {
|
||||
PrintAndLogEx(ERR, "Error: out of memory");
|
||||
rv = PM3_EMALLOC;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int high_low_demod_01_count = 0;
|
||||
|
||||
for (int idx = clock_start; idx + clock <= num_samples; idx += clock) {
|
||||
/* Trimmed mean of absolute values of first half: */
|
||||
|
||||
// Trimmed mean of absolute values of first half
|
||||
double clock_half1_val = trimmed_mean_abs(samples, idx, clock_half);
|
||||
/* Trimmed mean of absolute values of second half: */
|
||||
|
||||
// Trimmed mean of absolute values of second half
|
||||
double clock_half2_val = trimmed_mean_abs(samples, idx + clock_half, clock_half);
|
||||
|
||||
uint8_t half1 = (clock_half1_val >= threshold) ? 1 : 0;
|
||||
@@ -209,38 +156,52 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
high_low_demod_01_count += 2;
|
||||
}
|
||||
|
||||
/* Manchester demodulation buffer: */
|
||||
// Manchester demodulation buffer
|
||||
int manchester_demod_len = high_low_demod_01_count / 2;
|
||||
manchester_demod = calloc(manchester_demod_len, sizeof(uint8_t));
|
||||
if (!manchester_demod) {
|
||||
if (manchester_demod == NULL) {
|
||||
PrintAndLogEx(ERR, "Error: out of memory");
|
||||
rv = PM3_EMALLOC;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Manchester demodulation (Thomas) from raw high/low demod (high_low_demod_01) */
|
||||
// Manchester demodulation (Thomas) from raw high/low demod (high_low_demod_01)
|
||||
const int MAX_MANDEMOD_ERRORS = 64;
|
||||
bool demod_success = true;
|
||||
int manchester_count = 0;
|
||||
int mandemod_err_count = 0;
|
||||
|
||||
for (int i = 0; i + 1 < high_low_demod_01_count;) {
|
||||
|
||||
uint8_t half1 = high_low_demod_01[i];
|
||||
uint8_t half2 = high_low_demod_01[i + 1];
|
||||
|
||||
if (half1 == 0 && half2 == 1) {
|
||||
|
||||
manchester_demod[manchester_count++] = 0;
|
||||
i += 2;
|
||||
|
||||
} else if (half1 == 1 && half2 == 0) {
|
||||
|
||||
manchester_demod[manchester_count++] = 1;
|
||||
i += 2;
|
||||
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " Manchester demod error: index %d (sample #%" PRId32 "): half1=%u, half2=%u --> clock align by half cycle",
|
||||
i, (int32_t)(clock_start + i * clock_half), (unsigned)half1, (unsigned)half2);
|
||||
i += 1; /* re-align by one half-clock forward */
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Manchester demod error: index %d (sample #%" PRId32 "): half1=%u, half2=%u --> clock align by half cycle"
|
||||
, i
|
||||
, (int32_t)(clock_start + i * clock_half)
|
||||
, (unsigned)half1, (unsigned)half2
|
||||
);
|
||||
}
|
||||
|
||||
// re-align by one half-clock forward
|
||||
i += 1;
|
||||
|
||||
mandemod_err_count++;
|
||||
|
||||
if (mandemod_err_count >= MAX_MANDEMOD_ERRORS) {
|
||||
PrintAndLogEx(ERR, " Manchester demod: too many errors (%d), giving up", mandemod_err_count);
|
||||
fail = "too many Manchester errors";
|
||||
demod_success = false;
|
||||
break;
|
||||
}
|
||||
@@ -248,31 +209,34 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
}
|
||||
|
||||
if (demod_success) {
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Manchester demod: %d bits", manchester_count);
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
goto end;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Reverse order of bits */
|
||||
// Reverse order of bits
|
||||
manchester_demod_reversed = calloc(manchester_demod_len, sizeof(uint8_t));
|
||||
if (!manchester_demod_reversed) {
|
||||
if (manchester_demod_reversed == NULL) {
|
||||
PrintAndLogEx(ERR, "Error: out of memory");
|
||||
rv = PM3_EMALLOC;
|
||||
goto end;
|
||||
}
|
||||
for (int i = 0; i < manchester_count; i++)
|
||||
manchester_demod_reversed[i] = manchester_demod[manchester_count - 1 - i];
|
||||
|
||||
{
|
||||
for (int i = 0; i < manchester_count; i++) {
|
||||
manchester_demod_reversed[i] = manchester_demod[manchester_count - 1 - i];
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
char manchester_demod_reversed_str[manchester_count + 1];
|
||||
for (int i = 0; i < manchester_count; i++)
|
||||
for (int i = 0; i < manchester_count; i++) {
|
||||
manchester_demod_reversed_str[i] = '0' + manchester_demod_reversed[i];
|
||||
}
|
||||
manchester_demod_reversed_str[manchester_count] = '\0';
|
||||
PrintAndLogEx(SUCCESS, " Manchester demod reversed:");
|
||||
PrintAndLogEx(SUCCESS, " %s", manchester_demod_reversed_str);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
PrintAndLogEx(INFO, " Manchester demod reversed:");
|
||||
PrintAndLogEx(INFO, " %s", manchester_demod_reversed_str);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -284,21 +248,21 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
* Card number: 0x24A88F
|
||||
*/
|
||||
|
||||
/* Find preamble. */
|
||||
// Find preamble.
|
||||
static const uint8_t preamble_a[] = {
|
||||
/* type A: 62 zeros followed by 1,0,1,0,0,0 */
|
||||
// type A: 62 zeros followed by 1,0,1,0,0,0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0
|
||||
};
|
||||
static const uint8_t preamble_p[] = {
|
||||
/* type P: 55 zeros followed by 1,0,0,0,0,0,1 */
|
||||
// type P: 55 zeros followed by 1,0,0,0,0,0,1
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1
|
||||
};
|
||||
static const uint8_t preamble_p0[] = {
|
||||
/* type P-0: 61 zeros followed by 1 */
|
||||
// type P-0: 61 zeros followed by 1
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1
|
||||
@@ -320,8 +284,8 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
|
||||
for (int i = 0; i < manchester_count && preamble_index < 0; i++) {
|
||||
for (int p = 0; preamble_patterns[p].pat != NULL; p++) {
|
||||
if (i + preamble_patterns[p].len <= manchester_count &&
|
||||
memcmp(&manchester_demod_reversed[i], preamble_patterns[p].pat, preamble_patterns[p].len) == 0) {
|
||||
if (((i + preamble_patterns[p].len) <= manchester_count)
|
||||
&& (memcmp(&manchester_demod_reversed[i], preamble_patterns[p].pat, preamble_patterns[p].len) == 0)) {
|
||||
preamble_index = i;
|
||||
preamble_type = preamble_patterns[p].name;
|
||||
break;
|
||||
@@ -330,51 +294,64 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
}
|
||||
|
||||
if (preamble_index < 0) {
|
||||
PrintAndLogEx(INFO, " Preamble not found in manchester_demod_reversed");
|
||||
fail = "no preamble found";
|
||||
goto end;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Preamble found (type %s) in manchester_demod_reversed at index %d",
|
||||
preamble_type, preamble_index);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " Preamble found (type %s) in manchester_demod_reversed at index %d", preamble_type, preamble_index);
|
||||
}
|
||||
|
||||
/* data_bits: 128 bits starting at preamble */
|
||||
// data_bits: 128 bits starting at preamble
|
||||
if (preamble_index + LF_COTAG_DATA_LEN > manchester_count) {
|
||||
PrintAndLogEx(INFO, " Not enough bits after preamble for full 128-bit data block");
|
||||
fail = "preamble found but the capture ends before a full 128 bit block";
|
||||
rv = PM3_EPARTIAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
const uint8_t *data_bits = &manchester_demod_reversed[preamble_index];
|
||||
|
||||
/* Print raw 128 bits */
|
||||
{
|
||||
// Print raw 128 bits
|
||||
if (verbose) {
|
||||
char str[LF_COTAG_DATA_LEN + 1];
|
||||
for (int i = 0; i < LF_COTAG_DATA_LEN; i++)
|
||||
for (int i = 0; i < LF_COTAG_DATA_LEN; i++) {
|
||||
str[i] = '0' + data_bits[i];
|
||||
}
|
||||
str[LF_COTAG_DATA_LEN] = '\0';
|
||||
PrintAndLogEx(SUCCESS, " data bits: %s", str);
|
||||
}
|
||||
/* Print bits grouped by 4, space-separated */
|
||||
{
|
||||
|
||||
// Print bits grouped by 4, space-separated
|
||||
if (verbose) {
|
||||
char str[LF_COTAG_DATA_LEN + LF_COTAG_DATA_LEN / 4];
|
||||
|
||||
int p = 0;
|
||||
for (int i = 0; i < LF_COTAG_DATA_LEN; i += 4) {
|
||||
if (i > 0) str[p++] = ' ';
|
||||
for (int j = 0; j < 4; j++)
|
||||
|
||||
if (i > 0) {
|
||||
str[p++] = ' ';
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
str[p++] = '0' + data_bits[i + j];
|
||||
}
|
||||
}
|
||||
|
||||
str[p] = '\0';
|
||||
PrintAndLogEx(SUCCESS, " data bits: %s", str);
|
||||
}
|
||||
/* Print bits as hex nibbles */
|
||||
{
|
||||
|
||||
// Print bits as hex nibbles
|
||||
if (verbose) {
|
||||
char str[LF_COTAG_DATA_LEN / 4 * 5 + 1];
|
||||
int p = 0;
|
||||
for (int i = 0; i < LF_COTAG_DATA_LEN; i += 4) {
|
||||
int nibble = (data_bits[i] << 3)
|
||||
|
||||
int nibble = (data_bits[i] << 3)
|
||||
| (data_bits[i + 1] << 2)
|
||||
| (data_bits[i + 2] << 1)
|
||||
| data_bits[i + 3];
|
||||
|
||||
str[p++] = ' ';
|
||||
str[p++] = ' ';
|
||||
str[p++] = ' ';
|
||||
@@ -385,17 +362,19 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
PrintAndLogEx(SUCCESS, " data hex: %s", str);
|
||||
}
|
||||
|
||||
/* Card number: last 24 bits of data_bits as an integer */
|
||||
// Card number: last 24 bits of data_bits as an integer
|
||||
uint32_t c_num = 0;
|
||||
for (int i = LF_COTAG_DATA_LEN - 24; i < LF_COTAG_DATA_LEN; i++)
|
||||
for (int i = LF_COTAG_DATA_LEN - 24; i < LF_COTAG_DATA_LEN; i++) {
|
||||
c_num = (c_num << 1) | data_bits[i];
|
||||
PrintAndLogEx(SUCCESS, " card number: 0x%X == %u", c_num, c_num);
|
||||
}
|
||||
|
||||
/* Count how many subsequent 128-bit blocks equal data_bits */
|
||||
// Count how many subsequent 128-bit blocks equal data_bits
|
||||
int repeat_count = 0;
|
||||
bool fully_repeats = true;
|
||||
int pos = preamble_index + LF_COTAG_DATA_LEN;
|
||||
|
||||
while (pos + LF_COTAG_DATA_LEN <= manchester_count) {
|
||||
|
||||
if (memcmp(&manchester_demod_reversed[pos], data_bits, LF_COTAG_DATA_LEN) == 0) {
|
||||
repeat_count++;
|
||||
} else {
|
||||
@@ -405,14 +384,28 @@ static int demod_cotag(int32_t *samples, int num_samples, int clock, int clock_s
|
||||
pos += LF_COTAG_DATA_LEN;
|
||||
}
|
||||
|
||||
if (fully_repeats && repeat_count > 0)
|
||||
PrintAndLogEx(INFO, " Sequence fully repeats until the end %d time(s)", repeat_count);
|
||||
else
|
||||
PrintAndLogEx(INFO, " Sequence does NOT match at index %d (repeat count = %d)", pos, repeat_count);
|
||||
printf("\n");
|
||||
if (verbose) {
|
||||
if (fully_repeats && repeat_count > 0) {
|
||||
PrintAndLogEx(INFO, " Sequence fully repeats until the end %d time(s)", repeat_count);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " Sequence does NOT match at index %d (repeat count = %d)", pos, repeat_count);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "COTAG - Card number " _GREEN_("%u") " ( 0x%06X )", c_num, c_num);
|
||||
|
||||
rv = PM3_SUCCESS;
|
||||
end:
|
||||
// One line when there is no card number to show, so a failed demod says
|
||||
// how far it got rather than either going silent or dumping every stage.
|
||||
if (rv != PM3_SUCCESS && fail != NULL) {
|
||||
PrintAndLogEx(FAILED, "COTAG demod failed - %s ( %d Manchester bits at rf/%d )"
|
||||
, fail
|
||||
, manchester_count
|
||||
, clock
|
||||
);
|
||||
}
|
||||
|
||||
free(manchester_demod_reversed);
|
||||
free(manchester_demod);
|
||||
free(high_low_demod_01);
|
||||
@@ -431,7 +424,8 @@ int demodCOTAG(bool verbose, int clock, int threshold) {
|
||||
static int CmdCOTAGDemod(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf cotag demod",
|
||||
"Demodulate COTAG samples from g_GraphBuffer. Try to find COTAG preamble, if found decode / descramble data.",
|
||||
"Demodulate COTAG samples from g_GraphBuffer.\n"
|
||||
"Try to find COTAG preamble, if found decode / descramble data.",
|
||||
"lf cotag demod"
|
||||
);
|
||||
|
||||
@@ -490,8 +484,9 @@ static int CmdCOTAGReader(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (g_session.pm3_present == false)
|
||||
if (g_session.pm3_present == false) {
|
||||
return PM3_ENOTTY;
|
||||
}
|
||||
|
||||
uint8_t effective_divisor = (divisor > -1) ? (uint8_t)divisor : LF_COTAG_DIVISOR;
|
||||
|
||||
@@ -542,97 +537,13 @@ static int CmdCOTAGReader(const char *Cmd) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 // TODO: Remove this implementation?
|
||||
// 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
|
||||
int CmdCOTAGReader_old(const char *Cmd) {
|
||||
|
||||
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 = mode;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_COTAG_READ, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
uint8_t timeout = 3;
|
||||
int res = PM3_SUCCESS;
|
||||
while (WaitForResponseTimeout(CMD_LF_COTAG_READ, &resp, 1000) == false) {
|
||||
timeout--;
|
||||
if (timeout == 0) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
res = PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (timeout != 3)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
switch (payload.mode) {
|
||||
case 0:
|
||||
case 2: {
|
||||
CmdPlot("");
|
||||
CmdGrid("-x 384");
|
||||
getSamples(0, false);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
memcpy(g_DemodBuffer, resp.data.asBytes, resp.length);
|
||||
g_DemodBufferLen = resp.length;
|
||||
return demodCOTAG(true);
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdCOTAGDemod, AlwaysAvailable, "demodulate a COTAG tag"},
|
||||
{"reader", CmdCOTAGReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
@@ -662,22 +573,25 @@ static int cmp_int32_asc(const void *a, const void *b) {
|
||||
* resolution for very low amplitude captures.
|
||||
*/
|
||||
static double trimmed_mean_abs(const int32_t *samples, int start, int count) {
|
||||
/* The values are sorted and the top 1/TRIM_DROP_DEN are discarded before averaging */
|
||||
/// The values are sorted and the top 1/TRIM_DROP_DEN are discarded before averaging
|
||||
const int TRIM_DROP_DEN = 4; // trimmed mean denominator
|
||||
int32_t buf[count];
|
||||
|
||||
for (int k = 0; k < count; k++)
|
||||
for (int k = 0; k < count; k++) {
|
||||
buf[k] = abs(samples[start + k]);
|
||||
}
|
||||
|
||||
qsort(buf, count, sizeof(int32_t), cmp_int32_asc);
|
||||
|
||||
int keep = count - count / TRIM_DROP_DEN;
|
||||
if (keep < 1)
|
||||
if (keep < 1) {
|
||||
keep = 1;
|
||||
}
|
||||
|
||||
int64_t sum = 0;
|
||||
for (int k = 0; k < keep; k++)
|
||||
for (int k = 0; k < keep; k++) {
|
||||
sum += buf[k];
|
||||
}
|
||||
|
||||
return (double)sum / (double)keep;
|
||||
}
|
||||
@@ -691,24 +605,26 @@ static double trimmed_mean_abs(const int32_t *samples, int start, int count) {
|
||||
* @param out_high_level the highest window trimmed mean seen
|
||||
* @param out_low_level the lowest window trimmed mean seen
|
||||
*/
|
||||
static void find_avg_high_low(const int32_t *samples, int num_samples,
|
||||
int clock,
|
||||
double *out_high_level, double *out_low_level) {
|
||||
static void find_avg_high_low(const int32_t *samples, int num_samples, int clock, double *out_high_level, double *out_low_level) {
|
||||
const int WINDOW = 256;
|
||||
double high_level = -DBL_MAX;
|
||||
double low_level = DBL_MAX;
|
||||
|
||||
int scan_end = 8 * clock;
|
||||
if (scan_end > num_samples)
|
||||
if (scan_end > num_samples) {
|
||||
scan_end = num_samples;
|
||||
}
|
||||
|
||||
for (int i = 0; i + WINDOW <= scan_end; i++) {
|
||||
double window_val = trimmed_mean_abs(samples, i, WINDOW);
|
||||
|
||||
if (window_val < low_level)
|
||||
if (window_val < low_level) {
|
||||
low_level = window_val;
|
||||
if (window_val > high_level)
|
||||
}
|
||||
|
||||
if (window_val > high_level) {
|
||||
high_level = window_val;
|
||||
}
|
||||
}
|
||||
|
||||
*out_high_level = high_level;
|
||||
@@ -726,12 +642,13 @@ static void find_avg_high_low(const int32_t *samples, int num_samples,
|
||||
*
|
||||
* @return Index of the detected edge, or 0 if none found.
|
||||
*/
|
||||
static int detect_edge(const int32_t *samples, int num_samples,
|
||||
int index_start, double threshold) {
|
||||
static int detect_edge(const int32_t *samples, int num_samples, int index_start, double threshold) {
|
||||
|
||||
const int GLITCH_WINDOW = 10;
|
||||
|
||||
if (num_samples <= 0 || index_start < 0 || index_start >= num_samples)
|
||||
if (num_samples <= 0 || index_start < 0 || index_start >= num_samples) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool prev_high = abs(samples[index_start]) >= threshold;
|
||||
|
||||
@@ -739,18 +656,18 @@ static int detect_edge(const int32_t *samples, int num_samples,
|
||||
bool curr_high = abs(samples[i]) >= threshold;
|
||||
|
||||
if (curr_high != prev_high) {
|
||||
/* Need enough samples on both sides for glitch check */
|
||||
// Need enough samples on both sides for glitch check
|
||||
if ((int)i < GLITCH_WINDOW || i + GLITCH_WINDOW > num_samples) {
|
||||
prev_high = curr_high;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Sum of GLITCH_WINDOW absolute values before the crossing */
|
||||
// Sum of GLITCH_WINDOW absolute values before the crossing
|
||||
int64_t before_sum = 0;
|
||||
for (int k = 0; k < GLITCH_WINDOW; k++)
|
||||
before_sum += abs(samples[i - GLITCH_WINDOW + k]);
|
||||
|
||||
/* Sum of GLITCH_WINDOW absolute values after the crossing */
|
||||
// Sum of GLITCH_WINDOW absolute values after the crossing
|
||||
int64_t after_sum = 0;
|
||||
for (int k = 0; k < GLITCH_WINDOW; k++)
|
||||
after_sum += abs(samples[i + k]);
|
||||
@@ -758,8 +675,9 @@ static int detect_edge(const int32_t *samples, int num_samples,
|
||||
bool before_high = (double)before_sum >= threshold * GLITCH_WINDOW;
|
||||
bool after_high = (double)after_sum >= threshold * GLITCH_WINDOW;
|
||||
|
||||
if (before_high != after_high)
|
||||
if (before_high != after_high) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
prev_high = curr_high;
|
||||
|
||||
@@ -310,7 +310,6 @@ static int brute_em4x70(const em4x70_cmd_input_brute_t *opts, em4x70_cmd_output_
|
||||
// Lowers the cognitive load AND makes it easier to understand.
|
||||
// opts structure stored value in BIG ENDIAN
|
||||
// Note that the FIRMWARE side will swap the byte order back to BIG ENDIAN.
|
||||
// (yes, this is a bit of a mess, but it is what it is for now...)
|
||||
uint16_t start_key_be = (opts->partial_key_start[0] << 8) | opts->partial_key_start[1];
|
||||
etd.start_key = start_key_be;
|
||||
|
||||
@@ -994,7 +993,7 @@ static int CmdEM4x70Recover(const char *Cmd) {
|
||||
alt_grn.grn[2]
|
||||
);
|
||||
}
|
||||
printf("\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
// which of those keys actually validates?
|
||||
if (recover_ctx.opts.verify) {
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#define CMDLFEM4X70_H__
|
||||
|
||||
#include "common.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
int CmdLFEM4X70(const char *Cmd);
|
||||
|
||||
// for `lf search`:
|
||||
bool detect_4x70_block(void);
|
||||
|
||||
#endif
|
||||
|
||||
+844
-279
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,436 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low frequency Trovan animal ID commands
|
||||
//
|
||||
// Trovan is not ISO 11784/11785
|
||||
//
|
||||
// Differential biphase phase shift keying on an Fc/2 subcarrier, 16 carrier cycles to the bit.
|
||||
// A telegram is 64 bits:
|
||||
//
|
||||
// 8 bits sync, 01111111. Cannot occur anywhere in the body without
|
||||
// breaking row parity, which is what makes it a usable sync word.
|
||||
// 13 rows 3 data bits and 1 odd row parity bit, 39 data bits in total
|
||||
// 1 row 3 odd column parity bits and 1 odd row parity bit
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlftrovan.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h"
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // T55xx config register definitions
|
||||
#include "lfdemod.h" // psk1TOpsk2
|
||||
#include "cmdlft55xx.h" // clone_t55xx_tag
|
||||
#include "cmdlfem4x05.h" // em4x05_clone_tag
|
||||
|
||||
#define TROVAN_CLOCK 16
|
||||
#define TROVAN_TELEGRAM 64
|
||||
#define TROVAN_SYNC_LEN 8
|
||||
#define TROVAN_ROWS 14
|
||||
#define TROVAN_DATA_BITS 39
|
||||
|
||||
// samples for one telegram, times enough telegrams to survive a ragged start
|
||||
#define TROVAN_READ_SAMPLES (TROVAN_TELEGRAM * TROVAN_CLOCK * 10)
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static const uint8_t trovan_sync[TROVAN_SYNC_LEN] = { 0, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
// Check one 64 bit telegram and pull the ID out of it. `bits` holds one bit
|
||||
// per byte. Returns true and fills `id` when both parity planes hold.
|
||||
static bool trovan_check(const uint8_t *bits, uint64_t *id) {
|
||||
|
||||
const uint8_t *rows = bits + TROVAN_SYNC_LEN;
|
||||
|
||||
// odd parity across each 4 bit row
|
||||
for (uint8_t r = 0; r < TROVAN_ROWS; r++) {
|
||||
|
||||
uint8_t ones = 0;
|
||||
for (uint8_t c = 0; c < 4; c++) {
|
||||
ones += rows[(r * 4) + c];
|
||||
}
|
||||
|
||||
if ((ones & 1) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// odd parity down each of the three data columns, the fourth column is
|
||||
// the row parity itself and is not covered
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
|
||||
uint8_t ones = 0;
|
||||
for (uint8_t r = 0; r < TROVAN_ROWS; r++) {
|
||||
ones += rows[(r * 4) + c];
|
||||
}
|
||||
|
||||
if ((ones & 1) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 39 data bits, most significant first, the last row being parity only
|
||||
uint64_t v = 0;
|
||||
for (uint8_t r = 0; r < TROVAN_ROWS - 1; r++) {
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
v = (v << 1) | rows[(r * 4) + c];
|
||||
}
|
||||
}
|
||||
|
||||
*id = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hunt for a sync word and validate the telegram that follows it.
|
||||
// Returns the bit offset the telegram started at, or -1.
|
||||
static int trovan_find(const uint8_t *bits, size_t size, uint64_t *id) {
|
||||
|
||||
if (size < TROVAN_TELEGRAM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i + TROVAN_TELEGRAM <= size; i++) {
|
||||
|
||||
if (memcmp(bits + i, trovan_sync, TROVAN_SYNC_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trovan_check(bits + i, id)) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Conventional Trovan formatting is 10 hex digits in 2-4-4 groups.
|
||||
static void trovan_print(uint64_t id) {
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Trovan animal ID " _GREEN_("%02X-%04X-%04X")
|
||||
, (uint32_t)((id >> 32) & 0xFF)
|
||||
, (uint32_t)((id >> 16) & 0xFFFF)
|
||||
, (uint32_t)(id & 0xFFFF)
|
||||
);
|
||||
}
|
||||
|
||||
int demodTrovan(bool verbose) {
|
||||
|
||||
if (PSKDemod(TROVAN_CLOCK, 0, 100, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Trovan: PSK demod failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
psk1TOpsk2(g_DemodBuffer, g_DemodBufferLen);
|
||||
|
||||
if (g_DemodBufferLen < TROVAN_TELEGRAM) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Trovan: too few bits, %zu", g_DemodBufferLen);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// The demodulator settles on a polarity of its own choosing, and the parity checks cannot tell the two apart.
|
||||
uint8_t *bits = calloc(g_DemodBufferLen, sizeof(uint8_t));
|
||||
if (bits == NULL) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Trovan: out of memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
uint64_t id = 0;
|
||||
int idx = -1;
|
||||
bool inverted = false;
|
||||
|
||||
for (uint8_t pass = 0; pass < 2 && idx < 0; pass++) {
|
||||
|
||||
for (size_t i = 0; i < g_DemodBufferLen; i++) {
|
||||
bits[i] = (pass == 0) ? (g_DemodBuffer[i] & 1) : (g_DemodBuffer[i] & 1) ^ 1;
|
||||
}
|
||||
|
||||
idx = trovan_find(bits, g_DemodBufferLen, &id);
|
||||
inverted = (pass == 1);
|
||||
}
|
||||
|
||||
if (idx < 0) {
|
||||
free(bits);
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - Trovan: no valid telegram found");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
setDemodBuff(bits, TROVAN_TELEGRAM, (size_t)idx);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (idx * g_DemodClock));
|
||||
free(bits);
|
||||
|
||||
trovan_print(id);
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, " telegram at bit " _YELLOW_("%d") ", clock rf/%d, polarity %s"
|
||||
, idx
|
||||
, TROVAN_CLOCK
|
||||
, inverted ? "inverted" : "normal"
|
||||
);
|
||||
PrintAndLogEx(INFO, " raw " _YELLOW_("%010" PRIX64), id);
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int readTrovanUid(void) {
|
||||
return (demodTrovan(false) == PM3_SUCCESS);
|
||||
}
|
||||
|
||||
// Build the 64 bit telegram for an ID.
|
||||
static void trovan_encode(uint64_t id, uint8_t *bits) {
|
||||
|
||||
memcpy(bits, trovan_sync, TROVAN_SYNC_LEN);
|
||||
uint8_t *rows = bits + TROVAN_SYNC_LEN;
|
||||
|
||||
// 13 rows of 3 data bits, most significant first, each closed with an odd row parity bit
|
||||
for (uint8_t r = 0; r < TROVAN_ROWS - 1; r++) {
|
||||
|
||||
uint8_t ones = 0;
|
||||
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
const uint8_t shift = (uint8_t)(TROVAN_DATA_BITS - 1 - ((r * 3) + c));
|
||||
const uint8_t b = (uint8_t)((id >> shift) & 1);
|
||||
rows[(r * 4) + c] = b;
|
||||
ones += b;
|
||||
}
|
||||
|
||||
rows[(r * 4) + 3] = (ones & 1) ? 0 : 1;
|
||||
}
|
||||
|
||||
// the last row carries the column parities, then its own row parity
|
||||
uint8_t last = 0;
|
||||
|
||||
for (uint8_t c = 0; c < 3; c++) {
|
||||
|
||||
uint8_t ones = 0;
|
||||
for (uint8_t r = 0; r < TROVAN_ROWS - 1; r++) {
|
||||
ones += rows[(r * 4) + c];
|
||||
}
|
||||
|
||||
const uint8_t p = (ones & 1) ? 0 : 1;
|
||||
rows[((TROVAN_ROWS - 1) * 4) + c] = p;
|
||||
last += p;
|
||||
}
|
||||
|
||||
rows[((TROVAN_ROWS - 1) * 4) + 3] = (last & 1) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int CmdTrovanDemod(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf trovan demod",
|
||||
"Demodulate a Trovan animal ID tag from the GraphBuffer",
|
||||
"lf trovan demod\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool verbose = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
const int res = demodTrovan(verbose);
|
||||
|
||||
if (res != PM3_SUCCESS && verbose) {
|
||||
PrintAndLogEx(FAILED, "Trovan demod failed ( looked for a %d bit frame at rf/%d )"
|
||||
, TROVAN_TELEGRAM
|
||||
, TROVAN_CLOCK
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdTrovanReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf trovan reader",
|
||||
"read a Trovan animal ID tag",
|
||||
"lf trovan reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
bool verbose = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
do {
|
||||
lf_read(false, TROVAN_READ_SAMPLES);
|
||||
res = demodTrovan(verbose && (cm == false));
|
||||
} while (cm && (kbd_enter_pressed() == false));
|
||||
|
||||
// continuous mode is expected to come up empty between tag presentations,
|
||||
// so only a one shot read is worth reporting a miss for
|
||||
if (res != PM3_SUCCESS && (cm == false) && verbose) {
|
||||
PrintAndLogEx(FAILED, "Trovan demod failed ( looked for a %d bit frame at rf/%d )"
|
||||
, TROVAN_TELEGRAM
|
||||
, TROVAN_CLOCK
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdTrovanClone(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf trovan clone",
|
||||
"clone a Trovan animal ID to a T55x7, Q5/T5555 or EM4305/4469 tag\n"
|
||||
"The ID is the 10 hex digits printed on the tag, with or without dashes.",
|
||||
"lf trovan clone --id 0007F9043A\n"
|
||||
"lf trovan clone --id 00-07F9-043A\n"
|
||||
"lf trovan clone --id 0007F9043A --q5"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1(NULL, "id", "<hex>", "Trovan animal ID, 10 hex digits"),
|
||||
arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t raw[24] = {0};
|
||||
int rawlen = sizeof(raw) - 1;
|
||||
CLIGetStrWithReturn(ctx, 1, raw, &rawlen);
|
||||
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;
|
||||
}
|
||||
|
||||
// accept the dashed form the tags are printed in
|
||||
char digits[16] = {0};
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < rawlen; i++) {
|
||||
|
||||
if (raw[i] == '-' || raw[i] == ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n >= (int)sizeof(digits) - 1) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
|
||||
digits[n++] = (char)raw[i];
|
||||
}
|
||||
|
||||
if (n != 10) {
|
||||
PrintAndLogEx(FAILED, "ID must be 10 hex digits, got " _RED_("%d"), n);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char *end = NULL;
|
||||
const uint64_t id = strtoull(digits, &end, 16);
|
||||
|
||||
if (end == NULL || *end != '\0') {
|
||||
PrintAndLogEx(FAILED, "ID is not hex: " _RED_("%s"), digits);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// 10 hex digits is 40 bits but only 39 of them are carried
|
||||
if (id > 0x7FFFFFFFFFULL) {
|
||||
PrintAndLogEx(FAILED, "ID does not fit in the 39 bits a telegram carries");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t bits[TROVAN_TELEGRAM] = {0};
|
||||
trovan_encode(id, bits);
|
||||
|
||||
uint32_t blocks[3] = {0};
|
||||
for (uint8_t i = 0; i < 64; i++) {
|
||||
const uint8_t b = bits[i] ^ 1;
|
||||
blocks[1 + (i / 32)] |= ((uint32_t)b) << (31 - (i % 32));
|
||||
}
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
blocks[0] = T55x7_TESTMODE_DISABLED | T55x7_MODULATION_PSK2 | T55x7_PSKCF_RF_2 | T55x7_BITRATE_RF_16 | 2 << T55x7_MAXBLOCK_SHIFT;
|
||||
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK2 | T5555_SET_BITRATE(TROVAN_CLOCK) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
if (em) {
|
||||
PrintAndLogEx(FAILED, "EM4305/4469 does not support PSK, which Trovan needs");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Trovan to " _YELLOW_("%s") " with animal ID " _GREEN_("%02X-%04X-%04X")
|
||||
, cardtype
|
||||
, (uint32_t)((id >> 32) & 0xFF)
|
||||
, (uint32_t)((id >> 16) & 0xFFFF)
|
||||
, (uint32_t)(id & 0xFFFF)
|
||||
);
|
||||
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done!");
|
||||
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`lf trovan reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdTrovanDemod, AlwaysAvailable, "demodulate a Trovan tag from the GraphBuffer"},
|
||||
{"reader", CmdTrovanReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdTrovanClone, IfPm3Lf, "clone Trovan tag to T55x7 or Q5/T5555"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFTrovan(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low frequency Trovan animal ID commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDLFTROVAN_H__
|
||||
#define CMDLFTROVAN_H__
|
||||
|
||||
#include "common.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
int CmdLFTrovan(const char *Cmd);
|
||||
int demodTrovan(bool verbose);
|
||||
int readTrovanUid(void);
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -680,7 +680,7 @@ int flash_write(flash_file_t *ctx) {
|
||||
|
||||
int pct = 0;
|
||||
if (blocks > 50) {
|
||||
|
||||
|
||||
signal(SIGINT, hadouken_on_sigint);
|
||||
#ifndef _WIN32
|
||||
signal(SIGWINCH, hadouken_on_sigwinch);
|
||||
@@ -690,7 +690,7 @@ int flash_write(flash_file_t *ctx) {
|
||||
}
|
||||
|
||||
while (length) {
|
||||
|
||||
|
||||
uint32_t block_size = length;
|
||||
if (block_size > BLOCK_SIZE) {
|
||||
block_size = BLOCK_SIZE;
|
||||
|
||||
+24
-24
@@ -36,10 +36,10 @@ static int terminal_width(void) {
|
||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
}
|
||||
const char *c = getenv("COLUMNS");
|
||||
if (c) {
|
||||
int w = atoi(c);
|
||||
if (c) {
|
||||
int w = atoi(c);
|
||||
if (w > 0) {
|
||||
return w;
|
||||
return w;
|
||||
}
|
||||
}
|
||||
return 80;
|
||||
@@ -53,7 +53,7 @@ static int terminal_width(void) {
|
||||
return (int)ws.ws_col;
|
||||
}
|
||||
const char *c = getenv("COLUMNS");
|
||||
if (c) {
|
||||
if (c) {
|
||||
int w = atoi(c);
|
||||
if (w > 0) {
|
||||
return w;
|
||||
@@ -63,7 +63,7 @@ static int terminal_width(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// --- wave parameters (unchanged from hadouken_wave.c) -------------------
|
||||
// --- wave parameters (unchanged from hadouken_wave.c) -------------------
|
||||
#define ORIGIN_X 64.0
|
||||
#define ORIGIN_Y 8.0
|
||||
#define ASPECT 2.0
|
||||
@@ -91,7 +91,7 @@ static const char *GLYPHS = " .:;+xX#";
|
||||
// --- shared state --------------------------------------------------------
|
||||
static volatile sig_atomic_t g_resize = 0; // set by SIGWINCH
|
||||
static volatile int g_running = 0;
|
||||
static volatile int g_progress = 0; // 0..100
|
||||
static volatile int g_progress = 0; // 0..100
|
||||
static pthread_t g_thread;
|
||||
|
||||
// animation config – written once before hadouken_start()
|
||||
@@ -99,9 +99,9 @@ static double g_fps = 30.0;
|
||||
static int g_glyph_mode = 0;
|
||||
static int g_wave_mode = 0; // 0 = radial, 1 = beam
|
||||
|
||||
void hadouken_on_sigint(int s) {
|
||||
(void)s;
|
||||
g_running = 0;
|
||||
void hadouken_on_sigint(int s) {
|
||||
(void)s;
|
||||
g_running = 0;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -111,9 +111,9 @@ void hadouken_on_sigwinch(int s) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
/*
|
||||
* Compute the inner fill width for the progress bar from the current terminal
|
||||
* width, clamped to [BAR_MIN, BAR_MAX].
|
||||
* width, clamped to [BAR_MIN, BAR_MAX].
|
||||
*/
|
||||
static int bar_inner_width(void) {
|
||||
int w = terminal_width() - BAR_OVERHEAD;
|
||||
@@ -126,7 +126,7 @@ static int bar_inner_width(void) {
|
||||
return w;
|
||||
}
|
||||
|
||||
// --- colour helpers ------------------------------------------------------
|
||||
// --- colour helpers ------------------------------------------------------
|
||||
static inline int clamp8(double v) {
|
||||
if (v < 0) {
|
||||
return 0;
|
||||
@@ -175,11 +175,11 @@ static int render_anim_line(char *dst, int y, double t, int glyph_mode, int mode
|
||||
int ch = c->ch;
|
||||
int has = c->has;
|
||||
int r = 0;
|
||||
int g = 0;
|
||||
int g = 0;
|
||||
int b = 0;
|
||||
|
||||
if (ch == ' ' && !has) {
|
||||
pending_blanks++;
|
||||
if (ch == ' ' && !has) {
|
||||
pending_blanks++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ static int render_anim_line(char *dst, int y, double t, int glyph_mode, int mode
|
||||
|
||||
double lum = (r + g + b) / 765.0;
|
||||
|
||||
int idx = (int)(lum * 8);
|
||||
int idx = (int)(lum * 8);
|
||||
if (idx > 7) {
|
||||
idx = 7;
|
||||
}
|
||||
@@ -203,8 +203,8 @@ static int render_anim_line(char *dst, int y, double t, int glyph_mode, int mode
|
||||
}
|
||||
}
|
||||
} else if (has) {
|
||||
r = c->r;
|
||||
g = c->g;
|
||||
r = c->r;
|
||||
g = c->g;
|
||||
b = c->b;
|
||||
}
|
||||
|
||||
@@ -219,10 +219,10 @@ static int render_anim_line(char *dst, int y, double t, int glyph_mode, int mode
|
||||
len += sprintf(dst + len, ANSI_FG_RGB, r, g, b);
|
||||
} else {
|
||||
len += sprintf(dst + len, AEND);
|
||||
}
|
||||
last_has = has;
|
||||
last_r = r;
|
||||
last_g = g;
|
||||
}
|
||||
last_has = has;
|
||||
last_r = r;
|
||||
last_g = g;
|
||||
last_b = b;
|
||||
}
|
||||
dst[len++] = (char)ch;
|
||||
@@ -285,7 +285,7 @@ static void *anim_thread(void *arg) {
|
||||
static char prev[FH][FW * 24 + 16];
|
||||
static char out [FH * (FW * 24 + 32) + 512];
|
||||
|
||||
// bar buf: BAR_MAX fill chars + ANSI escapes per char + fixed overhead
|
||||
// bar buf: BAR_MAX fill chars + ANSI escapes per char + fixed overhead
|
||||
static char bar [BAR_MAX + 256];
|
||||
|
||||
int have_prev = 0;
|
||||
@@ -303,7 +303,7 @@ static void *anim_thread(void *arg) {
|
||||
have_prev = 0;
|
||||
}
|
||||
|
||||
// dynamic: re-queried every frame
|
||||
// dynamic: re-queried every frame
|
||||
int bw = bar_inner_width();
|
||||
|
||||
int n = 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,200 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Host side DSP primitives; FFT, windows, power spectrum, STFT
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef PM3_DSP_H__
|
||||
#define PM3_DSP_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PM3_DSP_MAX_FFT 262144
|
||||
#define PM3_DSP_DC_GUARD 2
|
||||
#define PM3_DSP_MAX_RESAMPLE (40000 * 32)
|
||||
#define PM3_DSP_NYQUIST_CLK 2.5
|
||||
#define PM3_DSP_ENVELOPE_SMOOTH 8
|
||||
#define PM3_DSP_ENVELOPE_DEPTH 0.6
|
||||
|
||||
#define PM3_DSP_FLIP_FRAC 0.7
|
||||
|
||||
typedef enum {
|
||||
PM3_WIN_HANN = 0,
|
||||
PM3_WIN_HAMMING,
|
||||
PM3_WIN_BLACKMAN,
|
||||
PM3_WIN_RECT,
|
||||
} pm3_window_t;
|
||||
|
||||
typedef struct {
|
||||
double re;
|
||||
double im;
|
||||
} pm3_cplx_t;
|
||||
|
||||
typedef struct {
|
||||
size_t n;
|
||||
pm3_cplx_t *twiddle; // n / 2 entries, exp(-2*pi*i*k/n)
|
||||
uint32_t *rev; // n entries, bit reversal permutation
|
||||
} pm3_fft_plan_t;
|
||||
|
||||
typedef struct {
|
||||
size_t n; // transform length
|
||||
size_t nbins; // n / 2 + 1, input is real
|
||||
double *mag; // linear magnitude per bin
|
||||
double peak; // largest magnitude found
|
||||
size_t peak_bin; // ... and where
|
||||
} pm3_spectrum_t;
|
||||
|
||||
typedef struct {
|
||||
size_t bin; // integer bin the peak was found in
|
||||
double freq; // cycles/sample, parabolic sub bin estimate
|
||||
double clk; // samples/symbol, 1.0 / freq
|
||||
double mag_db; // dB relative to the strongest bin in the spectrum
|
||||
double prominence; // dB above the local noise floor
|
||||
} pm3_peak_t;
|
||||
|
||||
typedef struct {
|
||||
size_t nframes;
|
||||
size_t nbins;
|
||||
size_t n; // window length
|
||||
size_t hop;
|
||||
size_t *frame_start; // nframes entries, offset of each frame
|
||||
double *peak_freq; // nframes entries, cycles/sample of dominant bin
|
||||
double *peak_mag; // nframes entries, magnitude of dominant bin
|
||||
double *frame_energy; // nframes entries, total in band energy
|
||||
double *ridge; // nframes * nbins, magnitude, row major
|
||||
} pm3_stft_t;
|
||||
|
||||
|
||||
#define PM3_DSP_MAX_PEAKS 16
|
||||
#define PM3_DSP_NDELAYS 4
|
||||
|
||||
typedef enum {
|
||||
PM3_FAM_UNKNOWN = 0,
|
||||
PM3_FAM_ASK,
|
||||
PM3_FAM_FSK,
|
||||
PM3_FAM_PSK,
|
||||
PM3_FAM_NRZ,
|
||||
PM3_FAM_MANCHESTER,
|
||||
} pm3_family_t;
|
||||
|
||||
typedef enum {
|
||||
PM3_CONF_NONE = 0,
|
||||
PM3_CONF_LOW,
|
||||
PM3_CONF_MEDIUM,
|
||||
PM3_CONF_HIGH,
|
||||
} pm3_confidence_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
size_t npeaks;
|
||||
pm3_peak_t peaks[PM3_DSP_MAX_PEAKS];
|
||||
bool have_sq;
|
||||
size_t nsq_peaks;
|
||||
pm3_peak_t sq_peaks[PM3_DSP_MAX_PEAKS];
|
||||
size_t ndelay;
|
||||
size_t delay[PM3_DSP_NDELAYS];
|
||||
pm3_peak_t delay_peak[PM3_DSP_NDELAYS];
|
||||
bool delay_valid[PM3_DSP_NDELAYS];
|
||||
|
||||
pm3_family_t family;
|
||||
pm3_confidence_t confidence;
|
||||
|
||||
double symbol_clk; // best symbol rate estimate, samples/symbol
|
||||
bool have_symbol_clk;
|
||||
|
||||
double carrier_clk; // subcarrier / field clock, when one is present
|
||||
bool have_carrier;
|
||||
|
||||
double fsk_clk_hi; // the shorter of the two FSK field clocks
|
||||
double fsk_clk_lo;
|
||||
double fsk_ratio;
|
||||
|
||||
bool transition_coded;
|
||||
double dc_ratio; // low frequency energy relative to the peak
|
||||
double sym_prominence; // prominence of the plain spectrum at symbol_clk
|
||||
double sq_prominence; // prominence of the squaring line
|
||||
|
||||
bool carrier_at_nyquist;
|
||||
double envelope_depth; // 0.0 constant amplitude, 1.0 switched fully off
|
||||
bool needs_envelope;
|
||||
} pm3_spec_analysis_t;
|
||||
|
||||
const char *pm3_family_name(pm3_family_t fam);
|
||||
const char *pm3_confidence_name(pm3_confidence_t conf);
|
||||
|
||||
int pm3_analyse(const double *sig, size_t len, size_t n, pm3_window_t win, pm3_spec_analysis_t *out);
|
||||
|
||||
pm3_fft_plan_t *pm3_fft_plan_create(size_t n);
|
||||
void pm3_fft_plan_destroy(pm3_fft_plan_t *plan);
|
||||
void pm3_fft(const pm3_fft_plan_t *plan, pm3_cplx_t *data, bool inverse);
|
||||
|
||||
size_t pm3_next_pow2(size_t v);
|
||||
bool pm3_window_from_str(const char *str, pm3_window_t *out);
|
||||
const char *pm3_window_name(pm3_window_t win);
|
||||
void pm3_apply_window(double *data, size_t len, pm3_window_t win);
|
||||
|
||||
double *pm3_extract(const int32_t *src, size_t len, size_t start, size_t count);
|
||||
void pm3_remove_mean(double *data, size_t len);
|
||||
double *pm3_envelope(const double *sig, size_t len, size_t smooth);
|
||||
|
||||
typedef struct {
|
||||
uint8_t *bits;
|
||||
size_t nbits;
|
||||
size_t nerrors;
|
||||
size_t phase; // sample offset of the first chip centre
|
||||
double eye; // mean distance from the threshold, 1.0 = fully open
|
||||
} pm3_slice_t;
|
||||
|
||||
int pm3_ask_slice(const double *sig, size_t len, double clk, pm3_slice_t *out);
|
||||
void pm3_slice_free(pm3_slice_t *out);
|
||||
bool pm3_is_switched_carrier(const double *sig, size_t len);
|
||||
double pm3_envelope_depth(const double *sig, size_t len);
|
||||
void pm3_delay_multiply(const double *in, size_t len, size_t lag, double *out);
|
||||
int pm3_spectrum(const double *sig, size_t len, size_t n, pm3_window_t win, pm3_spectrum_t *out);
|
||||
void pm3_spectrum_free(pm3_spectrum_t *spec);
|
||||
size_t pm3_find_peaks(const pm3_spectrum_t *spec, pm3_peak_t *peaks, size_t max_peaks);
|
||||
int pm3_stft(const double *sig, size_t len, size_t n, size_t hop, pm3_window_t win, double anchor, pm3_stft_t *out);
|
||||
void pm3_stft_free(pm3_stft_t *st);
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
double chip; // shortest repeated run length, samples
|
||||
double long_run; // 95th percentile run length, samples
|
||||
double run_ratio; // long_run / chip
|
||||
double short_fraction; // runs no longer than 2.5 chips, as a fraction
|
||||
bool transition_coded; // runs never much exceed two chips
|
||||
double period; // autocorrelation repeat period, 0 if none
|
||||
double period_strength; // normalised autocorrelation at that lag
|
||||
} pm3_sigstat_t;
|
||||
|
||||
|
||||
int pm3_signal_stats(const double *sig, size_t len, pm3_sigstat_t *out);
|
||||
double pm3_autocorr_period(const double *sig, size_t len, double *strength);
|
||||
int pm3_psk_demod(const double *sig, size_t len, int fc, double clk,
|
||||
uint8_t *bits, size_t *nbits, double *clk_out, int *phase_out,
|
||||
double *score_out, uint8_t *abs_bits);
|
||||
|
||||
int pm3_ask_chips(const double *sig, size_t len, double chip, uint8_t *chips, size_t *nchips, double *chip_out, int *phase_out);
|
||||
double *pm3_resample(const double *in, size_t len, double ratio, size_t *out_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // PM3_DSP_H__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Symbol template generation and matched filter hypothesis scoring
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef PM3_FIT_H__
|
||||
#define PM3_FIT_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "pm3_dsp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PM3_FIT_MIN_SYMBOLS 64
|
||||
|
||||
typedef enum {
|
||||
PM3_MOD_ASK = 0,
|
||||
PM3_MOD_FSK,
|
||||
PM3_MOD_PSK,
|
||||
PM3_MOD_NRZ,
|
||||
} pm3_mod_t;
|
||||
|
||||
typedef enum {
|
||||
PM3_ENC_RAW = 0,
|
||||
PM3_ENC_MANCHESTER,
|
||||
PM3_ENC_BIPHASE,
|
||||
} pm3_enc_t;
|
||||
|
||||
typedef enum {
|
||||
PM3_TPL_FLAT = 0, // one level held for the whole symbol
|
||||
PM3_TPL_HALF, // half high, half low - a mid symbol transition
|
||||
PM3_TPL_PSK, // subcarrier burst
|
||||
PM3_TPL_FSK, // one of two tones, scored non coherently
|
||||
} pm3_tpl_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
pm3_mod_t mod;
|
||||
pm3_enc_t enc;
|
||||
pm3_tpl_t tpl;
|
||||
|
||||
int clk; // samples per symbol
|
||||
int q; // assumed antenna Q used to shape the template
|
||||
int fc_hi; // FSK, the longer field clock ( pm3 `fchigh` )
|
||||
int fc_lo; // FSK, the shorter field clock ( pm3 `fclow` )
|
||||
int fc; // PSK subcarrier period
|
||||
|
||||
// results
|
||||
int phase; // best symbol phase, 0 .. clk-1
|
||||
double clk_fine; // refined clock, fractional - this is the useful one
|
||||
size_t nsym; // decision instants the score was built from
|
||||
double snr_dd; // decision directed SNR, dB
|
||||
double eye; // min / mean at the decision instants, 0 .. 1
|
||||
double mid; // mean at the mid symbol instants
|
||||
double mid_ratio; // mid / mean at the decision instants
|
||||
bool chip_rate; // decoded bits pair up 01/10 almost always, so
|
||||
double margin; // dB to the next best genuinely different decode
|
||||
} pm3_hyp_t;
|
||||
|
||||
typedef struct {
|
||||
int mod_mask; // bitmask of (1 << pm3_mod_t), 0 means all
|
||||
int clk_only; // restrict to this clock, 0 means all candidates
|
||||
bool keep_corr; // hand back the rank 1 correlator output
|
||||
} pm3_fit_opts_t;
|
||||
|
||||
typedef struct {
|
||||
pm3_hyp_t *items; // ranked, best first
|
||||
size_t count;
|
||||
pm3_sigstat_t stats; // structural facts measured from the waveform
|
||||
bool promoted; // rank 1 was chosen on structural evidence rather
|
||||
double *corr; // rank 1 decision statistic, when requested
|
||||
size_t corr_len;
|
||||
} pm3_fit_t;
|
||||
|
||||
const char *pm3_mod_name(pm3_mod_t mod);
|
||||
const char *pm3_enc_name(pm3_enc_t enc);
|
||||
|
||||
size_t pm3_fit_clocks(const int **clocks);
|
||||
int pm3_fit_run(const double *sig, size_t len, const pm3_fit_opts_t *opts, pm3_fit_t *out);
|
||||
void pm3_fit_free(pm3_fit_t *fit);
|
||||
|
||||
typedef struct {
|
||||
pm3_mod_t mod;
|
||||
pm3_enc_t enc;
|
||||
double clk; // may be fractional
|
||||
int fc_hi;
|
||||
int fc_lo;
|
||||
int fc;
|
||||
double noise;
|
||||
double drift;
|
||||
double envelope; // amplitude swing across the capture, 0 = none
|
||||
double jitter;
|
||||
double clip; // 0 = no clipping
|
||||
int q; // antenna Q to shape with, 0 for the default
|
||||
int repeat; // message length in bits, 0 for endless random data.
|
||||
uint32_t seed;
|
||||
} pm3_gen_opts_t;
|
||||
|
||||
int pm3_fit_generate(const pm3_gen_opts_t *opts, double *out, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // PM3_FIT_H__
|
||||
@@ -95,6 +95,10 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 1, "data manrawdecode" },
|
||||
{ 1, "data modulation" },
|
||||
{ 1, "data rawdemod" },
|
||||
{ 1, "data autodemod" },
|
||||
{ 1, "data fft" },
|
||||
{ 1, "data fitscore" },
|
||||
{ 1, "data spectrum" },
|
||||
{ 1, "data askedgedetect" },
|
||||
{ 1, "data autocorr" },
|
||||
{ 1, "data convertbitstream" },
|
||||
@@ -124,6 +128,7 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "data hexsamples" },
|
||||
{ 0, "data samples" },
|
||||
{ 1, "data qrcode" },
|
||||
{ 0, "data gensignal" },
|
||||
{ 0, "data test_ss8" },
|
||||
{ 0, "data test_ss32" },
|
||||
{ 0, "data test_ss32s" },
|
||||
@@ -217,7 +222,6 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "hf 15 writeafi" },
|
||||
{ 0, "hf 15 writedsfid" },
|
||||
{ 0, "hf 15 csetuid" },
|
||||
{ 0, "hf 15 cfinalize" },
|
||||
{ 1, "hf aliro help" },
|
||||
{ 1, "hf aliro list" },
|
||||
{ 0, "hf aliro info" },
|
||||
@@ -923,6 +927,10 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 1, "lf t55xx sniff" },
|
||||
{ 0, "lf t55xx special" },
|
||||
{ 0, "lf t55xx wipe" },
|
||||
{ 1, "lf trovan help" },
|
||||
{ 1, "lf trovan demod" },
|
||||
{ 0, "lf trovan reader" },
|
||||
{ 0, "lf trovan clone" },
|
||||
{ 1, "lf viking help" },
|
||||
{ 1, "lf viking demod" },
|
||||
{ 0, "lf viking reader" },
|
||||
|
||||
@@ -891,7 +891,7 @@ static int dumpmem_pm3(char *serial_port_name, const char *filename, uint32_t ad
|
||||
PrintAndLogEx(INFO, "Device is running the bootloader.");
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Device is running the bootloader, but the bootloader"
|
||||
" doesn't understand the READ MEM command.");
|
||||
" doesn't understand the READ MEM command.");
|
||||
goto finish2;
|
||||
}
|
||||
}
|
||||
|
||||
+179
-29
@@ -239,6 +239,28 @@
|
||||
],
|
||||
"usage": "data autocorr [-hg] [-w <dec>]"
|
||||
},
|
||||
"data autodemod": {
|
||||
"command": "data autodemod",
|
||||
"description": "Tries to work out the modulation, encoding and clock of the wave in the GraphBuffer then run the matching demodulator Adds no signal processing of its own, the analysis is `data spectrum` and `data fitscore` A fractional clock is resampled onto an integer grid first",
|
||||
"notes": [
|
||||
"data autodemod -> analyse and demodulate",
|
||||
"data autodemod --dry-run -> decide and print, demodulate nothing",
|
||||
"data autodemod --thres 6 -> insist on a 6 dB margin before trusting rank 1",
|
||||
"data autodemod --invert --amp -> pass invert and amplify through to the demod"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--start <int> first sample of the GraphBuffer to use (def 0)",
|
||||
"--size <int> samples to analyse (def 16384)",
|
||||
"--thres <dB> margin below which rank 1 is called ambiguous (def 3.0)",
|
||||
"--dry-run analyse and decide, but do not demodulate",
|
||||
"-a, --amp amplify the signal before ASK demodulation",
|
||||
"-i, --invert invert the demodulated output",
|
||||
"-v, --verbose show the demodulator's own output"
|
||||
],
|
||||
"usage": "data autodemod [-haiv] [--start <int>] [--size <int>] [--thres <dB>] [--dry-run]"
|
||||
},
|
||||
"data biphaserawdecode": {
|
||||
"command": "data biphaserawdecode",
|
||||
"description": "Biphase decode binary stream in DemodBuffer Converts 10 or 01 -> 1 and 11 or 00 -> 0 - must have binary sequence in DemodBuffer (run `data rawdemod --ar` before) - invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester",
|
||||
@@ -407,6 +429,50 @@
|
||||
],
|
||||
"usage": "data envelope [-h]"
|
||||
},
|
||||
"data fft": {
|
||||
"command": "data fft",
|
||||
"description": "Fourier transform of the samples in the GraphBuffer. Reports the magnitude spectrum of the first N/2+1 bins, the input being real. The DC component is removed and the window is normalised to unit variance before the transform, so magnitudes are comparable between captures.",
|
||||
"notes": [
|
||||
"data fft -> transform the whole buffer",
|
||||
"data fft --size 4096 --win blackman -> 4096 point transform, blackman window",
|
||||
"data fft --start 1000 --size 8192 --db -> magnitudes in dB relative to the peak",
|
||||
"data fft --size 4096 --graph -> put the spectrum in the graph window"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--start <int> first sample of the GraphBuffer to use (def 0)",
|
||||
"--size <int> transform length, rounded up to a power of two (def largest that fits)",
|
||||
"--win <hann|hamming|blackman|rect> window function (def hann)",
|
||||
"--db report magnitude in dB relative to the peak bin instead of linear",
|
||||
"--graph write the magnitude spectrum into the GraphBuffer and repaint",
|
||||
"--fs <int> sample rate in Hz, adds a frequency column in Hz",
|
||||
"--bins <int> how many bins to print (def 32, 0 for all)"
|
||||
],
|
||||
"usage": "data fft [-h] [--start <int>] [--size <int>] [--win <hann|hamming|blackman|rect>] [--db] [--graph] [--fs <int>] [--bins <int>]"
|
||||
},
|
||||
"data fitscore": {
|
||||
"command": "data fitscore",
|
||||
"description": "Rank matched filter hypotheses against the GraphBuffer. A hypothesis is a modulation, a symbol shape and a clock. Each one is scored by correlating the trace against a single symbol template and measuring how tightly the correlator output clusters at the decision instants. Phase is not searched: the correlation is done with an FFT, which yields every phase offset at once. Templates are shaped by an assumed antenna Q, because correlating a bandlimited signal against square edges biases the ranking toward short clocks.",
|
||||
"notes": [
|
||||
"data fitscore -> rank the whole bank",
|
||||
"data fitscore --mod ask --top 5 -> ASK hypotheses only",
|
||||
"data fitscore --clk 64 --all -> everything at clock 64",
|
||||
"data fitscore --verbose -> also put the rank 1 correlator output in the graph"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--start <int> first sample of the GraphBuffer to use (def 0)",
|
||||
"--size <int> samples to analyse, rounded up to a power of two (def 16384)",
|
||||
"--mod <ask|fsk|psk|nrz> restrict to one modulation (def all)",
|
||||
"--clk <int> restrict to one clock (def all candidates)",
|
||||
"--top <int> rows to print (def 10)",
|
||||
"--all print every scored hypothesis",
|
||||
"-v, --verbose write the rank 1 correlator output into the GraphBuffer"
|
||||
],
|
||||
"usage": "data fitscore [-hv] [--start <int>] [--size <int>] [--mod <ask|fsk|psk|nrz>] [--clk <int>] [--top <int>] [--all]"
|
||||
},
|
||||
"data fsktonrz": {
|
||||
"command": "data fsktonrz",
|
||||
"description": "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) Omitted values are autodetect instead",
|
||||
@@ -423,6 +489,34 @@
|
||||
],
|
||||
"usage": "data fsktonrz [-h] [-c <dec>] [--low <dec>] [--hi <dec>]"
|
||||
},
|
||||
"data gensignal": {
|
||||
"command": "data gensignal",
|
||||
"description": "Developer tool. Fill the GraphBuffer with a synthetic LF waveform. Used with `data fitscore` and `data autodemod`",
|
||||
"notes": [
|
||||
"data gensignal --mod ask --enc manchester --clk 64",
|
||||
"data gensignal --mod ask --enc manchester --clk 64.25 --noise 0.4 --len 20000"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--mod <ask|fsk|psk|nrz> modulation (def ask)",
|
||||
"--enc <raw|manchester|biphase> encoding (def raw)",
|
||||
"--clk <dbl> clock in samples/symbol, may be fractional (def 64)",
|
||||
"--len <int> samples to generate (def 16384)",
|
||||
"--noise <dbl> gaussian noise standard deviation (def 0)",
|
||||
"--drift <dbl> linear DC ramp across the capture (def 0)",
|
||||
"--env <dbl> amplitude envelope swing (def 0)",
|
||||
"--jitter <dbl> per symbol edge jitter, samples (def 0)",
|
||||
"--clip <dbl> hard clip level, 0 for none (def 0)",
|
||||
"--fc <int> PSK subcarrier period (def 4)",
|
||||
"--fchigh <int> FSK long field clock (def 10)",
|
||||
"--fclow <int> FSK short field clock (def 8)",
|
||||
"--q <int> antenna Q to shape the waveform with (def 8)",
|
||||
"--repeat <int> loop a message of this many bits, like a real tag (def 0, random)",
|
||||
"--seed <int> RNG seed, for reproducible runs (def 1)"
|
||||
],
|
||||
"usage": "data gensignal [-h] [--mod <ask|fsk|psk|nrz>] [--enc <raw|manchester|biphase>] [--clk <dbl>] [--len <int>] [--noise <dbl>] [--drift <dbl>] [--env <dbl>] [--jitter <dbl>] [--clip <dbl>] [--fc <int>] [--fchigh <int>] [--fclow <int>] [--q <int>] [--repeat <int>] [--seed <int>]"
|
||||
},
|
||||
"data getbitstream": {
|
||||
"command": "data getbitstream",
|
||||
"description": "Convert GraphBuffer's value accordingly - larger or equal to ONE becomes ONE - less than ONE becomes ZERO",
|
||||
@@ -452,7 +546,7 @@
|
||||
},
|
||||
"data help": {
|
||||
"command": "data help",
|
||||
"description": "help This help ----------- ------------------------- General------------------------- clear Clears various buffers used by the graph window hide Hide the graph window load Load contents of file into graph window num Converts dec/hex/bin plot Show the graph window print Print the data in the DemodBuffer save Save signal trace data setdebugmode Set Debugging Level on client side xor Xor a input string ----------- ------------------------- Modulation------------------------- biphaserawdecode Biphase decode bin stream in DemodBuffer detectclock Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer fsktonrz Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) manrawdecode Manchester decode binary stream in DemodBuffer modulation Identify LF signal for clock and modulation rawdemod Demodulate the data in the GraphBuffer and output binary ----------- ------------------------- Graph------------------------- askedgedetect Adjust Graph for manual ASK demod autocorr Autocorrelation over window convertbitstream Convert GraphBuffer's 0/1 values to 127 / -127 cthreshold Average out all values between dirthreshold Max rising higher up-thres/ Min falling lower down-thres decimate Decimate samples envelope Generate square envelope of samples grid overlay grid on graph window getbitstream Convert GraphBuffer's >=1 values to 1 and <1 to 0 hpf Remove DC offset from trace iir Apply IIR buttersworth filter on plot data ltrim Trim samples from left of trace mtrim Trim out samples from the specified start to the specified stop norm Normalize max/min to +/-128 rtrim Trim samples from right of trace setgraphmarkers Set the markers in the graph window shiftgraphzero Shift 0 for Graphed wave + or - shift value timescale Set cursor display timescale undecimate Un-decimate samples zerocrossings Count time between zero-crossings ----------- ------------------------- Operations------------------------- asn1 ASN1 decoder atr ATR lookup bmap Convert hex value according a binary template crypto Encrypt and decrypt data diff Diff of input files qrcode Create a QR code --------------------------------------------------------------------------------------- data clear available offline: yes This function clears the BigBuf on device side and graph window ( graphbuffer )",
|
||||
"description": "help This help ----------- ------------------------------ General ------------------------------- clear Clears various buffers used by the graph window hide Hide the graph window load Load contents of file into graph window num Converts dec/hex/bin plot Show the graph window print Print the data in the DemodBuffer save Save signal trace data setdebugmode Set Debugging Level on client side xor Xor a input string ----------- ----------------------------- Modulation ----------------------------- biphaserawdecode Biphase decode bin stream in DemodBuffer detectclock Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer fsktonrz Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) manrawdecode Manchester decode binary stream in DemodBuffer modulation Identify LF signal for clock and modulation rawdemod Demodulate the data in the GraphBuffer and output binary ----------- -------------------------- Frequency domain -------------------------- autodemod Detect modulation, encoding and clock, then demodulate fft Fourier transform of the GraphBuffer fitscore Rank matched filter hypotheses for modulation, encoding and clock spectrum Spectral peaks, symbol rate and modulation family hint ----------- ------------------------------- Graph -------------------------------- askedgedetect Adjust Graph for manual ASK demod autocorr Autocorrelation over window convertbitstream Convert GraphBuffer's 0/1 values to 127 / -127 cthreshold Average out all values between dirthreshold Max rising higher up-thres/ Min falling lower down-thres decimate Decimate samples envelope Generate square envelope of samples grid overlay grid on graph window getbitstream Convert GraphBuffer's >=1 values to 1 and <1 to 0 hpf Remove DC offset from trace iir Apply IIR buttersworth filter on plot data ltrim Trim samples from left of trace mtrim Trim out samples from the specified start to the specified stop norm Normalize max/min to +/-128 rtrim Trim samples from right of trace setgraphmarkers Set the markers in the graph window shiftgraphzero Shift 0 for Graphed wave + or - shift value timescale Set cursor display timescale undecimate Un-decimate samples zerocrossings Count time between zero-crossings ----------- ---------------------------- Operations ------------------------------ asn1 ASN1 decoder atr ATR lookup bmap Convert hex value according a binary template crypto Encrypt and decrypt data diff Diff of input files qrcode Create a QR code --------------------------------------------------------------------------------------- data clear available offline: yes This function clears the BigBuf on device side and graph window ( graphbuffer )",
|
||||
"notes": [
|
||||
"data clear"
|
||||
],
|
||||
@@ -774,6 +868,29 @@
|
||||
],
|
||||
"usage": "data shiftgraphzero [-h] -n <dec>"
|
||||
},
|
||||
"data spectrum": {
|
||||
"command": "data spectrum",
|
||||
"description": "Spectral analysis of the GraphBuffer. Reports the strongest spectral peaks with a sub bin estimate of the symbol clock, the squaring and delay-and-multiply spectra which expose rates the plain spectrum nulls out, and a modulation family hint derived from spectral shape alone. Run this on a trace that will not decode.",
|
||||
"notes": [
|
||||
"data spectrum -> peak table and family hint",
|
||||
"data spectrum --top 8 --sq -> more peaks, plus the squaring spectrum",
|
||||
"data spectrum --stft --size 2048 -> spectrogram over the whole capture",
|
||||
"data spectrum --stft --size 2048 --hop 256 -> finer time resolution"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--start <int> first sample of the GraphBuffer to use (def 0)",
|
||||
"--size <int> transform length, rounded up to a power of two (def largest that fits)",
|
||||
"--win <hann|hamming|blackman|rect> window function (def hann)",
|
||||
"--top <int> number of peaks to report (def 5)",
|
||||
"--sq also show the squaring and delay-and-multiply spectra",
|
||||
"--stft sliding window spectrogram, ridge tracking and drift",
|
||||
"--hop <int> STFT hop in samples (def size/4)",
|
||||
"--fs <int> sample rate in Hz, adds a frequency column in Hz"
|
||||
],
|
||||
"usage": "data spectrum [-h] [--start <int>] [--size <int>] [--win <hann|hamming|blackman|rect>] [--top <int>] [--sq] [--stft] [--hop <int>] [--fs <int>]"
|
||||
},
|
||||
"data test_ss32": {
|
||||
"command": "data test_ss32",
|
||||
"description": "Tests the implementation of Buffer Save States (32-bit buffer)",
|
||||
@@ -1774,35 +1891,20 @@
|
||||
],
|
||||
"usage": "hf 14b wrbl [-h] [-b <dec>] -d <hex> [--512] [--4k] [--sb] [--force]"
|
||||
},
|
||||
"hf 15 cfinalize": {
|
||||
"command": "hf 15 cfinalize",
|
||||
"description": "Finalize a magic ISO15693 'V3' tag. This operation is irreversible. After finalize the configuration area is erased and the UID can no longer be changed. Set the UID with `hf 15 csetuid --v3` first, then lock it in with this command.",
|
||||
"notes": [
|
||||
"hf 15 cfinalize -y"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-y, --yes Confirm the irreversible finalize operation"
|
||||
],
|
||||
"usage": "hf 15 cfinalize [-hy]"
|
||||
},
|
||||
"hf 15 csetuid": {
|
||||
"command": "hf 15 csetuid",
|
||||
"description": "Set UID for magic Chinese card (only works with such cards) For magic 'V3' tags this writes the UID configuration only and is repeatable; run `hf 15 cfinalize` afterwards to lock the UID permanently.",
|
||||
"description": "Set UID for magic Chinese card (only works with such cards)",
|
||||
"notes": [
|
||||
"hf 15 csetuid -u E011223344556677 -> use gen1 command",
|
||||
"hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command",
|
||||
"hf 15 csetuid -u E011223344556677 --v3 -> use gen3 (V3) magic tag"
|
||||
"hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-u, --uid <hex> UID, 8 hex bytes",
|
||||
"-2, --v2 Use gen2 magic command",
|
||||
"-3, --v3 Use gen3 (V3) magic tag (repeatable, needs cfinalize)"
|
||||
"-2, --v2 Use gen2 magic command"
|
||||
],
|
||||
"usage": "hf 15 csetuid [-h23] -u <hex>"
|
||||
"usage": "hf 15 csetuid [-h2] -u <hex>"
|
||||
},
|
||||
"hf 15 demod": {
|
||||
"command": "hf 15 demod",
|
||||
@@ -5095,11 +5197,12 @@
|
||||
},
|
||||
"hf legic clone": {
|
||||
"command": "hf legic clone",
|
||||
"description": "Rewrite a LEGIC dump for a new target tag or MCC. Use --mcc to rewrite only the dump obfuscation, or --write to clone to the current tag.",
|
||||
"description": "Rewrite a LEGIC dump for a new target tag or MCC. Use --mcc to rewrite only the dump obfuscation, or --write to clone to the current tag. Use --kgh with --write to recalculate UID-bound KGH payload CRCs.",
|
||||
"notes": [
|
||||
"hf legic clone -f src.bin -c 39 -o clone.bin",
|
||||
"hf legic clone -f src.bin --write",
|
||||
"hf legic clone -f src.bin --write -o clone.bin"
|
||||
"hf legic clone -f src.bin --write --kgh",
|
||||
"hf legic clone -f src.bin --write --kgh -o clone.bin"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
@@ -5107,9 +5210,10 @@
|
||||
"-f, --file <fn> Source dump file",
|
||||
"--mcc <hex> Target MCC byte for output-only cloning",
|
||||
"-o, --output <fn> Output cloned dump file",
|
||||
"-w, --write Write cloned dump to the currently attached tag"
|
||||
"-w, --write Write cloned dump to the currently attached tag",
|
||||
"--kgh Recalculate KGH payload CRCs"
|
||||
],
|
||||
"usage": "hf legic clone [-hw] -f <fn> [--mcc <hex>] [-o <fn>]"
|
||||
"usage": "hf legic clone [-hw] -f <fn> [--mcc <hex>] [-o <fn>] [--kgh]"
|
||||
},
|
||||
"hf legic crc": {
|
||||
"command": "hf legic crc",
|
||||
@@ -5249,16 +5353,18 @@
|
||||
"description": "Clone a LEGIC Prime dump to the currently attached tag. Optionally apply a DCF update after cloning, but only when explicitly requested.",
|
||||
"notes": [
|
||||
"hf legic migrate -f src.bin",
|
||||
"hf legic migrate -f src.bin --kgh",
|
||||
"hf legic migrate -f src.bin --dcf 60EA --danger"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-f, --file <fn> Source dump file",
|
||||
"--kgh Recalculate KGH payload CRCs",
|
||||
"--dcf <hex> Optional DCF bytes to write after clone",
|
||||
"--danger Allow the explicit DCF write"
|
||||
],
|
||||
"usage": "hf legic migrate [-h] -f <fn> [--dcf <hex>] [--danger]"
|
||||
"usage": "hf legic migrate [-h] -f <fn> [--kgh] [--dcf <hex>] [--danger]"
|
||||
},
|
||||
"hf legic rdbl": {
|
||||
"command": "hf legic rdbl",
|
||||
@@ -11997,7 +12103,7 @@
|
||||
},
|
||||
"lf help": {
|
||||
"command": "lf help",
|
||||
"description": "help This help ----------- -------------- Low Frequency -------------- awid { AWID RFIDs... } cotag { COTAG CHIPs... } destron { FDX-A Destron RFIDs... } em { EM CHIPs & RFIDs... } fdxb { FDX-B RFIDs... } gallagher { GALLAGHER RFIDs... } gproxii { Guardall Prox II RFIDs... } hid { HID Prox RFIDs... } hitag { Hitag CHIPs... } idteck { Idteck RFIDs... } indala { Indala RFIDs... } io { ioProx RFIDs... } jablotron { Jablotron RFIDs... } keri { KERI RFIDs... } motorola { Motorola Flexpass RFIDs... } nedap { Nedap RFIDs... } nexwatch { NexWatch RFIDs... } noralsy { Noralsy RFIDs... } pac { PAC/Stanley RFIDs... } paradox { Paradox RFIDs... } pcf7931 { PCF7931 CHIPs... } presco { Presco RFIDs... } pyramid { Farpointe/Pyramid RFIDs... } securakey { Securakey RFIDs... } ti { TI CHIPs... } t55xx { T55xx CHIPs... } viking { Viking RFIDs... } visa2000 { Visa2000 RFIDs... } ----------- --------------------- General --------------------- search Read and Search for valid known tag --------------------------------------------------------------------------------------- lf config available offline: no Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)",
|
||||
"description": "help This help ----------- -------------- Low Frequency -------------- awid { AWID RFIDs... } cotag { COTAG CHIPs... } destron { FDX-A Destron RFIDs... } em { EM CHIPs & RFIDs... } fdxb { FDX-B RFIDs... } gallagher { GALLAGHER RFIDs... } gproxii { Guardall Prox II RFIDs... } hid { HID Prox RFIDs... } hitag { Hitag CHIPs... } idteck { Idteck RFIDs... } indala { Indala RFIDs... } io { ioProx RFIDs... } jablotron { Jablotron RFIDs... } keri { KERI RFIDs... } motorola { Motorola Flexpass RFIDs... } nedap { Nedap RFIDs... } nexwatch { NexWatch RFIDs... } noralsy { Noralsy RFIDs... } pac { PAC/Stanley RFIDs... } paradox { Paradox RFIDs... } pcf7931 { PCF7931 CHIPs... } presco { Presco RFIDs... } pyramid { Farpointe/Pyramid RFIDs... } securakey { Securakey RFIDs... } ti { TI CHIPs... } t55xx { T55xx CHIPs... } trovan { Trovan animal IDs... } viking { Viking RFIDs... } visa2000 { Visa2000 RFIDs... } ----------- --------------------- General --------------------- search Read and Search for valid known tag --------------------------------------------------------------------------------------- lf config available offline: no Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)",
|
||||
"notes": [
|
||||
"lf config -> shows current config",
|
||||
"lf config -b 8 --125 -> samples at 125 kHz, 8 bps",
|
||||
@@ -13910,7 +14016,7 @@
|
||||
},
|
||||
"lf t55xx help": {
|
||||
"command": "lf t55xx help",
|
||||
"description": "----------- ---------------------------- notice ----------------------------- Remember to run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- --------------------- operations --------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) view Display content from tag dump file ----------- --------------------- recovery --------------------- sniff Attempt to recover T55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no Display a list of available commands for cloning specific techs on T5xx tags",
|
||||
"description": "----------- ------------------------------- notice --------------------------------- Always run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- ----------------------------- operations ------------------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) view Display content from tag dump file ----------- ------------------------------ recovery -------------------------------- sniff Attempt to recover T55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no Display a list of available commands for cloning specific techs on T5xx tags",
|
||||
"notes": [
|
||||
"lf t55xx clonehelp"
|
||||
],
|
||||
@@ -14222,6 +14328,50 @@
|
||||
],
|
||||
"usage": "lf ti write [-h] -r <hex> [--crc <hex>]"
|
||||
},
|
||||
"lf trovan clone": {
|
||||
"command": "lf trovan clone",
|
||||
"description": "clone a Trovan animal ID to a T55x7, Q5/T5555 or EM4305/4469 tag The ID is the 10 hex digits printed on the tag, with or without dashes.",
|
||||
"notes": [
|
||||
"lf trovan clone --id 0007F9043A",
|
||||
"lf trovan clone --id 00-07F9-043A",
|
||||
"lf trovan clone --id 0007F9043A --q5"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--id <hex> Trovan animal ID, 10 hex digits",
|
||||
"--q5 specify writing to Q5/T5555 tag",
|
||||
"--em specify writing to EM4305/4469 tag"
|
||||
],
|
||||
"usage": "lf trovan clone [-h] --id <hex> [--q5] [--em]"
|
||||
},
|
||||
"lf trovan help": {
|
||||
"command": "lf trovan help",
|
||||
"description": "help This help demod demodulate a Trovan tag from the GraphBuffer --------------------------------------------------------------------------------------- lf trovan demod available offline: yes Demodulate a Trovan animal ID tag from the GraphBuffer",
|
||||
"notes": [
|
||||
"lf trovan demod"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-v, --verbose verbose output"
|
||||
],
|
||||
"usage": "lf trovan demod [-hv]"
|
||||
},
|
||||
"lf trovan reader": {
|
||||
"command": "lf trovan reader",
|
||||
"description": "read a Trovan animal ID tag",
|
||||
"notes": [
|
||||
"lf trovan reader -@ -> continuous reader mode"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-@ optional - continuous reader mode",
|
||||
"-v, --verbose verbose output"
|
||||
],
|
||||
"usage": "lf trovan reader [-h@v]"
|
||||
},
|
||||
"lf tune": {
|
||||
"command": "lf tune",
|
||||
"description": "Continuously measure LF antenna tuning. Press button or <Enter> to interrupt.",
|
||||
@@ -15873,8 +16023,8 @@
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"commands_extracted": 889,
|
||||
"commands_extracted": 896,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2026-07-26T21:37:31+00:00"
|
||||
"extracted_on": "2026-07-30T14:44:57+00:00"
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -114,6 +114,10 @@ Check column "offline" for their availability.
|
||||
|`data manrawdecode `|Y |`Manchester decode binary stream in DemodBuffer`
|
||||
|`data modulation `|Y |`Identify LF signal for clock and modulation`
|
||||
|`data rawdemod `|Y |`Demodulate the data in the GraphBuffer and output binary`
|
||||
|`data autodemod `|Y |`Detect modulation, encoding and clock, then demodulate`
|
||||
|`data fft `|Y |`Fourier transform of the GraphBuffer`
|
||||
|`data fitscore `|Y |`Rank matched filter hypotheses for modulation, encoding and clock`
|
||||
|`data spectrum `|Y |`Spectral peaks, symbol rate and modulation family hint`
|
||||
|`data askedgedetect `|Y |`Adjust Graph for manual ASK demod`
|
||||
|`data autocorr `|Y |`Autocorrelation over window`
|
||||
|`data convertbitstream `|Y |`Convert GraphBuffer's 0/1 values to 127 / -127`
|
||||
@@ -143,6 +147,7 @@ Check column "offline" for their availability.
|
||||
|`data hexsamples `|N |`Dump big buffer as hex bytes`
|
||||
|`data samples `|N |`Get raw samples for graph window ( GraphBuffer )`
|
||||
|`data qrcode `|Y |`Create a QR code`
|
||||
|`data gensignal `|N |`Generate a synthetic LF waveform into the GraphBuffer`
|
||||
|`data test_ss8 `|N |`Test the implementation of Buffer Save States (8-bit buffer)`
|
||||
|`data test_ss32 `|N |`Test the implementation of Buffer Save States (32-bit buffer)`
|
||||
|`data test_ss32s `|N |`Test the implementation of Buffer Save States (32-bit signed buffer)`
|
||||
@@ -276,7 +281,6 @@ Check column "offline" for their availability.
|
||||
|`hf 15 writeafi `|N |`Writes the AFI on an ISO-15693 tag`
|
||||
|`hf 15 writedsfid `|N |`Writes the DSFID on an ISO-15693 tag`
|
||||
|`hf 15 csetuid `|N |`Set UID for magic card`
|
||||
|`hf 15 cfinalize `|N |`Finalize a magic V3 tag (irreversible)`
|
||||
|
||||
|
||||
### hf aliro
|
||||
@@ -1506,7 +1510,7 @@ Check column "offline" for their availability.
|
||||
|`lf t55xx info `|Y |`Show T55x7 configuration data (page 0/ blk 0)`
|
||||
|`lf t55xx p1detect `|N |`Try detecting if this is a t55xx tag by reading page 1`
|
||||
|`lf t55xx read `|N |`Read T55xx block data`
|
||||
|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it`
|
||||
|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start`
|
||||
|`lf t55xx restore `|N |`Restore T55xx card Page 0 / Page 1 blocks`
|
||||
|`lf t55xx trace `|Y |`Show T55x7 traceability data (page 1/ blk 0-1)`
|
||||
|`lf t55xx wakeup `|N |`Send AOR wakeup command`
|
||||
@@ -1521,6 +1525,18 @@ Check column "offline" for their availability.
|
||||
|`lf t55xx wipe `|N |`Wipe a T55xx tag and set defaults (will destroy any data on tag)`
|
||||
|
||||
|
||||
### lf trovan
|
||||
|
||||
{ Trovan animal IDs... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`lf trovan help `|Y |`This help`
|
||||
|`lf trovan demod `|Y |`demodulate a Trovan tag from the GraphBuffer`
|
||||
|`lf trovan reader `|N |`attempt to read and extract tag data`
|
||||
|`lf trovan clone `|N |`clone Trovan tag to T55x7 or Q5/T5555`
|
||||
|
||||
|
||||
### lf viking
|
||||
|
||||
{ Viking RFIDs... }
|
||||
|
||||
+4
-4
@@ -511,13 +511,13 @@ while true; do
|
||||
|
||||
echo -e "\n${C_BLUE}Testing LF:${C_NC}"
|
||||
if ! CheckExecute "lf hitag2 test" "$CLIENTBIN -c 'lf hitag test'" "Tests \( ok"; then break; fi
|
||||
if ! CheckExecute "lf cotag demod test 1/4" "$CLIENTBIN -c 'data load -f traces/lf_cotag_220_8331.pm3; lf cotag demod -c 272'" \
|
||||
if ! CheckExecute "lf cotag demod test 1/4" "$CLIENTBIN -c 'data load -f traces/lf_cotag_220_8331.pm3; lf cotag demod -c 272 -v'" \
|
||||
"data hex: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 5 8 2 4 E 0 0 0 0 8 0 2 3 D F 7 7"; then break; fi
|
||||
if ! CheckExecute "lf cotag demod test 2/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_passive_02402447_700000.pm3; lf cotag demod'" \
|
||||
if ! CheckExecute "lf cotag demod test 2/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_passive_02402447_700000.pm3; lf cotag demod -v'" \
|
||||
"data hex: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 5 8 2 4 E 0 0 0 0 8 0 2 4 A 8 8 F"; then break; fi
|
||||
if ! CheckExecute "lf cotag demod test 3/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_passive_bewator_01576814_700000.pm3; lf cotag demod'" \
|
||||
if ! CheckExecute "lf cotag demod test 3/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_passive_bewator_01576814_700000.pm3; lf cotag demod -v'" \
|
||||
"data hex: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 C B B 7 0 0 0 0 8 0 1 8 0 F 6 E"; then break; fi
|
||||
if ! CheckExecute "lf cotag demod test 4/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_active_00001577_700000.pm3; lf cotag demod'" \
|
||||
if ! CheckExecute "lf cotag demod test 4/4" "$CLIENTBIN -c 'data load -f traces/cotag/lf_cotag_active_00001577_700000.pm3; lf cotag demod -v'" \
|
||||
"data hex: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 8 2 7 B 0 4 8 E 0 0 0 0 0 6 2 9"; then break; fi
|
||||
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi
|
||||
if ! CheckExecute "lf EM410x test" "$CLIENTBIN -c 'data load -f traces/lf_EM4102-1.pm3;lf search -1'" "EM410x ID found"; then break; fi
|
||||
|
||||
Reference in New Issue
Block a user