Skip to content

Commit

Permalink
New 'lf hitag pwmdemod' cmd decoding the reader messages from graph b…
Browse files Browse the repository at this point in the history
…uffer
  • Loading branch information
codeflakes committed Oct 22, 2021
1 parent 908200b commit ed0a29b
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 17 deletions.
15 changes: 15 additions & 0 deletions client/src/cmddata.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "crypto/asn1utils.h" // ASN1 decode / print

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

// By default, disable bit range buffer by setting a
// zero value (tested in proxguiqt.cpp)
g_DemodBitRangeBuffer[0] = 0;

if (size > MAX_DEMOD_BUF_LEN - start_idx)
size = MAX_DEMOD_BUF_LEN - start_idx;

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

//set the g_DemodBuffer with given array ofq binary (one bit per byte)
//by marshmellow
void setDemodBuff2(uint8_t *buff, size_t size, size_t start_idx, uint8_t *bitRange) {
uint8_t b = bitRange[0];
setDemodBuff(buff, size, start_idx);
if (bitRange)
g_DemodBitRangeBuffer[0] = b;
}


bool getDemodBuff(uint8_t *buff, size_t *size) {
if (buff == NULL) return false;
if (size == NULL) return false;
Expand Down
2 changes: 2 additions & 0 deletions client/src/cmddata.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ int NRZrawDemod(int clk, int invert, int maxErr, bool verbose);
int printDemodBuff(uint8_t offset, bool strip_leading, bool invert, bool print_hex);

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

#define MAX_DEMOD_BUF_LEN (1024*128)
extern uint8_t g_DemodBuffer[MAX_DEMOD_BUF_LEN];
extern uint8_t g_DemodBitRangeBuffer[MAX_DEMOD_BUF_LEN];
extern size_t g_DemodBufferLen;

extern int g_DemodClock;
Expand Down
91 changes: 81 additions & 10 deletions client/src/cmdlfhitag.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
#include "protocols.h" // defines
#include "cliparser.h"

#include "graph.h" // MAX_GRAPH_TRACE_LEN
#include "lfdemod.h"
#include "cmddata.h" // setDemodBuff


static int CmdHelp(const char *Cmd);

static const char *getHitagTypeStr(uint32_t uid) {
Expand Down Expand Up @@ -883,6 +888,71 @@ static int CmdLFHitag2Dump(const char *Cmd) {
return PM3_SUCCESS;
}

static int CmdLFHitag2PWMDemod(const char *Cmd) {

CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag pwmdemod",
"Demodulate the data in the GraphBuffer and output binary\n",
"lf hitag pwmdemod -t 65 --> specify first wave index\n"
"lf hitag pwmdemod"
);

void *argtable[] = {
arg_param_begin,
arg_int0("t", "start", "<dec>", "first wave index"),
arg_param_end
};

CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t start_idx = (uint32_t)arg_get_int_def(ctx, 1, 0);
CLIParserFree(ctx);

uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(INFO, "failed to allocate memory");
return PM3_EMALLOC;
}

size_t size = getFromGraphBuf(bits);

PrintAndLogEx(DEBUG, "DEBUG: (Hitag2PWM) #samples from graphbuff: %zu", size);

if (size < 255) {
free(bits);
return PM3_ESOFT;
}

// TODO autodetect
uint8_t fchigh = 29;
uint8_t fclow = 20;

size = HitagPWMDemod(bits, size, &fchigh, &fclow, &start_idx, g_DemodBitRangeBuffer);
PrintAndLogEx(DEBUG, "DEBUG: start_idx=%d, size=%d", start_idx, size);
if (size > 0) {
setDemodBuff2(bits, size, 0, g_DemodBitRangeBuffer);
setClockGrid(32, start_idx);
uint32_t total = 0;
for (int i=0; i<size; i++) {
total += g_DemodBitRangeBuffer[i];
PrintAndLogEx(SUCCESS, "%d", g_DemodBitRangeBuffer[i]);
}
PrintAndLogEx(SUCCESS, "total %d", total);
}

if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: (Hitag2PWM) No wave detected");
free(bits);
return PM3_ESOFT;
}


PrintAndLogEx(SUCCESS, _YELLOW_("HITAG/PWM") " - decoded bitstream");
PrintAndLogEx(INFO, "--------------------------------------");
printDemodBuff(0, false, false, false);

free(bits);
return PM3_SUCCESS;
}

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

static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
{"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag2 tag information"},
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
{"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag2 tag information"},
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag"},
{"pwmdemod", CmdLFHitag2PWMDemod, AlwaysAvailable, "PWM Hitag2 reader message demodulation"},
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"},
{ NULL, NULL, 0, NULL }
};

Expand Down
33 changes: 27 additions & 6 deletions client/src/proxguiqt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ void Plot::setMaxAndStart(int *buffer, size_t len, QRect plotRect) {
gs_absVMax = (int)(gs_absVMax * 1.25 + 1);
}

void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum, uint32_t plotOffset) {
void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter,
int graphNum, uint32_t plotOffset, uint8_t *bitRange) {
if (len == 0 || g_PlotGridX <= 0) return;
//clock_t begin = clock();
QPainterPath penPath;
Expand All @@ -535,8 +536,19 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati
int absVMax = (int)(100 * 1.05 + 1);
delta_x = 0;
int clk = first_delta_x;
if (bitRange) {
int shift = grid_delta_x-first_delta_x; // can be negative
if (shift <= bitRange[BitStart])
clk = bitRange[BitStart] - shift;
else {
clk = bitRange[BitStart+1] - (shift - bitRange[BitStart]);
BitStart++;
}
}
//printf("old %d new %d BitStart %d\n", first_delta_x, clk, BitStart);

for (int i = BitStart; i < (int)len && xCoordOf(delta_x + DemodStart, plotRect) < plotRect.right(); i++) {
for (int j = 0; j < (clk) && i < (int)len && xCoordOf(DemodStart + delta_x + j, plotRect) < plotRect.right() ; j++) {
for (int j = 0; j < (clk) && i <= (int)len && xCoordOf(DemodStart + delta_x + j, plotRect) < plotRect.right() ; j++) {
int x = xCoordOf(DemodStart + delta_x + j, plotRect);
int v = buffer[i] * 200 - 100;

Expand All @@ -556,8 +568,14 @@ void Plot::PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotati
painter->drawText(x - 8, y + ((buffer[i] > 0) ? 18 : -6), str);
}
}
delta_x += clk;
clk = grid_delta_x;

if (bitRange) {
delta_x += (clk);
clk = bitRange[i+1];
} else {
delta_x += clk;
clk = grid_delta_x;
}
}

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

//Start painting graph
PlotGraph(g_GraphBuffer, g_GraphTraceLen, plotRect, infoRect, &painter, 0);
if (g_DemodBufferLen > 8) {
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx);
if (g_DemodBufferLen >= 5) {
if (g_DemodBitRangeBuffer[0])
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx, g_DemodBitRangeBuffer);
else
PlotDemod(g_DemodBuffer, g_DemodBufferLen, plotRect, infoRect, &painter, 2, g_DemodStartIdx, NULL);
}
if (gs_useOverlays) {
//init graph variables
Expand Down
3 changes: 2 additions & 1 deletion client/src/proxguiqt.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class Plot: public QWidget {
uint32_t CursorAPos;
uint32_t CursorBPos;
void PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum);
void PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter, int graphNum, uint32_t plotOffset);
void PlotDemod(uint8_t *buffer, size_t len, QRect plotRect, QRect annotationRect, QPainter *painter,
int graphNum, uint32_t plotOffset, uint8_t* bitRange);
void plotGridLines(QPainter *painter, QRect r);
int xCoordOf(int i, QRect r);
int yCoordOf(int v, QRect r, int maxVal);
Expand Down
88 changes: 88 additions & 0 deletions common/lfdemod.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,17 @@ static size_t findModStart(uint8_t *src, size_t size, uint8_t expWaveSize) {
return i;
}

static size_t findModStart2(uint8_t *src, size_t size, uint8_t expWaveSize) {
uint32_t i = 0;
uint8_t threshold = signalprop.amplitude / 10; // 10 %
for (; i < size - 20; i++) {
if (abs(src[i] - signalprop.mean) > threshold) {
break;
}
}
return i;
}

static int getClosestClock(int testclk) {
uint16_t clocks[] = {8, 16, 32, 40, 50, 64, 100, 128, 256, 384};
uint8_t limit[] = {1, 2, 4, 4, 5, 8, 8, 8, 8, 8};
Expand Down Expand Up @@ -1836,6 +1847,83 @@ int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int *startId
return 0;
}

size_t HitagPWMDemod(uint8_t *dest, size_t size, uint8_t *fchigh, uint8_t *fclow, uint32_t *startIdx, uint8_t *bitRange) {
printSignal();

if (g_debugMode == 2)
prnt("HitagWMDemod startIdx:%d low period:%d high period:%d", *startIdx, *fclow, *fchigh);

size_t idx = 0, numBits = 0;

//find start of modulating data in trace
if (*startIdx == 0) {
idx = findModStart2(dest, size, *fchigh);
*startIdx = idx;
if (g_debugMode == 2)
prnt("detected start %d", idx);
}

uint8_t wave_min = 255;
uint8_t wave_max = 0;
uint8_t sub_idx = 0;
uint32_t idx_min = 0;
uint32_t idx_max = 0;
uint32_t last_wave_start = idx;
uint8_t meanCrossCount = 0;
for (; idx < size - 20; idx++, sub_idx++) {

if (dest[idx] < wave_min) {
wave_min = dest[idx];
idx_min = idx;
}
if (dest[idx] > wave_max) {
wave_max = dest[idx];
idx_max = idx;
}

uint32_t period = idx - last_wave_start;
if (period > (*fchigh)*1.5) {
if (g_debugMode == 2)
prnt("period %d is too big", period);
break;
}

if ((dest[idx] >= signalprop.mean && dest[idx+1] < signalprop.mean) ||
(dest[idx] <= signalprop.mean && dest[idx+1] > signalprop.mean)) {
meanCrossCount++;
if (meanCrossCount > 2) return 0;
}
// wait to pass the beginning of the wave (> *fclow/2) and detect the next cross
// of the mean line.
if ((sub_idx > (*fclow)/2) && meanCrossCount == 2) {
if ((wave_max - wave_min) < signalprop.amplitude/2) {
if (g_debugMode == 2)
prnt("wave not strong enough, probably end of signal");
break;
}

if (g_debugMode == 2)
prnt("wave %d ends at %d [min:%d,%d,max:%d,%d], [%d -> %d] period=%d",
numBits+1, idx, idx_min, wave_min, idx_max, wave_max, last_wave_start, idx-1, period);
last_wave_start = idx;

sub_idx = 0;
idx_min = idx_max = 0;
wave_max = 0;
wave_min = 255;
meanCrossCount = 0;

// TODO : don't just compare high and low but verifty the period match to a certain %
bitRange[numBits] = period;
if (abs(period-*fchigh) > abs(period-*fclow))
dest[numBits++] = 0;
else
dest[numBits++] = 1;
}
}
return numBits;
}

//translate wave to 11111100000 (1 for each short wave [higher freq] 0 for each long wave [lower freq])
static size_t fsk_wave_demod(uint8_t *dest, size_t size, uint8_t fchigh, uint8_t fclow, int *startIdx) {

Expand Down
1 change: 1 addition & 0 deletions common/lfdemod.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ int pskRawDemod_ext(uint8_t *dest, size_t *size, int *clock, int *invert, i
void psk2TOpsk1(uint8_t *bits, size_t size);
void psk1TOpsk2(uint8_t *bits, size_t size);
size_t removeParity(uint8_t *bits, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen);
size_t HitagPWMDemod(uint8_t *dest, size_t size, uint8_t *fchigh, uint8_t *fclow, uint32_t *startIdx, uint8_t *bitRange);

//tag specific
int detectAWID(uint8_t *dest, size_t *size, int *waveStartIdx);
Expand Down

0 comments on commit ed0a29b

Please sign in to comment.