diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 1188b5308a..c0f2de0e5e 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -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; @@ -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; @@ -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; diff --git a/client/src/cmddata.h b/client/src/cmddata.h index ed8f076c79..18e34fbb2c 100644 --- a/client/src/cmddata.h +++ b/client/src/cmddata.h @@ -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); @@ -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; diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 02d84321a4..4c42731b71 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -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) { @@ -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", "", "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; idrawText(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 @@ -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 diff --git a/client/src/proxguiqt.h b/client/src/proxguiqt.h index 582727cabb..059cf2b6eb 100644 --- a/client/src/proxguiqt.h +++ b/client/src/proxguiqt.h @@ -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); diff --git a/common/lfdemod.c b/common/lfdemod.c index 16dc8a56b0..5fdefc01ff 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -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}; @@ -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) { diff --git a/common/lfdemod.h b/common/lfdemod.h index e8d516604c..486f434062 100644 --- a/common/lfdemod.h +++ b/common/lfdemod.h @@ -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);