From: marshmellow42 Date: Thu, 11 Jul 2019 17:17:36 +0000 (-0400) Subject: Merge pull request #837 from mwalker33/master X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/4d8a07c829139419f05fbce09135c89cbb3c512f?hp=2de26056ce3650d8ae48f30bf657e27b3669a0a3 Merge pull request #837 from mwalker33/master lf t55xx downlink modes support added --- diff --git a/CHANGELOG.md b/CHANGELOG.md index cb508cd9..037bab99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 [ 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] diff --git a/armsrc/lfops.c b/armsrc/lfops.c index ed207dbb..c9947d97 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -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) 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); } } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index b286c392..c64e5ef2 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,6 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -86,6 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -132,6 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -162,7 +168,7 @@ int usage_t55xx_wakup(){ PrintAndLog(" - [required] password 4bytes (8 hex symbols)"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); + PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); return 0; } int usage_t55xx_bruteforce(){ @@ -172,13 +178,16 @@ int usage_t55xx_bruteforce(){ PrintAndLog(" password must be 4 bytes (8 hex symbols)"); PrintAndLog("Options:"); PrintAndLog(" h - this help"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(" - 4 byte hex value to start pwd search at"); PrintAndLog(" - 4 byte hex value to end pwd search at"); PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(" lf t55xx bruteforce [r 2] aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce [r 2] i default_pwd.dic"); PrintAndLog(""); return 0; } @@ -302,21 +311,21 @@ int CmdT55xxSetConfig(const char *Cmd) { } // No args - if (cmdp == 0) return printConfiguration( config ); + if (cmdp == 0) return printConfiguration( config); //Validations if (errors) return usage_t55xx_config(); config.block0 = 0; - return printConfiguration ( config ); + return printConfiguration ( config); } -int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){ +int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ //Password mode if ( usepwd ) { // try reading the config block and verify that PWD bit is set before doing this! if ( !override ) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0; + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0; if ( !tryDetectModulation() ) { PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits."); return 0; @@ -330,7 +339,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 } } - if (!AquireData(page1, block, usepwd, password) ) return 0; + if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0; if (!DecodeT55xxBlock()) return 0; char blk[10]={0}; @@ -342,6 +351,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 int CmdT55xxReadBlock(const char *Cmd) { uint8_t block = REGULAR_READ_MODE_BLOCK; uint32_t password = 0; //default to blank Block 7 + uint8_t downlink_mode = 0; + bool usepwd = false; bool override = false; bool page1 = false; @@ -372,6 +383,12 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'r': + case 'R': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -386,7 +403,7 @@ int CmdT55xxReadBlock(const char *Cmd) { } printT5xxHeader(page1); - return T55xxReadBlock(block, page1, usepwd, override, password); + return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode); } bool DecodeT55xxBlock(){ @@ -459,12 +476,32 @@ bool DecodeT5555TraceBlock() { return (bool) ASKDemod("64 0 1", false, false, 1); } +void T55xx_Print_DownlinkMode (uint8_t downlink_mode) +{ + char Msg[80]; + sprintf (Msg,"Downlink Mode used : "); + + switch (downlink_mode) { + case 0 : strcat (Msg,"default/fixed bit length"); break; + case 1 : strcat (Msg,"long leading reference (r 1)"); break; + case 2 : strcat (Msg,"leading zero reference (r 2)"); break; + case 3 : strcat (Msg,"1 of 4 coding reference (r 3)"); break; + default : + strcat (Msg,"default/fixed bit length"); break; + + } + + PrintAndLog (Msg); + +} + int CmdT55xxDetect(const char *Cmd){ bool errors = false; bool useGB = false; bool usepwd = false; uint32_t password = 0; uint8_t cmdp = 0; + uint8_t downlink_mode = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { @@ -482,6 +519,12 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; + case 'r': + case 'R': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -491,13 +534,16 @@ int CmdT55xxDetect(const char *Cmd){ if (errors) return usage_t55xx_detect(); if ( !useGB) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) ) + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) ) return 0; } if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); - + else { + // Add downlink mode for reference. + T55xx_Print_DownlinkMode (downlink_mode); + } return 1; } @@ -649,7 +695,8 @@ bool tryDetectModulation(){ config.block0 = tests[0].block0; config.Q5 = tests[0].Q5; config.ST = tests[0].ST; - printConfiguration( config ); + + printConfiguration( config); return true; } @@ -657,7 +704,7 @@ bool tryDetectModulation(){ PrintAndLog("Found [%d] possible matches for modulation.",hits); for(int i=0; i 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -952,17 +1007,19 @@ int CmdT55xxWriteBlock(const char *Cmd) { UsbCommand resp; c.d.asBytes[0] = (page1) ? 0x2 : 0; c.d.asBytes[0] |= (testMode) ? 0x4 : 0; - + c.d.asBytes[0] |= (downlink_mode << 3); + char pwdStr[16] = {0}; snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); PrintAndLog("Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); - + //Password mode if (usepwd) { c.arg[2] = password; c.d.asBytes[0] |= 0x1; } + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ @@ -980,7 +1037,7 @@ int CmdT55xxReadTrace(const char *Cmd) { return usage_t55xx_trace(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) ) return 0; if ( config.Q5 ) { @@ -1144,7 +1201,7 @@ int CmdT55xxInfo(const char *Cmd){ return usage_t55xx_info(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) ) return 1; if (!DecodeT55xxBlock()) return 1; @@ -1212,20 +1269,21 @@ int CmdT55xxDump(const char *Cmd){ printT5xxHeader(0); for ( uint8_t i = 0; i <8; ++i) - T55xxReadBlock(i, 0, usepwd, override, password); + T55xxReadBlock(i, 0, usepwd, override, password,0); printT5xxHeader(1); for ( uint8_t i = 0; i<4; i++) - T55xxReadBlock(i, 1, usepwd, override, password); + T55xxReadBlock(i, 1, usepwd, override, password,0); return 1; } -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){ +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){ // arg0 bitmodes: // bit0 = pwdmode // bit1 = page to read from uint8_t arg0 = (page<<1) | pwdmode; + arg0 |= (downlink_mode << 3); UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}}; clearCommandBuffer(); @@ -1403,9 +1461,23 @@ int CmdT55xxBruteForce(const char *Cmd) { uint32_t start_password = 0x00000000; //start password uint32_t end_password = 0xFFFFFFFF; //end password bool found = false; - + uint8_t downlink_mode = 0; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + uint8_t cmd_offset = 0; + int cmd_opt = 0; + char cmdp = param_getchar(Cmd, 0); + if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce(); + if (cmdp == 'r' || cmdp == 'R') { + downlink_mode = param_getchar(Cmd, 1) - '0'; // get 2nd option, as this is fixed order. + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmd_opt += 2; // To help start/end passwords for range to be found + cmd_offset += 4; // r x To help the string offset for filename start position in cmd + cmdp = param_getchar(Cmd, 2); // get 3rd option, as this is fixed order. + } keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; @@ -1414,7 +1486,7 @@ int CmdT55xxBruteForce(const char *Cmd) { int len = strlen(Cmd+2); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd+2, len); + memcpy(filename, Cmd+2+cmd_offset, len); FILE * f = fopen( filename , "r"); @@ -1479,20 +1551,29 @@ int CmdT55xxBruteForce(const char *Cmd) { testpwd = bytes_to_num(keyBlock + 4*c, 4); PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) { + PrintAndLog("Acquiring data from device failed. Quitting"); + free(keyBlock); + return 0; + } - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } + found = tryDetectModulation(); - found = tryDetectModulation(); + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + + T55xx_Print_DownlinkMode (dl_mode); - if ( found ) { - PrintAndLog("Found valid password: [%08X]", testpwd); - free(keyBlock); - return 0; - } + return 0; + } + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; + } } PrintAndLog("Password NOT found."); free(keyBlock); @@ -1502,8 +1583,8 @@ int CmdT55xxBruteForce(const char *Cmd) { // Try to read Block 7, first :) // incremental pwd range search - start_password = param_get32ex(Cmd, 0, 0, 16); - end_password = param_get32ex(Cmd, 1, 0, 16); + start_password = param_get32ex(Cmd, cmd_opt , 0, 16); + end_password = param_get32ex(Cmd, cmd_opt+1 , 0, 16); if ( start_password >= end_password ) { free(keyBlock); @@ -1524,29 +1605,36 @@ int CmdT55xxBruteForce(const char *Cmd) { free(keyBlock); return 0; } + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) { + PrintAndLog("Acquiring data from device failed. Quitting"); + free(keyBlock); + return 0; + } + found = tryDetectModulation(); - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; + if (found) break; + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; } - found = tryDetectModulation(); - if (found) break; i++; } - PrintAndLog(""); - - if (found) + if (found){ PrintAndLog("Found valid password: [%08x]", i); - else + T55xx_Print_DownlinkMode (downlink_mode); + } + else{ + PrintAndLog(""); PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + } free(keyBlock); return 0; } - // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1558,7 +1646,7 @@ bool tryDetectP1(bool getData) { bool st = true; if ( getData ) { - if ( !AquireData(T55x7_PAGE1, 1, false, 0) ) + if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) ) return false; } @@ -1687,7 +1775,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ if (errors) return usage_t55xx_detectP1(); if ( !useGB ) { - if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) ) + if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) ) return false; } bool success = tryDetectP1(false); @@ -1697,7 +1785,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 2ae3e69b..4541bd3a 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -98,7 +98,7 @@ bool tryDetectModulation(void); extern bool tryDetectP1(bool getData); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5); int special(const char *Cmd); -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ); +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode ); void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ); void printT5555Trace( t5555_tracedata_t data, uint8_t repeat );