From 0e2ddb4196819e0fe4c287279359480843201c4b Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Wed, 12 Jul 2017 01:31:42 -0400 Subject: [PATCH] add data fsktonrz fsk cleaning util (#352) add fsk cleaning / demod tool fsktonrz - used old fskdemod for HID and adjusted it to build the tone tables for any fsk model detected or given. using the tone tables we are able to convert the fsk to clear strong NRZ/ASK even with very weak fsk waves. - also fixed a small textual bug in `lf search u` output - also added more graph clearing code to help ensure the demod overlay doesn't show when it shouldn't... - and improved strong NRZ clock detection. - fixed bugs in places it used old static values instead of dynamic read values. and removed redundant items. --- CHANGELOG.md | 1 + client/cmddata.c | 205 ++++++++++++++++++++++++++++++++++++++++++- client/cmdlf.c | 2 +- client/cmdlfindala.c | 6 +- common/lfdemod.c | 16 +++- 5 files changed, 223 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 045d9b2d..80c823d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed ### Added +- Added data fsktonrz, a fsk cleaning/demodulating routine for weak fsk signal. Note: follow this up with a `data rawdemod nr` to finish demoding your signal. - Added lf em 410xbrute, LF EM410x reader bruteforce attack by simulating UIDs from a file (Fl0-0) ## [3.0.1][2017-06-08] diff --git a/client/cmddata.c b/client/cmddata.c index c12c2ce6..1f548284 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -1234,6 +1234,7 @@ int getSamples(int n, bool silent) } setClockGrid(0,0); + DemodBufferLen = 0; RepaintGraphWindow(); return 0; } @@ -1338,6 +1339,7 @@ int CmdLoad(const char *Cmd) fclose(f); PrintAndLog("loaded %d samples", GraphTraceLen); setClockGrid(0,0); + DemodBufferLen = 0; RepaintGraphWindow(); return 0; } @@ -1395,8 +1397,7 @@ int CmdNorm(const char *Cmd) if (max != min) { for (i = 0; i < GraphTraceLen; ++i) { - GraphBuffer[i] = (GraphBuffer[i] - ((max + min) / 2)) * 256 / - (max - min); + GraphBuffer[i] = ((long)(GraphBuffer[i] - ((max + min) / 2)) * 256) / (max - min); //marshmelow: adjusted *1000 to *256 to make +/- 128 so demod commands still work } } @@ -1606,6 +1607,205 @@ int Cmdhex2bin(const char *Cmd) return 0; } + /* // example of FSK2 RF/50 Tones + static const int LowTone[] = { + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 + }; + static const int HighTone[] = { + 1, 1, 1, 1, 1, -1, -1, -1, -1, // note one extra 1 to padd due to 50/8 remainder (1/2 the remainder) + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, -1, // note one extra -1 to padd due to 50/8 remainder + }; + */ +void GetHiLoTone(int *LowTone, int *HighTone, int clk, int LowToneFC, int HighToneFC) { + int i,j=0; + int Left_Modifier = ((clk % LowToneFC) % 2) + ((clk % LowToneFC)/2); + int Right_Modifier = (clk % LowToneFC) / 2; + //int HighToneMod = clk mod HighToneFC; + int LeftHalfFCCnt = (LowToneFC % 2) + (LowToneFC/2); //truncate + int FCs_per_clk = clk/LowToneFC; + + // need to correctly split up the clock to field clocks. + // First attempt uses modifiers on each end to make up for when FCs don't evenly divide into Clk + + // start with LowTone + // set extra 1 modifiers to make up for when FC doesn't divide evenly into Clk + for (i = 0; i < Left_Modifier; i++) { + LowTone[i] = 1; + } + + // loop # of field clocks inside the main clock + for (i = 0; i < (FCs_per_clk); i++) { + // loop # of samples per field clock + for (j = 0; j < LowToneFC; j++) { + LowTone[(i*LowToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1; + } + } + + int k; + // add last -1 modifiers + for (k = 0; k < Right_Modifier; k++) { + LowTone[((i-1)*LowToneFC)+Left_Modifier+j+k] = -1; + } + + // now do hightone + Left_Modifier = ((clk % HighToneFC) % 2) + ((clk % HighToneFC)/2); + Right_Modifier = (clk % HighToneFC) / 2; + LeftHalfFCCnt = (HighToneFC % 2) + (HighToneFC/2); //truncate + FCs_per_clk = clk/HighToneFC; + + for (i = 0; i < Left_Modifier; i++) { + HighTone[i] = 1; + } + + // loop # of field clocks inside the main clock + for (i = 0; i < (FCs_per_clk); i++) { + // loop # of samples per field clock + for (j = 0; j < HighToneFC; j++) { + HighTone[(i*HighToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1; + } + } + + // add last -1 modifiers + for (k = 0; k < Right_Modifier; k++) { + PrintAndLog("(i-1)*HighToneFC+lm+j+k %i",((i-1)*HighToneFC)+Left_Modifier+j+k); + HighTone[((i-1)*HighToneFC)+Left_Modifier+j+k] = -1; + } + if (g_debugMode == 2) { + for ( i = 0; i < clk; i++) { + PrintAndLog("Low: %i, High: %i",LowTone[i],HighTone[i]); + } + } +} + +//old CmdFSKdemod adapted by marshmellow +//converts FSK to clear NRZ style wave. (or demodulates) +int FSKToNRZ(int *data, int *dataLen, int clk, int LowToneFC, int HighToneFC) { + uint8_t ans=0; + if (clk == 0 || LowToneFC == 0 || HighToneFC == 0) { + int firstClockEdge=0; + ans = fskClocks((uint8_t *) &LowToneFC, (uint8_t *) &HighToneFC, (uint8_t *) &clk, false, &firstClockEdge); + if (g_debugMode > 1) { + PrintAndLog ("DEBUG FSKtoNRZ: detected clocks: fc_low %i, fc_high %i, clk %i, firstClockEdge %i, ans %u", LowToneFC, HighToneFC, clk, firstClockEdge, ans); + } + } + // currently only know fsk modulations with field clocks < 10 samples and > 4 samples. filter out to remove false positives (and possibly destroying ask/psk modulated waves...) + if (ans == 0 || clk == 0 || LowToneFC == 0 || HighToneFC == 0 || LowToneFC > 10 || HighToneFC < 4) { + if (g_debugMode > 1) { + PrintAndLog ("DEBUG FSKtoNRZ: no fsk clocks found"); + } + return 0; + } + int LowTone[clk]; + int HighTone[clk]; + GetHiLoTone(LowTone, HighTone, clk, LowToneFC, HighToneFC); + + int i, j; + + // loop through ([all samples] - clk) + for (i = 0; i < *dataLen - clk; ++i) { + int lowSum = 0, highSum = 0; + + // sum all samples together starting from this sample for [clk] samples for each tone (multiply tone value with sample data) + for (j = 0; j < clk; ++j) { + lowSum += LowTone[j] * data[i+j]; + highSum += HighTone[j] * data[i + j]; + } + // get abs( [average sample value per clk] * 100 ) (or a rolling average of sorts) + lowSum = abs(100 * lowSum / clk); + highSum = abs(100 * highSum / clk); + // save these back to buffer for later use + data[i] = (highSum << 16) | lowSum; + } + + // now we have the abs( [average sample value per clk] * 100 ) for each tone + // loop through again [all samples] - clk - 16 + // note why 16??? is 16 the largest FC? changed to LowToneFC as that should be the > fc + for(i = 0; i < *dataLen - clk - LowToneFC; ++i) { + int lowTot = 0, highTot = 0; + + // sum a field clock width of abs( [average sample values per clk] * 100) for each tone + for (j = 0; j < LowToneFC; ++j) { //10 for fsk2 + lowTot += (data[i + j] & 0xffff); + } + for (j = 0; j < HighToneFC; j++) { //8 for fsk2 + highTot += (data[i + j] >> 16); + } + + // subtract the sum of lowTone averages by the sum of highTone averages as it + // and write back the new graph value + data[i] = lowTot - highTot; + } + // update dataLen to what we put back to the data sample buffer + *dataLen -= (clk + LowToneFC); + return 0; +} + +int usage_data_fsktonrz() { + PrintAndLog("Usage: data fsktonrz c l f "); + PrintAndLog("Options: "); + PrintAndLog(" h This help"); + PrintAndLog(" c enter the a clock (omit to autodetect)"); + PrintAndLog(" l enter a field clock (omit to autodetect)"); + PrintAndLog(" f enter a field clock (omit to autodetect)"); + return 0; +} + +int CmdFSKToNRZ(const char *Cmd) { + // take clk, fc_low, fc_high + // blank = auto; + bool errors = false; + int clk = 0; + char cmdp = 0; + int fc_low = 10, fc_high = 8; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_data_fsktonrz(); + case 'C': + case 'c': + clk = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'F': + case 'f': + fc_high = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + case 'L': + case 'l': + fc_low = param_get32ex(Cmd, cmdp+1, 0, 10); + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_data_fsktonrz(); + + setClockGrid(0,0); + DemodBufferLen = 0; + int ans = FSKToNRZ(GraphBuffer, &GraphTraceLen, clk, fc_low, fc_high); + CmdNorm(""); + RepaintGraphWindow(); + return ans; +} + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -1617,6 +1817,7 @@ static command_t CommandTable[] = {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"}, + {"fsktonrz", CmdFSKToNRZ, 1, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"}, {"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, diff --git a/client/cmdlf.c b/client/cmdlf.c index 49c9ea39..79bcee0b 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1081,7 +1081,7 @@ int CmdLFfind(const char *Cmd) if (ans>0) { PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'"); PrintAndLog("\nCould also be PSK3 - [currently not supported]"); - PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod'"); + PrintAndLog("\nCould also be NRZ - try 'data rawdemod nr'"); return CheckChipType(cmdp); } ans = CheckChipType(cmdp); diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index de1757e9..8ec04cbb 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -96,8 +96,12 @@ int CmdIndalaDemod(const char *Cmd) { uint8_t rawbits[4096]; int rawbit = 0; int worst = 0, worstPos = 0; - // PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32); + + //clear clock grid and demod plot + setClockGrid(0, 0); + DemodBufferLen = 0; + // PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32); // loop through raw signal - since we know it is psk1 rf/32 fc/2 skip every other value (+=2) for (i = 0; i < GraphTraceLen-1; i += 2) { count += 1; diff --git a/common/lfdemod.c b/common/lfdemod.c index d2e0fca4..880e2c2b 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -505,13 +505,14 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) { return bestStart[best]; } -int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){ +int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low, bool *strong) { //find shortest transition from high to low + *strong = false; size_t i = 0; size_t transition1 = 0; int lowestTransition = 255; bool lastWasHigh = false; - + size_t transitionSampleCount = 0; //find first valid beginning of a high or low wave while ((dest[i] >= peak || dest[i] <= low) && (i < size)) ++i; @@ -527,10 +528,17 @@ int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){ lastWasHigh = (dest[i] >= peak); if (i-transition1 < lowestTransition) lowestTransition = i-transition1; transition1 = i; + } else if (dest[i] < peak && dest[i] > low) { + transitionSampleCount++; } } if (lowestTransition == 255) lowestTransition = 0; if (g_debugMode==2) prnt("DEBUG NRZ: detectstrongNRZclk smallest wave: %d",lowestTransition); + // if less than 10% of the samples were not peaks (or 90% were peaks) then we have a strong wave + if (transitionSampleCount / size < 10) { + *strong = true; + lowestTransition = getClosestClock(lowestTransition); + } return lowestTransition; } @@ -550,7 +558,9 @@ int DetectNRZClock(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx int peak, low; if (getHiLo(dest, loopCnt, &peak, &low, 90, 90) < 1) return 0; - int lowestTransition = DetectStrongNRZClk(dest, size-20, peak, low); + bool strong = false; + int lowestTransition = DetectStrongNRZClk(dest, size-20, peak, low, &strong); + if (strong) return lowestTransition; size_t ii; uint8_t clkCnt; uint8_t tol = 0; -- 2.39.5