Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
ry4000
2026-07-31 01:19:04 +10:00
committed by GitHub
27 changed files with 6718 additions and 739 deletions
+1 -1
View File
@@ -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)
+4
View File
@@ -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
+3
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+7 -6
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -2
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+436
View File
@@ -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);
}
+29
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1812
View File
File diff suppressed because it is too large Load Diff
+200
View File
@@ -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__
+1066
View File
File diff suppressed because it is too large Load Diff
+119
View File
@@ -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__
+9 -1
View File
@@ -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" },
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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