Merge pull request #216 from marshmellow42/master

EM4x05/EM4x69 command rewrite and improvements
This commit is contained in:
pwpiwi 2017-02-22 17:38:56 +01:00 committed by GitHub
commit 2d0717853d
17 changed files with 748 additions and 184 deletions

View file

@ -5,6 +5,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased]
### Added
- Added EM4x05/EM4x69 chip detection to lf search (marshmellow)
- Added lf em 4x05dump command to read and output all the blocks of the chip (marshmellow)
- Added lf em 4x05info command to read and display information about the chip (marshmellow)
- Added lf cotag read, and added it to lf search (iceman)
- Added hitag2 read UID only and added that to lf search (marshmellow)
- Added lf pyramid commands (iceman)
@ -38,6 +41,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added option c to 'hf list' (mark CRC bytes) (piwi)
### Changed
- small changes to lf psk and fsk demods to improve results when the trace begins with noise or the chip isn't broadcasting yet (marshmellow)
- NOTE CHANGED ALL `lf em4x em*` cmds to simpler `lf em ` - example: `lf em4x em410xdemod` is now `lf em 410xdemod`
- Renamed and rebuilt `lf em readword` && readwordpwd to `lf em 4x05readword` - it now demods and outputs the read block (marshmellow/iceman)
- Renamed and rebuilt `lf em writeword` && writewordpwd to `lf em 4x05writeword` - it now also reads validation output from the tag (marshmellow/iceman)
- Fixed bug in lf sim and continuous demods not turning off antenna when finished
- Fixed bug(s) in hf iclass write
- Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow)

View file

@ -1017,10 +1017,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_EM4X_READ_WORD:
EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]);
EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]);
break;
case CMD_EM4X_WRITE_WORD:
EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);

View file

@ -88,7 +88,7 @@ void T55xxWakeUp(uint32_t Pwd);
void TurnReadLFOn();
//void T55xxReadTrace(void);
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd);
void Cotag(uint32_t arg0);
/// iso14443.h

View file

@ -684,7 +684,7 @@ void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream)
for (i=0; i<size; i++){
askSimBit(BitStream[i]^invert, &n, clk, encoding);
}
if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for biphase phase)
if (encoding==0 && BitStream[0]==BitStream[size-1]){ //run a second set inverted (for ask/raw || biphase phase)
for (i=0; i<size; i++){
askSimBit(BitStream[i]^invert^1, &n, clk, encoding);
}
@ -1358,7 +1358,7 @@ void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t
//Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7)
data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (7 << T55x7_MAXBLOCK_SHIFT);
//TODO add selection of chip for Q5 or T55x7
// data[0] = (((32-2)/2)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
// data[0] = (((32-2)>>1)<<T5555_BITRATE_SHIFT) | T5555_MODULATION_PSK1 | 7 << T5555_MAXBLOCK_SHIFT;
WriteT55xx(data, 0, 8);
//Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data)
// T5567WriteBlock(0x603E10E2,0);
@ -1367,7 +1367,7 @@ void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t
// clone viking tag to T55xx
void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5) {
uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), block1, block2};
if (Q5) data[0] = (32 << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
if (Q5) data[0] = ( ((32-2)>>1) << T5555_BITRATE_SHIFT) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
// Program the data blocks for supplied ID and the block 0 config
WriteT55xx(data, 0, 3);
LED_D_OFF();
@ -1571,8 +1571,6 @@ void SendForward(uint8_t fwd_bit_count) {
fwd_write_ptr = forwardLink_data;
fwd_bit_sz = fwd_bit_count;
LED_D_ON();
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
@ -1580,9 +1578,9 @@ void SendForward(uint8_t fwd_bit_count) {
fwd_bit_sz--; //prepare next bit modulation
fwd_write_ptr++;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(55*8); //55 cycles off (8us each)for 4305
SpinDelayUs(56*8); //55 cycles off (8us each)for 4305 /another reader has 37 here...
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(16*8); //16 cycles on (8us each)
SpinDelayUs(18*8); //16 cycles on (8us each) // another reader has 18 here
// now start writting
while(fwd_bit_sz-- > 0) { //prepare next bit modulation
@ -1591,9 +1589,9 @@ void SendForward(uint8_t fwd_bit_count) {
else {
//These timings work for 4469/4269/4305 (with the 55*8 above)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(23*8); //16-4 cycles off (8us each)
SpinDelayUs(23*8); //16-4 cycles off (8us each) //23 //one reader goes as high as 25 here
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(9*8); //16 cycles on (8us each)
SpinDelayUs(16*8); //16 cycles on (8us each) //9 // another reader goes to 17 here
}
}
}
@ -1615,13 +1613,11 @@ void EM4xLogin(uint32_t Password) {
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
uint8_t fwd_bit_count;
uint8_t *dest = BigBuf_get_addr();
uint16_t bufferlength = BigBuf_max_traceLen();
uint32_t i = 0;
// Clear destination buffer before sending the command
BigBuf_Clear_ext(false);
LED_A_ON();
//If password mode do login
if (PwdMode == 1) EM4xLogin(Pwd);
@ -1629,36 +1625,28 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
fwd_bit_count = Prepare_Cmd( FWD_CMD_READ );
fwd_bit_count += Prepare_Addr( Address );
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
SendForward(fwd_bit_count);
SpinDelayUs(400);
// Now do the acquisition
i = 0;
for(;;) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
i++;
if (i >= bufferlength) break;
}
}
DoPartialAcquisition(20, true, 6000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_A_OFF();
cmd_send(CMD_ACK,0,0,0,0,0);
LED_D_OFF();
}
void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
bool PwdMode = (flag & 0xF);
uint8_t Address = (flag >> 8) & 0xFF;
uint8_t fwd_bit_count;
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_ext(false);
LED_A_ON();
//If password mode do login
if (PwdMode == 1) EM4xLogin(Pwd);
if (PwdMode) EM4xLogin(Pwd);
forward_ptr = forwardLink_data;
fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE );
@ -1668,9 +1656,15 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode
SendForward(fwd_bit_count);
//Wait for write to complete
SpinDelay(20);
//SpinDelay(10);
SpinDelayUs(6500);
//Capture response if one exists
DoPartialAcquisition(20, true, 6000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
LED_A_OFF();
cmd_send(CMD_ACK,0,0,0,0,0);
}
/*
Reading a COTAG.

View file

@ -119,11 +119,11 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
* @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples.
*/
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent)
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize)
{
//.
uint8_t *dest = BigBuf_get_addr();
int bufsize = BigBuf_max_traceLen();
bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
//memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow)
@ -213,7 +213,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent)
{
return DoAcquisition(1,8,0,trigger_threshold,silent);
return DoAcquisition(1,8,0,trigger_threshold,silent,0);
}
uint32_t DoAcquisition_config( bool silent)
{
@ -221,7 +221,12 @@ uint32_t DoAcquisition_config( bool silent)
,config.bits_per_sample
,config.averaging
,config.trigger_threshold
,silent);
,silent
,0);
}
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size) {
return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size);
}
uint32_t ReadLF(bool activeField, bool silent)

View file

@ -24,9 +24,11 @@ uint32_t SampleLF(bool silent);
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SnoopLF();
// adds sample size to default options
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size);
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
* This method is typically used by tag-specific readers who just wants to read the samples

View file

@ -22,6 +22,7 @@ command_t * CmdDataCommands();
int CmdData(const char *Cmd);
void printDemodBuff(void);
void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx);
int CmdPrintDemodBuff(const char *Cmd);
int CmdAskEM410xDemod(const char *Cmd);
int CmdVikingDemod(const char *Cmd);
int CmdG_Prox_II_Demod(const char *Cmd);

View file

@ -1078,9 +1078,29 @@ int CmdVchDemod(const char *Cmd)
return 0;
}
//by marshmellow
int CheckChipType(char cmdp) {
uint32_t wordData = 0;
//check for em4x05/em4x69 chips first
save_restoreGB(1);
if ((!offline && (cmdp != '1')) && EM4x05Block0Test(&wordData)) {
PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nTry lf em 4x05... commands\n");
save_restoreGB(0);
return 1;
}
//TODO check for t55xx chip...
save_restoreGB(0);
return 1;
}
//by marshmellow
int CmdLFfind(const char *Cmd)
{
uint32_t wordData = 0;
int ans=0;
size_t minLength = 1000;
char cmdp = param_getchar(Cmd, 0);
@ -1116,6 +1136,11 @@ int CmdLFfind(const char *Cmd)
if (graphJustNoise(GraphBuffer, testLen)) {
// only run these tests if we are in online mode
if (!offline && (cmdp != '1')) {
// test for em4x05 in reader talk first mode.
if (EM4x05Block0Test(&wordData)) {
PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n");
return 1;
}
ans=CmdLFHitagReader("26");
if (ans==0) {
return 1;
@ -1132,49 +1157,49 @@ int CmdLFfind(const char *Cmd)
ans=CmdFSKdemodIO("");
if (ans>0) {
PrintAndLog("\nValid IO Prox ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdFSKdemodPyramid("");
if (ans>0) {
PrintAndLog("\nValid Pyramid ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdFSKdemodParadox("");
if (ans>0) {
PrintAndLog("\nValid Paradox ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdFSKdemodAWID("");
if (ans>0) {
PrintAndLog("\nValid AWID ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdFSKdemodHID("");
if (ans>0) {
PrintAndLog("\nValid HID Prox ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdAskEM410xDemod("");
if (ans>0) {
PrintAndLog("\nValid EM410x ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdG_Prox_II_Demod("");
if (ans>0) {
PrintAndLog("\nValid G Prox II ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdFDXBdemodBI("");
if (ans>0) {
PrintAndLog("\nValid FDX-B ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=EM4x50Read("", false);
@ -1186,24 +1211,25 @@ int CmdLFfind(const char *Cmd)
ans=CmdVikingDemod("");
if (ans>0) {
PrintAndLog("\nValid Viking ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdIndalaDecode("");
if (ans>0) {
PrintAndLog("\nValid Indala ID Found!");
return 1;
return CheckChipType(cmdp);
}
ans=CmdPSKNexWatch("");
if (ans>0) {
PrintAndLog("\nValid NexWatch ID Found!");
return 1;
return CheckChipType(cmdp);
}
PrintAndLog("\nNo Known Tags Found!\n");
if (testRaw=='u' || testRaw=='U'){
//test unknown tag formats (raw mode)
ans=CheckChipType(cmdp);
//test unknown tag formats (raw mode)0
PrintAndLog("\nChecking for Unknown tags:\n");
ans=AutoCorrelate(4000, FALSE, FALSE);
if (ans > 0) PrintAndLog("Possible Auto Correlation of %d repeating samples",ans);
@ -1239,7 +1265,7 @@ static command_t CommandTable[] =
{"help", CmdHelp, 1, "This help"},
{"awid", CmdLFAWID, 1, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, 1, "{ COTAG RFIDs... }"},
{"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
{"em", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
{"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
{"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
{"io", CmdLFIO, 1, "{ ioProx tags... }"},

View file

@ -140,7 +140,7 @@ int CmdAWIDClone(const char *Cmd) {
if (sscanf(Cmd, "%u %u", &fc, &cn ) != 2) return usage_lf_awid_clone();
if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q')
blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 50<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | ((50-2)>>1)<<T5555_BITRATE_SHIFT | 3<<T5555_MAXBLOCK_SHIFT;
if ((fc & 0xFF) != fc) {
fc &= 0xFF;

View file

@ -18,6 +18,7 @@
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdmain.h"
#include "cmdlfem4x.h"
#include "lfdemod.h"
@ -71,9 +72,9 @@ int CmdEM410xSim(const char *Cmd)
uint8_t uid[5] = {0x00};
if (cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: lf em4x em410xsim <UID> <clock>");
PrintAndLog("Usage: lf em 410xsim <UID> <clock>");
PrintAndLog("");
PrintAndLog(" sample: lf em4x em410xsim 0F0368568B");
PrintAndLog(" sample: lf em 410xsim 0F0368568B");
return 0;
}
/* clock is 64 in EM410x tags */
@ -227,6 +228,7 @@ int CmdEM410xWrite(const char *Cmd)
return 0;
}
//**************** Start of EM4x50 Code ************************
bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
{
if (rows*cols>size) return false;
@ -285,7 +287,7 @@ uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool
}
return code;
}
/* Read the transmitted data of an EM4x50 tag
/* Read the transmitted data of an EM4x50 tag from the graphbuffer
* Format:
*
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
@ -498,116 +500,497 @@ int CmdEM4x50Read(const char *Cmd)
return EM4x50Read(Cmd, true);
}
int CmdReadWord(const char *Cmd)
{
int Word = -1; //default to invalid word
UsbCommand c;
sscanf(Cmd, "%d", &Word);
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
PrintAndLog("Reading word %d", Word);
c.cmd = CMD_EM4X_READ_WORD;
c.d.asBytes[0] = 0x0; //Normal mode
c.arg[0] = 0;
c.arg[1] = Word;
c.arg[2] = 0;
SendCommand(&c);
//**************** Start of EM4x05/EM4x69 Code ************************
int usage_lf_em_read(void) {
PrintAndLog("Read EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLog("");
PrintAndLog("Usage: lf em 4x05readword [h] <address> <pwd>");
PrintAndLog("Options:");
PrintAndLog(" h - this help");
PrintAndLog(" address - memory address to read. (0-15)");
PrintAndLog(" pwd - password (hex) (optional)");
PrintAndLog("samples:");
PrintAndLog(" lf em 4x05readword 1");
PrintAndLog(" lf em 4x05readword 1 11223344");
return 0;
}
int CmdReadWordPWD(const char *Cmd)
{
int Word = -1; //default to invalid word
int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c;
sscanf(Cmd, "%d %x", &Word, &Password);
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
// for command responses from em4x05 or em4x69
// download samples from device and copy them to the Graphbuffer
bool downloadSamplesEM() {
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
uint8_t got[6000];
GetFromBigBuf(got, sizeof(got), 0);
if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) {
PrintAndLog("command execution time out");
return false;
}
setGraphBuf(got, sizeof(got));
return true;
}
PrintAndLog("Reading word %d with password %08X", Word, Password);
bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) {
// em4x05/em4x69 command response preamble is 00001010
// skip first two 0 bits as they might have been missed in the demod
uint8_t preamble[] = {0,0,1,0,1,0};
size_t startIdx = 0;
c.cmd = CMD_EM4X_READ_WORD;
c.d.asBytes[0] = 0x1; //Password mode
c.arg[0] = 0;
c.arg[1] = Word;
c.arg[2] = Password;
// set size to 20 to only test first 14 positions for the preamble or less if not a read command
size_t size = (readCmd) ? 20 : 11;
// sanity check
size = (size > DemodBufferLen) ? DemodBufferLen : size;
// test preamble
if ( !onePreambleSearch(DemodBuffer, preamble, sizeof(preamble), size, &startIdx) ) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305 preamble not found :: %d", startIdx);
return false;
}
// if this is a readword command, get the read bytes and test the parities
if (readCmd) {
if (!EM_EndParityTest(DemodBuffer + startIdx + sizeof(preamble), 45, 5, 9, 0)) {
if (g_debugMode) PrintAndLog("DEBUG: Error - End Parity check failed");
return false;
}
// test for even parity bits.
if ( removeParity(DemodBuffer, startIdx + sizeof(preamble),9,0,44) == 0 ) {
if (g_debugMode) PrintAndLog("DEBUG: Error - Parity not detected");
return false;
}
setDemodBuf(DemodBuffer, 40, 0);
*word = bytebits_to_byteLSBF(DemodBuffer, 32);
}
return true;
}
// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE
// should cover 90% of known used configs
// the rest will need to be manually demoded for now...
int demodEM4x05resp(uint32_t *word, bool readCmd) {
int ans = 0;
// test for FSK wave (easiest to 99% ID)
if (GetFskClock("", false, false)) {
//valid fsk clocks found
ans = FSKrawDemod("0 0", false);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: FSK Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
}
// PSK clocks should be easy to detect ( but difficult to demod a non-repeating pattern... )
ans = GetPskClock("", false, false);
if (ans>0) {
//try psk1
ans = PSKDemod("0 0 6", false);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
} else {
//try psk2
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
//try psk1 inverted
ans = PSKDemod("0 1 6", false);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
} else {
//try psk2
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
}
}
}
// manchester is more common than biphase... try first
bool stcheck = false;
// try manchester - NOTE: ST only applies to T55x7 tags.
ans = ASKDemod_ext("0,0,1", false, false, 1, &stcheck);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/Manchester Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
//try biphase
ans = ASKbiphaseDemod("0 0 1", false);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
//try diphase (differential biphase or inverted)
ans = ASKbiphaseDemod("0 1 1", false);
if (!ans) {
if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
} else {
if (EM4x05testDemodReadData(word, readCmd)) {
return 1;
}
}
return -1;
}
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData) {
UsbCommand c = {CMD_EM4X_READ_WORD, {addr, pwd, usePwd}};
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)){
PrintAndLog("Command timed out");
return -1;
}
if ( !downloadSamplesEM() ) {
return -1;
}
int testLen = (GraphTraceLen < 1000) ? GraphTraceLen : 1000;
if (graphJustNoise(GraphBuffer, testLen)) {
PrintAndLog("no tag not found");
return -1;
}
//attempt demod:
return demodEM4x05resp(wordData, true);
}
int EM4x05ReadWord(uint8_t addr, uint32_t pwd, bool usePwd) {
uint32_t wordData = 0;
int success = EM4x05ReadWord_ext(addr, pwd, usePwd, &wordData);
if (success == 1)
PrintAndLog("%s Address %02d | %08X", (addr>13) ? "Lock":" Got",addr,wordData);
else
PrintAndLog("Read Address %02d | failed",addr);
return success;
}
int CmdEM4x05ReadWord(const char *Cmd) {
uint8_t addr;
uint32_t pwd;
bool usePwd = false;
uint8_t ctmp = param_getchar(Cmd, 0);
if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_read();
addr = param_get8ex(Cmd, 0, 50, 10);
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
pwd = param_get32ex(Cmd, 1, 1, 16);
if ( (addr > 15) ) {
PrintAndLog("Address must be between 0 and 15");
return 1;
}
if ( pwd == 1 ) {
PrintAndLog("Reading address %02u", addr);
} else {
usePwd = true;
PrintAndLog("Reading address %02u | password %08X", addr, pwd);
}
return EM4x05ReadWord(addr, pwd, usePwd);
}
int usage_lf_em_dump(void) {
PrintAndLog("Dump EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLog("");
PrintAndLog("Usage: lf em 4x05dump [h] <pwd>");
PrintAndLog("Options:");
PrintAndLog(" h - this help");
PrintAndLog(" pwd - password (hex) (optional)");
PrintAndLog("samples:");
PrintAndLog(" lf em 4x05dump");
PrintAndLog(" lf em 4x05dump 11223344");
return 0;
}
int CmdWriteWord(const char *Cmd)
{
int Word = 16; //default to invalid block
int Data = 0xFFFFFFFF; //default to blank data
UsbCommand c;
int CmdEM4x05dump(const char *Cmd) {
uint8_t addr = 0;
uint32_t pwd;
bool usePwd = false;
uint8_t ctmp = param_getchar(Cmd, 0);
if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
sscanf(Cmd, "%x %d", &Data, &Word);
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
pwd = param_get32ex(Cmd, 0, 1, 16);
if (Word > 15) {
PrintAndLog("Word must be between 0 and 15");
return 1;
if ( pwd != 1 ) {
usePwd = true;
}
int success = 1;
for (; addr < 16; addr++) {
if (addr == 2) {
if (usePwd) {
PrintAndLog(" PWD Address %02u | %08X",addr,pwd);
} else {
PrintAndLog(" PWD Address 02 | cannot read");
}
} else {
success &= EM4x05ReadWord(addr, pwd, usePwd);
}
}
PrintAndLog("Writing word %d with data %08X", Word, Data);
return success;
}
c.cmd = CMD_EM4X_WRITE_WORD;
c.d.asBytes[0] = 0x0; //Normal mode
c.arg[0] = Data;
c.arg[1] = Word;
c.arg[2] = 0;
SendCommand(&c);
int usage_lf_em_write(void) {
PrintAndLog("Write EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLog("");
PrintAndLog("Usage: lf em 4x05writeword [h] <address> <data> <pwd>");
PrintAndLog("Options:");
PrintAndLog(" h - this help");
PrintAndLog(" address - memory address to write to. (0-15)");
PrintAndLog(" data - data to write (hex)");
PrintAndLog(" pwd - password (hex) (optional)");
PrintAndLog("samples:");
PrintAndLog(" lf em 4x05writeword 1");
PrintAndLog(" lf em 4x05writeword 1 deadc0de 11223344");
return 0;
}
int CmdWriteWordPWD(const char *Cmd)
{
int Word = 16; //default to invalid word
int Data = 0xFFFFFFFF; //default to blank data
int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c;
int CmdEM4x05WriteWord(const char *Cmd) {
uint8_t ctmp = param_getchar(Cmd, 0);
if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write();
sscanf(Cmd, "%x %d %x", &Data, &Word, &Password);
bool usePwd = false;
uint8_t addr = 16; // default to invalid address
uint32_t data = 0xFFFFFFFF; // default to blank data
uint32_t pwd = 0xFFFFFFFF; // default to blank password
addr = param_get8ex(Cmd, 0, 16, 10);
data = param_get32ex(Cmd, 1, 0, 16);
pwd = param_get32ex(Cmd, 2, 1, 16);
if ( (addr > 15) ) {
PrintAndLog("Address must be between 0 and 15");
return 1;
}
if ( pwd == 1 )
PrintAndLog("Writing address %d data %08X", addr, data);
else {
usePwd = true;
PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);
}
uint16_t flag = (addr << 8 ) | usePwd;
UsbCommand c = {CMD_EM4X_WRITE_WORD, {flag, data, pwd}};
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
PrintAndLog("Error occurred, device did not respond during write operation.");
return -1;
}
if ( !downloadSamplesEM() ) {
return -1;
}
//check response for 00001010 for write confirmation!
//attempt demod:
uint32_t dummy = 0;
int result = demodEM4x05resp(&dummy,false);
if (result == 1) {
PrintAndLog("Write Verified");
} else {
PrintAndLog("Write could not be verified");
}
return result;
}
void printEM4x05config(uint32_t wordData) {
uint16_t datarate = (((wordData & 0x3F)+1)*2);
uint8_t encoder = ((wordData >> 6) & 0xF);
char enc[14];
memset(enc,0,sizeof(enc));
uint8_t PSKcf = (wordData >> 10) & 0x3;
char cf[10];
memset(cf,0,sizeof(cf));
uint8_t delay = (wordData >> 12) & 0x3;
char cdelay[33];
memset(cdelay,0,sizeof(cdelay));
uint8_t LWR = (wordData >> 14) & 0xF; //last word read
switch (encoder) {
case 0: snprintf(enc,sizeof(enc),"NRZ"); break;
case 1: snprintf(enc,sizeof(enc),"Manchester"); break;
case 2: snprintf(enc,sizeof(enc),"Biphase"); break;
case 3: snprintf(enc,sizeof(enc),"Miller"); break;
case 4: snprintf(enc,sizeof(enc),"PSK1"); break;
case 5: snprintf(enc,sizeof(enc),"PSK2"); break;
case 6: snprintf(enc,sizeof(enc),"PSK3"); break;
case 7: snprintf(enc,sizeof(enc),"Unknown"); break;
case 8: snprintf(enc,sizeof(enc),"FSK1"); break;
case 9: snprintf(enc,sizeof(enc),"FSK2"); break;
default: snprintf(enc,sizeof(enc),"Unknown"); break;
}
switch (PSKcf) {
case 0: snprintf(cf,sizeof(cf),"RF/2"); break;
case 1: snprintf(cf,sizeof(cf),"RF/8"); break;
case 2: snprintf(cf,sizeof(cf),"RF/4"); break;
case 3: snprintf(cf,sizeof(cf),"unknown"); break;
}
switch (delay) {
case 0: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
case 1: snprintf(cdelay, sizeof(cdelay),"BP/8 or 1/8th bit period delay"); break;
case 2: snprintf(cdelay, sizeof(cdelay),"BP/4 or 1/4th bit period delay"); break;
case 3: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
}
PrintAndLog("ConfigWord: %08X (Word 4)\n", wordData);
PrintAndLog("Config Breakdown:", wordData);
PrintAndLog(" Data Rate: %02u | RF/%u", wordData & 0x3F, datarate);
PrintAndLog(" Encoder: %u | %s", encoder, enc);
PrintAndLog(" PSK CF: %u | %s", PSKcf, cf);
PrintAndLog(" Delay: %u | %s", delay, cdelay);
PrintAndLog(" LastWordR: %02u | Address of last word for default read", LWR);
PrintAndLog(" ReadLogin: %u | Read Login is %s", (wordData & 0x40000)>>18, (wordData & 0x40000) ? "Required" : "Not Required");
PrintAndLog(" ReadHKL: %u | Read Housekeeping Words Login is %s", (wordData & 0x80000)>>19, (wordData & 0x80000) ? "Required" : "Not Required");
PrintAndLog("WriteLogin: %u | Write Login is %s", (wordData & 0x100000)>>20, (wordData & 0x100000) ? "Required" : "Not Required");
PrintAndLog(" WriteHKL: %u | Write Housekeeping Words Login is %s", (wordData & 0x200000)>>21, (wordData & 0x200000) ? "Required" : "Not Required");
PrintAndLog(" R.A.W.: %u | Read After Write is %s", (wordData & 0x400000)>>22, (wordData & 0x400000) ? "On" : "Off");
PrintAndLog(" Disable: %u | Disable Command is %s", (wordData & 0x800000)>>23, (wordData & 0x800000) ? "Accepted" : "Not Accepted");
PrintAndLog(" R.T.F.: %u | Reader Talk First is %s", (wordData & 0x1000000)>>24, (wordData & 0x1000000) ? "Enabled" : "Disabled");
PrintAndLog(" Pigeon: %u | Pigeon Mode is %s\n", (wordData & 0x4000000)>>26, (wordData & 0x4000000) ? "Enabled" : "Disabled");
}
void printEM4x05info(uint8_t chipType, uint8_t cap, uint16_t custCode, uint32_t serial) {
switch (chipType) {
case 9: PrintAndLog("\n Chip Type: %u | EM4305", chipType); break;
case 4: PrintAndLog(" Chip Type: %u | Unknown", chipType); break;
case 2: PrintAndLog(" Chip Type: %u | EM4469", chipType); break;
//add more here when known
default: PrintAndLog(" Chip Type: %u Unknown", chipType); break;
}
switch (cap) {
case 3: PrintAndLog(" Cap Type: %u | 330pF",cap); break;
case 2: PrintAndLog(" Cap Type: %u | %spF",cap, (chipType==2)? "75":"210"); break;
case 1: PrintAndLog(" Cap Type: %u | 250pF",cap); break;
case 0: PrintAndLog(" Cap Type: %u | no resonant capacitor",cap); break;
default: PrintAndLog(" Cap Type: %u | unknown",cap); break;
}
PrintAndLog(" Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default": "Unknown");
if (serial != 0) {
PrintAndLog("\n Serial #: %08X\n", serial);
}
}
void printEM4x05ProtectionBits(uint32_t wordData) {
for (uint8_t i = 0; i < 15; i++) {
PrintAndLog(" Word: %02u | %s", i, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
if (i==14) {
PrintAndLog(" Word: %02u | %s", i+1, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
}
}
}
//quick test for EM4x05/EM4x69 tag
bool EM4x05Block0Test(uint32_t *wordData) {
if (EM4x05ReadWord_ext(0,0,false,wordData) == 1) {
return true;
}
return false;
}
int CmdEM4x05info(const char *Cmd) {
//uint8_t addr = 0;
uint32_t pwd;
uint32_t wordData = 0;
bool usePwd = false;
uint8_t ctmp = param_getchar(Cmd, 0);
if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
pwd = param_get32ex(Cmd, 0, 1, 16);
if ( pwd != 1 ) {
usePwd = true;
}
// read word 0 (chip info)
// block 0 can be read even without a password.
if ( !EM4x05Block0Test(&wordData) )
return -1;
uint8_t chipType = (wordData >> 1) & 0xF;
uint8_t cap = (wordData >> 5) & 3;
uint16_t custCode = (wordData >> 9) & 0x3FF;
// read word 1 (serial #) doesn't need pwd
wordData = 0;
if (EM4x05ReadWord_ext(1, 0, false, &wordData) != 1) {
//failed, but continue anyway...
}
printEM4x05info(chipType, cap, custCode, wordData);
// read word 4 (config block)
// needs password if one is set
wordData = 0;
if ( EM4x05ReadWord_ext(4, pwd, usePwd, &wordData) != 1 ) {
//failed
return 0;
}
printEM4x05config(wordData);
// read word 14 and 15 to see which is being used for the protection bits
wordData = 0;
if ( EM4x05ReadWord_ext(14, pwd, usePwd, &wordData) != 1 ) {
//failed
return 0;
}
// if status bit says this is not the used protection word
if (!(wordData & 0x8000)) {
if ( EM4x05ReadWord_ext(15, pwd, usePwd, &wordData) != 1 ) {
//failed
return 0;
}
}
if (!(wordData & 0x8000)) {
//something went wrong
return 0;
}
printEM4x05ProtectionBits(wordData);
if (Word > 15) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
c.cmd = CMD_EM4X_WRITE_WORD;
c.d.asBytes[0] = 0x1; //Password mode
c.arg[0] = Data;
c.arg[1] = Word;
c.arg[2] = Password;
SendCommand(&c);
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"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 in GraphBuffer"},
{"em410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
{"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)" },
{"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"},
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
{"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
{"410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
{"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
{"410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
{"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"4x05dump", CmdEM4x05dump, 0, "(pwd) -- Read EM4x05/EM4x69 all word data"},
{"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"},
{"4x05readword", CmdEM4x05ReadWord, 0, "<Word> (pwd) -- Read EM4x05/EM4x69 word data"},
{"4x05writeword", CmdEM4x05WriteWord, 0, "<Word> <data> (pwd) -- Write EM4x05/EM4x69 word data"},
{"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"},
{NULL, NULL, 0, NULL}
};

View file

@ -18,11 +18,14 @@ int CmdEM410xWatch(const char *Cmd);
int CmdEM410xWatchnSpoof(const char *Cmd);
int CmdEM410xWrite(const char *Cmd);
int CmdEM4x50Read(const char *Cmd);
int CmdLFEM4X(const char *Cmd);
int CmdReadWord(const char *Cmd);
int CmdReadWordPWD(const char *Cmd);
int CmdWriteWord(const char *Cmd);
int CmdWriteWordPWD(const char *Cmd);
int EM4x50Read(const char *Cmd, bool verbose);
int CmdLFEM4X(const char *Cmd);
bool EM4x05Block0Test(uint32_t *wordData);
int CmdEM4x05info(const char *Cmd);
int CmdEM4x05WriteWord(const char *Cmd);
int CmdEM4x05dump(const char *Cmd);
int CmdEM4x05ReadWord(const char *Cmd);
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData);
#endif

View file

@ -178,7 +178,7 @@ int CmdPrescoClone(const char *Cmd) {
if (GetWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == -1) return usage_lf_presco_clone();
if (Q5)
blocks[0] = T5555_MODULATION_MANCHESTER | 32<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
blocks[0] = T5555_MODULATION_MANCHESTER | ((32-2)>>1)<<T5555_BITRATE_SHIFT | 4<<T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF;

View file

@ -14,6 +14,7 @@
#include "ui.h"
#include "graph.h"
#include "lfdemod.h"
#include "cmddata.h" //for g_debugmode
int GraphBuffer[MAX_GRAPH_TRACE_LEN];
int GraphTraceLen;
@ -255,7 +256,7 @@ uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose)
if (size==0) return 0;
uint16_t ans = countFC(BitStream, size, 1);
if (ans==0) {
if (verbose) PrintAndLog("DEBUG: No data found");
if (verbose || g_debugMode) PrintAndLog("DEBUG: No data found");
return 0;
}
*fc1 = (ans >> 8) & 0xFF;
@ -263,7 +264,7 @@ uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose)
*rf1 = detectFSKClk(BitStream, size, *fc1, *fc2);
if (*rf1==0) {
if (verbose) PrintAndLog("DEBUG: Clock detect error");
if (verbose || g_debugMode) PrintAndLog("DEBUG: Clock detect error");
return 0;
}
return 1;

View file

@ -110,6 +110,23 @@ void print_hex(const uint8_t * data, const size_t len)
printf("\n");
}
void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
int rownum = 0;
printf("[%02d] | ", rownum);
for (int i = 0; i < len; ++i) {
printf("%02X ", data[i]);
// check if a line break is needed
if ( breaks > 0 && !((i+1) % breaks) && (i+1 < len) ) {
++rownum;
printf("\n[%02d] | ", rownum);
}
}
printf("\n");
}
char *sprint_hex(const uint8_t *data, const size_t len) {
int maxLen = ( len > 1024/3) ? 1024/3 : len;
@ -139,7 +156,7 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea
size_t in_index = 0;
// loop through the out_index to make sure we don't go too far
for (size_t out_index=0; out_index < max_len; out_index++) {
for (size_t out_index=0; out_index < max_len-1; out_index++) {
// set character - (should be binary but verify it isn't more than 1 digit)
if (data[in_index]<10)
sprintf(tmp++, "%u", (unsigned int) data[in_index]);
@ -158,6 +175,41 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea
char *sprint_bin(const uint8_t *data, const size_t len) {
return sprint_bin_break(data, len, 0);
}
char *sprint_hex_ascii(const uint8_t *data, const size_t len) {
static char buf[1024];
char *tmp = buf;
memset(buf, 0x00, 1024);
size_t max_len = (len > 1010) ? 1010 : len;
sprintf(tmp, "%s| ", sprint_hex(data, max_len) );
size_t i = 0;
size_t pos = (max_len * 3)+2;
while(i < max_len){
char c = data[i];
if ( (c < 32) || (c == 127))
c = '.';
sprintf(tmp+pos+i, "%c", c);
++i;
}
return buf;
}
char *sprint_ascii(const uint8_t *data, const size_t len) {
static char buf[1024];
char *tmp = buf;
memset(buf, 0x00, 1024);
size_t max_len = (len > 1010) ? 1010 : len;
size_t i = 0;
while(i < max_len){
char c = data[i];
tmp[i] = ((c < 32) || (c == 127)) ? '.' : c;
++i;
}
return buf;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
@ -184,6 +236,15 @@ void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) {
}
}
//least significant bit first
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
for(int i = 0 ; i < len ; ++i) {
dest[i] = n & 1;
n >>= 1;
}
}
// aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
// to
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
@ -200,6 +261,16 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS
return tmp;
}
// takes a uint8_t src array, for len items and reverses the byte order in blocksizes (8,16,32,64),
// returns: the dest array contains the reordered src array.
void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest){
for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
for (size_t i = 0; i < blockSize; i++){
dest[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)];
}
}
}
//assumes little endian
char * printBits(size_t const size, void const * const ptr)
{
@ -332,8 +403,6 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base)
return strtoull(&line[bg], NULL, base);
else
return deflt;
return 0;
}
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt)
@ -490,6 +559,7 @@ void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length)
*(target)= GetParity(source + length / 2, ODD, length / 2);
}
// xor two arrays together for len items. The dst array contains the new xored values.
void xor(unsigned char *dst, unsigned char *src, size_t len) {
for( ; len > 0; len--,dst++,src++)
*dst ^= *src;

View file

@ -13,7 +13,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <time.h> //time, gmtime
#include "data.h" //for FILE_PATH_SIZE
#ifndef ROTR
@ -42,12 +42,16 @@ void print_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_break(const uint8_t *data, const size_t len, const uint8_t breaks);
char * sprint_hex_ascii(const uint8_t *data, const size_t len);
char * sprint_ascii(const uint8_t *data, const size_t len);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
char * printBits(size_t const size, void const * const ptr);
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
char param_getchar(const char *line, int paramnum);
int param_getptr(const char *line, int *bg, int *en, int paramnum);

View file

@ -62,7 +62,7 @@ uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType)
for (uint8_t i = 0; i < bitLen; i++){
ans ^= ((bits >> i) & 1);
}
//PrintAndLog("DEBUG: ans: %d, ptype: %d",ans,pType);
if (g_debugMode) prnt("DEBUG: ans: %d, ptype: %d, bits: %08X",ans,pType,bits);
return (ans == pType);
}
@ -78,6 +78,8 @@ size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t p
parityWd = (parityWd << 1) | BitStream[startIdx+word+bit];
BitStream[j++] = (BitStream[startIdx+word+bit]);
}
if (word+pLen >= bLen) break;
j--; // overwrite parity with next data
// if parity fails then return 0
switch (pType) {
@ -148,6 +150,9 @@ uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits)
//search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx)
{
// Sanity check. If preamble length is bigger than bitstream length.
if ( *size <= pLen ) return 0;
uint8_t foundCnt=0;
for (int idx=0; idx < *size - pLen; idx++){
if (memcmp(BitStream+idx, preamble, pLen) == 0){
@ -165,6 +170,49 @@ uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_
return 0;
}
// search for given preamble in given BitStream and return success=1 or fail=0 and startIndex (where it was found)
// does not look for a repeating preamble
// em4x05/4x69 only sends preamble once, so look for it once in the first pLen bits
// leave it generic so it could be reused later...
bool onePreambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t size, size_t *startIdx) {
// Sanity check. If preamble length is bigger than bitstream length.
if ( size <= pLen ) return false;
for (size_t idx = 0; idx < size - pLen; idx++) {
if (memcmp(BitStream+idx, preamble, pLen) == 0) {
if (g_debugMode) prnt("DEBUG: preamble found at %u", idx);
*startIdx = idx;
return true;
}
}
return false;
}
// find start of modulating data (for fsk and psk) in case of beginning noise or slow chip startup.
size_t findModStart(uint8_t dest[], size_t size, uint8_t threshold_value, uint8_t expWaveSize) {
size_t i = 0;
size_t waveSizeCnt = 0;
uint8_t thresholdCnt = 0;
bool isAboveThreshold = dest[i++] >= threshold_value;
for (; i < size-20; i++ ) {
if(dest[i] < threshold_value && isAboveThreshold) {
thresholdCnt++;
if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;
isAboveThreshold = false;
waveSizeCnt = 0;
} else if (dest[i] >= threshold_value && !isAboveThreshold) {
thresholdCnt++;
if (thresholdCnt > 2 && waveSizeCnt < expWaveSize+1) break;
isAboveThreshold = true;
waveSizeCnt = 0;
} else {
waveSizeCnt++;
}
if (thresholdCnt > 10) break;
}
if (g_debugMode == 2) prnt("DEBUG: threshold Count reached at %u, count: %u",i, thresholdCnt);
return i;
}
//by marshmellow
//takes 1s and 0s and searches for EM410x format - output EM ID
uint8_t Em410xDecode(uint8_t *BitStream, size_t *size, size_t *startIdx, uint32_t *hi, uint64_t *lo)
@ -474,7 +522,6 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
{
size_t last_transition = 0;
size_t idx = 1;
//uint32_t maxVal=0;
if (fchigh==0) fchigh=10;
if (fclow==0) fclow=8;
//set the threshold close to 0 (graph) or 128 std to avoid static
@ -482,19 +529,22 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
size_t preLastSample = 0;
size_t LastSample = 0;
size_t currSample = 0;
// sync to first lo-hi transition, and threshold
if ( size < 1024 ) return 0; // not enough samples
//find start of modulating data in trace
idx = findModStart(dest, size, threshold_value, fchigh);
// Need to threshold first sample
// skip 160 samples to allow antenna/samples to settle
if(dest[160] < threshold_value) dest[0] = 0;
if(dest[idx] < threshold_value) dest[0] = 0;
else dest[0] = 1;
idx++;
size_t numBits = 0;
// count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
// or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere
// between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
// (could also be fc/5 && fc/7 for fsk1 = 4-9)
for(idx = 161; idx < size-20; idx++) {
for(; idx < size-20; idx++) {
// threshold current value
if (dest[idx] < threshold_value) dest[idx] = 0;
@ -509,13 +559,14 @@ size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow
//do nothing with extra garbage
} else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves (or 3-6 = 5)
//correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5)
if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample == 0 )){
if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1))){
dest[numBits-1]=1;
}
dest[numBits++]=1;
} else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage
//do nothing with beginning garbage
} else if (currSample > (fchigh+1) && numBits < 3) { //12 + and first two bit = unusable garbage
//do nothing with beginning garbage and reset.. should be rare..
numBits = 0;
} else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's)
dest[numBits++]=1;
} else { //9+ = 10 sample waves (or 6+ = 7)
@ -1292,7 +1343,10 @@ uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fc
continue;
// else new peak
// if we got less than the small fc + tolerance then set it to the small fc
if (fcCounter < fcLow+fcTol)
// if it is inbetween set it to the last counter
if (fcCounter < fcHigh && fcCounter > fcLow)
fcCounter = lastFCcnt;
else if (fcCounter < fcLow+fcTol)
fcCounter = fcLow;
else //set it to the large fc
fcCounter = fcHigh;
@ -1358,7 +1412,7 @@ uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fc
}
}
if (ii<0) return 0; // oops we went too far
if (ii<2) return 0; // oops we went too far
return clk[ii];
}
@ -1375,7 +1429,7 @@ uint16_t countFC(uint8_t *BitStream, size_t size, uint8_t fskAdj)
uint8_t lastFCcnt = 0;
uint8_t fcCounter = 0;
size_t i;
if (size == 0) return 0;
if (size < 180) return 0;
// prime i to first up transition
for (i = 160; i < size-20; i++)
@ -1462,27 +1516,37 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
size_t numBits=0;
uint8_t curPhase = *invert;
size_t i, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
uint8_t fc=0, fullWaveLen=0, tol=1;
uint16_t errCnt=0, waveLenCnt=0;
fc = countFC(dest, *size, 0);
size_t i=0, waveStart=1, waveEnd=0, firstFullWave=0, lastClkBit=0;
uint16_t fc=0, fullWaveLen=0, tol=1;
uint16_t errCnt=0, waveLenCnt=0, errCnt2=0;
fc = countFC(dest, *size, 1);
uint8_t fc2 = fc >> 8;
if (fc2 == 10) return -1; //fsk found - quit
fc = fc & 0xFF;
if (fc!=2 && fc!=4 && fc!=8) return -1;
//PrintAndLog("DEBUG: FC: %d",fc);
*clock = DetectPSKClock(dest, *size, *clock);
if (*clock == 0) return -1;
int avgWaveVal=0, lastAvgWaveVal=0;
//find start of modulating data in trace
uint8_t threshold_value = 123; //-5
i = findModStart(dest, *size, threshold_value, fc);
//find first phase shift
for (i=0; i<loopCnt; i++){
int avgWaveVal=0, lastAvgWaveVal=0;
waveStart = i;
for (; i<loopCnt; i++) {
// find peak
if (dest[i]+fc < dest[i+1] && dest[i+1] >= dest[i+2]){
waveEnd = i+1;
//PrintAndLog("DEBUG: waveEnd: %d",waveEnd);
if (g_debugMode == 2) prnt("DEBUG PSK: waveEnd: %u, waveStart: %u",waveEnd, waveStart);
waveLenCnt = waveEnd-waveStart;
if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+2)){ //not first peak and is a large wave but not out of whack
if (waveLenCnt > fc && waveStart > fc && !(waveLenCnt > fc+3)){ //not first peak and is a large wave but not out of whack
lastAvgWaveVal = avgWaveVal/(waveLenCnt);
firstFullWave = waveStart;
fullWaveLen=waveLenCnt;
//if average wave value is > graph 0 then it is an up wave or a 1
if (lastAvgWaveVal > 123) curPhase ^= 1; //fudge graph 0 a little 123 vs 128
//if average wave value is > graph 0 then it is an up wave or a 1 (could cause inverting)
if (lastAvgWaveVal > threshold_value) curPhase ^= 1;
break;
}
waveStart = i+1;
@ -1503,7 +1567,7 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
//set start of wave as clock align
lastClkBit = firstFullWave;
if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen);
if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
if (g_debugMode==2) prnt("DEBUG PSK: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
waveStart = 0;
dest[numBits++] = curPhase; //set first read bit
for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){
@ -1534,6 +1598,9 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
} else if (i+1 > lastClkBit + *clock + tol + fc){
lastClkBit += *clock; //no phase shift but clock bit
dest[numBits++] = curPhase;
} else if (waveLenCnt < fc - 1) { //wave is smaller than field clock (shouldn't happen often)
errCnt2++;
if(errCnt2 > 101) return errCnt2;
}
avgWaveVal = 0;
waveStart = i+1;

View file

@ -39,6 +39,7 @@ int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert);
int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert);
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);
bool onePreambleSearch(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);