Skip to content

Commit ed0a29b

Browse files
author
codeflakes
committed
New 'lf hitag pwmdemod' cmd decoding the reader messages from graph buffer
1 parent 908200b commit ed0a29b

File tree

7 files changed

+216
-17
lines changed

7 files changed

+216
-17
lines changed

client/src/cmddata.c

+15
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "crypto/asn1utils.h" // ASN1 decode / print
3131

3232
uint8_t g_DemodBuffer[MAX_DEMOD_BUF_LEN];
33+
uint8_t g_DemodBitRangeBuffer[MAX_DEMOD_BUF_LEN];
3334
size_t g_DemodBufferLen = 0;
3435
int32_t g_DemodStartIdx = 0;
3536
int g_DemodClock = 0;
@@ -41,6 +42,10 @@ static int CmdHelp(const char *Cmd);
4142
void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx) {
4243
if (buff == NULL) return;
4344

45+
// By default, disable bit range buffer by setting a
46+
// zero value (tested in proxguiqt.cpp)
47+
g_DemodBitRangeBuffer[0] = 0;
48+
4449
if (size > MAX_DEMOD_BUF_LEN - start_idx)
4550
size = MAX_DEMOD_BUF_LEN - start_idx;
4651

@@ -50,6 +55,16 @@ void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx) {
5055
g_DemodBufferLen = size;
5156
}
5257

58+
//set the g_DemodBuffer with given array ofq binary (one bit per byte)
59+
//by marshmellow
60+
void setDemodBuff2(uint8_t *buff, size_t size, size_t start_idx, uint8_t *bitRange) {
61+
uint8_t b = bitRange[0];
62+
setDemodBuff(buff, size, start_idx);
63+
if (bitRange)
64+
g_DemodBitRangeBuffer[0] = b;
65+
}
66+
67+
5368
bool getDemodBuff(uint8_t *buff, size_t *size) {
5469
if (buff == NULL) return false;
5570
if (size == NULL) return false;

client/src/cmddata.h

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ int NRZrawDemod(int clk, int invert, int maxErr, bool verbose);
7171
int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex);
7272

7373
void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx);
74+
void setDemodBuff2(uint8_t *buff, size_t size, size_t start_idx, uint8_t *bitRange);
7475
bool getDemodBuff(uint8_t *buff, size_t *size);
7576
void save_restoreDB(uint8_t saveOpt);// option '1' to save g_DemodBuffer any other to restore
7677
int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveGrph, bool verbose);
@@ -84,6 +85,7 @@ int AskEdgeDetect(const int *in, int *out, int len, int threshold);
8485

8586
#define MAX_DEMOD_BUF_LEN (1024*128)
8687
extern uint8_t g_DemodBuffer[MAX_DEMOD_BUF_LEN];
88+
extern uint8_t g_DemodBitRangeBuffer[MAX_DEMOD_BUF_LEN];
8789
extern size_t g_DemodBufferLen;
8890

8991
extern int g_DemodClock;

client/src/cmdlfhitag.c

+81-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
#include "protocols.h" // defines
1919
#include "cliparser.h"
2020

21+
#include "graph.h" // MAX_GRAPH_TRACE_LEN
22+
#include "lfdemod.h"
23+
#include "cmddata.h" // setDemodBuff
24+
25+
2126
static int CmdHelp(const char *Cmd);
2227

2328
static const char *getHitagTypeStr(uint32_t uid) {
@@ -883,6 +888,71 @@ static int CmdLFHitag2Dump(const char *Cmd) {
883888
return PM3_SUCCESS;
884889
}
885890

891+
static int CmdLFHitag2PWMDemod(const char *Cmd) {
892+
893+
CLIParserContext *ctx;
894+
CLIParserInit(&ctx, "lf hitag pwmdemod",
895+
"Demodulate the data in the GraphBuffer and output binary\n",
896+
"lf hitag pwmdemod -t 65 --> specify first wave index\n"
897+
"lf hitag pwmdemod"
898+
);
899+
900+
void *argtable[] = {
901+
arg_param_begin,
902+
arg_int0("t", "start", "<dec>", "first wave index"),
903+
arg_param_end
904+
};
905+
906+
CLIExecWithReturn(ctx, Cmd, argtable, true);
907+
uint32_t start_idx = (uint32_t)arg_get_int_def(ctx, 1, 0);
908+
CLIParserFree(ctx);
909+
910+
uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
911+
if (bits == NULL) {
912+
PrintAndLogEx(INFO, "failed to allocate memory");
913+
return PM3_EMALLOC;
914+
}
915+
916+
size_t size = getFromGraphBuf(bits);
917+
918+
PrintAndLogEx(DEBUG, "DEBUG: (Hitag2PWM) #samples from graphbuff: %zu", size);
919+
920+
if (size < 255) {
921+
free(bits);
922+
return PM3_ESOFT;
923+
}
924+
925+
// TODO autodetect
926+
uint8_t fchigh = 29;
927+
uint8_t fclow = 20;
928+
929+
size = HitagPWMDemod(bits, size, &fchigh, &fclow, &start_idx, g_DemodBitRangeBuffer);
930+
PrintAndLogEx(DEBUG, "DEBUG: start_idx=%d, size=%d", start_idx, size);
931+
if (size > 0) {
932+
setDemodBuff2(bits, size, 0, g_DemodBitRangeBuffer);
933+
setClockGrid(32, start_idx);
934+
uint32_t total = 0;
935+
for (int i=0; i<size; i++) {
936+
total += g_DemodBitRangeBuffer[i];
937+
PrintAndLogEx(SUCCESS, "%d", g_DemodBitRangeBuffer[i]);
938+
}
939+
PrintAndLogEx(SUCCESS, "total %d", total);
940+
}
941+
942+
if (size == 0) {
943+
PrintAndLogEx(DEBUG, "DEBUG: (Hitag2PWM) No wave detected");
944+
free(bits);
945+
return PM3_ESOFT;
946+
}
947+
948+
949+
PrintAndLogEx(SUCCESS, _YELLOW_("HITAG/PWM") " - decoded bitstream");
950+
PrintAndLogEx(INFO, "--------------------------------------");
951+
printDemodBuff(0, false, false, false);
952+
953+
free(bits);
954+
return PM3_SUCCESS;
955+
}
886956

887957
// Annotate HITAG protocol
888958
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
@@ -943,16 +1013,17 @@ void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
9431013
}
9441014

9451015
static command_t CommandTable[] = {
946-
{"help", CmdHelp, AlwaysAvailable, "This help"},
947-
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
948-
{"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
949-
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag2 tag information"},
950-
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
951-
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
952-
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
953-
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
954-
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
955-
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
1016+
{"help", CmdHelp, AlwaysAvailable, "This help"},
1017+
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
1018+
{"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
1019+
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag2 tag information"},
1020+
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
1021+
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
1022+
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
1023+
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
1024+
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
1025+
{"pwmdemod", CmdLFHitag2PWMDemod, AlwaysAvailable, "PWM Hitag2 reader message demodulation"},
1026+
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
9561027
{ NULL, NULL, 0, NULL }
9571028
};
9581029

client/src/proxguiqt.cpp

+27-6
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,8 @@ void Plot::setMaxAndStart(int *buffer, size_t len, QRect plotRect) {
510510
gs_absVMax = (int)(gs_absVMax * 1.25 + 1);
511511
}
512512

513-
void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum, uint32_t plotOffset) {
513+
void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter,
514+
int graphNum, uint32_t plotOffset, uint8_t *bitRange) {
514515
if (len == 0 || g_PlotGridX <= 0) return;
515516
//clock_t begin = clock();
516517
QPainterPath penPath;
@@ -535,8 +536,19 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati
535536
int absVMax = (int)(100 * 1.05 + 1);
536537
delta_x = 0;
537538
int clk = first_delta_x;
539+
if (bitRange) {
540+
int shift = grid_delta_x-first_delta_x; // can be negative
541+
if (shift <= bitRange[BitStart])
542+
clk = bitRange[BitStart] - shift;
543+
else {
544+
clk = bitRange[BitStart+1] - (shift - bitRange[BitStart]);
545+
BitStart++;
546+
}
547+
}
548+
//printf("old %d new %d BitStart %d\n", first_delta_x, clk, BitStart);
549+
538550
for (int i = BitStart; i < (int)len && xCoordOf(delta_x + DemodStart, plotRect) < plotRect.right(); i++) {
539-
for (int j = 0; j < (clk) && i < (int)len && xCoordOf(DemodStart + delta_x + j, plotRect) < plotRect.right() ; j++) {
551+
for (int j = 0; j < (clk) && i <= (int)len && xCoordOf(DemodStart + delta_x + j, plotRect) < plotRect.right() ; j++) {
540552
int x = xCoordOf(DemodStart + delta_x + j, plotRect);
541553
int v = buffer[i] * 200 - 100;
542554

@@ -556,8 +568,14 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati
556568
painter->drawText(x - 8, y + ((buffer[i] > 0) ? 18 : -6), str);
557569
}
558570
}
559-
delta_x += clk;
560-
clk = grid_delta_x;
571+
572+
if (bitRange) {
573+
delta_x += (clk);
574+
clk = bitRange[i+1];
575+
} else {
576+
delta_x += clk;
577+
clk = grid_delta_x;
578+
}
561579
}
562580

563581
// Graph annotations
@@ -711,8 +729,11 @@ void Plot::paintEvent(QPaintEvent *event) {
711729

712730
//Start painting graph
713731
PlotGraph(g_GraphBuffer, g_GraphTraceLen, plotRect, infoRect, &painter, 0);
714-
if (g_DemodBufferLen > 8) {
715-
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx);
732+
if (g_DemodBufferLen >= 5) {
733+
if (g_DemodBitRangeBuffer[0])
734+
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx, g_DemodBitRangeBuffer);
735+
else
736+
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx, NULL);
716737
}
717738
if (gs_useOverlays) {
718739
//init graph variables

client/src/proxguiqt.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class Plot: public QWidget {
3636
uint32_t CursorAPos;
3737
uint32_t CursorBPos;
3838
void PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum);
39-
void PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum, uint32_t plotOffset);
39+
void PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter,
40+
int graphNum, uint32_t plotOffset, uint8_t* bitRange);
4041
void plotGridLines(QPainter *painter, QRect r);
4142
int xCoordOf(int i, QRect r);
4243
int yCoordOf(int v, QRect r, int maxVal);

common/lfdemod.c

+88
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,17 @@ static size_t findModStart(uint8_t *src, size_t size, uint8_t expWaveSize) {
423423
return i;
424424
}
425425

426+
static size_t findModStart2(uint8_t *src, size_t size, uint8_t expWaveSize) {
427+
uint32_t i = 0;
428+
uint8_t threshold = signalprop.amplitude / 10; // 10 %
429+
for (; i < size - 20; i++) {
430+
if (abs(src[i] - signalprop.mean) > threshold) {
431+
break;
432+
}
433+
}
434+
return i;
435+
}
436+
426437
static int getClosestClock(int testclk) {
427438
uint16_t clocks[] = {8, 16, 32, 40, 50, 64, 100, 128, 256, 384};
428439
uint8_t limit[] = {1, 2, 4, 4, 5, 8, 8, 8, 8, 8};
@@ -1836,6 +1847,83 @@ int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int *startId
18361847
return 0;
18371848
}
18381849

1850+
size_t HitagPWMDemod(uint8_t *dest, size_t size, uint8_t *fchigh, uint8_t *fclow, uint32_t *startIdx, uint8_t *bitRange) {
1851+
printSignal();
1852+
1853+
if (g_debugMode == 2)
1854+
prnt("HitagWMDemod startIdx:%d low period:%d high period:%d", *startIdx, *fclow, *fchigh);
1855+
1856+
size_t idx = 0, numBits = 0;
1857+
1858+
//find start of modulating data in trace
1859+
if (*startIdx == 0) {
1860+
idx = findModStart2(dest, size, *fchigh);
1861+
*startIdx = idx;
1862+
if (g_debugMode == 2)
1863+
prnt("detected start %d", idx);
1864+
}
1865+
1866+
uint8_t wave_min = 255;
1867+
uint8_t wave_max = 0;
1868+
uint8_t sub_idx = 0;
1869+
uint32_t idx_min = 0;
1870+
uint32_t idx_max = 0;
1871+
uint32_t last_wave_start = idx;
1872+
uint8_t meanCrossCount = 0;
1873+
for (; idx < size - 20; idx++, sub_idx++) {
1874+
1875+
if (dest[idx] < wave_min) {
1876+
wave_min = dest[idx];
1877+
idx_min = idx;
1878+
}
1879+
if (dest[idx] > wave_max) {
1880+
wave_max = dest[idx];
1881+
idx_max = idx;
1882+
}
1883+
1884+
uint32_t period = idx - last_wave_start;
1885+
if (period > (*fchigh)*1.5) {
1886+
if (g_debugMode == 2)
1887+
prnt("period %d is too big", period);
1888+
break;
1889+
}
1890+
1891+
if ((dest[idx] >= signalprop.mean && dest[idx+1] < signalprop.mean) ||
1892+
(dest[idx] <= signalprop.mean && dest[idx+1] > signalprop.mean)) {
1893+
meanCrossCount++;
1894+
if (meanCrossCount > 2) return 0;
1895+
}
1896+
// wait to pass the beginning of the wave (> *fclow/2) and detect the next cross
1897+
// of the mean line.
1898+
if ((sub_idx > (*fclow)/2) && meanCrossCount == 2) {
1899+
if ((wave_max - wave_min) < signalprop.amplitude/2) {
1900+
if (g_debugMode == 2)
1901+
prnt("wave not strong enough, probably end of signal");
1902+
break;
1903+
}
1904+
1905+
if (g_debugMode == 2)
1906+
prnt("wave %d ends at %d [min:%d,%d,max:%d,%d], [%d -> %d] period=%d",
1907+
numBits+1, idx, idx_min, wave_min, idx_max, wave_max, last_wave_start, idx-1, period);
1908+
last_wave_start = idx;
1909+
1910+
sub_idx = 0;
1911+
idx_min = idx_max = 0;
1912+
wave_max = 0;
1913+
wave_min = 255;
1914+
meanCrossCount = 0;
1915+
1916+
// TODO : don't just compare high and low but verifty the period match to a certain %
1917+
bitRange[numBits] = period;
1918+
if (abs(period-*fchigh) > abs(period-*fclow))
1919+
dest[numBits++] = 0;
1920+
else
1921+
dest[numBits++] = 1;
1922+
}
1923+
}
1924+
return numBits;
1925+
}
1926+
18391927
//translate wave to 11111100000 (1 for each short wave [higher freq] 0 for each long wave [lower freq])
18401928
static size_t fsk_wave_demod(uint8_t *dest, size_t size, uint8_t fchigh, uint8_t fclow, int *startIdx) {
18411929

common/lfdemod.h

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ int pskRawDemod_ext(uint8_t *dest, size_t *size, int *clock, int *invert, i
7373
void psk2TOpsk1(uint8_t *bits, size_t size);
7474
void psk1TOpsk2(uint8_t *bits, size_t size);
7575
size_t removeParity(uint8_t *bits, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen);
76+
size_t HitagPWMDemod(uint8_t *dest, size_t size, uint8_t *fchigh, uint8_t *fclow, uint32_t *startIdx, uint8_t *bitRange);
7677

7778
//tag specific
7879
int detectAWID(uint8_t *dest, size_t *size, int *waveStartIdx);

0 commit comments

Comments
 (0)