diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 35c9e5bf..237d3008 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1055,6 +1055,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_PCF7931_WRITE: 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_PCF7931_BRUTEFORCE: + BruteForcePCF7931(c->arg[0], (c->arg[1] & 0xFF), c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128); + break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]); break; diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index e4ba1da5..d5f630cc 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -8,7 +8,7 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -int DemodPCF7931(uint8_t **outBlocks) { +size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; @@ -18,13 +18,12 @@ int DemodPCF7931(uint8_t **outBlocks) { if ( GraphTraceLen > 18000 ) GraphTraceLen = 18000; - int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; int pmc, block_done; int lc, warnings = 0; - int num_blocks = 0; + size_t num_blocks = 0; int lmin=128, lmax=128; uint8_t dir; //clear read buffer @@ -141,136 +140,344 @@ int DemodPCF7931(uint8_t **outBlocks) { return num_blocks; } -int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; +uint8_t IsBlock0PCF7931(uint8_t *block) +{ + // assuming all RFU bits are set to 0 + // if PAC is enabled password is set to 0 + if (block[7] == 0x01) + { + if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return 1; + } + else if (block[7] == 0x00) + { + if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return 1; + } return 0; } -int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) - if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) +uint8_t IsBlock1PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) + if((block[14] & 0x7f) <= 9 && block[15] <= 9) return 1; return 0; } -void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; +static inline void print_block(uint8_t *data) +{ + Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], + data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); +} - memset(Blocks, 0, 8*17*sizeof(uint8_t)); +void ReadPCF7931() +{ + int found_blocks = 0; // successfully read blocks + int max_blocks = 8; // readable blocks + uint8_t memory_blocks[8][17]; // PCF content + + uint8_t single_blocks[8][17]; // PFC blocks with unknown position + int single_blocks_cnt = 0; - do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); + size_t n = 0; // transmitted blocks + uint8_t tmp_blocks[4][16]; // temporary read buffer + + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found + int errors = 0; // error counter + int tries = 0; // tries counter + + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); + memset(single_blocks, 0, 8*17*sizeof(uint8_t)); + + int i = 0, j = 0; + + do + { + i = 0; + + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); + n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) - error++; - if(error==10 && num_blocks == 0) { + errors++; + + // exit if no block is received + if (errors == 10 && found_blocks == 0) + { Dbprintf("Error, no tag or bad tag"); return; } - else if (tries==20 || error==10) { + // exit if too many errors during reading + else if (tries > 50 && (float)(errors/tries) > .5f) + { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } + else + { + // Trying to re-order blocks + // Look for identical block in memory blocks + while (i < n-1) + { + // skip all zeroes blocks + if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) + { + for (j = 1; j < max_blocks - 1; ++j) + { + if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) + { + memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16); + memory_blocks[j+1][ALLOC] = 1; + if (++found_blocks >= max_blocks) goto end; } } } + if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) + { + for (j = 0; j < max_blocks; ++j) + { + if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) + { + if (j == 0) + { + memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16); + memory_blocks[max_blocks - 1][ALLOC] = 1; + } + else + { + memcpy(memory_blocks[j-1], tmp_blocks[i], 16); + memory_blocks[j-1][ALLOC] = 1; + } + if (++found_blocks >= max_blocks) goto end; + } + } + } + ++i; } } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); + ++tries; + if (BUTTON_PRESS()) + { + Dbprintf("Button pressed, stopping."); + goto end; + } + } + while (found_blocks != max_blocks); + end: Dbprintf("-----------------------------------------"); Dbprintf("Memory content:"); Dbprintf("-----------------------------------------"); - for(i=0; i", i); } Dbprintf("-----------------------------------------"); - + + if (found_blocks < max_blocks) + { + Dbprintf("-----------------------------------------"); + Dbprintf("Blocks with unknown position:"); + Dbprintf("-----------------------------------------"); + for (i = 0; i < single_blocks_cnt; ++i) + print_block(single_blocks[i]); + + Dbprintf("-----------------------------------------"); + } cmd_send(CMD_ACK,0,0,0,0,0); } +static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) +{ + uint32_t tab[1024]={0}; // data times frame + uint32_t u = 0; + uint8_t parity = 0; + bool comp = 0; + + //BUILD OF THE DATA FRAME + //alimentation of the tag (time for initializing) + AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); + AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); + //password indication bit + AddBitPCF7931(1, tab, l, p); + // password (on 56 bits) + AddBytePCF7931(pass[0], tab, l, p); + AddBytePCF7931(pass[1], tab, l, p); + AddBytePCF7931(pass[2], tab, l, p); + AddBytePCF7931(pass[3], tab, l, p); + AddBytePCF7931(pass[4], tab, l, p); + AddBytePCF7931(pass[5], tab, l, p); + AddBytePCF7931(pass[6], tab, l, p); + //programming mode (0 or 1) + AddBitPCF7931(0, tab, l, p); + + //block adress on 6 bits + for (u = 0; u < 6; ++u) + { + if (address & (1 << u)) { // bit 1 + ++parity; + AddBitPCF7931(1, tab, l, p); + } else { // bit 0 + AddBitPCF7931(0, tab, l, p); + } + } + + //byte address on 4 bits + for (u = 0; u < 4; ++u) + { + if (byte & (1 << u)) + { // bit 1 + parity++; + AddBitPCF7931(1, tab, l, p); + } + else // bit 0 + AddBitPCF7931(0, tab, l, p); + } + + //data on 8 bits + for (u=0; u<8; u++) + { + if (data&(1< 0xFFFF) + { + tab[u] -= 0xFFFF; + comp = 0; + } + } + + SendCmdPCF7931(tab); +} + +void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p) +{ + uint8_t i = 0; + uint8_t pass_array[7]; + + while (password < 0x00FFFFFFFFFFFFFF) + { + if (BUTTON_PRESS()) + { + Dbprintf("Button pressed, stopping bruteforce ..."); + return; + } + + pass_array[0] = password & 0xFF; + pass_array[1] = (password >> 8) & 0xFF; + pass_array[2] = (password >> 16) & 0xFF; + pass_array[3] = (password >> 24) & 0xFF; + pass_array[4] = (password >> 32) & 0xFF; + pass_array[5] = (password >> 48) & 0xFF; + pass_array[6] = (password >> 56) & 0xFF; + + Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", + pass_array[0], + pass_array[1], + pass_array[2], + pass_array[3], + pass_array[4], + pass_array[5], + pass_array[6]); + + for (i = 0; i < tries; ++i) + RealWritePCF7931 + ( + pass_array, + init_delay, + l, + p, + 0, + 7, + 0x01 + ); + + ++password; + } +} /* Write on a byte of a PCF7931 tag * @param address : address of the block to write @@ -279,105 +486,16 @@ void ReadPCF7931() { */ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { - - uint32_t tab[1024]={0}; // data times frame - uint32_t u = 0; - uint8_t parity = 0; - bool comp = 0; - - //BUILD OF THE DATA FRAME - - //alimentation of the tag (time for initializing) - AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); - - //PMC Dbprintf("Initialization delay : %d us", init_delay); - AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); - Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); - - //password indication bit - AddBitPCF7931(1, tab, l, p); - - - //password (on 56 bits) - Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7); - AddBytePCF7931(pass1, tab, l, p); - AddBytePCF7931(pass2, tab, l, p); - AddBytePCF7931(pass3, tab, l, p); - AddBytePCF7931(pass4, tab, l, p); - AddBytePCF7931(pass5, tab, l, p); - AddBytePCF7931(pass6, tab, l, p); - AddBytePCF7931(pass7, tab, l, p); - - //programming mode (0 or 1) - AddBitPCF7931(0, tab, l, p); - - //block adress on 6 bits + Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7); Dbprintf("Block address : %02x", address); - for (u=0; u<6; u++) - { - if (address&(1< 0xFFFF){ - tab[u] -= 0xFFFF; - comp = 0; - } - } - } - - SendCmdPCF7931(tab); + + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; + + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); } @@ -390,12 +508,10 @@ void SendCmdPCF7931(uint32_t * tab){ uint16_t u=0; uint16_t tempo=0; - Dbprintf("SENDING DATA FRAME..."); + Dbprintf("Sending data frame ..."); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); LED_A_ON(); @@ -412,41 +528,31 @@ void SendCmdPCF7931(uint32_t * tab){ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TCB->TCB_BCR = 1; - tempo = AT91C_BASE_TC0->TC_CV; - for(u=0;tab[u]!= 0;u+=3){ - - + for (u = 0; tab[u] != 0; u += 3) + { // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]){ + while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - } - + // stop modulating antenna LOW(GPIO_SSC_DOUT); - while(tempo != tab[u+1]){ + while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV; - } - // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u+2]){ + while(tempo != tab[u+2]) tempo = AT91C_BASE_TC0->TC_CV; - } - - } LED_A_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - DbpString("FINISH !"); - DbpString("(Could be usefull to send the same trame many times)"); + DbpString("Data frame sent (multiple sends may be needed)"); LED(0xFFFF, 1000); } @@ -482,8 +588,7 @@ bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){ uint8_t u = 0; - for(u=0;tab[u]!=0;u+=3){} //we put the cursor at the last value of the array - + for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array if(b==1){ //add a bit 1 if(u==0) tab[u] = 34*T0_PCF+p; diff --git a/armsrc/pcf7931.h b/armsrc/pcf7931.h index 26aaff68..662017aa 100644 --- a/armsrc/pcf7931.h +++ b/armsrc/pcf7931.h @@ -1,14 +1,15 @@ #ifndef __PCF7931_H #define __PCF7931_H -int DemodPCF7931(uint8_t **outBlocks); -int IsBlock0PCF7931(uint8_t *Block); -int IsBlock1PCF7931(uint8_t *Block); +size_t DemodPCF7931(uint8_t **outBlocks); +uint8_t IsBlock0PCF7931(uint8_t *Block); +uint8_t IsBlock1PCF7931(uint8_t *Block); void ReadPCF7931(); void SendCmdPCF7931(uint32_t * tab); bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p); bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p); bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab); void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data); +void BruteForcePCF7931(uint64_t start_password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p); #endif diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 9c694b8d..559f6d18 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake +// 2018 sguerrini97 // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -76,6 +77,19 @@ int usage_pcf7931_write(){ return 0; } +int usage_pcf7931_bruteforce() +{ + PrintAndLog("Usage: lf pcf7931 bruteforce [h] "); + PrintAndLog("This command tries to write a PCF7931 tag."); + PrintAndLog("Options:"); + PrintAndLog(" h This help"); + PrintAndLog(" start password hex password to start from"); + PrintAndLog(" tries How many times to send the same data frame"); + PrintAndLog("Examples:"); + PrintAndLog(" lf pcf7931 bruteforce 00000000123456 3"); + return 0; +} + int usage_pcf7931_config(){ PrintAndLog("Usage: lf pcf7931 config [h] [r] "); PrintAndLog("This command tries to set the configuration used with PCF7931 commands"); @@ -159,12 +173,47 @@ int CmdLFPCF7931Write(const char *Cmd){ return 0; } +int CmdLFPCF7931BruteForce(const char *Cmd){ + + uint8_t ctmp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); + + uint64_t start_password = 0; + uint8_t tries = 3; + + if (param_gethex(Cmd, 0, (uint8_t*)(&start_password), 14)) return usage_pcf7931_bruteforce(); + if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce(); + + PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x", + start_password & 0xFF, + (start_password >> 8) & 0xFF, + (start_password >> 16) & 0xFF, + (start_password >> 24) & 0xFF, + (start_password >> 32) & 0xFF, + (start_password >> 48) & 0xFF, + (start_password >> 56) & 0xFF); + + PrintAndLog("Trying each password %d times", tries); + + UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {start_password, tries} }; + + c.d.asDwords[7] = (configPcf.OffsetWidth + 128); + c.d.asDwords[8] = (configPcf.OffsetPosition + 128); + c.d.asDwords[9] = configPcf.InitDelay; + + clearCommandBuffer(); + SendCommand(&c); + //no ack? + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"}, {"write", CmdLFPCF7931Write, 0, "Write data on a PCF7931 transponder."}, {"config", CmdLFPCF7931Config, 1, "Configure the password, the tags initialization delay and time offsets (optional)"}, + {"bruteforce", CmdLFPCF7931BruteForce, 0, "Bruteforce a PCF7931 transponder password."}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfpcf7931.h b/client/cmdlfpcf7931.h index 8b24f03a..32f8491e 100644 --- a/client/cmdlfpcf7931.h +++ b/client/cmdlfpcf7931.h @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake +// 2018 sguerrini97 // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -26,12 +27,14 @@ int pcf7931_printConfig(); int usage_pcf7931_read(); int usage_pcf7931_write(); +int usage_pcf7931_bruteforce(); int usage_pcf7931_config(); int CmdLFPCF7931(const char *Cmd); int CmdLFPCF7931Read(const char *Cmd); int CmdLFPCF7931Write(const char *Cmd); +int CmdLFPCF7931BruteForce(const char *Cmd); int CmdLFPCF7931Config(const char *Cmd); #endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index fa66634f..f744a03f 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -97,6 +97,7 @@ typedef struct{ #define CMD_T55XX_RESET_READ 0x0216 #define CMD_PCF7931_READ 0x0217 #define CMD_PCF7931_WRITE 0x0222 +#define CMD_PCF7931_BRUTEFORCE 0x0226 #define CMD_EM4X_READ_WORD 0x0218 #define CMD_EM4X_WRITE_WORD 0x0219 #define CMD_IO_DEMOD_FSK 0x021A