Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New 'lf hitag pwmdemod' cmd decoding the reader messages from graph b… #1515

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work as a int32_t? As it currently stands, builds are failing under the Darwin compiler due to period being unsigned.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if "period" and "last_wave_start" are made size_t (to match idx) rather then uint32_t ?
i.e. is size_t the same size as uint32_t ? (on some systems I believe size_t is 8 bytes, which would make it 64 bits, twice the size of a unit32_t.

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