]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge pull request #837 from mwalker33/master
authormarshmellow42 <marshmellow42@users.noreply.github.com>
Thu, 11 Jul 2019 17:17:36 +0000 (13:17 -0400)
committerGitHub <noreply@github.com>
Thu, 11 Jul 2019 17:17:36 +0000 (13:17 -0400)
lf t55xx downlink modes support added

CHANGELOG.md
armsrc/lfops.c
client/cmdlft55xx.c
client/cmdlft55xx.h

index cb508cd906867f081f0aa08513bbf6a2e45061b4..037bab990ca0ca5c113786df7c4ea70b92491ba2 100644 (file)
@@ -35,6 +35,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi)
 - Added Legic detection to `hf search` (dnet)
 - Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992)
+- Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce`
+- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password
+
 
 ## [v3.1.0][2018-10-10]
 
index ed207dbb39122eb4bc13f2f27828dca820f77c06..c9947d97599e6e150f457c38f224dd36c455cacc 100644 (file)
@@ -1199,6 +1199,17 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
  * Q5 tags seems to have issues when these values changes. 
  */
 
+ /*
+ // Original Timings for reference
+//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds)
+#define START_GAP 31*8 // was 250 // SPEC:  1*8 to 50*8 - typ 15*8 (or 15fc)
+#define WRITE_GAP 20*8 // was 160 // SPEC:  1*8 to 20*8 - typ 10*8 (or 10fc)
+#define WRITE_0   18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc)
+#define WRITE_1   50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc)  432 for T55x7; 448 for E5550
+#define READ_GAP  15*8 
+
+*/
 /* Q5 timing datasheet:
  * Type                  |  MIN   | Typical |  Max   |
  * Start_Gap             |  10*8  |    ?    |  50*8  |
@@ -1232,12 +1243,33 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
  * Write_1   Fast Mode   |  24*8  |   28*8  |  32*8  |
 */
 
-//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds)
-#define START_GAP 31*8 //31*8 // was 250 // SPEC:  1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 
-#define WRITE_GAP 20*8 //20*8 // was 160 // SPEC:  1*8 to 20*8 - typ 10*8 (or 10fc) - T5557:  8*8 to 30*8 typ 50-150us
-#define WRITE_0   18*8 //18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) - T5557: 16*8 to 31*8 typ 24*8
-#define WRITE_1   50*8 //50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) - T5557: 48*8 to 63*8 typ 54*8       432 for T55x7; 448 for E5550
-#define READ_GAP  15*8 
+// Structure to hold Timing values.  In future will be simplier to add user changable timings.
+typedef struct  {
+       uint16_t  START_GAP;
+       uint16_t  WRITE_GAP;
+       uint16_t  WRITE_0;
+       uint16_t  WRITE_1;
+       uint16_t  WRITE_2;
+       uint16_t  WRITE_3;
+       uint16_t  READ_GAP;
+} T55xx_Timing;
+
+// Set Initial/Default Values.  Note: *8 can occure when used.  This should keep things simplier here.
+T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8   , 20 * 8   , 18 * 8 , 50 * 8 , 0      , 0      , 15 * 8   };
+T55xx_Timing T55xx_Timing_LLR      = { 31 * 8   , 20 * 8   , 18 * 8 , 50 * 8 , 0      , 0      , 15 * 8   };
+T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8   , 20 * 8   , 18 * 8 , 40 * 8 , 0      , 0      , 15 * 8   };
+T55xx_Timing T55xx_Timing_1of4     = { 31 * 8   , 20 * 8   , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8   };
+
+// Some defines for readability
+#define T55xx_DLMode_Fixed         0 // Default Mode
+#define T55xx_DLMode_LLR           1 // Long Leading Reference
+#define T55xx_DLMode_Leading0      2 // Leading Zero
+#define T55xx_DLMode_1of4          3 // 1 of 4
+#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference
+// Macro for code readability
+#define BitStream_Byte(X) ((X) >> 3)
+#define BitStream_Bit(X)  ((X) &  7)  
+
 
 void TurnReadLFOn(int delay) {
        FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
@@ -1246,36 +1278,179 @@ void TurnReadLFOn(int delay) {
 }
 
 // Write one bit to card
-void T55xxWriteBit(int bit) {
-       if (!bit)
-               TurnReadLFOn(WRITE_0);
-       else
-               TurnReadLFOn(WRITE_1);
+void T55xxWriteBit(int bit, T55xx_Timing *Timings) {
+
+       // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0        
+       // Dbprintf ("Bits : %d",bit);
+       switch (bit){
+               case 0 : TurnReadLFOn(Timings->WRITE_0);             break; // Send bit  0/00
+               case 1 : TurnReadLFOn(Timings->WRITE_1);             break; // Send bit  1/01
+               case 2 : TurnReadLFOn(Timings->WRITE_2);             break; // Send bits   10
+               case 3 : TurnReadLFOn(Timings->WRITE_3);             break; // Send bits   11
+               case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference
+       }
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       WaitUS(WRITE_GAP);
+       WaitUS(Timings->WRITE_GAP);
 }
 
-// Send T5577 reset command then read stream (see if we can identify the start of the stream)
-void T55xxResetRead(void) {
-       LED_A_ON();
-       //clear buffer now so it does not interfere with timing later
-       BigBuf_Clear_keep_EM();
+// Function to abstract an Arbitrary length byte array to store bit pattern.
+// bit_array    - Array to hold data/bit pattern
+// start_offset - bit location to start storing new bits.
+// data         - upto 32 bits of data to store
+// num_bits     - how many bits (low x bits of data)  Max 32 bits at a time
+// max_len         - how many bytes can the bit_array hold (ensure no buffer overflow)
+// returns "Next" bit offset / bits stored (for next store)
+//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data      , int num_bits, int max_len)
+int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len)
+{
+       int8_t offset;
+       int8_t NextOffset = start_offset;
+
+       // Check if data will fit.
+       if ((start_offset + num_bits) <= (max_len*8)) {
+               // Loop through the data and store
+               for (offset = (num_bits-1); offset >= 0; offset--) {
+
+                       if ((data >> offset) & 1)  BitStream[BitStream_Byte(NextOffset)] |= (1         << BitStream_Bit(NextOffset));     // Set the bit to 1
+                       else                       BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset)));    // Set the bit to 0
+
+                       NextOffset++;
+               }
+       }
+       else {
+               // Note: This should never happen unless some code changes cause it.  
+               // So short message for coders when testing.
+               Dbprintf ("T55 too many bits"); 
+       }
+       return NextOffset;
+}
+
+// Send one downlink command to the card 
+void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { 
+
+       /*
+               arg bits
+               xxxxxxx1 0x01 PwdMode
+               xxxxxx1x 0x02 Page
+               xxxxx1xx 0x04 testMode
+               xxx11xxx 0x18 downlink mode
+               xx1xxxxx 0x20 !reg_readmode
+               x1xxxxxx 0x40 called for a read, so no data packet
+               1xxxxxxx 0x80 reset
+
+       */
+       bool PwdMode      = ((arg & 0x01) == 0x01);
+       bool Page         =  (arg & 0x02);
+       bool testMode     = ((arg & 0x04) == 0x04);
+       uint8_t downlink_mode = (arg >> 3) & 0x03;
+       bool reg_readmode = ((arg & 0x20) == 0x20);
+       bool read_cmd     = ((arg & 0x40) == 0x40);
+       bool reset        =  (arg & 0x80);
+
+       uint8_t i = 0;
+       uint8_t BitStream[10];  // Max Downlink Command size ~74 bits, so 10 bytes (80 bits)
+       uint8_t BitStreamLen;
+       T55xx_Timing *Timing;
+       uint8_t SendBits;
+
+       // Assigning Downlink Timeing for write
+       switch (downlink_mode)
+       {
+               case T55xx_DLMode_Fixed    : Timing = &T55xx_Timing_FixedBit;  break; 
+               case T55xx_DLMode_LLR      : Timing = &T55xx_Timing_LLR;       break;
+               case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0;  break;
+               case T55xx_DLMode_1of4     : Timing = &T55xx_Timing_1of4;      break;
+               default:
+                               Timing = &T55xx_Timing_FixedBit;
+       }
 
+       // Build Bit Stream to send.
+       memset (BitStream,0x00,sizeof(BitStream));
+       
+       BitStreamLen = 0; // Ensure 0 bit index to start.
+       
+       // Add Leading 0 and 1 of 4 reference bit
+       if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4))
+               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); 
+
+       // Add extra reference 0 for 1 of 4
+       if (downlink_mode == T55xx_DLMode_1of4)
+               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); 
+
+       // Add Opcode 
+       if (reset) {
+               //  Reset : r*) 00
+               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); 
+       }
+       else
+       {
+               if (testMode) Dbprintf("TestMODE");
+               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1    , 1,sizeof(BitStream));
+               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream));
+
+               if (PwdMode) {
+                       // Leading 0 and 1 of 4 00 fixed bits if passsword used         
+                       if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) {
+                               BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
+                       }
+                       BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream));
+               }
+
+               // Add Lock bit 0
+               if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
+
+               // Add Data if a write command
+               if (!read_cmd)  BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream));
+
+               // Add Address
+               if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream));
+       }
+
+       // Send Bits to T55xx
        // Set up FPGA, 125kHz
        LFSetupFPGAForADC(95, true);
        StartTicks();
        // make sure tag is fully powered up...
        WaitMS(5);
-       
        // Trigger T55x7 in mode.
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       WaitUS(START_GAP);
+       WaitUS(Timing->START_GAP);
+
+       // If long leading 0 send long reference pulse
+       if (downlink_mode ==  T55xx_DLMode_LLR) 
+               T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference
+
+       if ((downlink_mode ==  T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time
+               for ( i = 0; i < BitStreamLen-1; i+=2 ) {
+                       SendBits  = (BitStream[BitStream_Byte(i  )] >> (BitStream_Bit(i  )) & 1) << 1;   // Bit i
+                       SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1);        // Bit i+1;
+                       T55xxWriteBit (SendBits & 3,Timing);
+               }
+       }
+       else {
+               for (i = 0; i < BitStreamLen; i++) {
+                       SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i));
+                       T55xxWriteBit (SendBits & 1,Timing);
+               }
+       }
+}
+
+// Send T5577 reset command then read stream (see if we can identify the start of the stream)
+void T55xxResetRead(void) {
+       LED_A_ON();
+
+       //  send  r* 00 
+       uint8_t arg = 0x80;  // SendCMD will add correct reference mode based on flags (when added).
+
+       // Add in downlink_mode when ready
+       //    arg |= 0x00;  // dlmode << 3  (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 )
+
+       //clear buffer now so it does not interfere with timing later
+       BigBuf_Clear_keep_EM();
 
-       // reset tag - op code 00
-       T55xxWriteBit(0);
-       T55xxWriteBit(0);
+       T55xx_SendCMD (0, 0, 0, arg); //, true);
 
-       TurnReadLFOn(READ_GAP);
+       TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP);
 
        // Acquisition
        DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0);
@@ -1287,42 +1462,23 @@ void T55xxResetRead(void) {
 }
 
 // Write one card block in page 0, no lock
-void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
-       LED_A_ON();
-       bool PwdMode = arg & 0x1;
-       uint8_t Page = (arg & 0x2)>>1;
-       bool testMode = arg & 0x4;
-       uint32_t i = 0;
-
-       // Set up FPGA, 125kHz
-       LFSetupFPGAForADC(95, true);
-       StartTicks();
-       // make sure tag is fully powered up...
-       WaitMS(5);
-       // Trigger T55x7 in mode.
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       WaitUS(START_GAP);
-
-       if (testMode) Dbprintf("TestMODE");
-       // Std Opcode 10
-       T55xxWriteBit(testMode ? 0 : 1);
-       T55xxWriteBit(testMode ? 1 : Page); //Page 0
-
-       if (PwdMode) {
-               // Send Pwd
-               for (i = 0x80000000; i != 0; i >>= 1)
-                       T55xxWriteBit(Pwd & i);
-       }
-       // Send Lock bit
-       T55xxWriteBit(0);
-
-       // Send Data
-       for (i = 0x80000000; i != 0; i >>= 1)
-               T55xxWriteBit(Data & i);
-
-       // Send Block number
-       for (i = 0x04; i != 0; i >>= 1)
-               T55xxWriteBit(Block & i);
+void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
+       /*
+               arg bits
+               xxxxxxx1 0x01 PwdMode
+               xxxxxx1x 0x02 Page
+               xxxxx1xx 0x04 testMode
+               xxx11xxx 0x18 downlink mode
+               xx1xxxxx 0x20 !reg_readmode
+               x1xxxxxx 0x40 called for a read, so no data packet
+               1xxxxxxx 0x80 reset
+       */
+       
+       bool testMode = ((arg & 0x04) == 0x04);
+       arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
+       
+       LED_A_ON ();
+       T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false); 
 
        // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
        // so wait a little more)
@@ -1351,57 +1507,43 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg
 
                //DoPartialAcquisition(20, true, 12000);
        }
-
        // turn field off
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       LED_A_OFF();
-}
 
-// Write one card block in page 0, no lock
-void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
-       T55xxWriteBlockExt(Data, Block, Pwd, arg);
        cmd_send(CMD_ACK,0,0,0,0,0);
+
+       LED_A_OFF ();
 }
 
 // Read one card block in page [page]
-void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
+void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) {
+
        LED_A_ON();
-       bool PwdMode = arg0 & 0x1;
-       uint8_t Page = (arg0 & 0x2) >> 1;
-       uint32_t i = 0;
-       bool RegReadMode = (Block == 0xFF);//regular read mode
 
-       //clear buffer now so it does not interfere with timing later
-       BigBuf_Clear_ext(false);
+       /*
+               arg bits
+               xxxxxxx1 0x01 PwdMode
+               xxxxxx1x 0x02 Page
+               xxxxx1xx 0x04 testMode
+               xxx11xxx 0x18 downlink mode
+               xx1xxxxx 0x20 !reg_readmode
+               x1xxxxxx 0x40 called for a read, so no data packet
+               1xxxxxxx 0x80 reset
+       */
 
+       // Set Read Flag to ensure SendCMD does not add "data" to the packet
+       arg0 |= 0x40;
+
+       // RegRead Mode true of block 0xff
+       if (Block == 0xff) arg0 |= 0x20;
+       
        //make sure block is at max 7
        Block &= 0x7;
 
-       // Set up FPGA, 125kHz to power up the tag
-       LFSetupFPGAForADC(95, true);
-       StartTicks();
-       // make sure tag is fully powered up...
-       WaitMS(5);
-       // Trigger T55x7 Direct Access Mode with start gap
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       WaitUS(START_GAP);
-
-       // Opcode 1[page]
-       T55xxWriteBit(1);
-       T55xxWriteBit(Page); //Page 0
-
-       if (PwdMode) {
-               // Send Pwd
-               for (i = 0x80000000; i != 0; i >>= 1)
-                       T55xxWriteBit(Pwd & i);
-       }
-       // Send a zero bit separation
-       T55xxWriteBit(0);
+       //clear buffer now so it does not interfere with timing later
+       BigBuf_Clear_ext(false);
 
-       // Send Block number (if direct access mode)
-       if (!RegReadMode)
-               for (i = 0x04; i != 0; i >>= 1)
-                       T55xxWriteBit(Block & i);               
+       T55xx_SendCMD (0, Block, Pwd, arg0); //, true);
 
        // Turn field on to read the response
        // 137*8 seems to get to the start of data pretty well... 
@@ -1415,30 +1557,31 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
        // Turn the field off
        FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
        cmd_send(CMD_ACK,0,0,0,0,0);    
+
        LED_A_OFF();
 }
 
 void T55xxWakeUp(uint32_t Pwd){
        LED_B_ON();
-       uint32_t i = 0;
-       
-       // Set up FPGA, 125kHz
-       LFSetupFPGAForADC(95, true);
-       StartTicks();
-       // make sure tag is fully powered up...
-       WaitMS(5);
-       
-       // Trigger T55x7 Direct Access Mode
-       FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-       WaitUS(START_GAP);
-       
-       // Opcode 10
-       T55xxWriteBit(1);
-       T55xxWriteBit(0); //Page 0
+       /*
+               arg bits
+               xxxxxxx1 0x01 PwdMode
+               xxxxxx1x 0x02 Page
+               xxxxx1xx 0x04 testMode
+               xxx11xxx 0x18 downlink mode
+               xx1xxxxx 0x20 !reg_readmode 
+               x1xxxxxx 0x40 called for a read, so no data packet
+               1xxxxxxx 0x80 reset
+       */
+
+       // r* 10 (00) <pwd>   r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD
+       // So, default Opcode 10 and pwd.
+       uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block
+
+       // Add in downlink_mode when ready
+       //    arg |= 0x00;  // dlmode << 3  (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 )
 
-       // Send Pwd
-       for (i = 0x80000000; i != 0; i >>= 1)
-               T55xxWriteBit(Pwd & i);
+       T55xx_SendCMD (0, 0, Pwd, arg); //, true);
 
        // Turn and leave field on to let the begin repeating transmission
        TurnReadLFOn(20*1000);
@@ -1449,7 +1592,8 @@ void T55xxWakeUp(uint32_t Pwd){
 void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) {
        // write last block first and config block last (if included)
        for (uint8_t i = numblocks+startblock; i > startblock; i--) {
-               T55xxWriteBlockExt(blockdata[i-1],i-1,0,0);
+               T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit);
+               //T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit);
        }
 }
 
index b286c392493334c13187c18dc1253a1300463f74..c64e5ef24eb00b68348d070a7b93c646de878b59 100644 (file)
@@ -67,6 +67,8 @@ int usage_t55xx_read(){
        PrintAndLog("     p <password> - OPTIONAL password (8 hex characters)");\r
        PrintAndLog("     o            - OPTIONAL override safety check");\r
        PrintAndLog("     1            - OPTIONAL read Page 1 instead of Page 0");\r
+       PrintAndLog("     r <mode>     - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");\r
+       PrintAndLog("                                               '2' leading zero,               '3' 1 of 4 coding reference"); \r
        PrintAndLog("     ****WARNING****");\r
        PrintAndLog("     Use of read with password on a tag not configured for a pwd");\r
        PrintAndLog("     can damage the tag");\r
@@ -86,6 +88,8 @@ int usage_t55xx_write(){
        PrintAndLog("     p <password> - OPTIONAL password 4bytes (8 hex characters)");\r
        PrintAndLog("     1            - OPTIONAL write Page 1 instead of Page 0");\r
        PrintAndLog("     t            - OPTIONAL test mode write - ****DANGER****");   \r
+       PrintAndLog("     r <mode>     - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");\r
+       PrintAndLog("                                               '2' leading zero,               '3' 1 of 4 coding reference"); \r
        PrintAndLog("");\r
        PrintAndLog("Examples:");\r
        PrintAndLog("      lf t55xx write b 3 d 11223344            - write 11223344 to block 3");\r
@@ -132,6 +136,8 @@ int usage_t55xx_detect(){
        PrintAndLog("Options:");\r
        PrintAndLog("     1             - if set, use Graphbuffer otherwise read data from tag.");\r
        PrintAndLog("     p <password>  - OPTIONAL password (8 hex characters)");\r
+       PrintAndLog("     r <mode>      - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");\r
+       PrintAndLog("                                                '2' leading zero,               '3' 1 of 4 coding reference"); \r
        PrintAndLog("");\r
        PrintAndLog("Examples:");\r
        PrintAndLog("      lf t55xx detect");\r
@@ -162,7 +168,7 @@ int usage_t55xx_wakup(){
        PrintAndLog("     <password>  - [required] password 4bytes (8 hex symbols)");\r
        PrintAndLog("");\r
        PrintAndLog("Examples:");\r
-               PrintAndLog("      lf t55xx wakeup 11223344  - send wakeup password");\r
+       PrintAndLog("      lf t55xx wakeup 11223344  - send wakeup password");\r
        return 0;\r
 }\r
 int usage_t55xx_bruteforce(){\r
@@ -172,13 +178,16 @@ int usage_t55xx_bruteforce(){
        PrintAndLog("       password must be 4 bytes (8 hex symbols)");\r
        PrintAndLog("Options:");\r
        PrintAndLog("     h           - this help");\r
+       PrintAndLog("     r <mode>    - OPTIONAL downlink encoding '0' fixed bit length (default)"); \r
+       PrintAndLog("                                  '1' long leading reference,  '2' leading zero ");\r
+       PrintAndLog("                                  '3' 1 of 4 coding reference, '4' special - try all downlink modes");\r
        PrintAndLog("     <start_pwd> - 4 byte hex value to start pwd search at");\r
        PrintAndLog("     <end_pwd>   - 4 byte hex value to end pwd search at");\r
        PrintAndLog("     i <*.dic>   - loads a default keys dictionary file <*.dic>");\r
        PrintAndLog("");\r
        PrintAndLog("Examples:");\r
-       PrintAndLog("       lf t55xx bruteforce aaaaaaaa bbbbbbbb");\r
-       PrintAndLog("       lf t55xx bruteforce i default_pwd.dic");\r
+       PrintAndLog("       lf t55xx bruteforce [r 2] aaaaaaaa bbbbbbbb");\r
+       PrintAndLog("       lf t55xx bruteforce [r 2] i default_pwd.dic");\r
        PrintAndLog("");\r
        return 0;\r
 }\r
@@ -302,21 +311,21 @@ int CmdT55xxSetConfig(const char *Cmd) {
        }\r
 \r
        // No args\r
-       if (cmdp == 0) return printConfiguration( config );\r
+       if (cmdp == 0) return printConfiguration( config);\r
 \r
        //Validations\r
        if (errors) return usage_t55xx_config();\r
 \r
        config.block0 = 0;\r
-       return printConfiguration ( config );\r
+       return printConfiguration ( config);\r
 }\r
 \r
-int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){\r
+int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){\r
        //Password mode\r
        if ( usepwd ) {\r
                // try reading the config block and verify that PWD bit is set before doing this!\r
                if ( !override ) {\r
-                       if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0;\r
+                       if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0;\r
                        if ( !tryDetectModulation() ) {\r
                                PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits.");\r
                                return 0;\r
@@ -330,7 +339,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32
                }\r
        }\r
 \r
-       if (!AquireData(page1, block, usepwd, password) )       return 0;\r
+       if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0;\r
        if (!DecodeT55xxBlock()) return 0;\r
 \r
        char blk[10]={0};\r
@@ -342,6 +351,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32
 int CmdT55xxReadBlock(const char *Cmd) {\r
        uint8_t block = REGULAR_READ_MODE_BLOCK;\r
        uint32_t password = 0; //default to blank Block 7\r
+       uint8_t downlink_mode = 0;\r
+       \r
        bool usepwd = false;\r
        bool override = false;\r
        bool page1 = false;\r
@@ -372,6 +383,12 @@ int CmdT55xxReadBlock(const char *Cmd) {
                        page1 = true;\r
                        cmdp++;\r
                        break;\r
+               case 'r':\r
+               case 'R':\r
+                       downlink_mode = param_getchar(Cmd, cmdp+1) - '0';\r
+                       if (downlink_mode > 3) downlink_mode = 0;\r
+                       cmdp +=2;\r
+                       break;\r
                default:\r
                        PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));\r
                        errors = true;\r
@@ -386,7 +403,7 @@ int CmdT55xxReadBlock(const char *Cmd) {
        }\r
 \r
        printT5xxHeader(page1);\r
-       return T55xxReadBlock(block, page1, usepwd, override, password);\r
+       return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode);\r
 }\r
 \r
 bool DecodeT55xxBlock(){\r
@@ -459,12 +476,32 @@ bool DecodeT5555TraceBlock() {
        return (bool) ASKDemod("64 0 1", false, false, 1);\r
 }\r
 \r
+void T55xx_Print_DownlinkMode (uint8_t downlink_mode)\r
+{\r
+       char Msg[80];\r
+       sprintf (Msg,"Downlink Mode used : ");\r
+       \r
+               switch (downlink_mode) {\r
+                       case  0 :       strcat (Msg,"default/fixed bit length"); break;\r
+                       case  1 :   strcat (Msg,"long leading reference (r 1)");   break;\r
+                       case  2 :   strcat (Msg,"leading zero reference (r 2)");   break;\r
+                       case  3 :   strcat (Msg,"1 of 4 coding reference (r 3)");  break;\r
+                       default :\r
+                                       strcat (Msg,"default/fixed bit length"); break;\r
+\r
+               }\r
+       \r
+       PrintAndLog (Msg);\r
+       \r
+}\r
+\r
 int CmdT55xxDetect(const char *Cmd){\r
        bool errors = false;\r
        bool useGB = false;\r
        bool usepwd = false;\r
        uint32_t password = 0;\r
        uint8_t cmdp = 0;\r
+       uint8_t downlink_mode = 0;\r
 \r
        while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {\r
                switch(param_getchar(Cmd, cmdp)) {\r
@@ -482,6 +519,12 @@ int CmdT55xxDetect(const char *Cmd){
                        useGB = true;\r
                        cmdp++;\r
                        break;\r
+               case 'r':\r
+               case 'R':\r
+                       downlink_mode = param_getchar(Cmd, cmdp+1) - '0';\r
+                       if (downlink_mode > 3) downlink_mode = 0;\r
+                       cmdp +=2;\r
+                       break;                  \r
                default:\r
                        PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));\r
                        errors = true;\r
@@ -491,13 +534,16 @@ int CmdT55xxDetect(const char *Cmd){
        if (errors) return usage_t55xx_detect();\r
        \r
        if ( !useGB) {\r
-               if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) )\r
+               if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) )\r
                        return 0;\r
        }\r
        \r
        if ( !tryDetectModulation() )\r
                PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'");\r
-\r
+       else {\r
+               // Add downlink mode for reference.\r
+               T55xx_Print_DownlinkMode (downlink_mode);\r
+       }\r
        return 1;\r
 }\r
 \r
@@ -649,7 +695,8 @@ bool tryDetectModulation(){
                config.block0 = tests[0].block0;\r
                config.Q5 = tests[0].Q5;\r
                config.ST = tests[0].ST;\r
-               printConfiguration( config );\r
+               \r
+               printConfiguration( config);\r
                return true;\r
        }\r
        \r
@@ -657,7 +704,7 @@ bool tryDetectModulation(){
                PrintAndLog("Found [%d] possible matches for modulation.",hits);\r
                for(int i=0; i<hits; ++i){\r
                        PrintAndLog("--[%d]---------------", i+1);\r
-                       printConfiguration( tests[i] );\r
+                       printConfiguration( tests[i]);\r
                }\r
        }\r
        return false;\r
@@ -898,6 +945,8 @@ int CmdT55xxWriteBlock(const char *Cmd) {
        uint8_t block = 0xFF; //default to invalid block\r
        uint32_t data = 0; //default to blank Block \r
        uint32_t password = 0; //default to blank Block 7\r
+       uint32_t downlink_mode = 0;\r
+       \r
        bool usepwd = false;\r
        bool page1 = false;     \r
        bool gotdata = false;\r
@@ -935,6 +984,12 @@ int CmdT55xxWriteBlock(const char *Cmd) {
                        page1 = true;\r
                        cmdp++;\r
                        break;\r
+               case 'r':\r
+               case 'R':\r
+                       downlink_mode = param_getchar(Cmd, cmdp+1) - '0';\r
+                       if (downlink_mode > 3) downlink_mode = 0;\r
+                       cmdp +=2;\r
+                       break;\r
                default:\r
                        PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));\r
                        errors = true;\r
@@ -952,17 +1007,19 @@ int CmdT55xxWriteBlock(const char *Cmd) {
        UsbCommand resp;\r
        c.d.asBytes[0] = (page1) ? 0x2 : 0; \r
        c.d.asBytes[0] |= (testMode) ? 0x4 : 0; \r
-\r
+       c.d.asBytes[0] |= (downlink_mode << 3);\r
+       \r
        char pwdStr[16] = {0};\r
        snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password);\r
 \r
        PrintAndLog("Writing page %d  block: %02d  data: 0x%08X %s", page1, block, data,  (usepwd) ? pwdStr : "" );\r
-\r
+       \r
        //Password mode\r
        if (usepwd) {\r
                c.arg[2] = password;\r
                c.d.asBytes[0] |= 0x1; \r
        }\r
+       \r
        clearCommandBuffer();\r
        SendCommand(&c);\r
        if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){\r
@@ -980,7 +1037,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
                return usage_t55xx_trace();\r
 \r
        if (strlen(Cmd)==0)\r
-               if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) )\r
+               if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) )\r
                        return 0;\r
 \r
        if ( config.Q5 ) {\r
@@ -1144,7 +1201,7 @@ int CmdT55xxInfo(const char *Cmd){
                return usage_t55xx_info();\r
        \r
        if (strlen(Cmd)==0)\r
-               if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) )\r
+               if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) )\r
                        return 1;\r
 \r
        if (!DecodeT55xxBlock()) return 1;\r
@@ -1212,20 +1269,21 @@ int CmdT55xxDump(const char *Cmd){
        \r
        printT5xxHeader(0);\r
        for ( uint8_t i = 0; i <8; ++i)\r
-               T55xxReadBlock(i, 0, usepwd, override, password);\r
+               T55xxReadBlock(i, 0, usepwd, override, password,0);\r
 \r
        printT5xxHeader(1);\r
        for ( uint8_t   i = 0; i<4; i++)\r
-               T55xxReadBlock(i, 1, usepwd, override, password);               \r
+               T55xxReadBlock(i, 1, usepwd, override, password,0);             \r
 \r
        return 1;\r
 }\r
 \r
-int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){\r
+int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){\r
        // arg0 bitmodes:\r
        // bit0 = pwdmode\r
        // bit1 = page to read from\r
        uint8_t arg0 = (page<<1) | pwdmode;\r
+       arg0 |= (downlink_mode << 3);\r
        UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}};\r
 \r
        clearCommandBuffer();\r
@@ -1403,9 +1461,23 @@ int CmdT55xxBruteForce(const char *Cmd) {
        uint32_t start_password = 0x00000000; //start password\r
        uint32_t end_password   = 0xFFFFFFFF; //end   password\r
        bool found = false;\r
-\r
+       uint8_t downlink_mode = 0;\r
+       bool try_all_dl_modes = false;\r
+       uint8_t dl_mode = 0;\r
+       uint8_t cmd_offset = 0;\r
+       int cmd_opt = 0;\r
+               \r
        char cmdp = param_getchar(Cmd, 0);\r
+       \r
        if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce();\r
+       if (cmdp == 'r' || cmdp == 'R') {\r
+               downlink_mode = param_getchar(Cmd, 1) - '0'; // get 2nd option, as this is fixed order.\r
+               if (downlink_mode == 4) try_all_dl_modes = true;\r
+               if (downlink_mode > 3) downlink_mode = 0;\r
+               cmd_opt += 2;    // To help start/end passwords for range to be found\r
+               cmd_offset += 4; // r <sp> x <sp> To help the string offset for filename start position in cmd\r
+               cmdp = param_getchar(Cmd, 2); // get 3rd option, as this is fixed order.\r
+       }\r
 \r
        keyBlock = calloc(stKeyBlock, 6);\r
        if (keyBlock == NULL) return 1;\r
@@ -1414,7 +1486,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
 \r
                int len = strlen(Cmd+2);\r
                if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;\r
-               memcpy(filename, Cmd+2, len);\r
+               memcpy(filename, Cmd+2+cmd_offset, len);\r
 \r
                FILE * f = fopen( filename , "r");\r
 \r
@@ -1479,20 +1551,29 @@ int CmdT55xxBruteForce(const char *Cmd) {
                        testpwd = bytes_to_num(keyBlock + 4*c, 4);\r
 \r
                        PrintAndLog("Testing %08X", testpwd);\r
+                       \r
+                       // Try each downlink_mode if asked to \r
+                       // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3\r
+                       for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){\r
+                               if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) {\r
+                                       PrintAndLog("Acquiring data from device failed. Quitting");\r
+                                       free(keyBlock);\r
+                                       return 0;\r
+                               }\r
 \r
-                       if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) {\r
-                               PrintAndLog("Aquireing data from device failed. Quitting");\r
-                               free(keyBlock);\r
-                               return 0;\r
-                       }\r
+                               found = tryDetectModulation();\r
 \r
-                       found = tryDetectModulation();\r
+                               if ( found ) {\r
+                                       PrintAndLog("Found valid password: [%08X]", testpwd);\r
+                                       free(keyBlock);\r
+                                       \r
+                                       T55xx_Print_DownlinkMode (dl_mode);\r
 \r
-                       if ( found ) {\r
-                               PrintAndLog("Found valid password: [%08X]", testpwd);\r
-                               free(keyBlock);\r
-                               return 0;\r
-                       }\r
+                                       return 0;\r
+                               }\r
+                               if (!try_all_dl_modes) // Exit loop if not trying all downlink modes\r
+                                       dl_mode = 4;\r
+                       }       \r
                }\r
                PrintAndLog("Password NOT found.");\r
                free(keyBlock);\r
@@ -1502,8 +1583,8 @@ int CmdT55xxBruteForce(const char *Cmd) {
        // Try to read Block 7, first :)\r
 \r
        // incremental pwd range search\r
-       start_password = param_get32ex(Cmd, 0, 0, 16);\r
-       end_password = param_get32ex(Cmd, 1, 0, 16);\r
+       start_password = param_get32ex(Cmd, cmd_opt , 0, 16);\r
+       end_password = param_get32ex(Cmd, cmd_opt+1 , 0, 16);\r
 \r
        if ( start_password >= end_password ) {\r
                free(keyBlock);\r
@@ -1524,29 +1605,36 @@ int CmdT55xxBruteForce(const char *Cmd) {
                        free(keyBlock);\r
                        return 0;\r
                }\r
+               // Try each downlink_mode if asked to \r
+               // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3\r
+               for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){\r
+                       if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) {\r
+                               PrintAndLog("Acquiring data from device failed. Quitting");\r
+                               free(keyBlock);\r
+                               return 0;\r
+                       }\r
+                       found = tryDetectModulation();\r
 \r
-               if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) {\r
-                       PrintAndLog("Aquireing data from device failed. Quitting");\r
-                       free(keyBlock);\r
-                       return 0;\r
+                       if (found) break;\r
+                       if (!try_all_dl_modes) // Exit loop if not trying all downlink modes\r
+                               dl_mode = 4;                    \r
                }\r
-               found = tryDetectModulation();\r
-\r
                if (found) break;\r
                i++;\r
        }\r
 \r
-       PrintAndLog("");\r
-\r
-       if (found)\r
+       if (found){\r
                PrintAndLog("Found valid password: [%08x]", i);\r
-       else\r
+               T55xx_Print_DownlinkMode (downlink_mode);\r
+       }\r
+       else{\r
+               PrintAndLog("");\r
                PrintAndLog("Password NOT found. Last tried: [%08x]", --i);\r
+       }\r
 \r
        free(keyBlock);\r
        return 0;\r
 }\r
-\r
 // note length of data returned is different for different chips.  \r
 //   some return all page 1 (64 bits) and others return just that block (32 bits) \r
 //   unfortunately the 64 bits makes this more likely to get a false positive...\r
@@ -1558,7 +1646,7 @@ bool tryDetectP1(bool getData) {
        bool st = true;\r
 \r
        if ( getData ) {\r
-               if ( !AquireData(T55x7_PAGE1, 1, false, 0) )\r
+               if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) )\r
                        return false;\r
        }\r
 \r
@@ -1687,7 +1775,7 @@ int CmdT55xxDetectPage1(const char *Cmd){
        if (errors) return usage_t55xx_detectP1();\r
 \r
        if ( !useGB ) {\r
-               if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) )\r
+               if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) )\r
                        return false;\r
        }\r
        bool success = tryDetectP1(false);\r
@@ -1697,7 +1785,7 @@ int CmdT55xxDetectPage1(const char *Cmd){
 \r
 static command_t CommandTable[] = {\r
   {"help",      CmdHelp,           1, "This help"},\r
-       {"bruteforce",CmdT55xxBruteForce,0, "<start password> <end password> [i <*.dic>] Simple bruteforce attack to find password"},\r
+  {"bruteforce",CmdT55xxBruteForce,0, "<start password> <end password> [i <*.dic>] Simple bruteforce attack to find password"},\r
   {"config",    CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"},\r
   {"detect",    CmdT55xxDetect,    1, "[1] Try detecting the tag modulation from reading the configuration block."},\r
   {"p1detect",  CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"},\r
index 2ae3e69b571f0b11cd8d927fbec2dedac83080ac..4541bd3a6742c1149269dacb1d376002a6d668dd 100644 (file)
@@ -98,7 +98,7 @@ bool tryDetectModulation(void);
 extern bool tryDetectP1(bool getData);\r
 bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5);\r
 int special(const char *Cmd);\r
-int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password );\r
+int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode );\r
 \r
 void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat );\r
 void printT5555Trace( t5555_tracedata_t data, uint8_t repeat );\r
Impressum, Datenschutz