Merge branch 'master' of github.com:Proxmark/proxmark3

This commit is contained in:
Martin Holst Swende 2015-04-23 09:51:04 +02:00
commit a3abb02897
30 changed files with 1848 additions and 2065 deletions

View file

@ -4,11 +4,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [Unreleased][unreleased] ## [Unreleased][unreleased]
### Changed ### Changed
- Improved LF manchester and biphase demodulation and ask clock detection especially for reads with heavy clipping. (marshmellow)
- Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman) - Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman)
- *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi) - *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi)
### Fixed ### Fixed
- Fixed issue #19, problems with LF T55xx commands (marshmellow) - Fixed EM4x50 read/demod of the tags broadcasted memory blocks. 'lf em4x em4x50read' (not page read) (marshmellow)
- Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow)
### Added ### Added
- Added changelog - Added changelog

View file

@ -861,7 +861,7 @@ void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol)
size = BigBuf_max_traceLen(); size = BigBuf_max_traceLen();
//askdemod and manchester decode //askdemod and manchester decode
if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format
errCnt = askmandemod(dest, &size, &clk, &invert, maxErr); errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1);
WDT_HIT(); WDT_HIT();
if (errCnt<0) continue; if (errCnt<0) continue;

File diff suppressed because it is too large Load diff

View file

@ -15,10 +15,7 @@ command_t * CmdDataCommands();
int CmdData(const char *Cmd); int CmdData(const char *Cmd);
void printDemodBuff(void); void printDemodBuff(void);
void printBitStream(uint8_t BitStream[], uint32_t bitLen);
void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx); void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx);
int CmdAmp(const char *Cmd);
int Cmdaskdemod(const char *Cmd);
int CmdAskEM410xDemod(const char *Cmd); int CmdAskEM410xDemod(const char *Cmd);
int CmdG_Prox_II_Demod(const char *Cmd); int CmdG_Prox_II_Demod(const char *Cmd);
int Cmdaskrawdemod(const char *Cmd); int Cmdaskrawdemod(const char *Cmd);
@ -27,12 +24,10 @@ int AutoCorrelate(int window, bool SaveGrph, bool verbose);
int CmdAutoCorr(const char *Cmd); int CmdAutoCorr(const char *Cmd);
int CmdBiphaseDecodeRaw(const char *Cmd); int CmdBiphaseDecodeRaw(const char *Cmd);
int CmdBitsamples(const char *Cmd); int CmdBitsamples(const char *Cmd);
int CmdBitstream(const char *Cmd);
int CmdBuffClear(const char *Cmd); int CmdBuffClear(const char *Cmd);
int CmdDec(const char *Cmd); int CmdDec(const char *Cmd);
int CmdDetectClockRate(const char *Cmd); int CmdDetectClockRate(const char *Cmd);
int CmdFSKdemodAWID(const char *Cmd); int CmdFSKdemodAWID(const char *Cmd);
int CmdFSKdemod(const char *Cmd);
int CmdFSKdemodHID(const char *Cmd); int CmdFSKdemodHID(const char *Cmd);
int CmdFSKdemodIO(const char *Cmd); int CmdFSKdemodIO(const char *Cmd);
int CmdFSKdemodParadox(const char *Cmd); int CmdFSKdemodParadox(const char *Cmd);
@ -40,6 +35,7 @@ int CmdFSKdemodPyramid(const char *Cmd);
int CmdFSKrawdemod(const char *Cmd); int CmdFSKrawdemod(const char *Cmd);
int CmdPSK1rawDemod(const char *Cmd); int CmdPSK1rawDemod(const char *Cmd);
int CmdPSK2rawDemod(const char *Cmd); int CmdPSK2rawDemod(const char *Cmd);
int CmdPSKNexWatch(const char *Cmd);
int CmdGrid(const char *Cmd); int CmdGrid(const char *Cmd);
int CmdGetBitStream(const char *Cmd); int CmdGetBitStream(const char *Cmd);
int CmdHexsamples(const char *Cmd); int CmdHexsamples(const char *Cmd);
@ -49,24 +45,22 @@ int CmdLoad(const char *Cmd);
int CmdLtrim(const char *Cmd); int CmdLtrim(const char *Cmd);
int CmdRtrim(const char *Cmd); int CmdRtrim(const char *Cmd);
int Cmdmandecoderaw(const char *Cmd); int Cmdmandecoderaw(const char *Cmd);
int CmdManchesterDemod(const char *Cmd);
int CmdManchesterMod(const char *Cmd);
int CmdNorm(const char *Cmd); int CmdNorm(const char *Cmd);
int CmdNRZrawDemod(const char *Cmd); int CmdNRZrawDemod(const char *Cmd);
int CmdPlot(const char *Cmd); int CmdPlot(const char *Cmd);
int CmdPrintDemodBuff(const char *Cmd);
int CmdRawDemod(const char *Cmd); int CmdRawDemod(const char *Cmd);
int CmdSamples(const char *Cmd); int CmdSamples(const char *Cmd);
int CmdTuneSamples(const char *Cmd); int CmdTuneSamples(const char *Cmd);
int CmdSave(const char *Cmd); int CmdSave(const char *Cmd);
int CmdScale(const char *Cmd); int CmdScale(const char *Cmd);
int CmdThreshold(const char *Cmd);
int CmdDirectionalThreshold(const char *Cmd); int CmdDirectionalThreshold(const char *Cmd);
int CmdZerocrossings(const char *Cmd); int CmdZerocrossings(const char *Cmd);
int CmdIndalaDecode(const char *Cmd); int CmdIndalaDecode(const char *Cmd);
int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo );
int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose);
int ASKbiphaseDemod(const char *Cmd, bool verbose); int ASKbiphaseDemod(const char *Cmd, bool verbose);
int ASKmanDemod(const char *Cmd, bool verbose, bool emSearch); int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType);
int ASKrawDemod(const char *Cmd, bool verbose);
int FSKrawDemod(const char *Cmd, bool verbose); int FSKrawDemod(const char *Cmd, bool verbose);
int PSKDemod(const char *Cmd, bool verbose); int PSKDemod(const char *Cmd, bool verbose);
int NRZrawDemod(const char *Cmd, bool verbose); int NRZrawDemod(const char *Cmd, bool verbose);
@ -77,7 +71,7 @@ int getSamples(const char *Cmd, bool silent);
#define MAX_DEMOD_BUF_LEN (1024*128) #define MAX_DEMOD_BUF_LEN (1024*128)
extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
extern int DemodBufferLen; extern int DemodBufferLen;
extern uint8_t g_debugMode;
#define BIGBUF_SIZE 40000 #define BIGBUF_SIZE 40000
#endif #endif

View file

@ -1499,16 +1499,16 @@ int CmdHF14AMfCSetUID(const char *Cmd)
int CmdHF14AMfCSetBlk(const char *Cmd) int CmdHF14AMfCSetBlk(const char *Cmd)
{ {
uint8_t uid[8] = {0x00};
uint8_t memBlock[16] = {0x00}; uint8_t memBlock[16] = {0x00};
uint8_t blockNo = 0; uint8_t blockNo = 0;
bool wipeCard = FALSE;
int res; int res;
if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {
PrintAndLog("Usage: hf mf csetblk <block number> <block data (32 hex symbols)>"); PrintAndLog("Usage: hf mf csetblk <block number> <block data (32 hex symbols)> [w]");
PrintAndLog("sample: hf mf csetblk 1 01020304050607080910111213141516"); PrintAndLog("sample: hf mf csetblk 1 01020304050607080910111213141516");
PrintAndLog("Set block data for magic Chinese card (only works with!!!)"); PrintAndLog("Set block data for magic Chinese card (only works with such cards)");
PrintAndLog("If you want wipe card then add 'w' into command line. \n"); PrintAndLog("If you also want wipe the card then add 'w' at the end of the command line");
return 0; return 0;
} }
@ -1519,14 +1519,15 @@ int CmdHF14AMfCSetBlk(const char *Cmd)
return 1; return 1;
} }
char ctmp = param_getchar(Cmd, 2);
wipeCard = (ctmp == 'w' || ctmp == 'W');
PrintAndLog("--block number:%2d data:%s", blockNo, sprint_hex(memBlock, 16)); PrintAndLog("--block number:%2d data:%s", blockNo, sprint_hex(memBlock, 16));
res = mfCSetBlock(blockNo, memBlock, uid, 0, CSETBLOCK_SINGLE_OPER); res = mfCSetBlock(blockNo, memBlock, NULL, wipeCard, CSETBLOCK_SINGLE_OPER);
if (res) { if (res) {
PrintAndLog("Can't write block. error=%d", res); PrintAndLog("Can't write block. error=%d", res);
return 1; return 1;
} }
return 0; return 0;
} }
@ -1637,7 +1638,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) {
if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {
PrintAndLog("Usage: hf mf cgetblk <block number>"); PrintAndLog("Usage: hf mf cgetblk <block number>");
PrintAndLog("sample: hf mf cgetblk 1"); PrintAndLog("sample: hf mf cgetblk 1");
PrintAndLog("Get block data from magic Chinese card (only works with!!!)\n"); PrintAndLog("Get block data from magic Chinese card (only works with such cards)\n");
return 0; return 0;
} }
@ -1664,7 +1665,7 @@ int CmdHF14AMfCGetSc(const char *Cmd) {
if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {
PrintAndLog("Usage: hf mf cgetsc <sector number>"); PrintAndLog("Usage: hf mf cgetsc <sector number>");
PrintAndLog("sample: hf mf cgetsc 0"); PrintAndLog("sample: hf mf cgetsc 0");
PrintAndLog("Get sector data from magic Chinese card (only works with!!!)\n"); PrintAndLog("Get sector data from magic Chinese card (only works with such cards)\n");
return 0; return 0;
} }

View file

@ -522,7 +522,8 @@ static void ChkBitstream(const char *str)
} }
} }
} }
//appears to attempt to simulate manchester //Attempt to simulate any wave in buffer (one bit per output sample)
// converts GraphBuffer to bitstream (based on zero crossings) if needed.
int CmdLFSim(const char *Cmd) int CmdLFSim(const char *Cmd)
{ {
int i,j; int i,j;
@ -530,11 +531,11 @@ int CmdLFSim(const char *Cmd)
sscanf(Cmd, "%i", &gap); sscanf(Cmd, "%i", &gap);
/* convert to bitstream if necessary */ // convert to bitstream if necessary
ChkBitstream(Cmd); ChkBitstream(Cmd);
//can send 512 bits at a time (1 byte sent per bit...) //can send only 512 bits at a time (1 byte sent per bit...)
printf("Sending [%d bytes]", GraphTraceLen); printf("Sending [%d bytes]", GraphTraceLen);
for (i = 0; i < GraphTraceLen; i += USB_CMD_DATA_SIZE) { for (i = 0; i < GraphTraceLen; i += USB_CMD_DATA_SIZE) {
UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}}; UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
@ -606,8 +607,8 @@ int usage_lf_simpsk(void)
// - allow pull data from DemodBuffer // - allow pull data from DemodBuffer
int CmdLFfskSim(const char *Cmd) int CmdLFfskSim(const char *Cmd)
{ {
//might be able to autodetect FC and clock from Graphbuffer if using demod buffer //might be able to autodetect FCs and clock from Graphbuffer if using demod buffer
//will need FChigh, FClow, Clock, and bitstream // otherwise will need FChigh, FClow, Clock, and bitstream
uint8_t fcHigh=0, fcLow=0, clk=0; uint8_t fcHigh=0, fcLow=0, clk=0;
uint8_t invert=0; uint8_t invert=0;
bool errors = FALSE; bool errors = FALSE;
@ -682,6 +683,8 @@ int CmdLFfskSim(const char *Cmd)
} else { } else {
setDemodBuf(data, dataLen, 0); setDemodBuf(data, dataLen, 0);
} }
//default if not found
if (clk == 0) clk = 50; if (clk == 0) clk = 50;
if (fcHigh == 0) fcHigh = 10; if (fcHigh == 0) fcHigh = 10;
if (fcLow == 0) fcLow = 8; if (fcLow == 0) fcLow = 8;
@ -706,9 +709,8 @@ int CmdLFfskSim(const char *Cmd)
int CmdLFaskSim(const char *Cmd) int CmdLFaskSim(const char *Cmd)
{ {
//autodetect clock from Graphbuffer if using demod buffer //autodetect clock from Graphbuffer if using demod buffer
//will need clock, invert, manchester/raw as m or r, separator as s, and bitstream // needs clock, invert, manchester/raw as m or r, separator as s, and bitstream
uint8_t encoding = 1, separator = 0; uint8_t encoding = 1, separator = 0;
//char cmdp = Cmd[0], par3='m', par4=0;
uint8_t clk=0, invert=0; uint8_t clk=0, invert=0;
bool errors = FALSE; bool errors = FALSE;
char hexData[32] = {0x00}; char hexData[32] = {0x00};
@ -913,30 +915,6 @@ int CmdLFSimBidir(const char *Cmd)
return 0; return 0;
} }
/* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */
/*
int CmdLFSimManchester(const char *Cmd)
{
static int clock, gap;
static char data[1024], gapstring[8];
sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap);
ClearGraph(0);
for (int i = 0; i < strlen(data) ; ++i)
AppendGraph(0, clock, data[i]- '0');
CmdManchesterMod("");
RepaintGraphWindow();
sprintf(&gapstring[0], "%i", gap);
CmdLFSim(gapstring);
return 0;
}
*/
int CmdVchDemod(const char *Cmd) int CmdVchDemod(const char *Cmd)
{ {
// Is this the entire sync pattern, or does this also include some // Is this the entire sync pattern, or does this also include some
@ -1033,8 +1011,8 @@ int CmdLFfind(const char *Cmd)
} }
if (!offline && (cmdp != '1')){ if (!offline && (cmdp != '1')){
ans=CmdLFRead(""); CmdLFRead("s");
ans=CmdSamples("20000"); getSamples("30000",false);
} else if (GraphTraceLen < 1000) { } else if (GraphTraceLen < 1000) {
PrintAndLog("Data in Graphbuffer was too small."); PrintAndLog("Data in Graphbuffer was too small.");
return 0; return 0;
@ -1094,26 +1072,36 @@ int CmdLFfind(const char *Cmd)
return 1; return 1;
} }
ans=EM4x50Read("", false);
if (ans>0) {
PrintAndLog("\nValid EM4x50 ID Found!");
return 1;
}
ans=CmdPSKNexWatch("");
if (ans>0) {
PrintAndLog("\nValid NexWatch ID Found!");
return 1;
}
PrintAndLog("\nNo Known Tags Found!\n"); PrintAndLog("\nNo Known Tags Found!\n");
if (testRaw=='u' || testRaw=='U'){ if (testRaw=='u' || testRaw=='U'){
//test unknown tag formats (raw mode) //test unknown tag formats (raw mode)
PrintAndLog("\nChecking for Unknown tags:\n"); PrintAndLog("\nChecking for Unknown tags:\n");
ans=AutoCorrelate(4000, FALSE, FALSE); ans=AutoCorrelate(4000, FALSE, FALSE);
if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans); if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
ans=GetFskClock("",FALSE,FALSE); //CmdDetectClockRate("F"); // ans=GetFskClock("",FALSE,FALSE);
if (ans != 0){ //fsk if (ans != 0){ //fsk
ans=FSKrawDemod("",FALSE); ans=FSKrawDemod("",TRUE);
if (ans>0) { if (ans>0) {
PrintAndLog("\nUnknown FSK Modulated Tag Found!"); PrintAndLog("\nUnknown FSK Modulated Tag Found!");
printDemodBuff();
return 1; return 1;
} }
} }
ans=ASKmanDemod("",FALSE,FALSE); ans=ASKDemod("0 0 0",TRUE,FALSE,1);
if (ans>0) { if (ans>0) {
PrintAndLog("\nUnknown ASK Modulated and Manchester encoded Tag Found!"); PrintAndLog("\nUnknown ASK Modulated and Manchester encoded Tag Found!");
PrintAndLog("\nif it does not look right it could instead be ASK/Biphase - try 'data rawdemod ab'"); PrintAndLog("\nif it does not look right it could instead be ASK/Biphase - try 'data rawdemod ab'");
printDemodBuff();
return 1; return 1;
} }
ans=CmdPSK1rawDemod(""); ans=CmdPSK1rawDemod("");
@ -1121,7 +1109,6 @@ int CmdLFfind(const char *Cmd)
PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'"); 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 PSK3 - [currently not supported]");
PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod"); PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod");
printDemodBuff();
return 1; return 1;
} }
PrintAndLog("\nNo Data Found!\n"); PrintAndLog("\nNo Data Found!\n");
@ -1147,7 +1134,6 @@ static command_t CommandTable[] =
{"simfsk", CmdLFfskSim, 0, "[c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>] -- Simulate LF FSK tag from demodbuffer or input"}, {"simfsk", CmdLFfskSim, 0, "[c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>] -- Simulate LF FSK tag from demodbuffer or input"},
{"simpsk", CmdLFpskSim, 0, "[1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>] -- Simulate LF PSK tag from demodbuffer or input"}, {"simpsk", CmdLFpskSim, 0, "[1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>] -- Simulate LF PSK tag from demodbuffer or input"},
{"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
//{"simman", CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
{"snoop", CmdLFSnoop, 0, "['l'|'h'|<divisor>] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|<divisor>] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"},
{"ti", CmdLFTI, 1, "{ TI RFIDs... }"}, {"ti", CmdLFTI, 1, "{ TI RFIDs... }"},
{"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},

View file

@ -23,7 +23,6 @@ int CmdLFaskSim(const char *Cmd);
int CmdLFfskSim(const char *Cmd); int CmdLFfskSim(const char *Cmd);
int CmdLFpskSim(const char *Cmd); int CmdLFpskSim(const char *Cmd);
int CmdLFSimBidir(const char *Cmd); int CmdLFSimBidir(const char *Cmd);
//int CmdLFSimManchester(const char *Cmd);
int CmdLFSnoop(const char *Cmd); int CmdLFSnoop(const char *Cmd);
int CmdVchDemod(const char *Cmd); int CmdVchDemod(const char *Cmd);
int CmdLFfind(const char *Cmd); int CmdLFfind(const char *Cmd);

View file

@ -19,6 +19,7 @@
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "cmdlfem4x.h" #include "cmdlfem4x.h"
#include "lfdemod.h"
char *global_em410xId; char *global_em410xId;
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -26,11 +27,11 @@ static int CmdHelp(const char *Cmd);
int CmdEMdemodASK(const char *Cmd) int CmdEMdemodASK(const char *Cmd)
{ {
char cmdp = param_getchar(Cmd, 0); char cmdp = param_getchar(Cmd, 0);
int findone = (cmdp == '1') ? 1 : 0; int findone = (cmdp == '1') ? 1 : 0;
UsbCommand c={CMD_EM410X_DEMOD}; UsbCommand c={CMD_EM410X_DEMOD};
c.arg[0]=findone; c.arg[0]=findone;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
/* Read the ID of an EM410x tag. /* Read the ID of an EM410x tag.
@ -43,21 +44,21 @@ int CmdEMdemodASK(const char *Cmd)
*/ */
int CmdEM410xRead(const char *Cmd) int CmdEM410xRead(const char *Cmd)
{ {
uint32_t hi=0; uint32_t hi=0;
uint64_t lo=0; uint64_t lo=0;
if(!AskEm410xDemod("", &hi, &lo)) return 0; if(!AskEm410xDemod("", &hi, &lo, false)) return 0;
PrintAndLog("EM410x pattern found: "); PrintAndLog("EM410x pattern found: ");
printEM410x(hi, lo); printEM410x(hi, lo);
if (hi){ if (hi){
PrintAndLog ("EM410x XL pattern found"); PrintAndLog ("EM410x XL pattern found");
return 0; return 0;
} }
char id[12] = {0x00}; char id[12] = {0x00};
sprintf(id, "%010llx",lo); sprintf(id, "%010llx",lo);
global_em410xId = id; global_em410xId = id;
return 1; return 1;
} }
// emulate an EM410X tag // emulate an EM410X tag
@ -83,52 +84,52 @@ int CmdEM410xSim(const char *Cmd)
PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X", uid[0],uid[1],uid[2],uid[3],uid[4]); PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X", uid[0],uid[1],uid[2],uid[3],uid[4]);
PrintAndLog("Press pm3-button to about simulation"); PrintAndLog("Press pm3-button to about simulation");
/* clock is 64 in EM410x tags */ /* clock is 64 in EM410x tags */
int clock = 64; int clock = 64;
/* clear our graph */ /* clear our graph */
ClearGraph(0); ClearGraph(0);
/* write 9 start bits */ /* write 9 start bits */
for (i = 0; i < 9; i++) for (i = 0; i < 9; i++)
AppendGraph(0, clock, 1); AppendGraph(0, clock, 1);
/* for each hex char */ /* for each hex char */
parity[0] = parity[1] = parity[2] = parity[3] = 0; parity[0] = parity[1] = parity[2] = parity[3] = 0;
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
{ {
/* read each hex char */ /* read each hex char */
sscanf(&Cmd[i], "%1x", &n); sscanf(&Cmd[i], "%1x", &n);
for (j = 3; j >= 0; j--, n/= 2) for (j = 3; j >= 0; j--, n/= 2)
binary[j] = n % 2; binary[j] = n % 2;
/* append each bit */ /* append each bit */
AppendGraph(0, clock, binary[0]); AppendGraph(0, clock, binary[0]);
AppendGraph(0, clock, binary[1]); AppendGraph(0, clock, binary[1]);
AppendGraph(0, clock, binary[2]); AppendGraph(0, clock, binary[2]);
AppendGraph(0, clock, binary[3]); AppendGraph(0, clock, binary[3]);
/* append parity bit */ /* append parity bit */
AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
/* keep track of column parity */ /* keep track of column parity */
parity[0] ^= binary[0]; parity[0] ^= binary[0];
parity[1] ^= binary[1]; parity[1] ^= binary[1];
parity[2] ^= binary[2]; parity[2] ^= binary[2];
parity[3] ^= binary[3]; parity[3] ^= binary[3];
} }
/* parity columns */ /* parity columns */
AppendGraph(0, clock, parity[0]); AppendGraph(0, clock, parity[0]);
AppendGraph(0, clock, parity[1]); AppendGraph(0, clock, parity[1]);
AppendGraph(0, clock, parity[2]); AppendGraph(0, clock, parity[2]);
AppendGraph(0, clock, parity[3]); AppendGraph(0, clock, parity[3]);
/* stop bit */ /* stop bit */
AppendGraph(1, clock, 0); AppendGraph(1, clock, 0);
CmdLFSim("0"); //240 start_gap. CmdLFSim("0"); //240 start_gap.
return 0; return 0;
} }
/* Function is equivalent of lf read + data samples + em410xread /* Function is equivalent of lf read + data samples + em410xread
@ -139,7 +140,6 @@ int CmdEM410xSim(const char *Cmd)
* rate gets lower, then grow the number of samples * rate gets lower, then grow the number of samples
* Changed by martin, 4000 x 4 = 16000, * Changed by martin, 4000 x 4 = 16000,
* see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235 * see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235
*/ */
int CmdEM410xWatch(const char *Cmd) int CmdEM410xWatch(const char *Cmd)
{ {
@ -150,12 +150,13 @@ int CmdEM410xWatch(const char *Cmd)
} }
CmdLFRead("s"); CmdLFRead("s");
getSamples("8192",true); //capture enough to get 2 full messages getSamples("8201",true); //capture enough to get 2 complete preambles (4096*2+9)
} while (!CmdEM410xRead("")); } while (!CmdEM410xRead(""));
return 0; return 0;
} }
//currently only supports manchester modulations
int CmdEM410xWatchnSpoof(const char *Cmd) int CmdEM410xWatchnSpoof(const char *Cmd)
{ {
CmdEM410xWatch(Cmd); CmdEM410xWatch(Cmd);
@ -164,154 +165,10 @@ int CmdEM410xWatchnSpoof(const char *Cmd)
return 0; return 0;
} }
/* Read the transmitted data of an EM4x50 tag
* Format:
*
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* CCCCCCCC <- column parity bits
* 0 <- stop bit
* LW <- Listen Window
*
* This pattern repeats for every block of data being transmitted.
* Transmission starts with two Listen Windows (LW - a modulated
* pattern of 320 cycles each (32/32/128/64/64)).
*
* Note that this data may or may not be the UID. It is whatever data
* is stored in the blocks defined in the control word First and Last
* Word Read values. UID is stored in block 32.
*/
int CmdEM4x50Read(const char *Cmd)
{
int i, j, startblock, skip, block, start, end, low, high;
bool complete= false;
int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
char tmp[6];
high= low= 0;
memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
/* first get high and low values */
for (i = 0; i < GraphTraceLen; i++)
{
if (GraphBuffer[i] > high)
high = GraphBuffer[i];
else if (GraphBuffer[i] < low)
low = GraphBuffer[i];
}
/* populate a buffer with pulse lengths */
i= 0;
j= 0;
while (i < GraphTraceLen)
{
// measure from low to low
while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
++i;
start= i;
while ((GraphBuffer[i] < high) && (i<GraphTraceLen))
++i;
while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
++i;
if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
break;
}
tmpbuff[j++]= i - start;
}
/* look for data start - should be 2 pairs of LW (pulses of 192,128) */
start= -1;
skip= 0;
for (i= 0; i < j - 4 ; ++i)
{
skip += tmpbuff[i];
if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
{
start= i + 3;
break;
}
}
startblock= i + 3;
/* skip over the remainder of the LW */
skip += tmpbuff[i+1]+tmpbuff[i+2];
while (skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)
++skip;
skip += 8;
/* now do it again to find the end */
end= start;
for (i += 3; i < j - 4 ; ++i)
{
end += tmpbuff[i];
if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
{
complete= true;
break;
}
}
if (start >= 0)
PrintAndLog("Found data at sample: %i",skip);
else
{
PrintAndLog("No data found!");
PrintAndLog("Try again with more samples.");
return 0;
}
if (!complete)
{
PrintAndLog("*** Warning!");
PrintAndLog("Partial data - no end found!");
PrintAndLog("Try again with more samples.");
}
/* get rid of leading crap */
sprintf(tmp,"%i",skip);
CmdLtrim(tmp);
/* now work through remaining buffer printing out data blocks */
block= 0;
i= startblock;
while (block < 6)
{
PrintAndLog("Block %i:", block);
// mandemod routine needs to be split so we can call it for data
// just print for now for debugging
CmdManchesterDemod("i 64");
skip= 0;
/* look for LW before start of next block */
for ( ; i < j - 4 ; ++i)
{
skip += tmpbuff[i];
if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
break;
}
while (GraphBuffer[skip] > low)
++skip;
skip += 8;
sprintf(tmp,"%i",skip);
CmdLtrim(tmp);
start += skip;
block++;
}
return 0;
}
int CmdEM410xWrite(const char *Cmd) int CmdEM410xWrite(const char *Cmd)
{ {
uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
int card = 0xFF; // invalid card value int card = 0xFF; // invalid card value
unsigned int clock = 0; // invalid clock value unsigned int clock = 0; // invalid clock value
sscanf(Cmd, "%" PRIx64 " %d %d", &id, &card, &clock); sscanf(Cmd, "%" PRIx64 " %d %d", &id, &card, &clock);
@ -370,133 +227,404 @@ int CmdEM410xWrite(const char *Cmd)
return 0; return 0;
} }
UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}}; UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
SendCommand(&c); SendCommand(&c);
return 0; return 0;
}
bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
{
if (rows*cols>size) return false;
uint8_t colP=0;
//assume last col is a parity and do not test
for (uint8_t colNum = 0; colNum < cols-1; colNum++) {
for (uint8_t rowNum = 0; rowNum < rows; rowNum++) {
colP ^= BitStream[(rowNum*cols)+colNum];
}
if (colP != pType) return false;
}
return true;
}
bool EM_ByteParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
{
if (rows*cols>size) return false;
uint8_t rowP=0;
//assume last row is a parity row and do not test
for (uint8_t rowNum = 0; rowNum < rows-1; rowNum++) {
for (uint8_t colNum = 0; colNum < cols; colNum++) {
rowP ^= BitStream[(rowNum*cols)+colNum];
}
if (rowP != pType) return false;
}
return true;
}
uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest)
{
if (size<45) return 0;
uint32_t code = bytebits_to_byte(BitStream,8);
code = code<<8 | bytebits_to_byte(BitStream+9,8);
code = code<<8 | bytebits_to_byte(BitStream+18,8);
code = code<<8 | bytebits_to_byte(BitStream+27,8);
if (verbose || g_debugMode){
for (uint8_t i = 0; i<5; i++){
if (i == 4) PrintAndLog(""); //parity byte spacer
PrintAndLog("%d%d%d%d%d%d%d%d %d -> 0x%02x",
BitStream[i*9],
BitStream[i*9+1],
BitStream[i*9+2],
BitStream[i*9+3],
BitStream[i*9+4],
BitStream[i*9+5],
BitStream[i*9+6],
BitStream[i*9+7],
BitStream[i*9+8],
bytebits_to_byte(BitStream+i*9,8)
);
}
if (pTest)
PrintAndLog("Parity Passed");
else
PrintAndLog("Parity Failed");
}
return code;
}
/* Read the transmitted data of an EM4x50 tag
* Format:
*
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
* CCCCCCCC <- column parity bits
* 0 <- stop bit
* LW <- Listen Window
*
* This pattern repeats for every block of data being transmitted.
* Transmission starts with two Listen Windows (LW - a modulated
* pattern of 320 cycles each (32/32/128/64/64)).
*
* Note that this data may or may not be the UID. It is whatever data
* is stored in the blocks defined in the control word First and Last
* Word Read values. UID is stored in block 32.
*/
//completed by Marshmellow
int EM4x50Read(const char *Cmd, bool verbose)
{
uint8_t fndClk[] = {8,16,32,40,50,64,128};
int clk = 0;
int invert = 0;
int tol = 0;
int i, j, startblock, skip, block, start, end, low, high, minClk;
bool complete = false;
int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
uint32_t Code[6];
char tmp[6];
char tmp2[20];
int phaseoff;
high = low = 0;
memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
// get user entry if any
sscanf(Cmd, "%i %i", &clk, &invert);
// save GraphBuffer - to restore it later
save_restoreGB(1);
// first get high and low values
for (i = 0; i < GraphTraceLen; i++) {
if (GraphBuffer[i] > high)
high = GraphBuffer[i];
else if (GraphBuffer[i] < low)
low = GraphBuffer[i];
}
i = 0;
j = 0;
minClk = 255;
// get to first full low to prime loop and skip incomplete first pulse
while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
++i;
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
skip = i;
// populate tmpbuff buffer with pulse lengths
while (i < GraphTraceLen) {
// measure from low to low
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
start= i;
while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
++i;
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
break;
}
tmpbuff[j++]= i - start;
if (i-start < minClk && i < GraphTraceLen) {
minClk = i - start;
}
}
// set clock
if (!clk) {
for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
tol = fndClk[clkCnt]/8;
if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) {
clk=fndClk[clkCnt];
break;
}
}
if (!clk) return 0;
} else tol = clk/8;
// look for data start - should be 2 pairs of LW (pulses of clk*3,clk*2)
start = -1;
for (i= 0; i < j - 4 ; ++i) {
skip += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
{
start= i + 4;
break;
}
}
startblock = i + 4;
// skip over the remainder of LW
skip += tmpbuff[i+1] + tmpbuff[i+2] + clk;
if (tmpbuff[i+3]>clk)
phaseoff = tmpbuff[i+3]-clk;
else
phaseoff = 0;
// now do it again to find the end
end = skip;
for (i += 3; i < j - 4 ; ++i) {
end += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
{
complete= true;
break;
}
}
end = i;
// report back
if (verbose || g_debugMode) {
if (start >= 0) {
PrintAndLog("\nNote: one block = 50 bits (32 data, 12 parity, 6 marker)");
} else {
PrintAndLog("No data found!, clock tried:%d",clk);
PrintAndLog("Try again with more samples.");
PrintAndLog(" or after a 'data askedge' command to clean up the read");
return 0;
}
} else if (start < 0) return 0;
start = skip;
snprintf(tmp2, sizeof(tmp2),"%d %d 1000 %d", clk, invert, clk*47);
// get rid of leading crap
snprintf(tmp, sizeof(tmp), "%i", skip);
CmdLtrim(tmp);
bool pTest;
bool AllPTest = true;
// now work through remaining buffer printing out data blocks
block = 0;
i = startblock;
while (block < 6) {
if (verbose || g_debugMode) PrintAndLog("\nBlock %i:", block);
skip = phaseoff;
// look for LW before start of next block
for ( ; i < j - 4 ; ++i) {
skip += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol)
if (tmpbuff[i+1] >= clk-tol)
break;
}
if (i >= j-4) break; //next LW not found
skip += clk;
if (tmpbuff[i+1]>clk)
phaseoff = tmpbuff[i+1]-clk;
else
phaseoff = 0;
i += 2;
if (ASKDemod(tmp2, false, false, 1) < 1) {
save_restoreGB(0);
return 0;
}
//set DemodBufferLen to just one block
DemodBufferLen = skip/clk;
//test parities
pTest = EM_ByteParityTest(DemodBuffer,DemodBufferLen,5,9,0);
pTest &= EM_EndParityTest(DemodBuffer,DemodBufferLen,5,9,0);
AllPTest &= pTest;
//get output
Code[block] = OutputEM4x50_Block(DemodBuffer,DemodBufferLen,verbose, pTest);
if (g_debugMode) PrintAndLog("\nskipping %d samples, bits:%d", skip, skip/clk);
//skip to start of next block
snprintf(tmp,sizeof(tmp),"%i",skip);
CmdLtrim(tmp);
block++;
if (i >= end) break; //in case chip doesn't output 6 blocks
}
//print full code:
if (verbose || g_debugMode || AllPTest){
if (!complete) {
PrintAndLog("*** Warning!");
PrintAndLog("Partial data - no end found!");
PrintAndLog("Try again with more samples.");
}
PrintAndLog("Found data at sample: %i - using clock: %i", start, clk);
end = block;
for (block=0; block < end; block++){
PrintAndLog("Block %d: %08x",block,Code[block]);
}
if (AllPTest) {
PrintAndLog("Parities Passed");
} else {
PrintAndLog("Parities Failed");
PrintAndLog("Try cleaning the read samples with 'data askedge'");
}
}
//restore GraphBuffer
save_restoreGB(0);
return (int)AllPTest;
}
int CmdEM4x50Read(const char *Cmd)
{
return EM4x50Read(Cmd, true);
} }
int CmdReadWord(const char *Cmd) int CmdReadWord(const char *Cmd)
{ {
int Word = -1; //default to invalid word int Word = -1; //default to invalid word
UsbCommand c; UsbCommand c;
sscanf(Cmd, "%d", &Word); sscanf(Cmd, "%d", &Word);
if ( (Word > 15) | (Word < 0) ) { if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15"); PrintAndLog("Word must be between 0 and 15");
return 1; return 1;
} }
PrintAndLog("Reading word %d", Word); PrintAndLog("Reading word %d", Word);
c.cmd = CMD_EM4X_READ_WORD; c.cmd = CMD_EM4X_READ_WORD;
c.d.asBytes[0] = 0x0; //Normal mode c.d.asBytes[0] = 0x0; //Normal mode
c.arg[0] = 0; c.arg[0] = 0;
c.arg[1] = Word; c.arg[1] = Word;
c.arg[2] = 0; c.arg[2] = 0;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdReadWordPWD(const char *Cmd) int CmdReadWordPWD(const char *Cmd)
{ {
int Word = -1; //default to invalid word int Word = -1; //default to invalid word
int Password = 0xFFFFFFFF; //default to blank password int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c; UsbCommand c;
sscanf(Cmd, "%d %x", &Word, &Password); sscanf(Cmd, "%d %x", &Word, &Password);
if ( (Word > 15) | (Word < 0) ) { if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15"); PrintAndLog("Word must be between 0 and 15");
return 1; return 1;
} }
PrintAndLog("Reading word %d with password %08X", Word, Password); PrintAndLog("Reading word %d with password %08X", Word, Password);
c.cmd = CMD_EM4X_READ_WORD; c.cmd = CMD_EM4X_READ_WORD;
c.d.asBytes[0] = 0x1; //Password mode c.d.asBytes[0] = 0x1; //Password mode
c.arg[0] = 0; c.arg[0] = 0;
c.arg[1] = Word; c.arg[1] = Word;
c.arg[2] = Password; c.arg[2] = Password;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdWriteWord(const char *Cmd) int CmdWriteWord(const char *Cmd)
{ {
int Word = 16; //default to invalid block int Word = 16; //default to invalid block
int Data = 0xFFFFFFFF; //default to blank data int Data = 0xFFFFFFFF; //default to blank data
UsbCommand c; UsbCommand c;
sscanf(Cmd, "%x %d", &Data, &Word); sscanf(Cmd, "%x %d", &Data, &Word);
if (Word > 15) { if (Word > 15) {
PrintAndLog("Word must be between 0 and 15"); PrintAndLog("Word must be between 0 and 15");
return 1; return 1;
} }
PrintAndLog("Writing word %d with data %08X", Word, Data); PrintAndLog("Writing word %d with data %08X", Word, Data);
c.cmd = CMD_EM4X_WRITE_WORD; c.cmd = CMD_EM4X_WRITE_WORD;
c.d.asBytes[0] = 0x0; //Normal mode c.d.asBytes[0] = 0x0; //Normal mode
c.arg[0] = Data; c.arg[0] = Data;
c.arg[1] = Word; c.arg[1] = Word;
c.arg[2] = 0; c.arg[2] = 0;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdWriteWordPWD(const char *Cmd) int CmdWriteWordPWD(const char *Cmd)
{ {
int Word = 16; //default to invalid word int Word = 16; //default to invalid word
int Data = 0xFFFFFFFF; //default to blank data int Data = 0xFFFFFFFF; //default to blank data
int Password = 0xFFFFFFFF; //default to blank password int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c; UsbCommand c;
sscanf(Cmd, "%x %d %x", &Data, &Word, &Password); sscanf(Cmd, "%x %d %x", &Data, &Word, &Password);
if (Word > 15) { if (Word > 15) {
PrintAndLog("Word must be between 0 and 15"); PrintAndLog("Word must be between 0 and 15");
return 1; return 1;
} }
PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password); PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
c.cmd = CMD_EM4X_WRITE_WORD; c.cmd = CMD_EM4X_WRITE_WORD;
c.d.asBytes[0] = 0x1; //Password mode c.d.asBytes[0] = 0x1; //Password mode
c.arg[0] = Data; c.arg[0] = Data;
c.arg[1] = Word; c.arg[1] = Word;
c.arg[2] = Password; c.arg[2] = Password;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"em410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"}, {"em410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
{"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"}, {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
{"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"}, {"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, {"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, {"em410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"em410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"}, {"em410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"}, {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"}, {"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"}, {"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"}, {"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
{"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"}, {"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
int CmdLFEM4X(const char *Cmd) int CmdLFEM4X(const char *Cmd)
{ {
CmdsParse(CommandTable, Cmd); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }
int CmdHelp(const char *Cmd) int CmdHelp(const char *Cmd)
{ {
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return 0;
} }

View file

@ -11,7 +11,6 @@
#ifndef CMDLFEM4X_H__ #ifndef CMDLFEM4X_H__
#define CMDLFEM4X_H__ #define CMDLFEM4X_H__
int CmdLFEM4X(const char *Cmd);
int CmdEMdemodASK(const char *Cmd); int CmdEMdemodASK(const char *Cmd);
int CmdEM410xRead(const char *Cmd); int CmdEM410xRead(const char *Cmd);
int CmdEM410xSim(const char *Cmd); int CmdEM410xSim(const char *Cmd);
@ -19,9 +18,11 @@ int CmdEM410xWatch(const char *Cmd);
int CmdEM410xWatchnSpoof(const char *Cmd); int CmdEM410xWatchnSpoof(const char *Cmd);
int CmdEM410xWrite(const char *Cmd); int CmdEM410xWrite(const char *Cmd);
int CmdEM4x50Read(const char *Cmd); int CmdEM4x50Read(const char *Cmd);
int CmdLFEM4X(const char *Cmd);
int CmdReadWord(const char *Cmd); int CmdReadWord(const char *Cmd);
int CmdReadWordPWD(const char *Cmd); int CmdReadWordPWD(const char *Cmd);
int CmdWriteWord(const char *Cmd); int CmdWriteWord(const char *Cmd);
int CmdWriteWordPWD(const char *Cmd); int CmdWriteWordPWD(const char *Cmd);
int EM4x50Read(const char *Cmd, bool verbose);
#endif #endif

View file

@ -17,7 +17,7 @@
#include "cmdlfhid.h" #include "cmdlfhid.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/*
int CmdHIDDemod(const char *Cmd) int CmdHIDDemod(const char *Cmd)
{ {
if (GraphTraceLen < 4800) { if (GraphTraceLen < 4800) {
@ -36,7 +36,7 @@ int CmdHIDDemod(const char *Cmd)
RepaintGraphWindow(); RepaintGraphWindow();
return 0; return 0;
} }
*/
int CmdHIDDemodFSK(const char *Cmd) int CmdHIDDemodFSK(const char *Cmd)
{ {
int findone=0; int findone=0;
@ -106,7 +106,7 @@ int CmdHIDClone(const char *Cmd)
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"demod", CmdHIDDemod, 1, "Demodulate HID Prox Card II (not optimal)"}, //{"demod", CmdHIDDemod, 1, "Demodulate HID Prox Card II (not optimal)"},
{"fskdemod", CmdHIDDemodFSK, 0, "['1'] Realtime HID FSK demodulator (option '1' for one tag only)"}, {"fskdemod", CmdHIDDemodFSK, 0, "['1'] Realtime HID FSK demodulator (option '1' for one tag only)"},
{"sim", CmdHIDSim, 0, "<ID> -- HID tag simulator"}, {"sim", CmdHIDSim, 0, "<ID> -- HID tag simulator"},
{"clone", CmdHIDClone, 0, "<ID> ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"}, {"clone", CmdHIDClone, 0, "<ID> ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"},

View file

@ -12,9 +12,9 @@
#define CMDLFHID_H__ #define CMDLFHID_H__
int CmdLFHID(const char *Cmd); int CmdLFHID(const char *Cmd);
//int CmdHIDDemod(const char *Cmd);
int CmdHIDDemod(const char *Cmd);
int CmdHIDDemodFSK(const char *Cmd); int CmdHIDDemodFSK(const char *Cmd);
int CmdHIDSim(const char *Cmd); int CmdHIDSim(const char *Cmd);
int CmdHIDClone(const char *Cmd);
#endif #endif

View file

@ -24,7 +24,7 @@ int CmdIODemodFSK(const char *Cmd)
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
/*
int CmdIOProxDemod(const char *Cmd){ int CmdIOProxDemod(const char *Cmd){
if (GraphTraceLen < 4800) { if (GraphTraceLen < 4800) {
PrintAndLog("too short; need at least 4800 samples"); PrintAndLog("too short; need at least 4800 samples");
@ -37,7 +37,7 @@ int CmdIOProxDemod(const char *Cmd){
RepaintGraphWindow(); RepaintGraphWindow();
return 0; return 0;
} }
*/
int CmdIOClone(const char *Cmd) int CmdIOClone(const char *Cmd)
{ {
unsigned int hi = 0, lo = 0; unsigned int hi = 0, lo = 0;
@ -67,7 +67,7 @@ int CmdIOClone(const char *Cmd)
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"demod", CmdIOProxDemod, 1, "Demodulate Stream"}, //{"demod", CmdIOProxDemod, 1, "Demodulate Stream"},
{"fskdemod", CmdIODemodFSK, 0, "['1'] Realtime IO FSK demodulator (option '1' for one tag only)"}, {"fskdemod", CmdIODemodFSK, 0, "['1'] Realtime IO FSK demodulator (option '1' for one tag only)"},
{"clone", CmdIOClone, 0, "Clone ioProx Tag"}, {"clone", CmdIOClone, 0, "Clone ioProx Tag"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
@ -83,4 +83,4 @@ int CmdHelp(const char *Cmd)
{ {
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return 0;
} }

View file

@ -10,6 +10,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
#include <time.h>
#include "proxmark3.h" #include "proxmark3.h"
#include "ui.h" #include "ui.h"
#include "graph.h" #include "graph.h"
@ -147,31 +148,37 @@ int CmdT55xxSetConfig(const char *Cmd) {
param_getstr(Cmd, cmdp+1, modulation); param_getstr(Cmd, cmdp+1, modulation);
cmdp += 2; cmdp += 2;
if ( strcmp(modulation, "FSK" ) == 0) if ( strcmp(modulation, "FSK" ) == 0) {
config.modulation = DEMOD_FSK; config.modulation = DEMOD_FSK;
else if ( strcmp(modulation, "FSK1" ) == 0) } else if ( strcmp(modulation, "FSK1" ) == 0) {
config.modulation = DEMOD_FSK1; config.modulation = DEMOD_FSK1;
else if ( strcmp(modulation, "FSK1a" ) == 0) config.inverted=1;
} else if ( strcmp(modulation, "FSK1a" ) == 0) {
config.modulation = DEMOD_FSK1a; config.modulation = DEMOD_FSK1a;
else if ( strcmp(modulation, "FSK2" ) == 0) config.inverted=0;
} else if ( strcmp(modulation, "FSK2" ) == 0) {
config.modulation = DEMOD_FSK2; config.modulation = DEMOD_FSK2;
else if ( strcmp(modulation, "FSK2a" ) == 0) config.inverted=0;
} else if ( strcmp(modulation, "FSK2a" ) == 0) {
config.modulation = DEMOD_FSK2a; config.modulation = DEMOD_FSK2a;
else if ( strcmp(modulation, "ASK" ) == 0) config.inverted=1;
} else if ( strcmp(modulation, "ASK" ) == 0) {
config.modulation = DEMOD_ASK; config.modulation = DEMOD_ASK;
else if ( strcmp(modulation, "NRZ" ) == 0) } else if ( strcmp(modulation, "NRZ" ) == 0) {
config.modulation = DEMOD_NRZ; config.modulation = DEMOD_NRZ;
else if ( strcmp(modulation, "PSK1" ) == 0) } else if ( strcmp(modulation, "PSK1" ) == 0) {
config.modulation = DEMOD_PSK1; config.modulation = DEMOD_PSK1;
else if ( strcmp(modulation, "PSK2" ) == 0) } else if ( strcmp(modulation, "PSK2" ) == 0) {
config.modulation = DEMOD_PSK2; config.modulation = DEMOD_PSK2;
else if ( strcmp(modulation, "PSK3" ) == 0) } else if ( strcmp(modulation, "PSK3" ) == 0) {
config.modulation = DEMOD_PSK3; config.modulation = DEMOD_PSK3;
else if ( strcmp(modulation, "BIa" ) == 0) } else if ( strcmp(modulation, "BIa" ) == 0) {
config.modulation = DEMOD_BIa; config.modulation = DEMOD_BIa;
else if ( strcmp(modulation, "BI" ) == 0) config.inverted=1;
} else if ( strcmp(modulation, "BI" ) == 0) {
config.modulation = DEMOD_BI; config.modulation = DEMOD_BI;
else { config.inverted=0;
} else {
PrintAndLog("Unknown modulation '%s'", modulation); PrintAndLog("Unknown modulation '%s'", modulation);
errors = TRUE; errors = TRUE;
} }
@ -255,77 +262,51 @@ int CmdT55xxReadBlock(const char *Cmd) {
bool DecodeT55xxBlock(){ bool DecodeT55xxBlock(){
char buf[8] = {0x00}; char buf[30] = {0x00};
char *cmdStr = buf; char *cmdStr = buf;
int ans = 0; int ans = 0;
uint8_t bitRate[8] = {8,16,32,40,50,64,100,128}; uint8_t bitRate[8] = {8,16,32,40,50,64,100,128};
DemodBufferLen = 0x00; DemodBufferLen = 0x00;
//trim 1/2 a clock from beginning
snprintf(cmdStr, sizeof(buf),"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
switch( config.modulation ){ switch( config.modulation ){
case DEMOD_FSK: case DEMOD_FSK:
//CmdLtrim("26"); snprintf(cmdStr, sizeof(buf),"%d %d", bitRate[config.bitrate], config.inverted );
sprintf(cmdStr,"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
sprintf(cmdStr,"%d %d", bitRate[config.bitrate], config.inverted );
ans = FSKrawDemod(cmdStr, FALSE); ans = FSKrawDemod(cmdStr, FALSE);
break; break;
case DEMOD_FSK1: case DEMOD_FSK1:
//CmdLtrim("26");
sprintf(cmdStr,"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
sprintf(cmdStr,"%d 1 8 5", bitRate[config.bitrate] );
ans = FSKrawDemod(cmdStr, FALSE);
break;
case DEMOD_FSK1a: case DEMOD_FSK1a:
//CmdLtrim("26"); snprintf(cmdStr, sizeof(buf),"%d %d 8 5", bitRate[config.bitrate], config.inverted );
sprintf(cmdStr,"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
sprintf(cmdStr,"%d 0 8 5", bitRate[config.bitrate] );
ans = FSKrawDemod(cmdStr, FALSE); ans = FSKrawDemod(cmdStr, FALSE);
break; break;
case DEMOD_FSK2: case DEMOD_FSK2:
//CmdLtrim("26");
sprintf(cmdStr,"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
sprintf(cmdStr,"%d 0 10 8", bitRate[config.bitrate] );
ans = FSKrawDemod(cmdStr, FALSE);
break;
case DEMOD_FSK2a: case DEMOD_FSK2a:
//CmdLtrim("26"); snprintf(cmdStr, sizeof(buf),"%d %d 10 8", bitRate[config.bitrate], config.inverted );
sprintf(cmdStr,"%d", bitRate[config.bitrate]/2 );
CmdLtrim(cmdStr);
sprintf(cmdStr,"%d 1 10 8", bitRate[config.bitrate] );
ans = FSKrawDemod(cmdStr, FALSE); ans = FSKrawDemod(cmdStr, FALSE);
break; break;
case DEMOD_ASK: case DEMOD_ASK:
sprintf(cmdStr,"%d %d 1", bitRate[config.bitrate], config.inverted ); snprintf(cmdStr, sizeof(buf),"%d %d 0", bitRate[config.bitrate], config.inverted );
ans = ASKmanDemod(cmdStr, FALSE, FALSE); ans = ASKDemod(cmdStr, FALSE, FALSE, 1);
break; break;
case DEMOD_PSK1: case DEMOD_PSK1:
sprintf(cmdStr,"%d %d 1", bitRate[config.bitrate], config.inverted ); snprintf(cmdStr, sizeof(buf),"%d %d 0", bitRate[config.bitrate], config.inverted );
ans = PSKDemod(cmdStr, FALSE); ans = PSKDemod(cmdStr, FALSE);
break; break;
case DEMOD_PSK2: case DEMOD_PSK2: //inverted won't affect this
sprintf(cmdStr,"%d 1", bitRate[config.bitrate] ); case DEMOD_PSK3: //not fully implemented
ans = PSKDemod(cmdStr, FALSE); snprintf(cmdStr, sizeof(buf),"%d 0 1", bitRate[config.bitrate] );
psk1TOpsk2(DemodBuffer, DemodBufferLen);
break;
case DEMOD_PSK3:
sprintf(cmdStr,"%d %d 1", bitRate[config.bitrate], config.inverted );
ans = PSKDemod(cmdStr, FALSE); ans = PSKDemod(cmdStr, FALSE);
psk1TOpsk2(DemodBuffer, DemodBufferLen); psk1TOpsk2(DemodBuffer, DemodBufferLen);
break; break;
case DEMOD_NRZ: case DEMOD_NRZ:
sprintf(cmdStr,"%d %d 1", bitRate[config.bitrate], config.inverted ); snprintf(cmdStr, sizeof(buf),"%d %d 1", bitRate[config.bitrate], config.inverted );
ans = NRZrawDemod(cmdStr, FALSE); ans = NRZrawDemod(cmdStr, FALSE);
break; break;
case DEMOD_BI: case DEMOD_BI:
sprintf(cmdStr,"0 %d 0 1", bitRate[config.bitrate] );
ans = ASKbiphaseDemod(cmdStr, FALSE);
break;
case DEMOD_BIa: case DEMOD_BIa:
sprintf(cmdStr,"0 %d 1 1", bitRate[config.bitrate] ); snprintf(cmdStr, sizeof(buf),"0 %d %d 0", bitRate[config.bitrate], config.inverted );
ans = ASKbiphaseDemod(cmdStr, FALSE); ans = ASKbiphaseDemod(cmdStr, FALSE);
break; break;
default: default:
@ -354,114 +335,141 @@ bool tryDetectModulation(){
char cmdStr[8] = {0}; char cmdStr[8] = {0};
uint8_t hits = 0; uint8_t hits = 0;
t55xx_conf_block_t tests[15]; t55xx_conf_block_t tests[15];
int bitRate=0;
uint8_t fc1 = 0, fc2 = 0, clk=0;
save_restoreGB(1);
if (GetFskClock("", FALSE, FALSE)){ if (GetFskClock("", FALSE, FALSE)){
uint8_t fc1 = 0, fc2 = 0, clk=0;
fskClocks(&fc1, &fc2, &clk, FALSE); fskClocks(&fc1, &fc2, &clk, FALSE);
sprintf(cmdStr,"%d", clk/2); sprintf(cmdStr,"%d", clk/2);
CmdLtrim(cmdStr); CmdLtrim(cmdStr);
if ( FSKrawDemod("0 0", FALSE) && test(DEMOD_FSK, &tests[hits].offset)){ if ( FSKrawDemod("0 0", FALSE) && test(DEMOD_FSK, &tests[hits].offset, &bitRate)){
tests[hits].modulation = DEMOD_FSK; tests[hits].modulation = DEMOD_FSK;
if (fc1==8 && fc2 == 5) if (fc1==8 && fc2 == 5)
tests[hits].modulation = DEMOD_FSK1a; tests[hits].modulation = DEMOD_FSK1a;
else if (fc1==10 && fc2 == 8) else if (fc1==10 && fc2 == 8)
tests[hits].modulation = DEMOD_FSK2; tests[hits].modulation = DEMOD_FSK2;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE; tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits; ++hits;
} }
if ( FSKrawDemod("0 1", FALSE) && test(DEMOD_FSK, &tests[hits].offset)) { if ( FSKrawDemod("0 1", FALSE) && test(DEMOD_FSK, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_FSK; tests[hits].modulation = DEMOD_FSK;
if (fc1==8 && fc2 == 5) if (fc1 == 8 && fc2 == 5)
tests[hits].modulation = DEMOD_FSK1; tests[hits].modulation = DEMOD_FSK1;
else if (fc1==10 && fc2 == 8) else if (fc1 == 10 && fc2 == 8)
tests[hits].modulation = DEMOD_FSK2a; tests[hits].modulation = DEMOD_FSK2a;
tests[hits].bitrate = bitRate;
tests[hits].inverted = TRUE; tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits; ++hits;
} }
} else { } else {
if ( ASKmanDemod("0 0 1", FALSE, FALSE) && test(DEMOD_ASK, &tests[hits].offset)) { clk = GetAskClock("", FALSE, FALSE);
tests[hits].modulation = DEMOD_ASK; if (clk>0) {
tests[hits].inverted = FALSE; sprintf(cmdStr,"%d", clk/2);
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); CmdLtrim(cmdStr);
++hits; if ( ASKDemod("0 0 0", FALSE, FALSE, 1) && test(DEMOD_ASK, &tests[hits].offset, &bitRate)) {
} tests[hits].modulation = DEMOD_ASK;
tests[hits].bitrate = bitRate;
if ( ASKmanDemod("0 1 1", FALSE, FALSE) && test(DEMOD_ASK, &tests[hits].offset)) {
tests[hits].modulation = DEMOD_ASK;
tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( NRZrawDemod("0 0 1", FALSE) && test(DEMOD_NRZ, &tests[hits].offset)) {
tests[hits].modulation = DEMOD_NRZ;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( NRZrawDemod("0 1 1", FALSE) && test(DEMOD_NRZ, &tests[hits].offset)) {
tests[hits].modulation = DEMOD_NRZ;
tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( PSKDemod("0 0 1", FALSE) && test(DEMOD_PSK1, &tests[hits].offset)) {
tests[hits].modulation = DEMOD_PSK1;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( PSKDemod("0 1 1", FALSE) && test(DEMOD_PSK1, &tests[hits].offset)) {
tests[hits].modulation = DEMOD_PSK1;
tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
// PSK2 - needs a call to psk1TOpsk2.
if ( PSKDemod("0 0 1", FALSE)) {
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (test(DEMOD_PSK2, &tests[hits].offset)){
tests[hits].modulation = DEMOD_PSK2;
tests[hits].inverted = FALSE; tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits; ++hits;
} }
} // inverse waves does not affect this demod if ( ASKDemod("0 1 0", FALSE, FALSE, 1) && test(DEMOD_ASK, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_ASK;
// PSK3 - needs a call to psk1TOpsk2. tests[hits].bitrate = bitRate;
if ( PSKDemod("0 0 1", FALSE)) { tests[hits].inverted = TRUE;
psk1TOpsk2(DemodBuffer, DemodBufferLen); tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
if (test(DEMOD_PSK3, &tests[hits].offset)){ ++hits;
tests[hits].modulation = DEMOD_PSK3; }
if ( ASKbiphaseDemod("0 0 0 0", FALSE) && test(DEMOD_BI, &tests[hits].offset, &bitRate) ) {
tests[hits].modulation = DEMOD_BI;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE; tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits; ++hits;
} }
} // inverse waves does not affect this demod if ( ASKbiphaseDemod("0 0 1 0", FALSE) && test(DEMOD_BIa, &tests[hits].offset, &bitRate) ) {
tests[hits].modulation = DEMOD_BIa;
if ( ASKbiphaseDemod("0 0 0 1", FALSE) && test(DEMOD_BI, &tests[hits].offset) ) { tests[hits].bitrate = bitRate;
tests[hits].modulation = DEMOD_BI; tests[hits].inverted = TRUE;
tests[hits].inverted = FALSE; tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); ++hits;
++hits; }
} }
if ( ASKbiphaseDemod("0 0 1 1", FALSE) && test(DEMOD_BIa, &tests[hits].offset) ) { //undo trim from ask
tests[hits].modulation = DEMOD_BIa; save_restoreGB(0);
tests[hits].inverted = TRUE; clk = GetNrzClock("", FALSE, FALSE);
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer); if (clk>0) {
++hits; sprintf(cmdStr,"%d", clk/2);
CmdLtrim(cmdStr);
if ( NRZrawDemod("0 0 1", FALSE) && test(DEMOD_NRZ, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_NRZ;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( NRZrawDemod("0 1 1", FALSE) && test(DEMOD_NRZ, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_NRZ;
tests[hits].bitrate = bitRate;
tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
}
//undo trim from nrz
save_restoreGB(0);
clk = GetPskClock("", FALSE, FALSE);
if (clk>0) {
PrintAndLog("clk %d",clk);
sprintf(cmdStr,"%d", clk/2);
CmdLtrim(cmdStr);
if ( PSKDemod("0 0 1", FALSE) && test(DEMOD_PSK1, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_PSK1;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
if ( PSKDemod("0 1 1", FALSE) && test(DEMOD_PSK1, &tests[hits].offset, &bitRate)) {
tests[hits].modulation = DEMOD_PSK1;
tests[hits].bitrate = bitRate;
tests[hits].inverted = TRUE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
// PSK2 - needs a call to psk1TOpsk2.
if ( PSKDemod("0 0 1", FALSE)) {
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (test(DEMOD_PSK2, &tests[hits].offset, &bitRate)){
tests[hits].modulation = DEMOD_PSK2;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
} // inverse waves does not affect this demod
// PSK3 - needs a call to psk1TOpsk2.
if ( PSKDemod("0 0 1", FALSE)) {
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (test(DEMOD_PSK3, &tests[hits].offset, &bitRate)){
tests[hits].modulation = DEMOD_PSK3;
tests[hits].bitrate = bitRate;
tests[hits].inverted = FALSE;
tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
++hits;
}
} // inverse waves does not affect this demod
} }
} }
if ( hits == 1) { if ( hits == 1) {
config.modulation = tests[0].modulation; config.modulation = tests[0].modulation;
config.bitrate = tests[0].bitrate;
config.inverted = tests[0].inverted; config.inverted = tests[0].inverted;
config.offset = tests[0].offset; config.offset = tests[0].offset;
config.block0 = tests[0].block0; config.block0 = tests[0].block0;
@ -516,81 +524,32 @@ bool testBitRate(uint8_t readRate, uint8_t mod){
uint8_t detRate = 0; uint8_t detRate = 0;
switch( mod ){ switch( mod ){
case DEMOD_FSK: case DEMOD_FSK:
detRate = GetFskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_FSK1: case DEMOD_FSK1:
detRate = GetFskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_FSK1a: case DEMOD_FSK1a:
detRate = GetFskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_FSK2: case DEMOD_FSK2:
detRate = GetFskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_FSK2a: case DEMOD_FSK2a:
detRate = GetFskClock("",FALSE, FALSE); detRate = GetFskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) { if (expected[readRate] == detRate)
config.bitrate = readRate;
return TRUE; return TRUE;
}
break; break;
case DEMOD_ASK: case DEMOD_ASK:
case DEMOD_BI:
case DEMOD_BIa:
detRate = GetAskClock("",FALSE, FALSE); detRate = GetAskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) { if (expected[readRate] == detRate)
config.bitrate = readRate;
return TRUE; return TRUE;
}
break; break;
case DEMOD_PSK1: case DEMOD_PSK1:
detRate = GetPskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_PSK2: case DEMOD_PSK2:
detRate = GetPskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break;
case DEMOD_PSK3: case DEMOD_PSK3:
detRate = GetPskClock("",FALSE, FALSE); detRate = GetPskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) { if (expected[readRate] == detRate)
config.bitrate = readRate;
return TRUE; return TRUE;
}
break; break;
case DEMOD_NRZ: case DEMOD_NRZ:
detRate = GetNrzClock("",FALSE, FALSE); detRate = GetNrzClock("",FALSE, FALSE);
if (expected[readRate] == detRate) { if (expected[readRate] == detRate)
config.bitrate = readRate;
return TRUE; return TRUE;
}
break;
case DEMOD_BI:
detRate = GetAskClock("",FALSE, FALSE);
if (expected[readRate] == detRate) {
config.bitrate = readRate;
return TRUE;
}
break; break;
default: default:
return FALSE; return FALSE;
@ -598,26 +557,27 @@ bool testBitRate(uint8_t readRate, uint8_t mod){
return FALSE; return FALSE;
} }
bool test(uint8_t mode, uint8_t *offset){ bool test(uint8_t mode, uint8_t *offset, int *fndBitRate){
if ( !DemodBufferLen) return FALSE; if ( DemodBufferLen < 64 ) return FALSE;
uint8_t si = 0; uint8_t si = 0;
for (uint8_t idx = 0; idx < 64; idx++){ for (uint8_t idx = 0; idx < 64; idx++){
si = idx; si = idx;
if ( PackBits(si, 32, DemodBuffer) == 0x00 ) continue; if ( PackBits(si, 32, DemodBuffer) == 0x00 ) continue;
uint8_t safer = PackBits(si, 4, DemodBuffer); si += 4; //master key uint8_t safer = PackBits(si, 4, DemodBuffer); si += 4; //master key
uint8_t resv = PackBits(si, 4, DemodBuffer); si += 4; //was 7 & +=7+3 //should be only 4 bits if extended mode uint8_t resv = PackBits(si, 4, DemodBuffer); si += 4; //was 7 & +=7+3 //should be only 4 bits if extended mode
// 2nibble must be zeroed. // 2nibble must be zeroed.
// moved test to here, since this gets most faults first. // moved test to here, since this gets most faults first.
if ( resv > 0x00) continue; if ( resv > 0x00) continue;
uint8_t xtRate = PackBits(si, 3, DemodBuffer); si += 3; //new uint8_t xtRate = PackBits(si, 3, DemodBuffer); si += 3; //extended mode part of rate
uint8_t bitRate = PackBits(si, 3, DemodBuffer); si += 3; //new could check bit rate int bitRate = PackBits(si, 3, DemodBuffer); si += 3; //bit rate
if (bitRate > 7) continue;
uint8_t extend = PackBits(si, 1, DemodBuffer); si += 1; //bit 15 extended mode uint8_t extend = PackBits(si, 1, DemodBuffer); si += 1; //bit 15 extended mode
uint8_t modread = PackBits(si, 5, DemodBuffer); si += 5+2+1; //new uint8_t modread = PackBits(si, 5, DemodBuffer); si += 5+2+1;
//uint8_t pskcr = PackBits(si, 2, DemodBuffer); si += 2+1; //new could check psk cr //uint8_t pskcr = PackBits(si, 2, DemodBuffer); si += 2+1; //could check psk cr
uint8_t nml01 = PackBits(si, 1, DemodBuffer); si += 1+5; //bit 24 , 30, 31 could be tested for 0 if not extended mode uint8_t nml01 = PackBits(si, 1, DemodBuffer); si += 1+5; //bit 24, 30, 31 could be tested for 0 if not extended mode
uint8_t nml02 = PackBits(si, 2, DemodBuffer); si += 2; uint8_t nml02 = PackBits(si, 2, DemodBuffer); si += 2;
//if extended mode //if extended mode
@ -628,15 +588,15 @@ bool test(uint8_t mode, uint8_t *offset){
} }
//test modulation //test modulation
if (!testModulation(mode, modread)) continue; if (!testModulation(mode, modread)) continue;
*offset = idx;
if (!testBitRate(bitRate, mode)) continue; if (!testBitRate(bitRate, mode)) continue;
*fndBitRate = bitRate;
*offset = idx;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
void printT55xxBlock(const char *demodStr){ void printT55xxBlock(const char *blockNum){
uint8_t i = config.offset; uint8_t i = config.offset;
uint8_t endpos = 32 + i; uint8_t endpos = 32 + i;
@ -654,7 +614,7 @@ void printT55xxBlock(const char *demodStr){
bits[i - config.offset]=DemodBuffer[i]; bits[i - config.offset]=DemodBuffer[i];
blockData = PackBits(0, 32, bits); blockData = PackBits(0, 32, bits);
PrintAndLog("0x%08X %s [%s]", blockData, sprint_bin(bits,32), demodStr); PrintAndLog("[%s] 0x%08X %s", blockNum, blockData, sprint_bin(bits,32));
} }
int special(const char *Cmd) { int special(const char *Cmd) {
@ -746,16 +706,28 @@ int CmdT55xxReadTrace(const char *Cmd)
uint32_t bl0 = PackBits(si, 32, DemodBuffer); uint32_t bl0 = PackBits(si, 32, DemodBuffer);
uint32_t bl1 = PackBits(si+32, 32, DemodBuffer); uint32_t bl1 = PackBits(si+32, 32, DemodBuffer);
uint32_t acl = PackBits(si, 8, DemodBuffer); si += 8; uint32_t acl = PackBits(si, 8, DemodBuffer); si += 8;
uint32_t mfc = PackBits(si, 8, DemodBuffer); si += 8; uint32_t mfc = PackBits(si, 8, DemodBuffer); si += 8;
uint32_t cid = PackBits(si, 5, DemodBuffer); si += 5; uint32_t cid = PackBits(si, 5, DemodBuffer); si += 5;
uint32_t icr = PackBits(si, 3, DemodBuffer); si += 3; uint32_t icr = PackBits(si, 3, DemodBuffer); si += 3;
uint32_t year = PackBits(si, 4, DemodBuffer); si += 4; uint32_t year = PackBits(si, 4, DemodBuffer); si += 4;
uint32_t quarter = PackBits(si, 2, DemodBuffer); si += 2; uint32_t quarter = PackBits(si, 2, DemodBuffer); si += 2;
uint32_t lotid = PackBits(si, 14, DemodBuffer); si += 14; uint32_t lotid = PackBits(si, 14, DemodBuffer); si += 14;
uint32_t wafer = PackBits(si, 5, DemodBuffer); si += 5; uint32_t wafer = PackBits(si, 5, DemodBuffer); si += 5;
uint32_t dw = PackBits(si, 15, DemodBuffer); uint32_t dw = PackBits(si, 15, DemodBuffer);
time_t t = time(NULL);
struct tm tm = *localtime(&t);
if ( year > tm.tm_year-110)
year += 2000;
else
year += 2010;
if ( acl != 0xE0 ) {
PrintAndLog("The modulation is most likely wrong since the ACL is not 0xE0. ");
return 1;
}
PrintAndLog(""); PrintAndLog("");
PrintAndLog("-- T55xx Trace Information ----------------------------------"); PrintAndLog("-- T55xx Trace Information ----------------------------------");
PrintAndLog("-------------------------------------------------------------"); PrintAndLog("-------------------------------------------------------------");
@ -764,7 +736,7 @@ int CmdT55xxReadTrace(const char *Cmd)
PrintAndLog(" CID : 0x%02X (%d) - %s", cid, cid, GetModelStrFromCID(cid)); PrintAndLog(" CID : 0x%02X (%d) - %s", cid, cid, GetModelStrFromCID(cid));
PrintAndLog(" ICR IC Revision : %d",icr ); PrintAndLog(" ICR IC Revision : %d",icr );
PrintAndLog(" Manufactured"); PrintAndLog(" Manufactured");
PrintAndLog(" Year/Quarter : 20?%d/%d",year, quarter); PrintAndLog(" Year/Quarter : %d/%d",year, quarter);
PrintAndLog(" Lot ID : %d", lotid ); PrintAndLog(" Lot ID : %d", lotid );
PrintAndLog(" Wafer number : %d", wafer); PrintAndLog(" Wafer number : %d", wafer);
PrintAndLog(" Die Number : %d", dw); PrintAndLog(" Die Number : %d", dw);
@ -774,8 +746,6 @@ int CmdT55xxReadTrace(const char *Cmd)
PrintAndLog(" Block 1 : 0x%08X %s", bl1, sprint_bin(DemodBuffer+config.offset+repeat+32,32) ); PrintAndLog(" Block 1 : 0x%08X %s", bl1, sprint_bin(DemodBuffer+config.offset+repeat+32,32) );
PrintAndLog("-------------------------------------------------------------"); PrintAndLog("-------------------------------------------------------------");
if ( acl != 0xE0 )
PrintAndLog("The modulation is most likely wrong since the ACL is not 0xE0. ");
/* /*
TRACE - BLOCK O TRACE - BLOCK O
Bits Definition HEX Bits Definition HEX
@ -809,10 +779,10 @@ int CmdT55xxInfo(const char *Cmd){
if (strlen(Cmd)==0) if (strlen(Cmd)==0)
AquireData( CONFIGURATION_BLOCK ); AquireData( CONFIGURATION_BLOCK );
if (!DecodeT55xxBlock()) return 1; if (!DecodeT55xxBlock()) return 1;
if ( !DemodBufferLen) return 1; if ( DemodBufferLen < 32) return 1;
uint8_t si = config.offset; uint8_t si = config.offset;
uint32_t bl0 = PackBits(si, 32, DemodBuffer); uint32_t bl0 = PackBits(si, 32, DemodBuffer);
@ -922,7 +892,8 @@ int AquireData( uint8_t block ){
} }
char * GetBitRateStr(uint32_t id){ char * GetBitRateStr(uint32_t id){
static char buf[40]; static char buf[25];
char *retStr = buf; char *retStr = buf;
switch (id){ switch (id){
case 0: case 0:
@ -957,7 +928,6 @@ char * GetBitRateStr(uint32_t id){
return buf; return buf;
} }
char * GetSaferStr(uint32_t id){ char * GetSaferStr(uint32_t id){
static char buf[40]; static char buf[40];
char *retStr = buf; char *retStr = buf;
@ -974,7 +944,7 @@ char * GetSaferStr(uint32_t id){
} }
char * GetModulationStr( uint32_t id){ char * GetModulationStr( uint32_t id){
static char buf[40]; static char buf[60];
char *retStr = buf; char *retStr = buf;
switch (id){ switch (id){
@ -1003,7 +973,7 @@ char * GetModulationStr( uint32_t id){
snprintf(retStr,sizeof(buf),"%d - FSK 2a RF/10 RF/8",id); snprintf(retStr,sizeof(buf),"%d - FSK 2a RF/10 RF/8",id);
break; break;
case 8: case 8:
snprintf(retStr,sizeof(buf),"%d - Manschester",id); snprintf(retStr,sizeof(buf),"%d - Manchester",id);
break; break;
case 16: case 16:
snprintf(retStr,sizeof(buf),"%d - Biphase",id); snprintf(retStr,sizeof(buf),"%d - Biphase",id);
@ -1026,8 +996,8 @@ char * GetModelStrFromCID(uint32_t cid){
static char buf[10]; static char buf[10];
char *retStr = buf; char *retStr = buf;
if (cid == 1) sprintf(retStr,"ATA5577M1"); if (cid == 1) snprintf(retStr, sizeof(buf),"ATA5577M1");
if (cid == 2) sprintf(retStr,"ATA5577M2"); if (cid == 2) snprintf(retStr, sizeof(buf),"ATA5577M2");
return buf; return buf;
} }

View file

@ -53,13 +53,13 @@ char * GetSaferStr(uint32_t id);
char * GetModulationStr( uint32_t id); char * GetModulationStr( uint32_t id);
char * GetModelStrFromCID(uint32_t cid); char * GetModelStrFromCID(uint32_t cid);
char * GetSelectedModulationStr( uint8_t id); char * GetSelectedModulationStr( uint8_t id);
uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bitstream); uint32_t PackBits(uint8_t start, uint8_t len, uint8_t *bitstream);
void printT55xxBlock(const char *demodStr); void printT55xxBlock(const char *demodStr);
void printConfiguration( t55xx_conf_block_t b); void printConfiguration( t55xx_conf_block_t b);
bool DecodeT55xxBlock(); bool DecodeT55xxBlock();
bool tryDetectModulation(); bool tryDetectModulation();
bool test(uint8_t mode, uint8_t *offset); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate);
int special(const char *Cmd); int special(const char *Cmd);
int AquireData( uint8_t block ); int AquireData( uint8_t block );

View file

@ -17,7 +17,6 @@
int GraphBuffer[MAX_GRAPH_TRACE_LEN]; int GraphBuffer[MAX_GRAPH_TRACE_LEN];
int GraphTraceLen; int GraphTraceLen;
/* write a manchester bit to the graph */ /* write a manchester bit to the graph */
void AppendGraph(int redraw, int clock, int bit) void AppendGraph(int redraw, int clock, int bit)
{ {
@ -46,6 +45,24 @@ int ClearGraph(int redraw)
return gtl; return gtl;
} }
// option '1' to save GraphBuffer any other to restore
void save_restoreGB(uint8_t saveOpt)
{
static int SavedGB[MAX_GRAPH_TRACE_LEN];
static int SavedGBlen;
static bool GB_Saved = false;
if (saveOpt==1) { //save
memcpy(SavedGB, GraphBuffer, sizeof(GraphBuffer));
SavedGBlen = GraphTraceLen;
GB_Saved=true;
} else if (GB_Saved){ //restore
memcpy(GraphBuffer, SavedGB, sizeof(GraphBuffer));
GraphTraceLen = SavedGBlen;
RepaintGraphWindow();
}
return;
}
// DETECT CLOCK NOW IN LFDEMOD.C // DETECT CLOCK NOW IN LFDEMOD.C
@ -126,10 +143,10 @@ int GetAskClock(const char str[], bool printAns, bool verbose)
PrintAndLog("Failed to copy from graphbuffer"); PrintAndLog("Failed to copy from graphbuffer");
return -1; return -1;
} }
DetectASKClock(grph, size, &clock, 20); int start = DetectASKClock(grph, size, &clock, 20);
// Only print this message if we're not looping something // Only print this message if we're not looping something
if (printAns){ if (printAns){
PrintAndLog("Auto-detected clock rate: %d", clock); PrintAndLog("Auto-detected clock rate: %d, Best Starting Position: %d", clock, start);
} }
return clock; return clock;
} }

View file

@ -23,6 +23,7 @@ uint8_t GetNrzClock(const char str[], bool printAns, bool verbose);
uint8_t GetFskClock(const char str[], bool printAns, bool verbose); uint8_t GetFskClock(const char str[], bool printAns, bool verbose);
uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose); uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose);
void setGraphBuf(uint8_t *buff, size_t size); void setGraphBuf(uint8_t *buff, size_t size);
void save_restoreGB(uint8_t saveOpt);
bool HasGraphData(); bool HasGraphData();
void DetectHighLowInGraph(int *high, int *low, bool addFuzz); void DetectHighLowInGraph(int *high, int *low, bool addFuzz);

View file

@ -138,6 +138,8 @@ local _commands = {
CMD_MIFAREUC_AUTH1 = 0x0724, CMD_MIFAREUC_AUTH1 = 0x0724,
CMD_MIFAREUC_AUTH2 = 0x0725, CMD_MIFAREUC_AUTH2 = 0x0725,
CMD_MIFAREUC_READCARD = 0x0726, CMD_MIFAREUC_READCARD = 0x0726,
CMD_MIFAREUC_SETPWD = 0x0727,
CMD_MIFAREU_SETUID = 0x0728,
--// mifare desfire --// mifare desfire
CMD_MIFARE_DESFIRE_READBL = 0x0728, CMD_MIFARE_DESFIRE_READBL = 0x0728,
@ -153,10 +155,10 @@ local _commands = {
local _reverse_lookup,k,v = {} local _reverse_lookup,k,v = {}
for k, v in pairs(_commands) do for k, v in pairs(_commands) do
_reverse_lookup[v] = k _reverse_lookup[v] = k
end end
_commands.tostring = function(command) _commands.tostring = function(command)
if(type(command) == 'number') then if(type(command) == 'number') then
return ("%s (%d)"):format(_reverse_lookup[command]or "ERROR UNDEFINED!", command) return ("%s (%d)"):format(_reverse_lookup[command]or "ERROR UNDEFINED!", command)
end end
@ -217,7 +219,6 @@ function Command:getBytes()
local data = self.data local data = self.data
local cmd = self.cmd local cmd = self.cmd
local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3 local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3
return bin.pack("LLLLH",cmd, arg1, arg2, arg3, data);
return bin.pack("LLLLH",cmd, arg1, arg2, arg3,data);
end end
return _commands return _commands

View file

@ -1,196 +1,333 @@
local _names = { local _names = {
--[[ --[[ decimal, hexadecimal, ccc, elements, group, name
--]] --]]
["0000"]="WHIRLWIND", {"0", "0000", "0030", "air", "regular", "Whirlwind"},
["0100"]="SONIC BOOM", --{"0", "0000", "0030", "air", "regular", "Elite Whirlwind"},
["0200"]="WARNADO", --{"0", "0000", "0030", "air", "regular", "Polar Whirlwind"},
["0300"]="LIGHTNINGROD", {"1", "0100", "0030", "air", "regular", "Sonic Boom"},
["0400"]="BASH", {"2", "0200", "0030", "air", "regular", "Warnado"},
["0500"]="TERRAFIN", {"3", "0300", "0030", "air", "regular", "Lightning Rod"},
["0600"]="DINORANG" , {"4", "0400", "0030", "earth", "regular", "Bash"},
["0700"]="LIGHTCORE PRISM BREAK", --{"4", "0400", "0030", "earth", "regular", "Birthday Bash"},
["0800"]="SUNBURN", {"5", "0500", "0030", "earth", "regular", "Terrafin"},
["0900"]="LIGHTCORE ERUPTOR", --{"5", "0500", "0030", "earth", "regular", "Elite Terrafin"},
["0A00"]="IGNITOR", {"6", "0600", "0030", "earth", "regular", "Dino Rang"},
["0B00"]="FLAMESLINGER", {"7", "0700", "0030", "earth", "regular", "Prism Break"}, --lightcore
["0C00"]="ZAP", {"8", "0800", "0030", "fire", "regular", "Sunburn"},
["0D00"]="WHAM SHELL", {"9", "0900", "0030", "fire", "regular", "Eruptor"}, --lightcore
["0E00"]="GILL GRUNT", --{"9", "0900", "0030", "fire", "regular", "Elite Eruptor"},
["0F00"]="SLAMBAM", --{"9", "0900", "0030", "fire", "regular", "Volcanic Eruptor"},
["1000"]="SPYRO", {"10", "0a00", "0030", "fire", "regular", "Ignitor"},
["1100"]="VOODOOD", {"11", "0b00", "0030", "fire", "regular", "Flameslinger"},
["1200"]="DOUBLE TROUBLE", --{"11", "0b00", "0030", "fire", "regular", "Cupid Flameslinger"},
["1300"]="TRIGGER HAPPY", {"12", "0c00", "0030", "water", "regular", "Zap"},
["1400"]="DROBOT", {"13", "0d00", "0030", "water", "regular", "Wham Shell"},
["1500"]="DRILLSERGEANT", {"14", "0e00", "0030", "water", "regular", "Gill Grunt"},
["1600"]="BOOMER", --{"14", "0e00", "0030", "water", "regular", "Elite Gill Grunt"},
["1700"]="WRECKING BALL", {"15", "0f00", "0030", "water", "regular", "Slam Bam"},
["1800"]="CAMO", --{"15", "0f00", "0030", "water", "regular", "Surfer Slam Bam"},
["1900"]="ZOOK", {"16", "1000", "0030", "magic", "regular", "Spyro"},
["1A00"]="STEALTH ELF", {"17", "1100", "0030", "magic", "regular", "Voodood"},
["1B00"]="STUMP SMASH", {"18", "1200", "0030", "magic", "regular", "Double Trouble"},
["1D00"]="HEX", --{"18", "1200", "0030", "magic", "regular", "Royal Double Trouble"},
["1C00"]="DARK SPYRO", {"19", "1300", "0030", "tech", "regular", "Trigger Happy"},
["1E00"]="CHOPCHOP", --{"19", "1300", "0030", "tech", "regular", "Elite Trigger Happy"},
["1F00"]="GHOST ROASTER", --{"19", "1300", "0030", "tech", "regular", "Springtime Trigger Happy"},
["2000"]="CYNDER", {"20", "1400", "0030", "tech", "regular", "Drobot"},
--[[ {"21", "1500", "0030", "tech", "regular", "Drill Sergeant"},
GIANTS {"22", "1600", "0030", "tech", "regular", "Boomer"},
--]] --{"22", "1600", "0030", "tech", "regular", "Lucky Boomer"},
["6400"]="GIANT JET-VAC", {"23", "1700", "0030", "magic", "regular", "Wrecking Ball"},
["6500"]="GIANT SWARM", --{"23", "1700", "0030", "magic", "regular", "Buddy Wrecking Ball"},
["6600"]="GIANT CRUSHER", {"24", "1800", "0030", "life", "regular", "Camo"},
["6700"]="GIANT FLASHWING", {"25", "1900", "0030", "life", "regular", "Zook"},
["6800"]="GIANT HOTHEAD", {"26", "1a00", "0030", "life", "regular", "Stealth Elf"},
["6900"]="GIANT HOTDOG", --{"26", "1a00", "0030", "life", "regular", "Elite Stealth Elf"},
["6A00"]="GIANT CHILL", --{"26", "1a00", "0030", "life", "regular", "Dark Stealth Elf"},
["6B00"]="GIANT THUMPBACK", {"27", "1b00", "0030", "life", "regular", "Stump Smash"},
["6C00"]="GIANT POPFIZZ", {"27", "1b00", "0118", "life", "regular", "Stump Smash"},
["6D00"]="GIANT NINJINI", --{"27", "1b00", "0030", "life", "regular", "Autumn Stump Smash"},
["6E00"]="GIANT BOUNCER", {"28", "1c00", "0030", "magic", "regular", "Dark Spyro"},
["6F00"]="GIANT SPROCKET", --{"28", "1c00", "0030", "magic", "regular", "Elite Spyro"},
["7000"]="GIANT TREE REX", {"29", "1d00", "0030", "undead", "regular", "Hex"},
["7100"]="LIGHTCORE SHROOMBOOM", --{"29", "1d00", "0030", "undead", "regular", "Hallows' Eve Hex"},
["7200"]="GIANT EYEBROAWL", {"30", "1e00", "0030", "undead", "regular", "Chop Chop"},
["7300"]="GIANT FRIGHTRIDER", --{"30", "1e00", "0030", "undead", "regular", "Elite Chop Chop"},
--{"30", "1e00", "0030", "undead", "regular", "Grill Master Chop Chop"},
{"31", "1f00", "0030", "undead", "regular", "Ghost Roaster"},
{"32", "2000", "0030", "undead", "regular", "Cynder"},
--{"32", "2000", "0030", "undead", "regular", "Skeletal Cynder"},
--[[ {"100", "6400", "0030", "air", "giant", "Jet Vac"},
ITEM {"101", "6500", "0030", "air", "giant", "Swarm"},
--]] {"102", "6600", "0030", "earth", "giant", "Crusher"},
["C800"]="ANVIL", {"103", "6700", "0030", "earth", "giant", "Flashwing"},
["C900"]="SECRET STASH", --{"103", "6700", "0030", "earth", "giant", "Jade Flashwing"},
["CA00"]="REGENERATION", {"104", "6800", "0030", "fire", "giant", "Hot Head"},
["CD00"]="SHIELD", {"105", "6900", "0030", "fire", "giant", "Hot Dog"},
["CB00"]="CROSSED SWORDS", --{"105", "6900", "0030", "fire", "giant", "Molten Hot Dog"},
["CC00"]="HOURGLASS", {"106", "6a00", "0030", "water", "giant", "Chill"},
["CE00"]="SPEED BOOTS", {"107", "6b00", "0030", "water", "giant", "Thumpback"},
["CF00"]="SPARX", --{"107", "6b00", "0030", "water", "giant", "Admiral Thumpback"},
["D000"]="CANNON", {"108", "6c00", "0030", "magic", "giant", "Pop Fizz"},
["D100"]="SCORPIONSTRIKER", --{"108", "6c00", "0030", "magic", "giant", "Hoppity Pop Fizz"},
{"108", "6c00", "023c", "magic", "giant", "Love Potion Pop Fizz"},
--{"108", "6c00", "0030", "magic", "giant", "Punch Pop Fizz"},
{"109", "6d00", "0030", "magic", "giant", "Nin Jini"},
{"110", "6e00", "0030", "tech", "giant", "Bouncer"},
{"111", "6f00", "0030", "tech", "giant", "Sprocket"},
{"112", "7000", "0030", "life", "giant", "Tree Rex"},
--{"112", "7000", "0030", "life", "giant", "Gnarly Tree Rex"},
{"113", "7100", "0030", "life", "giant", "Shroomboom"}, --lightcore
{"114", "7200", "0030", "undead", "giant", "Eye Broawl"},
{"115", "7300", "0030", "undead", "giant", "Fright Rider"},
--[[ {"200", "c800", "0030", "", "item", "Anvil Rain"},
ITEM TRAPS {"201", "c900", "0030", "", "item", "Platinum Treasure Chest"},
--]] {"202", "ca00", "0030", "", "item", "Healing Elixer"},
["D200"]="MAGIC TRAP", {"203", "cb00", "0030", "", "item", "Ghost Pirate Swords"},
["D300"]="WATER TRAP", {"204", "cc00", "0030", "", "item", "Time Twist Hourglass"},
["D400"]="AIR TRAP", {"205", "cd00", "0030", "", "item", "Sky Iron Shield"},
["D500"]="UNDEAD TRAP", {"206", "ce00", "0030", "", "item", "Winged Boots"},
["D600"]="TECH TRAP", {"207", "cf00", "0030", "", "item", "Sparx"},
["D700"]="FIRE TRAP", {"208", "d000", "0030", "", "item", "Cannon"},
["D800"]="EARTH TRAP", {"209", "d100", "0030", "", "item", "Scorpion Striker"},
["D900"]="LIFE TRAP",
["DA00"]="DARK TRAP",
["DB00"]="LIGHT TRAP",
["DC00"]="KAOS TRAP",
--[[ {"210", "d200", "0230", "magic", "trap", "Biter's Bane"},
ITEM {"210", "d200", "0830", "magic", "trap", "Sorcerous Skull"},
--]] -- legendary Sorcerous Skull?
["E600"]="HAND OF FATE", {"210", "d200", "0b30", "magic", "trap", "Axe Of Illusion"},
["E700"]="PIGGYBANK", {"210", "d200", "0e30", "magic", "trap", "Arcane Hourglass"},
["E800"]="ROCKET RAM", {"210", "d200", "1230", "magic", "trap", "Spell Slapper"},
["E900"]="TIKI SPEAKY", {"210", "d200", "1430", "magic", "trap", "Rune Rocket"},
{"211", "d300", "0130", "water", "trap", "Tidal Tiki"},
{"211", "d300", "0230", "water", "trap", "Wet Walter"},
{"211", "d300", "0630", "water", "trap", "Flood Flask"},
-- legendary flood flask?
{"211", "d300", "0730", "water", "trap", "Soaking Staff"},
{"211", "d300", "0b30", "water", "trap", "Aqua Axe"},
{"211", "d300", "1630", "water", "trap", "Frost Helm"},
{"212", "d400", "0330", "air", "trap", "Breezy Bird"},
{"212", "d400", "0630", "air", "trap", "Drafty Decanter"},
{"212", "d400", "0d30", "air", "trap", "Tempest Timer"},
{"212", "d400", "1030", "air", "trap", "Cloudy Cobra"},
{"212", "d400", "1130", "air", "trap", "Storm Warning"},
{"212", "d400", "1830", "air", "trap", "Cycone Saber"},
{"213", "d500", "0430", "undead", "trap", "Spirit Sphere"},
{"213", "d500", "0830", "undead", "trap", "Spectral Skull"},
{"213", "d500", "0b30", "undead", "trap", "Haunted Hatchet"},
{"213", "d500", "0c30", "undead", "trap", "Grim Gripper"},
{"213", "d500", "1030", "undead", "trap", "Spooky Snake"},
{"213", "d500", "1730", "undead", "trap", "Dream Piercer"},
{"214", "d600", "0030", "tech", "trap", "tech Totem"},
{"214", "d600", "0730", "tech", "trap", "Automatic Angel"},
{"214", "d600", "0930", "tech", "trap", "Factory Flower"},
{"214", "d600", "0c30", "tech", "trap", "Grabbing Gadget"},
{"214", "d600", "1630", "tech", "trap", "Makers Mana"},
{"214", "d600", "1a30", "tech", "trap", "Topsy techy"},
{"215", "d700", "0530", "fire", "trap", "Eternal Flame"},
{"215", "d700", "0930", "fire", "trap", "fire Flower"},
{"215", "d700", "1130", "fire", "trap", "Scorching Stopper"},
{"215", "d700", "1230", "fire", "trap", "Searing Spinner"},
{"215", "d700", "1730", "fire", "trap", "Spark Spear"},
{"215", "d700", "1b30", "fire", "trap", "Blazing Belch"},
{"216", "d800", "0030", "earth", "trap", "Banded Boulder"},
{"216", "d800", "0330", "earth", "trap", "Rock Hawk"},
{"216", "d800", "0a30", "earth", "trap", "Slag Hammer"},
{"216", "d800", "0e30", "earth", "trap", "Dust Of Time"},
{"216", "d800", "1330", "earth", "trap", "Spinning Sandstorm"},
{"216", "d800", "1a30", "earth", "trap", "Rubble Trouble"},
{"217", "d900", "0330", "life", "trap", "Oak Eagle"},
{"217", "d900", "0530", "life", "trap", "Emerald Energy"},
{"217", "d900", "0a30", "life", "trap", "Weed Whacker"},
{"217", "d900", "1030", "life", "trap", "Seed Serpent"},
{"217", "d900", "1830", "life", "trap", "Jade Blade"},
{"217", "d900", "1b30", "life", "trap", "Shrub Shrieker"},
{"218", "da00", "0030", "dark", "trap", "dark Dagger"},
{"218", "da00", "1430", "dark", "trap", "Shadow Spider"},
{"218", "da00", "1a30", "dark", "trap", "Ghastly Grimace"},
{"219", "db00", "0030", "light", "trap", "Shining Ship"},
{"219", "db00", "0f30", "light", "trap", "Heavenly Hawk"},
{"219", "db00", "1b30", "light", "trap", "Beam Scream"},
{"220", "dc00", "3030", "kaos", "trap", "Kaos trap!"},
--{"220", "dc00", "3130", "kaos", "trap", "Ultimate Kaos trap!"}, ?
--[[ {"230", "e600", "0030", "none", "item", "Hand Of Fate"},
EXPANSION {"231", "e700", "0030", "none", "item", "Piggy Bank"},
--]] {"232", "e800", "0030", "none", "item", "Rocket Ram"},
["012C"]="DRAGONS PEAK", {"233", "e900", "0030", "none", "item", "Tiki Speaky"},
["012D"]="EMPIRE OF ICE",
["012E"]="PIRATE SEAS", {"300", "2c01", "0030", "none", "location", "Dragons Peak"},
["012F"]="DARKLIGHT CRYPT", {"301", "2d01", "0030", "none", "location", "Empire Of Ice"},
["0130"]="VOLCANIC VAULT", {"302", "2e01", "0030", "none", "location", "Pirate Seas"},
["0131"]="MIRROR OF MYSTERY", {"303", "2f01", "0030", "none", "location", "darklight Crypt"},
["0132"]="NIGHTMARE EXPRESS", {"304", "3001", "0030", "none", "location", "Volcanic Vault"},
["0133"]="SUNSCRAPER SPIRE", {"305", "3101", "0030", "none", "location", "Mirror Of Mystery"},
["0134"]="MIDNIGHT MUSEUM", {"306", "3201", "0030", "none", "location", "Nightmare Express"},
{"307", "3301", "0030", "light", "location", "Sunscraper Spire"},
{"308", "3401", "0030", "dark", "location", "Midnight Museum"},
{"404", "9401", "0030", "earth", "legendary","Bash"},
{"416", "a001", "0030", "magic", "legendary", "Spyro"},
--{"", "", "0030", "magic", "legendary", "Deja Vu"},
{"419", "a301", "0030", "tech", "legendary", "Trigger Happy"},
--{"", "", "0030", "tech", "legendary", "bouncer"},
--{"", "", "0030", "tech", "legendary", "jawbreaker"},
{"430", "ae01", "0030", "undead", "legendary", "Chop Chop"},
--{"", "", "0030", "undead", "legendary", "grim creeper"},
--{"", "", "0030", "undead", "legendary", "night shift"},
--[[ --{"", "", "0030", "air", "legendary", "blades"},
LEGENDARY --{"", "", "0030", "air", "legendary", "jet vac"},
--]] --{"", "", "0030", "air", "legendary", "Free Ranger"},
["0194"]="LEGENDARY BASH", --{"", "", "0030", "life", "legendary", "stealth elf"},
["01A0"]="LEGENDARY SPYRO", --{"", "", "0030", "life", "legendary", "Bushwhack"},
["01A3"]="LEGENDARY TRIGGER HAPPY", --{"", "", "0030", "fire", "legendary", "ignitor"},
["01AE"]="LEGENDARY CHOPCHOP", --{"", "", "0030", "water", "legendary", "slam bam"},
--{"", "", "0030", "water", "legendary", "chill"},
--{"", "", "0030", "", "legendary", "zoo lou"},
--[[ {"450", "c201", "0030", "air", "trapmaster", "Gusto"},
TRAPTEAM --{"450", "c201", "0234", "air", "trapmaster", "Special Gusto"},
--]] {"451", "c301", "0030", "air", "trapmaster", "Thunderbolt"},
["01C2"]="TRAPTEAM GUSTO", --{"451", "c301", "0234", "air", "trapmaster", "Special Thunderbolt"},
["01C3"]="TRAPTEAM THUNDERBOLT", {"452", "c401", "0030", "air", "regular", "Fling Kong"},
["01C4"]="TRAPTEAM FLING KONG", {"453", "c501", "0030", "air", "regular", "Blades"},
["01C5"]="TRAPTEAM BLADES", {"454", "c601", "0030", "earth", "trapmaster", "Wallop"},
["01C6"]="TRAPTEAM WALLOP", --{"454", "c601", "0234", "earth", "trapmaster", "Special Wallop"},
["01C7"]="TRAPTEAM HEAD RUSH", {"455", "c701", "0030", "earth", "trapmaster", "Head Rush"},
["01C8"]="TRAPTEAM FIST BUMP", {"455", "c701", "0234", "earth", "trapmaster", "Nitro Head Rush"},
["01C9"]="TRAPTEAM ROCKY ROLL", {"456", "c801", "0030", "earth", "regular", "Fist Bump"},
["01CA"]="TRAPTEAM WILDFIRE", {"457", "c901", "0030", "earth", "regular", "Rocky Roll"},
["01CB"]="TRAPTEAM KA BOOM", --{"457", "c901", "0030", "earth", "regular", "Rocky Egg Roll"},
["01CC"]="TRAPTEAM TRAIL BLAZER", {"458", "ca01", "0030", "fire", "trapmaster", "Wildfire"},
["01CD"]="TRAPTEAM TORCH", {"458", "ca01", "0234", "fire", "trapmaster", "Dark Wildfire"},
["01CE"]="TRAPTEAM SNAP SHOT", {"459", "cb01", "0030", "fire", "trapmaster", "Ka Boom"},
["01CF"]="TRAPTEAM LOB STAR", --{"459", "cb01", "0234", "fire", "trapmaster", "Special Ka Boom"},
["01D0"]="TRAPTEAM FLIP WRECK", {"460", "cc01", "0030", "fire", "regular", "Trail Blazer"},
["01D1"]="TRAPTEAM ECHO", {"461", "cd01", "0030", "fire", "regular", "Torch"},
["01D2"]="TRAPTEAM BLASTERMIND", {"462", "ce01", "0030", "water", "trapmaster", "Snap Shot"},
["01D3"]="TRAPTEAM ENIGMA", {"462", "ce01", "0234", "water", "trapmaster", "Dark Snap Shot"},
["01D4"]="TRAPTEAM DEJA VU", {"462", "6c00", "023c", "water", "trapmaster", "Instant Snap Shot"},
["01D5"]="TRAPTEAM COBRA CADABRA", --, "water", "trapmaster", "Merry Snap Shot"},
["01D6"]="TRAPTEAM JAWBREAKER", {"463", "cf01", "0030", "water", "trapmaster", "Lob Star"},
["01D7"]="TRAPTEAM GEARSHIFT", {"463", "cf01", "0234", "water", "trapmaster", "Winterfest Lob Star"},
["01D8"]="TRAPTEAM CHOPPER", {"464", "d001", "0030", "water", "regular", "Flip Wreck"},
["01D9"]="TRAPTEAM TREAD HEAD", {"465", "d101", "0030", "water", "regular", "Echo"},
["01DA"]="TRAPTEAM BUSHWHACK", {"466", "d201", "0030", "magic", "trapmaster", "Blastermind"},
["01DB"]="TRAPTEAM TUFF LUCK", --{"466", "d201", "0234", "magic", "trapmaster", "Special Blastermind"},
["01DC"]="TRAPTEAM FOOD FIGHT", {"467", "d301", "0030", "magic", "trapmaster", "Enigma"},
["01DD"]="TRAPTEAM HIGH FIVE", --{"467", "d301", "0234", "magic", "trapmaster", "Special Enigma"},
["01DE"]="TRAPTEAM NITRO KRYPT KING", {"468", "d401", "0030", "magic", "regular", "Deja Vu"},
["01DF"]="TRAPTEAM SHORT CUT", {"469", "d501", "0030", "magic", "regular", "Cobra Cadabra"},
["01E0"]="TRAPTEAM BAT SPIN", --{"469", "d501", "0030", "magic", "regular", "Charming Cobra Cadabra"},
["01E1"]="TRAPTEAM FUNNY BONE", --{"469", "d501", "0030", "magic", "regular", "King Cobra Cadabra"},
["01E2"]="TRAPTEAM KNIGHT LIGHT", {"470", "d601", "0030", "tech", "trapmaster", "Jawbreaker"},
["01E3"]="TRAPTEAM SPOTLIGHT", --{"470", "d601", "0234", "tech", "trapmaster", "Special Jawbreaker"},
["01E4"]="TRAPTEAM KNIGHT MARE", --{"470", "d601", "0234", "tech", "trapmaster", "Knockout Jawbreaker"},
["01E5"]="TRAPTEAM BLACKOUT", {"471", "d701", "0030", "tech", "trapmaster", "Gearshift"},
--{"471", "d701", "0234", "tech", "trapmaster", "Special Gearshift"},
{"472", "d801", "0030", "tech", "regular", "Chopper"},
{"473", "d901", "0030", "tech", "regular", "Tread Head"},
{"474", "da01", "0030", "life", "trapmaster", "Bushwhack"},
--{"474", "da01", "0234", "life", "trapmaster", "Special Bushwhack"},
{"475", "db01", "0030", "life", "trapmaster", "Tuff Luck"},
--{"475", "db01", "0234", "life", "trapmaster", "Special Tuff Luck"},
{"476", "dc01", "0030", "life", "regular", "Food Fight"},
{"476", "dc01", "0612", "life", "regular", "LightCore Food Fight"},
--{"476", "dc01", "0030", "life", "regular", "Dark Food Fight"},
--{"476", "dc01", "0030", "life", "regular", "Frosted Food Fight"},
--{"476", "dc01", "0030", "life", "regular", "Instant Food Fight"},
{"477", "dd01", "0030", "life", "regular", "High Five"},
{"478", "de01", "0030", "undead", "trapmaster", "Krypt King"},
{"478", "de01", "0234", "undead", "trapmaster", "Nitro Krypt King"},
{"479", "df01", "0030", "undead", "trapmaster", "Short Cut"},
--{"479", "df01", "0234", "undead", "trapmaster", "Special Short Cut"},
{"480", "e001", "0030", "undead", "regular", "Bat Spin"},
{"481", "e101", "0030", "undead", "regular", "Funny Bone"},
{"481", "e101", "0612", "undead", "regular", "LightCore Funny Bone"},
--{"481", "e101", "0030", "undead", "regular", "Fortune Funny Bone"},
{"482", "e201", "0030", "light", "trapmaster", "Knight light"},
--{"482", "e201", "0234", "light", "trapmaster", "Special Knight light"},
{"483", "e301", "0030", "light", "regular", "Spotlight"},
--{"483", "e301", "0234", "light", "regular", "Special Spotlight"},
{"484", "e401", "0030", "dark", "trapmaster", "Knight Mare"},
--{"484", "e401", "0234", "dark", "trapmaster", "Special Knight Mare"},
{"485", "e501", "0030", "dark", "regular", "Blackout"},
--{"485", "e501", "0234", "dark", "regular", "Special Blackout"},
--[[ {"502", "f601", "0030", "earth", "mini", "Bop"},
PET {"503", "f701", "0030", "magic", "mini", "Spry"},
--]] {"504", "f801", "0030", "undead", "mini", "Hijinx"},
["01F6"]="PET BOP", {"505", "f901", "0030", "earth", "mini", "Terrabite"},
["01F7"]="PET SPRY", {"506", "fa01", "0030", "air", "mini", "Breeze"},
["01F8"]="PET HIJINX", {"507", "fb01", "0030", "fire", "mini", "Weeruptor"},
["01F9"]="PET TERRAFIN", --{"507", "fb01", "0030", "fire", "mini", "Eggsellent Weeruptor"},
["01FA"]="PET BREEZE", {"508", "fc01", "0030", "air", "mini", "Pet Vac"},
["01FB"]="PET WEERUPTOR", --{"508", "fc01", "0030", "air", "mini", "Power Punch Pet Vac"},
["01FC"]="PET PET VAC", {"509", "fd01", "0030", "fire", "mini", "Small Fry"},
["01FD"]="PET SMALL FRY", {"510", "fe01", "0030", "tech", "mini", "Drobit"},
["01FE"]="PET DROBIT", {"514", "0202", "0030", "water", "mini", "Gill Runt"},
["0202"]="PET GILL GRUNT", {"519", "0702", "0030", "tech", "mini", "Trigger Snappy"},
["0207"]="PET TRIGGER SNAPPY", {"526", "0e02", "0030", "life", "mini", "Whisper Elf"},
["020E"]="PET WHISPER ELF", {"540", "1c02", "0030", "life", "mini", "Barkley"},
["021C"]="PET BARKLEY", --{"540", "1c02", "0030", "life", "mini", "Gnarly Barkley"},
["021D"]="PET THUMPLING", {"541", "1d02", "0030", "water", "mini", "Thumpling"},
["021E"]="PET MINI JINI", {"542", "1e02", "0030", "magic", "mini", "mini Jini"},
["021F"]="PET EYE SMALL", {"543", "1f02", "0030", "undead", "mini", "Eye Small"},
--[[ {"3000", "b80b", "0030", "air", "SWAPFORCE", "Scratch"},
SWAP FORCE {"3001", "b90b", "0030", "air", "SWAPFORCE", "Pop Thorn"},
--]] --{"3001", "b90b", "0030", "air", "SWAPFORCE", "Buttered Pop Thorn"},
["0BB8"]="SWAPFORCE SCRATCH", {"3002", "ba0b", "0030", "earth", "SWAPFORCE", "Slobber Tooth"},
["0BB9"]="SWAPFORCE POPTHORN", --{"3002", "ba0b", "0030", "earth", "SWAPFORCE", "Dark Slobber Tooth"},
["0BBA"]="SWAPFORCE SLOBBER TOOTH", --{"3002", "ba0b", "0030", "earth", "SWAPFORCE", "Sundae Slobber Tooth"},
["0BBB"]="SWAPFORCE SCORP", {"3003", "bb0b", "0030", "earth", "SWAPFORCE", "Scorp"},
["0BBC"]="SWAPFORCE HOG WILD FRYNO", {"3004", "bc0b", "0030", "fire", "SWAPFORCE", "Fryno"},
["0BBD"]="SWAPFORCE SMOLDER DASH", {"3004", "bc0b", "0138", "fire", "SWAPFORCE", "Hog Wild Fryno"},
["0BBE"]="SWAPFORCE BUMBLE BLAST", --{"3004", "bc0b", "0138", "fire", "SWAPFORCE", "Flip flop Fryno"},
["0BBF"]="SWAPFORCE ZOO LOU", {"3005", "bd0b", "0030", "fire", "SWAPFORCE", "Smolderdash"},
["0BC0"]="SWAPFORCE DUNE BUG", {"3006", "be0b", "0030", "life", "SWAPFORCE", "Bumble Blast"},
["0BC1"]="SWAPFORCE STAR STRIKE", --{"3006", "be0b", "0030", "life", "SWAPFORCE", "Jolly Bumble Blast"},
["0BC2"]="SWAPFORCE COUNTDOWN", {"3007", "bf0b", "0030", "life", "SWAPFORCE", "Zoo Lou"},
["0BC3"]="SWAPFORCE WIND UP", {"3008", "c00b", "0030", "magic", "SWAPFORCE", "Dune Bug"},
["0BC4"]="SWAPFORCE ROLLER BRAWL", {"3009", "c10b", "0030", "magic", "SWAPFORCE", "Star Strike"},
["0BC5"]="SWAPFORCE GRIM CREEPER", --{"3009", "c10b", "0030", "magic", "SWAPFORCE", "Enchanted Star Strike"},
["0BC6"]="SWAPFORCE RIP TIDE", --{"3009", "c10b", "0030", "magic", "SWAPFORCE", "Mystic Star Strike"},
["0BC7"]="SWAPFORCE PUNK SHOCK", {"3010", "c20b", "0030", "tech", "SWAPFORCE", "Countdown"},
--{"3010", "c20b", "0030", "tech", "SWAPFORCE", "Kickoff Countdown"},
--{"3010", "c20b", "0030", "tech", "SWAPFORCE", "New Year's Countdown"},
{"3011", "c30b", "0030", "tech", "SWAPFORCE", "Wind Up"},
{"3012", "c40b", "0030", "undead", "SWAPFORCE", "Roller Brawl"},
--{"3012", "c40b", "0030", "undead", "SWAPFORCE", "Snowler Roller Brawl"},
{"3013", "c50b", "0030", "undead", "SWAPFORCE", "Grim Creeper"},
{"3014", "c60b", "0030", "water", "SWAPFORCE", "Rip Tide"},
{"3015", "c70b", "0030", "water", "SWAPFORCE", "Punk Shock"},
}
local function find( main, sub)
main = main:lower()
sub = sub:lower()
for k, v in pairs(_names) do
if ( v[2]:lower() == main and v[3]:lower() == sub) then
return v
end
end
return nil
end
return {
Find = find,
} }
return _names

View file

@ -205,7 +205,7 @@ local function main( args)
-- NDEF compliant? -- NDEF compliant?
if b3chars[1] ~= 0xE1 then if b3chars[1] ~= 0xE1 then
return oops("This tag is not NDEF-Complian") return oops("This tag is not NDEF-Compliant")
end end
local ndefVersion = b3chars[2] local ndefVersion = b3chars[2]

View file

@ -95,6 +95,7 @@ end
function test() function test()
local y local y
local block = "00"
for y = 0x0, 0x1d, 0x4 do for y = 0x0, 0x1d, 0x4 do
for _ = 1, #procedurecmds do for _ = 1, #procedurecmds do
local pcmd = procedurecmds[_] local pcmd = procedurecmds[_]
@ -107,7 +108,7 @@ function test()
dbg(('lf t55xx write 0 %s'):format(config)) dbg(('lf t55xx write 0 %s'):format(config))
config = tonumber(config,16) config = tonumber(config,16)
local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK, arg1 = config} local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"}
local err = core.SendCommand(writecmd:getBytes()) local err = core.SendCommand(writecmd:getBytes())
if err then return oops(err) end if err then return oops(err) end
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)

View file

@ -89,6 +89,7 @@ end
function test() function test()
local y local y
local block = "00"
for y = 1, 0x1D, 4 do for y = 1, 0x1D, 4 do
for _ = 1, #procedurecmds do for _ = 1, #procedurecmds do
local pcmd = procedurecmds[_] local pcmd = procedurecmds[_]
@ -98,10 +99,10 @@ function test()
elseif _ == 1 then elseif _ == 1 then
local config = pcmd:format(config1, y, config2) local config = pcmd:format(config1, y, config2)
dbg(('lf t55xx wr 0 %s'):format(config)) dbg(('lf t55xx write 0 %s'):format(config))
config = tonumber(config,16) config = tonumber(config,16)
local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK, arg1 = config} local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"}
local err = core.SendCommand(writecmd:getBytes()) local err = core.SendCommand(writecmd:getBytes())
if err then return oops(err) end if err then return oops(err) end
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)

View file

@ -92,6 +92,7 @@ end
function test(modulation) function test(modulation)
local y local y
local block = "00"
for y = 0x0, 0x1d, 0x4 do for y = 0x0, 0x1d, 0x4 do
for _ = 1, #procedurecmds do for _ = 1, #procedurecmds do
local pcmd = procedurecmds[_] local pcmd = procedurecmds[_]
@ -104,7 +105,7 @@ function test(modulation)
dbg(('lf t55xx write 0 %s'):format(config)) dbg(('lf t55xx write 0 %s'):format(config))
config = tonumber(config,16) config = tonumber(config,16)
local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK, arg1 = config} local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"}
local err = core.SendCommand(writecmd:getBytes()) local err = core.SendCommand(writecmd:getBytes())
if err then return oops(err) end if err then return oops(err) end
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)

View file

@ -108,6 +108,7 @@ end
function test(modulation) function test(modulation)
local bitrate local bitrate
local clockrate local clockrate
local block = "00"
for bitrate = 0x0, 0x1d, 0x4 do for bitrate = 0x0, 0x1d, 0x4 do
for clockrate = 0,8,4 do for clockrate = 0,8,4 do
@ -125,8 +126,8 @@ function test(modulation)
dbg(('lf t55xx write 0 %s'):format(config)) dbg(('lf t55xx write 0 %s'):format(config))
config = tonumber(config,16) config = tonumber(config,16)
local writecommand = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK, arg1 = config ,arg2 = 0, arg3 = 0} local writecmd = Command:new{cmd = cmds.CMD_T55XX_WRITE_BLOCK,arg1 = config, arg2 = block, arg3 = "00", data = "00"}
local err = core.SendCommand(writecommand:getBytes()) local err = core.SendCommand(writecmd:getBytes())
if err then return oops(err) end if err then return oops(err) end
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT) local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
else else

View file

@ -0,0 +1,161 @@
local cmds = require('commands')
local getopt = require('getopt')
local lib14a = require('read14a')
local utils = require('utils')
local pre = require('precalc')
local toys = require('default_toys')
local lsh = bit32.lshift
local rsh = bit32.rshift
local bor = bit32.bor
local band = bit32.band
example =[[
script run tnp3clone
script run tnp3clone -h
script run tnp3clone -t aa00 -s 0030
]]
author = "Iceman"
usage = "script run tnp3clone -t <toytype> -s <subtype>"
desc =[[
This script will try making a barebone clone of a tnp3 tag on to a magic generation1 card.
Arguments:
-h : this help
-t <data> : toytype id, 4hex symbols.
-s <data> : subtype id, 4hex symbols
For fun, try the following subtype id:
0612 - Lightcore
0118 - Series 1
0138 - Series 2
0234 - Special
023c - Special
]]
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
end
-- Usage help
function help()
print(desc)
print("Example usage")
print(example)
end
local function waitCmd()
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,2000)
if response then
local count,cmd,arg0 = bin.unpack('LL',response)
if(arg0==1) then
local count,arg1,arg2,data = bin.unpack('LLH511',response,count)
return data:sub(1,32)
else
return nil, "Couldn't read block."
end
end
return nil, "No response from device"
end
local function readblock( blocknum, keyA )
-- Read block 0
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blocknum, arg2 = 0, arg3 = 0, data = keyA}
err = core.SendCommand(cmd:getBytes())
if err then return nil, err end
local block0, err = waitCmd()
if err then return nil, err end
return block0
end
local function readmagicblock( blocknum )
-- Read block 0
local CSETBLOCK_SINGLE_OPERATION = 0x1F
cmd = Command:new{cmd = cmds.CMD_MIFARE_CGETBLOCK, arg1 = CSETBLOCK_SINGLE_OPERATION, arg2 = 0, arg3 = blocknum}
err = core.SendCommand(cmd:getBytes())
if err then return nil, err end
local block0, err = waitCmd()
if err then return nil, err end
return block0
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
local numBlocks = 64
local cset = 'hf mf csetbl '
local csetuid = 'hf mf csetuid '
local cget = 'hf mf cgetbl '
local empty = '00000000000000000000000000000000'
local AccAndKeyB = '7F078869000000000000'
-- Defaults to Gusto
local toytype = 'C201'
local subtype = '0030'
local DEBUG = true
-- Arguments for the script
for o, a in getopt.getopt(args, 'ht:s:') do
if o == "h" then return help() end
if o == "t" then toytype = a end
if o == "s" then subtype = a end
end
if #toytype ~= 4 then return oops('Wrong size - toytype. (4hex symbols)') end
if #subtype ~= 4 then return oops('Wrong size - subtype. (4hex symbols)') end
-- look up type, find & validate types
local item = toys.Find( toytype, subtype)
if item then
print( (' Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) )
else
print('Didn\'t find item type. If you are sure about it, report it in')
end
--15,16
--13-14
-- find tag
result, err = lib14a.read1443a(false)
if not result then return oops(err) end
-- load keys
local akeys = pre.GetAll(result.uid)
local keyA = akeys:sub(1, 12 )
local b0 = readblock(0,keyA)
if not b0 then
print('failed reading block with factorydefault key. Trying chinese magic read.')
b0, err = readmagicblock(0)
if not b0 then
oops(err)
return oops('failed reading block with chinese magic command. quitting...')
end
end
-- wipe card.
local cmd = (csetuid..'%s 0004 08 w'):format(result.uid)
core.console(cmd)
local b1 = toytype..'00000000000000000000'..subtype
local calc = utils.Crc16(b0..b1)
local calcEndian = bor(rsh(calc,8), lsh(band(calc, 0xff), 8))
local cmd = (cset..'1 %s%04x'):format( b1, calcEndian)
core.console(cmd)
local pos, key
for blockNo = 2, numBlocks-1, 1 do
pos = (math.floor( blockNo / 4 ) * 12)+1
key = akeys:sub(pos, pos + 11 )
if blockNo%4 == 3 then
cmd = ('%s %d %s%s'):format(cset,blockNo,key,AccAndKeyB)
core.console(cmd)
end
end
core.clearCommandBuffer()
end
main(args)

View file

@ -5,19 +5,21 @@ local lib14a = require('read14a')
local utils = require('utils') local utils = require('utils')
local md5 = require('md5') local md5 = require('md5')
local dumplib = require('html_dumplib') local dumplib = require('html_dumplib')
local toyNames = require('default_toys') local toys = require('default_toys')
example =[[ example =[[
1. script run tnp3dump script run tnp3dump
2. script run tnp3dump -n script run tnp3dump -n
3. script run tnp3dump -k aabbccddeeff script run tnp3dump -p
4. script run tnp3dump -k aabbccddeeff -n script run tnp3dump -k aabbccddeeff
5. script run tnp3dump -o myfile script run tnp3dump -k aabbccddeeff -n
6. script run tnp3dump -n -o myfile script run tnp3dump -o myfile
7. script run tnp3dump -k aabbccddeeff -n -o myfile script run tnp3dump -n -o myfile
script run tnp3dump -p -o myfile
script run tnp3dump -k aabbccddeeff -n -o myfile
]] ]]
author = "Iceman" author = "Iceman"
usage = "script run tnp3dump -k <key> -n -o <filename>" usage = "script run tnp3dump -k <key> -n -p -o <filename>"
desc =[[ desc =[[
This script will try to dump the contents of a Mifare TNP3xxx card. This script will try to dump the contents of a Mifare TNP3xxx card.
It will need a valid KeyA in order to find the other keys and decode the card. It will need a valid KeyA in order to find the other keys and decode the card.
@ -25,11 +27,10 @@ Arguments:
-h : this help -h : this help
-k <key> : Sector 0 Key A. -k <key> : Sector 0 Key A.
-n : Use the nested cmd to find all keys -n : Use the nested cmd to find all keys
-p : Use the precalc to find all keys
-o : filename for the saved dumps -o : filename for the saved dumps
]] ]]
local RANDOM = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
local DEBUG = false -- the debug flag local DEBUG = false -- the debug flag
local numBlocks = 64 local numBlocks = 64
@ -93,16 +94,6 @@ local function waitCmd()
return nil, "No response from device" return nil, "No response from device"
end end
local function computeCrc16(s)
local hash = core.crc16(utils.ConvertHexToAscii(s))
return hash
end
local function reverseCrcBytes(crc)
crc2 = crc:sub(3,4)..crc:sub(1,2)
return tonumber(crc2,16)
end
local function main(args) local function main(args)
print( string.rep('--',20) ) print( string.rep('--',20) )
@ -112,18 +103,20 @@ local function main(args)
local cmd local cmd
local err local err
local useNested = false local useNested = false
local usePreCalc = false
local cmdReadBlockString = 'hf mf rdbl %d A %s' local cmdReadBlockString = 'hf mf rdbl %d A %s'
local input = "dumpkeys.bin" local input = "dumpkeys.bin"
local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S");
-- Arguments for the script -- Arguments for the script
for o, a in getopt.getopt(args, 'hk:no:') do for o, a in getopt.getopt(args, 'hk:npo:') do
if o == "h" then return help() end if o == "h" then return help() end
if o == "k" then keyA = a end if o == "k" then keyA = a end
if o == "n" then useNested = true end if o == "n" then useNested = true end
if o == "p" then usePreCalc = true end
if o == "o" then outputTemplate = a end if o == "o" then outputTemplate = a end
end end
-- validate input args. -- validate input args.
keyA = keyA or '4b0b20107ccb' keyA = keyA or '4b0b20107ccb'
if #(keyA) ~= 12 then if #(keyA) ~= 12 then
@ -141,30 +134,31 @@ local function main(args)
core.clearCommandBuffer() core.clearCommandBuffer()
if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
return oops('This is not a TNP3xxx tag. aborting.')
end
-- Show tag info -- Show tag info
print((' Found tag : %s'):format(result.name)) print((' Found tag %s'):format(result.name))
print(('Using keyA : %s'):format(keyA))
dbg(('Using keyA : %s'):format(keyA))
--Trying to find the other keys --Trying to find the other keys
if useNested then if useNested then
core.console( ('hf mf nested 1 0 A %s d'):format(keyA) ) core.console( ('hf mf nested 1 0 A %s d'):format(keyA) )
end end
core.clearCommandBuffer() core.clearCommandBuffer()
-- Loading keyfile local akeys = ''
print('Loading dumpkeys.bin') if usePreCalc then
local hex, err = utils.ReadDumpFile(input) local pre = require('precalc')
if not hex then akeys = pre.GetAll(result.uid)
return oops(err) else
print('Loading dumpkeys.bin')
local hex, err = utils.ReadDumpFile(input)
if not hex then
return oops(err)
end
akeys = hex:sub(0,12*16)
end end
local akeys = hex:sub(0,12*16)
-- Read block 0 -- Read block 0
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA} cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA}
err = core.SendCommand(cmd:getBytes()) err = core.SendCommand(cmd:getBytes())
@ -179,6 +173,8 @@ local function main(args)
local block1, err = waitCmd() local block1, err = waitCmd()
if err then return oops(err) end if err then return oops(err) end
local tmpHash = block0..block1..'%02x'..RANDOM
local key local key
local pos = 0 local pos = 0
local blockNo local blockNo
@ -188,7 +184,7 @@ local function main(args)
core.clearCommandBuffer() core.clearCommandBuffer()
-- main loop -- main loop
io.write('Decrypting blocks > ') io.write('Reading blocks > ')
for blockNo = 0, numBlocks-1, 1 do for blockNo = 0, numBlocks-1, 1 do
if core.ukbhit() then if core.ukbhit() then
@ -204,25 +200,23 @@ local function main(args)
local blockdata, err = waitCmd() local blockdata, err = waitCmd()
if err then return oops(err) end if err then return oops(err) end
if blockNo%4 ~= 3 then if blockNo%4 ~= 3 then
if blockNo < 8 then if blockNo < 8 then
-- Block 0-7 not encrypted -- Block 0-7 not encrypted
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
else else
local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT)
local baseStr = utils.ConvertHexToAscii(base)
local md5hash = md5.sumhexa(baseStr)
local aestest = core.aes(md5hash, blockdata)
local hex = utils.ConvertAsciiToBytes(aestest)
hex = utils.ConvertBytesToHex(hex)
-- blocks with zero not encrypted. -- blocks with zero not encrypted.
if string.find(blockdata, '^0+$') then if string.find(blockdata, '^0+$') then
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata) blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
else else
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex) local baseStr = utils.ConvertHexToAscii(tmpHash:format(blockNo))
io.write( blockNo..',') local key = md5.sumhexa(baseStr)
local aestest = core.aes128_decrypt(key, blockdata)
local hex = utils.ConvertAsciiToBytes(aestest)
hex = utils.ConvertBytesToHex(hex)
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex)
end end
end end
else else
@ -246,31 +240,38 @@ local function main(args)
emldata = emldata..slice..'\n' emldata = emldata..slice..'\n'
for c in (str):gmatch('.') do for c in (str):gmatch('.') do
bindata[#bindata+1] = c bindata[#bindata+1] = c
end end
end end
print( string.rep('--',20) )
local uid = block0:sub(1,8) local uid = block0:sub(1,8)
local itemtype = block1:sub(1,4) local toytype = block1:sub(1,4)
local cardidLsw = block1:sub(9,16)
local cardidMsw = block1:sub(16,24)
local cardid = block1:sub(9,24) local cardid = block1:sub(9,24)
local traptype = block1:sub(25,28) local subtype = block1:sub(25,28)
-- Write dump to files -- Write dump to files
if not DEBUG then if not DEBUG then
local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'_uid_'..uid..'.bin') local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'-'..uid..'.bin')
print(("Wrote a BIN dump to the file %s"):format(foo)) print(("Wrote a BIN dump to: %s"):format(foo))
local bar = dumplib.SaveAsText(emldata, outputTemplate..'_uid_'..uid..'.eml') local bar = dumplib.SaveAsText(emldata, outputTemplate..'-'..uid..'.eml')
print(("Wrote a EML dump to the file %s"):format(bar)) print(("Wrote a EML dump to: %s"):format(bar))
end end
-- Show info
print( string.rep('--',20) )
print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
print( (' Alter ego / traptype : 0x%s'):format(traptype) )
print( (' UID : 0x%s'):format(uid) )
print( (' CARDID : 0x%s'):format(cardid ) )
print( string.rep('--',20) ) print( string.rep('--',20) )
-- Show info
local item = toys.Find(toytype, subtype)
if item then
print((' ITEM TYPE : %s - %s (%s)'):format(item[6],item[5], item[4]) )
else
print((' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype))
end
print( (' UID : 0x%s'):format(uid) )
print( (' CARDID : 0x%s'):format(cardid ) )
print( string.rep('--',20) )
end end
main(args) main(args)

View file

@ -4,7 +4,7 @@ local bin = require('bin')
local lib14a = require('read14a') local lib14a = require('read14a')
local utils = require('utils') local utils = require('utils')
local md5 = require('md5') local md5 = require('md5')
local toyNames = require('default_toys') local toys = require('default_toys')
example =[[ example =[[
1. script run tnp3sim 1. script run tnp3sim
@ -27,6 +27,17 @@ Arguments:
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
local DEBUG = true -- the debug flag local DEBUG = true -- the debug flag
local band = bit32.band
local bor = bit32.bor
local lshift = bit32.lshift
local rshift = bit32.rshift
local byte = string.byte
local char = string.char
local sub = string.sub
local format = string.format
--- ---
-- A debug printout-function -- A debug printout-function
function dbg(args) function dbg(args)
@ -65,7 +76,6 @@ function ExitMsg(msg)
print() print()
end end
local function writedumpfile(infile) local function writedumpfile(infile)
t = infile:read("*all") t = infile:read("*all")
len = string.len(t) len = string.len(t)
@ -187,7 +197,6 @@ local function ValidateCheckSums(blocks)
io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk)) io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
end end
local function LoadEmulator(blocks) local function LoadEmulator(blocks)
local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20' local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
local cmd local cmd
@ -219,6 +228,102 @@ local function LoadEmulator(blocks)
io.write('\n') io.write('\n')
end end
local function Num2Card(m, l)
local k = {
0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B,
0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54,0x56, 0x57, 0x58, 0x59, 0x5A, 0x00
}
local msw = tonumber(utils.SwapEndiannessStr(m,32),16)
local lsw = tonumber(utils.SwapEndiannessStr(l,32),16)
if msw > 0x17ea1 then
return "too big"
end
if msw == 0x17ea1 and lsw > 0x8931fee8 then
return "out of range"
end
local s = ""
local index
for i = 1,10 do
index, msw, lsw = DivideByK( msw, lsw)
if ( index <= 1 ) then
s = char(k[index]) .. s
else
s = char(k[index-1]) .. s
end
print (index-1, msw, lsw)
end
return s
end
--33LRT-LM9Q9
--7, 122, 3474858630
--20, 4, 1008436634
--7, 0, 627182959
--17, 0, 21626998
--16, 0, 745758
--23, 0, 25715
--21, 0, 886
--16, 0, 30
--1, 0, 1
--1, 0, 0
function DivideByK(msw, lsw)
local lowLSW
local highLSW
local remainder = 0
local RADIX = 29
--local num = 0 | band( rshift(msw,16), 0xffff)
local num = band( rshift(msw, 16), 0xffff)
--highLSW = 0 | lshift( (num / RADIX) , 16)
highLSW = lshift( (num / RADIX) , 16)
remainder = num % RADIX
num = bor( lshift(remainder,16), band(msw, 0xffff))
--highLSW |= num / RADIX
highLSW = highLSW or (num / RADIX)
remainder = num % RADIX
num = bor( lshift(remainder,16), ( band(rshift(lsw,16), 0xffff)))
--lowLSW = 0 | (num / RADIX) << 16
lowLSW = 0 or (lshift( (num / RADIX), 16))
remainder = num % RADIX
num = bor( lshift(remainder,16) , band(lsw, 0xffff) )
lowLSW = bor(lowLSW, (num / RADIX))
remainder = num % RADIX
return remainder, highLSW, lowLSW
-- uint num = 0 | (msw >> 16) & 0xffff;
-- highLSW = 0 | (num / RADIX) << 16;
-- remainder = num % RADIX;
-- num = (remainder << 16) | (msw & 0xffff);
-- highLSW |= num / RADIX;
-- remainder = num % RADIX;
-- num = (remainder << 16) | ((lsw >> 16) & 0xffff);
-- lowLSW = 0 | (num / RADIX) << 16;
-- remainder = num % RADIX;
-- num = (remainder << 16) | (lsw & 0xffff);
-- lowLSW |= num / RADIX;
-- remainder = num % RADIX;
end
local function main(args) local function main(args)
print( string.rep('--',20) ) print( string.rep('--',20) )
@ -277,16 +382,31 @@ local function main(args)
print( string.rep('--',20) ) print( string.rep('--',20) )
print(' Gathering info') print(' Gathering info')
local uid = blocks[0]:sub(1,8) local uid = blocks[0]:sub(1,8)
local itemtype = blocks[1]:sub(1,4) local toytype = blocks[1]:sub(1,4)
local cardid = blocks[1]:sub(9,24) local cardidLsw = blocks[1]:sub(9,16)
local cardidMsw = blocks[1]:sub(17,24)
local subtype = blocks[1]:sub(25,28)
-- Show info -- Show info
print( string.rep('--',20) ) print( string.rep('--',20) )
print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
local item = toys.Find( toytype, subtype)
if item then
local itemStr = ('%s - %s (%s)'):format(item[6],item[5], item[4])
print(' ITEM TYPE :'..itemStr )
else
print( (' ITEM TYPE : 0x%s 0x%s'):format(toytype, subtype) )
end
print( (' UID : 0x%s'):format(uid) ) print( (' UID : 0x%s'):format(uid) )
print( (' CARDID : 0x%s'):format(cardid ) ) print( (' CARDID : 0x%s %s [%s]'):format(
cardidMsw,cardidLsw,
--Num2Card(cardidMsw, cardidLsw))
'')
)
print( string.rep('--',20) ) print( string.rep('--',20) )
-- lets do something. -- lets do something.
-- --
local experience = blocks[8]:sub(1,6) local experience = blocks[8]:sub(1,6)
@ -351,7 +471,7 @@ local function main(args)
err = LoadEmulator(blocks) err = LoadEmulator(blocks)
if err then return oops(err) end if err then return oops(err) end
core.clearCommandBuffer() core.clearCommandBuffer()
print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..' x\" <--') print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..'\" <--')
end end
end end
main(args) main(args)

View file

@ -121,19 +121,24 @@ char * sprint_hex(const uint8_t * data, const size_t len) {
return buf; return buf;
} }
char * sprint_bin(const uint8_t * data, const size_t len) { char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks) {
int maxLen = ( len > 1024) ? 1024 : len; int maxLen = ( len > 1024) ? 1024 : len;
static char buf[1024]; static char buf[1024];
char * tmp = buf; char *tmp = buf;
size_t i;
for (i=0; i < maxLen; ++i, ++tmp) for (size_t i=0; i < maxLen; ++i){
sprintf(tmp, "%u", data[i]); sprintf(tmp++, "%u", data[i]);
if (breaks > 0 && !((i+1) % breaks))
sprintf(tmp++, "%s","\n");
}
return buf; return buf;
} }
char *sprint_bin(const uint8_t *data, const size_t len) {
return sprint_bin_break(data, len, 0);
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{ {
while (len--) { while (len--) {

View file

@ -39,6 +39,7 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
void print_hex(const uint8_t * data, const size_t len); void print_hex(const uint8_t * data, const size_t len);
char * sprint_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len);
char * sprint_bin(const uint8_t * data, const size_t len); char * sprint_bin(const uint8_t * data, const size_t len);
char * sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len); uint64_t bytes_to_num(uint8_t* src, size_t len);

View file

@ -81,10 +81,8 @@ uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_
// otherwise could be a void with no arguments // otherwise could be a void with no arguments
//set defaults //set defaults
uint32_t i = 0; uint32_t i = 0;
if (BitStream[1]>1){ //allow only 1s and 0s if (BitStream[1]>1) return 0; //allow only 1s and 0s
// PrintAndLog("no data found");
return 0;
}
// 111111111 bit pattern represent start of frame // 111111111 bit pattern represent start of frame
// include 0 in front to help get start pos // include 0 in front to help get start pos
uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1}; uint8_t preamble[] = {0,1,1,1,1,1,1,1,1,1};
@ -115,216 +113,11 @@ uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_
} }
//by marshmellow //by marshmellow
//takes 3 arguments - clock, invert, maxErr as integers //demodulates strong heavily clipped samples
//attempts to demodulate ask while decoding manchester
//prints binary found and saves in graphbuffer for further commands
int askmandemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr)
{
size_t i;
int start = DetectASKClock(BinStream, *size, clk, 20); //clock default
if (*clk==0 || start < 0) return -3;
if (*invert != 1) *invert=0;
uint8_t initLoopMax = 255;
if (initLoopMax > *size) initLoopMax = *size;
// Detect high and lows
// 25% fuzz in case highs and lows aren't clipped [marshmellow]
int high, low;
if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1) return -2; //just noise
// PrintAndLog("DEBUG - valid high: %d - valid low: %d",high,low);
int lastBit = 0; //set first clock check
uint16_t bitnum = 0; //output counter
uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave
if (*clk <= 32) tol=1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely
size_t iii = 0;
//if 0 errors allowed then only try first 2 clock cycles as we want a low tolerance
if (!maxErr) initLoopMax = *clk * 2;
uint16_t errCnt = 0, MaxBits = 512;
uint16_t bestStart = start;
uint16_t bestErrCnt = 0;
// PrintAndLog("DEBUG - lastbit - %d",lastBit);
// if best start position not already found by detect clock then
if (start <= 0 || start > initLoopMax){
bestErrCnt = maxErr+1;
// loop to find first wave that works
for (iii=0; iii < initLoopMax; ++iii){
// if no peak skip
if (BinStream[iii] < high && BinStream[iii] > low) continue;
lastBit = iii - *clk;
// loop through to see if this start location works
for (i = iii; i < *size; ++i) {
if ((i-lastBit) > (*clk-tol) && (BinStream[i] >= high || BinStream[i] <= low)) {
lastBit += *clk;
} else if ((i-lastBit) > (*clk+tol)) {
errCnt++;
lastBit += *clk;
}
if ((i-iii) > (MaxBits * *clk) || errCnt > maxErr) break; //got plenty of bits or too many errors
}
//we got more than 64 good bits and not all errors
if ((((i-iii)/ *clk) > (64)) && (errCnt<=maxErr)) {
//possible good read
if (!errCnt || errCnt < bestErrCnt){
bestStart = iii; //set this as new best run
bestErrCnt = errCnt;
if (!errCnt) break; //great read - finish
}
}
errCnt = 0;
}
}
if (bestErrCnt > maxErr){
*invert = bestStart;
*clk = iii;
return -1;
}
//best run is good enough set to best run and set overwrite BinStream
lastBit = bestStart - *clk;
errCnt = 0;
for (i = bestStart; i < *size; ++i) {
if ((BinStream[i] >= high) && ((i-lastBit) > (*clk-tol))){
//high found and we are expecting a bar
lastBit += *clk;
BinStream[bitnum++] = *invert;
} else if ((BinStream[i] <= low) && ((i-lastBit) > (*clk-tol))){
//low found and we are expecting a bar
lastBit += *clk;
BinStream[bitnum++] = *invert ^ 1;
} else if ((i-lastBit)>(*clk+tol)){
//should have hit a high or low based on clock!!
//PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit);
if (bitnum > 0) {
BinStream[bitnum++] = 77;
errCnt++;
}
lastBit += *clk;//skip over error
}
if (bitnum >= MaxBits) break;
}
*size = bitnum;
return bestErrCnt;
}
//by marshmellow
//encode binary data into binary manchester
int ManchesterEncode(uint8_t *BitStream, size_t size)
{
size_t modIdx=20000, i=0;
if (size>modIdx) return -1;
for (size_t idx=0; idx < size; idx++){
BitStream[idx+modIdx++] = BitStream[idx];
BitStream[idx+modIdx++] = BitStream[idx]^1;
}
for (; i<(size*2); i++){
BitStream[i] = BitStream[i+20000];
}
return i;
}
//by marshmellow
//take 10 and 01 and manchester decode
//run through 2 times and take least errCnt
int manrawdecode(uint8_t * BitStream, size_t *size)
{
uint16_t bitnum=0, MaxBits = 512, errCnt = 0;
size_t i, ii;
uint16_t bestErr = 1000, bestRun = 0;
if (size == 0) return -1;
for (ii=0;ii<2;++ii){
for (i=ii; i<*size-2; i+=2)
if (BitStream[i]==BitStream[i+1])
errCnt++;
if (bestErr>errCnt){
bestErr=errCnt;
bestRun=ii;
}
errCnt=0;
}
if (bestErr<20){
for (i=bestRun; i < *size-2; i+=2){
if(BitStream[i] == 1 && (BitStream[i+1] == 0)){
BitStream[bitnum++]=0;
} else if((BitStream[i] == 0) && BitStream[i+1] == 1){
BitStream[bitnum++]=1;
} else {
BitStream[bitnum++]=77;
}
if(bitnum>MaxBits) break;
}
*size=bitnum;
}
return bestErr;
}
//by marshmellow
//take 01 or 10 = 1 and 11 or 00 = 0
//check for phase errors - should never have 111 or 000 should be 01001011 or 10110100 for 1010
//decodes biphase or if inverted it is AKA conditional dephase encoding AKA differential manchester encoding
int BiphaseRawDecode(uint8_t *BitStream, size_t *size, int offset, int invert)
{
uint16_t bitnum = 0;
uint16_t errCnt = 0;
size_t i = offset;
uint16_t MaxBits=512;
//if not enough samples - error
if (*size < 51) return -1;
//check for phase change faults - skip one sample if faulty
uint8_t offsetA = 1, offsetB = 1;
for (; i<48; i+=2){
if (BitStream[i+1]==BitStream[i+2]) offsetA=0;
if (BitStream[i+2]==BitStream[i+3]) offsetB=0;
}
if (!offsetA && offsetB) offset++;
for (i=offset; i<*size-3; i+=2){
//check for phase error
if (BitStream[i+1]==BitStream[i+2]) {
BitStream[bitnum++]=77;
errCnt++;
}
if((BitStream[i]==1 && BitStream[i+1]==0) || (BitStream[i]==0 && BitStream[i+1]==1)){
BitStream[bitnum++]=1^invert;
} else if((BitStream[i]==0 && BitStream[i+1]==0) || (BitStream[i]==1 && BitStream[i+1]==1)){
BitStream[bitnum++]=invert;
} else {
BitStream[bitnum++]=77;
errCnt++;
}
if(bitnum>MaxBits) break;
}
*size=bitnum;
return errCnt;
}
//by marshmellow
void askAmp(uint8_t *BitStream, size_t size)
{
int shift = 127;
int shiftedVal=0;
for(size_t i = 1; i<size; i++){
if (BitStream[i]-BitStream[i-1]>=30) //large jump up
shift=127;
else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down
shift=-127;
shiftedVal=BitStream[i]+shift;
if (shiftedVal>255)
shiftedVal=255;
else if (shiftedVal<0)
shiftedVal=0;
BitStream[i-1] = shiftedVal;
}
return;
}
// demodulates strong heavily clipped samples
int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low) int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int high, int low)
{ {
size_t bitCnt=0, smplCnt=0, errCnt=0; size_t bitCnt=0, smplCnt=0, errCnt=0;
uint8_t waveHigh = 0; uint8_t waveHigh = 0;
//PrintAndLog("clk: %d", clk);
for (size_t i=0; i < *size; i++){ for (size_t i=0; i < *size; i++){
if (BinStream[i] >= high && waveHigh){ if (BinStream[i] >= high && waveHigh){
smplCnt++; smplCnt++;
@ -335,7 +128,7 @@ int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int
if (smplCnt > clk-(clk/4)-1) { //full clock if (smplCnt > clk-(clk/4)-1) { //full clock
if (smplCnt > clk + (clk/4)+1) { //too many samples if (smplCnt > clk + (clk/4)+1) { //too many samples
errCnt++; errCnt++;
BinStream[bitCnt++]=77; BinStream[bitCnt++]=7;
} else if (waveHigh) { } else if (waveHigh) {
BinStream[bitCnt++] = invert; BinStream[bitCnt++] = invert;
BinStream[bitCnt++] = invert; BinStream[bitCnt++] = invert;
@ -371,111 +164,79 @@ int cleanAskRawDemod(uint8_t *BinStream, size_t *size, int clk, int invert, int
} }
//by marshmellow //by marshmellow
//takes 3 arguments - clock, invert and maxErr as integers void askAmp(uint8_t *BitStream, size_t size)
//attempts to demodulate ask only {
int askrawdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp) for(size_t i = 1; i<size; i++){
if (BitStream[i]-BitStream[i-1]>=30) //large jump up
BitStream[i]=127;
else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down
BitStream[i]=-127;
}
return;
}
//by marshmellow
//attempts to demodulate ask modulations, askType == 0 for ask/raw, askType==1 for ask/manchester
int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType)
{ {
if (*size==0) return -1; if (*size==0) return -1;
int start = DetectASKClock(BinStream, *size, clk, 20); //clock default int start = DetectASKClock(BinStream, *size, clk, maxErr); //clock default
if (*clk==0 || start < 0) return -1; if (*clk==0 || start < 0) return -3;
if (*invert != 1) *invert = 0; if (*invert != 1) *invert = 0;
if (amp==1) askAmp(BinStream, *size); if (amp==1) askAmp(BinStream, *size);
uint8_t initLoopMax = 255; uint8_t initLoopMax = 255;
if (initLoopMax > *size) initLoopMax=*size; if (initLoopMax > *size) initLoopMax = *size;
// Detect high and lows // Detect high and lows
//25% clip in case highs and lows aren't clipped [marshmellow] //25% clip in case highs and lows aren't clipped [marshmellow]
int high, low; int high, low;
if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1) if (getHiLo(BinStream, initLoopMax, &high, &low, 75, 75) < 1)
return -1; //just noise return -2; //just noise
size_t errCnt = 0;
// if clean clipped waves detected run alternate demod // if clean clipped waves detected run alternate demod
if (DetectCleanAskWave(BinStream, *size, high, low)) if (DetectCleanAskWave(BinStream, *size, high, low)) {
return cleanAskRawDemod(BinStream, size, *clk, *invert, high, low); errCnt = cleanAskRawDemod(BinStream, size, *clk, *invert, high, low);
if (askType) //askman
return manrawdecode(BinStream, size, 0);
else //askraw
return errCnt;
}
int lastBit = 0; //set first clock check - can go negative int lastBit; //set first clock check - can go negative
size_t i, iii = 0; size_t i, bitnum = 0; //output counter
size_t errCnt = 0, bitnum = 0; //output counter
uint8_t midBit = 0; uint8_t midBit = 0;
size_t bestStart = start, bestErrCnt = 0; //(*size/1000); uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave
if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely
size_t MaxBits = 1024; size_t MaxBits = 1024;
lastBit = start - *clk;
//if 0 errors allowed then only try first 2 clock cycles as we want a low tolerance for (i = start; i < *size; ++i) {
if (!maxErr) initLoopMax = *clk * 2; if (i-lastBit >= *clk-tol){
//if best start not already found by detectclock
if (start <= 0 || start > initLoopMax){
bestErrCnt = maxErr+1;
//PrintAndLog("DEBUG - lastbit - %d",lastBit);
//loop to find first wave that works
for (iii=0; iii < initLoopMax; ++iii){
if ((BinStream[iii] >= high) || (BinStream[iii] <= low)){
lastBit = iii - *clk;
//loop through to see if this start location works
for (i = iii; i < *size; ++i) {
if (i-lastBit > *clk && (BinStream[i] >= high || BinStream[i] <= low)){
lastBit += *clk;
midBit = 0;
} else if (i-lastBit > (*clk/2) && midBit == 0) {
midBit = 1;
} else if ((i-lastBit) > *clk) {
//should have hit a high or low based on clock!!
//PrintAndLog("DEBUG - no wave in expected area - location: %d, expected: %d-%d, lastBit: %d - resetting search",i,(lastBit+(clk-((int)(tol)))),(lastBit+(clk+((int)(tol)))),lastBit);
errCnt++;
lastBit += *clk;//skip over until hit too many errors
if (errCnt > maxErr)
break;
}
if ((i-iii)>(MaxBits * *clk)) break; //got enough bits
}
//we got more than 64 good bits and not all errors
if ((((i-iii)/ *clk) > 64) && (errCnt<=maxErr)) {
//possible good read
if (errCnt==0){
bestStart=iii;
bestErrCnt=errCnt;
break; //great read - finish
}
if (errCnt<bestErrCnt){ //set this as new best run
bestErrCnt=errCnt;
bestStart = iii;
}
}
errCnt=0;
}
}
}
if (bestErrCnt > maxErr){
*invert = bestStart;
*clk = iii;
return -1;
}
//best run is good enough - set to best run and overwrite BinStream
lastBit = bestStart - *clk - 1;
errCnt = 0;
for (i = bestStart; i < *size; ++i) {
if (i - lastBit > *clk){
if (BinStream[i] >= high) { if (BinStream[i] >= high) {
BinStream[bitnum++] = *invert; BinStream[bitnum++] = *invert;
} else if (BinStream[i] <= low) { } else if (BinStream[i] <= low) {
BinStream[bitnum++] = *invert ^ 1; BinStream[bitnum++] = *invert ^ 1;
} else { } else if (i-lastBit >= *clk+tol) {
if (bitnum > 0) { if (bitnum > 0) {
BinStream[bitnum++]=77; BinStream[bitnum++]=7;
errCnt++; errCnt++;
} }
} else { //in tolerance - looking for peak
continue;
} }
midBit = 0; midBit = 0;
lastBit += *clk; lastBit += *clk;
} else if (i-lastBit > (*clk/2) && midBit == 0){ } else if (i-lastBit >= (*clk/2-tol) && !midBit && !askType){
if (BinStream[i] >= high) { if (BinStream[i] >= high) {
BinStream[bitnum++] = *invert; BinStream[bitnum++] = *invert;
} else if (BinStream[i] <= low) { } else if (BinStream[i] <= low) {
BinStream[bitnum++] = *invert ^ 1; BinStream[bitnum++] = *invert ^ 1;
} else { } else if (i-lastBit >= *clk/2+tol) {
BinStream[bitnum] = BinStream[bitnum-1]; BinStream[bitnum] = BinStream[bitnum-1];
bitnum++; bitnum++;
} else { //in tolerance - looking for peak
continue;
} }
midBit = 1; midBit = 1;
} }
@ -485,6 +246,98 @@ int askrawdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int max
return errCnt; return errCnt;
} }
//by marshmellow
//take 10 and 01 and manchester decode
//run through 2 times and take least errCnt
int manrawdecode(uint8_t * BitStream, size_t *size, uint8_t invert)
{
uint16_t bitnum=0, MaxBits = 512, errCnt = 0;
size_t i, ii;
uint16_t bestErr = 1000, bestRun = 0;
if (*size < 16) return -1;
//find correct start position [alignment]
for (ii=0;ii<2;++ii){
for (i=ii; i<*size-3; i+=2)
if (BitStream[i]==BitStream[i+1])
errCnt++;
if (bestErr>errCnt){
bestErr=errCnt;
bestRun=ii;
}
errCnt=0;
}
//decode
for (i=bestRun; i < *size-3; i+=2){
if(BitStream[i] == 1 && (BitStream[i+1] == 0)){
BitStream[bitnum++]=invert;
} else if((BitStream[i] == 0) && BitStream[i+1] == 1){
BitStream[bitnum++]=invert^1;
} else {
BitStream[bitnum++]=7;
}
if(bitnum>MaxBits) break;
}
*size=bitnum;
return bestErr;
}
//by marshmellow
//encode binary data into binary manchester
int ManchesterEncode(uint8_t *BitStream, size_t size)
{
size_t modIdx=20000, i=0;
if (size>modIdx) return -1;
for (size_t idx=0; idx < size; idx++){
BitStream[idx+modIdx++] = BitStream[idx];
BitStream[idx+modIdx++] = BitStream[idx]^1;
}
for (; i<(size*2); i++){
BitStream[i] = BitStream[i+20000];
}
return i;
}
//by marshmellow
//take 01 or 10 = 1 and 11 or 00 = 0
//check for phase errors - should never have 111 or 000 should be 01001011 or 10110100 for 1010
//decodes biphase or if inverted it is AKA conditional dephase encoding AKA differential manchester encoding
int BiphaseRawDecode(uint8_t *BitStream, size_t *size, int offset, int invert)
{
uint16_t bitnum = 0;
uint16_t errCnt = 0;
size_t i = offset;
uint16_t MaxBits=512;
//if not enough samples - error
if (*size < 51) return -1;
//check for phase change faults - skip one sample if faulty
uint8_t offsetA = 1, offsetB = 1;
for (; i<48; i+=2){
if (BitStream[i+1]==BitStream[i+2]) offsetA=0;
if (BitStream[i+2]==BitStream[i+3]) offsetB=0;
}
if (!offsetA && offsetB) offset++;
for (i=offset; i<*size-3; i+=2){
//check for phase error
if (BitStream[i+1]==BitStream[i+2]) {
BitStream[bitnum++]=7;
errCnt++;
}
if((BitStream[i]==1 && BitStream[i+1]==0) || (BitStream[i]==0 && BitStream[i+1]==1)){
BitStream[bitnum++]=1^invert;
} else if((BitStream[i]==0 && BitStream[i+1]==0) || (BitStream[i]==1 && BitStream[i+1]==1)){
BitStream[bitnum++]=invert;
} else {
BitStream[bitnum++]=7;
errCnt++;
}
if(bitnum>MaxBits) break;
}
*size=bitnum;
return errCnt;
}
// by marshmellow
// demod gProxIIDemod // demod gProxIIDemod
// error returns as -x // error returns as -x
// success returns start position in BitStream // success returns start position in BitStream
@ -780,12 +633,13 @@ int PyramiddemodFSK(uint8_t *dest, size_t *size)
return (int)startIdx; return (int)startIdx;
} }
// by marshmellow
uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, int high, int low) // to detect a wave that has heavily clipped (clean) samples
uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low)
{ {
uint16_t allPeaks=1; uint16_t allPeaks=1;
uint16_t cntPeaks=0; uint16_t cntPeaks=0;
size_t loopEnd = 572; size_t loopEnd = 512+60;
if (loopEnd > size) loopEnd = size; if (loopEnd > size) loopEnd = size;
for (size_t i=60; i<loopEnd; i++){ for (size_t i=60; i<loopEnd; i++){
if (dest[i]>low && dest[i]<high) if (dest[i]>low && dest[i]<high)
@ -801,53 +655,39 @@ uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, int high, int low)
// by marshmellow // by marshmellow
// to help detect clocks on heavily clipped samples // to help detect clocks on heavily clipped samples
// based on counts between zero crossings // based on count of low to low
int DetectStrongAskClock(uint8_t dest[], size_t size) int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low)
{ {
int clk[]={0,8,16,32,40,50,64,100,128}; uint8_t fndClk[] = {8,16,32,40,50,64,128};
size_t idx = 40; size_t startwave;
uint8_t high=0; size_t i = 0;
size_t cnt = 0; size_t minClk = 255;
size_t highCnt = 0; // get to first full low to prime loop and skip incomplete first pulse
size_t highCnt2 = 0; while ((dest[i] < high) && (i < size))
for (;idx < size; idx++){ ++i;
if (dest[idx]>128) { while ((dest[i] > low) && (i < size))
if (!high){ ++i;
high=1;
if (cnt > highCnt){ // loop through all samples
if (highCnt != 0) highCnt2 = highCnt; while (i < size) {
highCnt = cnt; // measure from low to low
} else if (cnt > highCnt2) { while ((dest[i] > low) && (i < size))
highCnt2 = cnt; ++i;
} startwave= i;
cnt=1; while ((dest[i] < high) && (i < size))
} else { ++i;
cnt++; while ((dest[i] > low) && (i < size))
} ++i;
} else if (dest[idx] <= 128){ //get minimum measured distance
if (high) { if (i-startwave < minClk && i < size)
high=0; minClk = i - startwave;
if (cnt > highCnt) {
if (highCnt != 0) highCnt2 = highCnt;
highCnt = cnt;
} else if (cnt > highCnt2) {
highCnt2 = cnt;
}
cnt=1;
} else {
cnt++;
}
}
} }
uint8_t tol; // set clock
for (idx=8; idx>0; idx--){ for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
tol = clk[idx]/8; if (minClk >= fndClk[clkCnt]-(fndClk[clkCnt]/8) && minClk <= fndClk[clkCnt]+1)
if (clk[idx] >= highCnt - tol && clk[idx] <= highCnt + tol) return fndClk[clkCnt];
return clk[idx];
if (clk[idx] >= highCnt2 - tol && clk[idx] <= highCnt2 + tol)
return clk[idx];
} }
return -1; return 0;
} }
// by marshmellow // by marshmellow
@ -856,45 +696,61 @@ int DetectStrongAskClock(uint8_t dest[], size_t size)
// return start index of best starting position for that clock and return clock (by reference) // return start index of best starting position for that clock and return clock (by reference)
int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr)
{ {
size_t i=0; size_t i=1;
uint8_t clk[]={8,16,32,40,50,64,100,128,255}; uint8_t clk[] = {255,8,16,32,40,50,64,100,128,255};
uint8_t clkEnd = 9;
uint8_t loopCnt = 255; //don't need to loop through entire array... uint8_t loopCnt = 255; //don't need to loop through entire array...
if (size <= loopCnt) return -1; //not enough samples if (size <= loopCnt) return -1; //not enough samples
//if we already have a valid clock quit
//if we already have a valid clock
for (;i<8;++i) uint8_t clockFnd=0;
if (clk[i] == *clock) return 0; for (;i<clkEnd;++i)
if (clk[i] == *clock) clockFnd = i;
//clock found but continue to find best startpos
//get high and low peak //get high and low peak
int peak, low; int peak, low;
if (getHiLo(dest, loopCnt, &peak, &low, 75, 75) < 1) return -1; if (getHiLo(dest, loopCnt, &peak, &low, 75, 75) < 1) return -1;
//test for large clean peaks //test for large clean peaks
if (DetectCleanAskWave(dest, size, peak, low)==1){ if (!clockFnd){
int ans = DetectStrongAskClock(dest, size); if (DetectCleanAskWave(dest, size, peak, low)==1){
for (i=7; i>0; i--){ int ans = DetectStrongAskClock(dest, size, peak, low);
if (clk[i] == ans) { for (i=clkEnd-1; i>0; i--){
*clock = ans; if (clk[i] == ans) {
return 0; *clock = ans;
//clockFnd = i;
return 0; // for strong waves i don't use the 'best start position' yet...
//break; //clock found but continue to find best startpos [not yet]
}
} }
} }
} }
uint8_t ii; uint8_t ii;
uint8_t clkCnt, tol = 0; uint8_t clkCnt, tol = 0;
uint16_t bestErr[]={1000,1000,1000,1000,1000,1000,1000,1000,1000}; uint16_t bestErr[]={1000,1000,1000,1000,1000,1000,1000,1000,1000};
uint8_t bestStart[]={0,0,0,0,0,0,0,0,0}; uint8_t bestStart[]={0,0,0,0,0,0,0,0,0};
size_t errCnt = 0; size_t errCnt = 0;
size_t arrLoc, loopEnd; size_t arrLoc, loopEnd;
if (clockFnd>0) {
clkCnt = clockFnd;
clkEnd = clockFnd+1;
}
else clkCnt=1;
//test each valid clock from smallest to greatest to see which lines up //test each valid clock from smallest to greatest to see which lines up
for(clkCnt=0; clkCnt < 8; clkCnt++){ for(; clkCnt < clkEnd; clkCnt++){
if (clk[clkCnt] == 32){ if (clk[clkCnt] <= 32){
tol=1; tol=1;
}else{ }else{
tol=0; tol=0;
} }
if (!maxErr) loopCnt=clk[clkCnt]*2; //if no errors allowed - keep start within the first clock
if (!maxErr && size > clk[clkCnt]*2 + tol && clk[clkCnt]<128) loopCnt=clk[clkCnt]*2;
bestErr[clkCnt]=1000; bestErr[clkCnt]=1000;
//try lining up the peaks by moving starting point (try first 256) //try lining up the peaks by moving starting point (try first few clocks)
for (ii=0; ii < loopCnt; ii++){ for (ii=0; ii < loopCnt; ii++){
if (dest[ii] < peak && dest[ii] > low) continue; if (dest[ii] < peak && dest[ii] > low) continue;
@ -910,11 +766,11 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr)
errCnt++; errCnt++;
} }
} }
//if we found no errors then we can stop here //if we found no errors then we can stop here and a low clock (common clocks)
// this is correct one - return this clock // this is correct one - return this clock
//PrintAndLog("DEBUG: clk %d, err %d, ii %d, i %d",clk[clkCnt],errCnt,ii,i); //PrintAndLog("DEBUG: clk %d, err %d, ii %d, i %d",clk[clkCnt],errCnt,ii,i);
if(errCnt==0 && clkCnt<6) { if(errCnt==0 && clkCnt<7) {
*clock = clk[clkCnt]; if (!clockFnd) *clock = clk[clkCnt];
return ii; return ii;
} }
//if we found errors see if it is lowest so far and save it as best run //if we found errors see if it is lowest so far and save it as best run
@ -924,9 +780,9 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr)
} }
} }
} }
uint8_t iii=0; uint8_t iii;
uint8_t best=0; uint8_t best=0;
for (iii=0; iii<8; ++iii){ for (iii=1; iii<clkEnd; ++iii){
if (bestErr[iii] < bestErr[best]){ if (bestErr[iii] < bestErr[best]){
if (bestErr[iii] == 0) bestErr[iii]=1; if (bestErr[iii] == 0) bestErr[iii]=1;
// current best bit to error ratio vs new bit to error ratio // current best bit to error ratio vs new bit to error ratio
@ -935,8 +791,8 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr)
} }
} }
} }
if (bestErr[best] > maxErr) return -1; //if (bestErr[best] > maxErr) return -1;
*clock = clk[best]; if (!clockFnd) *clock = clk[best];
return bestStart[best]; return bestStart[best];
} }
@ -1115,7 +971,7 @@ void psk1TOpsk2(uint8_t *BitStream, size_t size)
size_t i=1; size_t i=1;
uint8_t lastBit=BitStream[0]; uint8_t lastBit=BitStream[0];
for (; i<size; i++){ for (; i<size; i++){
if (BitStream[i]==77){ if (BitStream[i]==7){
//ignore errors //ignore errors
} else if (lastBit!=BitStream[i]){ } else if (lastBit!=BitStream[i]){
lastBit=BitStream[i]; lastBit=BitStream[i];
@ -1308,7 +1164,7 @@ int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int maxErr)
if (ignoreCnt == 0){ if (ignoreCnt == 0){
bitHigh = 0; bitHigh = 0;
if (errBitHigh == 1){ if (errBitHigh == 1){
dest[bitnum++] = 77; dest[bitnum++] = 7;
errCnt++; errCnt++;
} }
errBitHigh=0; errBitHigh=0;
@ -1583,7 +1439,7 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
//noise after a phase shift - ignore //noise after a phase shift - ignore
} else { //phase shift before supposed to based on clock } else { //phase shift before supposed to based on clock
errCnt++; errCnt++;
dest[numBits++] = 77; dest[numBits++] = 7;
} }
} else if (i+1 > lastClkBit + *clock + tol + fc){ } else if (i+1 > lastClkBit + *clock + tol + fc){
lastClkBit += *clock; //no phase shift but clock bit lastClkBit += *clock; //no phase shift but clock bit

View file

@ -15,34 +15,37 @@
#define LFDEMOD_H__ #define LFDEMOD_H__
#include <stdint.h> #include <stdint.h>
int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr); //generic
uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, int high, int low); int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType);
int askmandemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr); int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert);
uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo); uint32_t bytebits_to_byte(uint8_t* src, size_t numbits);
int ManchesterEncode(uint8_t *BitStream, size_t size); uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj);
int manrawdecode(uint8_t *BitStream, size_t *size); int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr);
int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert); uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low);
int askrawdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp); uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow);
int DetectNRZClock(uint8_t dest[], size_t size, int clock);
int DetectPSKClock(uint8_t dest[], size_t size, int clock);
int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low);
uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo);
int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow);
int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo);
int ManchesterEncode(uint8_t *BitStream, size_t size);
int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert);
int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int maxErr);
uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType);
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx);
int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert);
void psk2TOpsk1(uint8_t *BitStream, size_t size);
void psk1TOpsk2(uint8_t *BitStream, size_t size);
size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen);
//tag specific
int AWIDdemodFSK(uint8_t *dest, size_t *size);
int gProxII_Demod(uint8_t BitStream[], size_t *size); int gProxII_Demod(uint8_t BitStream[], size_t *size);
int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); int HIDdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo);
int IOdemodFSK(uint8_t *dest, size_t size); int IOdemodFSK(uint8_t *dest, size_t size);
int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow);
uint32_t bytebits_to_byte(uint8_t* src, size_t numbits);
int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int maxErr);
void psk1TOpsk2(uint8_t *BitStream, size_t size);
void psk2TOpsk1(uint8_t *BitStream, size_t size);
int DetectNRZClock(uint8_t dest[], size_t size, int clock);
int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert); int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert);
int PyramiddemodFSK(uint8_t *dest, size_t *size); int PyramiddemodFSK(uint8_t *dest, size_t *size);
int AWIDdemodFSK(uint8_t *dest, size_t *size);
size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen);
uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj);
uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow);
int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo);
int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo); int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo);
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx);
uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType);
int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert);
int DetectPSKClock(uint8_t dest[], size_t size, int clock);
#endif #endif