Added T55 downlink mode support

This commit is contained in:
mwalker33 2019-07-23 09:50:28 +10:00
commit 4e0e69ed63
8 changed files with 1017 additions and 415 deletions

View file

@ -293,6 +293,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk) - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk)
- Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk) - Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk)
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk) - Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
- Added T55x7 downlink mode support r <mode> 0 Default, 1 Long Leading 0, 2 Leading 0, 3 1 of 4 and 4 (in some commands) try all.
### Fixed ### Fixed
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)

View file

@ -873,12 +873,13 @@ static void PacketReceived(PacketCommandNG *packet) {
case CMD_T55XX_READ_BLOCK: { case CMD_T55XX_READ_BLOCK: {
struct p { struct p {
uint32_t password; uint32_t password;
uint8_t blockno; uint8_t blockno;
uint8_t page; uint8_t page;
bool pwdmode; bool pwdmode;
uint8_t downlink_mode;
} PACKED; } PACKED;
struct p *payload = (struct p *) packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
T55xxReadBlock(payload->page, payload->pwdmode, false, payload->blockno, payload->password); T55xxReadBlock(payload->page, payload->pwdmode, false, payload->blockno, payload->password,payload->downlink_mode);
break; break;
} }
case CMD_T55XX_WRITE_BLOCK: { case CMD_T55XX_WRITE_BLOCK: {
@ -887,15 +888,15 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_T55XX_WAKEUP: { case CMD_T55XX_WAKEUP: {
T55xxWakeUp(packet->oldarg[0]); T55xxWakeUp(packet->oldarg[0],packet->oldarg[1]);
break; break;
} }
case CMD_T55XX_RESET_READ: { case CMD_T55XX_RESET_READ: {
T55xxResetRead(); T55xxResetRead(packet->data.asBytes[0]&0xff);
break; break;
} }
case CMD_T55XX_CHKPWDS: { case CMD_T55XX_CHKPWDS: {
T55xx_ChkPwds(); T55xx_ChkPwds(packet->data.asBytes[0]&0xff);
break; break;
} }
case CMD_PCF7931_READ: { case CMD_PCF7931_READ: {

View file

@ -102,12 +102,13 @@ void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5);
void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo); void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo);
void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7 void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7
void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7); // Clone Indala 224-bit tag by UID to T55x7 void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7); // Clone Indala 224-bit tag by UID to T55x7
void T55xxResetRead(void); void T55xxResetRead(uint8_t flags);
//id T55xxWriteBlock(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
void T55xxWriteBlock(uint8_t *data); void T55xxWriteBlock(uint8_t *data);
void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags); // void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd); void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd,uint8_t downlink_mode);
void T55xxWakeUp(uint32_t Pwd); void T55xxWakeUp(uint32_t Pwd, uint8_t flags);
void T55xx_ChkPwds(void); void T55xx_ChkPwds(uint8_t flags);
void TurnReadLFOn(uint32_t delay); void TurnReadLFOn(uint32_t delay);

View file

@ -46,31 +46,133 @@
// = 1us = 1.5ticks // = 1us = 1.5ticks
// 1fc = 8us = 12ticks // 1fc = 8us = 12ticks
/* /*
Default LF T55xx config is set to: ==========================================================================================================
startgap = 31*8 T55x7 Timing
writegap = 17*8 ==========================================================================================================
write_0 = 15*8
write_1 = 47*8 // t55xx_config t_config = { 29 * 8, 17 * 8, 15 * 8, 47 * 8, 15 * 8 } ;
read_gap = 15*8
ATA5577 Downlink Protocol Timings.
Note: All absolute times assume TC = 1 / fC = 8 μs (fC = 125 kHz)
-----------------------------------------------------------------------
Fixed-bit-length Protocol | Normal Downlink | Fast Downlink |
------------------------------+-----------------------------------+-----------------------------------+------
| Parameter | Remark | Symbol | Min. | Typ. | Max. | Min. | Typ. | Max. | Unit |
|------------+--------+--------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Start gap | | Sgap | 8 | 15 | 50 | 8 | 15 | 50 | Tc |
| Write gap | | Wgap | 8 | 10 | 20 | 8 | 10 | 20 | Tc |
|------------+--------+--------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| coding | 0 data | d0 | 16 | 24 | 32 | 8 | 12 | 16 | Tc |
| | 1 data | d1 | 48 | 56 | 64 | 24 | 28 | 32 | Tc |
-------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------
Long Leading Reference | Normal Downlink | Fast Downlink |
------------------------------+-----------------------------------+-----------------------------------+------
| Parameter | Remark | Symbol | Min. | Typ. | Max. | Min. | Typ. | Max. | Unit |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Start gap | | Sgap | 8 | 10 | 50 | 8 | 10 | 50 | Tc |
| Write gap | | Wgap | 8 | 10 | 20 | 8 | 10 | 20 | Tc |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Write | Ref | | 152 | 160 | 168 | 140 | 144 | 148 | Tc |
| data | Pulse | dref | 136 clocks + 0 data bit | 132 clocks + 0 data bit | Tc |
| coding |--------+---------+-----------------------------------+-----------------------------------+------|
| | 0 data | d0 |dref 143 |dref 136 |dref 128 |dref 135 |dref 132 |dref 124 | Tc |
| | 1 data | d1 |dref 111 |dref 104 |dref 96 |dref 119 |dref 116 |dref 112 | Tc |
-------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------
Leading-zero Reference | Normal Downlink | Fast Downlink |
------------------------------+-----------------------------------+-----------------------------------+------
| Parameter | Remark | Symbol | Min. | Typ. | Max. | Min. | Typ. | Max. | Unit |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Start gap | | Sgap | 8 | 10 | 50 | 8 | 10 | 50 | Tc |
| Write gap | | Wgap | 8 | 10 | 20 | 8 | 10 | 20 | Tc |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Write | Ref | dref | 12 | | 72 | 8 | | 68 | Tc |
| data | 0 data | d0 | dref 7 | dref | dref + 8 | dref 3 | dref | dref + 4 | Tc |
| coding | 1 data | d1 | dref + 9 | dref + 16 | dref + 24 | dref + 5 | dref + 8 | dref + 12 | Tc |
-------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------
1-of-4 Coding | Normal Downlink | Fast Downlink |
------------------------------+-----------------------------------+-----------------------------------+------
| Parameter | Remark | Symbol | Min. | Typ. | Max. | Min. | Typ. | Max. | Unit |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Start gap | | Sgap | 8 | 10 | 50 | 8 | 10 | 50 | Tc |
| Write gap | | Wgap | 8 | 10 | 20 | 8 | 10 | 20 | Tc |
|-----------+--------+---------+-----------+-----------+-----------+-----------+-----------+-----------+------|
| Write | Ref 00 | dref | 8 | | 68 | 12 | | 72 | Tc |
| data |00 data | d00 | dref 7 | dref | dref + 8 | dref 3 | dref | dref+ 4 | Tc |
| coding |01 data | d01 | dref + 9 | dref + 16 | dref + 24 | dref + 5 | dref + 8 | dref + 12 | Tc |
| |10 data | d10 | dref + 25 | dref + 32 | dref + 40 | dref + 13 | dref + 16 | dref + 20 | Tc |
| |11 data | d11 | dref + 41 | dref + 48 | dref + 56 | dref + 21 | dref + 24 | dref + 28 | Tc |
-------------------------------------------------------------------------------------------------------------
*/ */
t55xx_config t_config = { 29 * 8, 17 * 8, 15 * 8, 47 * 8, 15 * 8 } ; // Initial values if not in flash
// Note: Moved * 8 to apply when used. Saving 28 bytes here (- the *8) and 28 bytes flash.
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
t55xx_config T55xx_Timing = {{{ 29 , 17 , 15 , 50 , 0 , 0 , 15 }, // Default Fixed
{ 31 , 20 , 18 , 50 , 0 , 0 , 15 }, // Long Leading Ref.
{ 31 , 20 , 18 , 40 , 0 , 0 , 15 }, // Leading 0
{ 29 , 17 , 15 , 31 , 47 , 63 , 15 } }}; // 1 of 4
/*
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
t55xx_config T55xx_Timing = {{{ 29 * 8 , 17 * 8 , 15 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }, // Default Fixed
{ 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }, // Long Leading Ref.
{ 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }, // Leading 0
{ 29 * 8 , 17 * 8 , 15 * 8 , 31 * 8 , 47 * 8, 63 * 8, 15 * 8 } }}; // 1 of 4
*/
// 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
void printT55xxConfig(void) { void printT55xxConfig(void) {
int DLMode;
DbpString(_BLUE_("LF T55XX config")); DbpString(_BLUE_("LF T55XX config"));
Dbprintf(" [a] startgap............%d*8 (%d)", t_config.start_gap / 8, t_config.start_gap); for (DLMode = 0; DLMode < 4; DLMode++) {
Dbprintf(" [b] writegap............%d*8 (%d)", t_config.write_gap / 8, t_config.write_gap); switch (DLMode){
Dbprintf(" [c] write_0.............%d*8 (%d)", t_config.write_0 / 8, t_config.write_0); case T55xx_DLMode_Fixed : Dbprintf("r 0 fixed bit length (default)"); break;
Dbprintf(" [d] write_1.............%d*8 (%d)", t_config.write_1 / 8, t_config.write_1); case T55xx_DLMode_LLR : Dbprintf("r 1 long leading reference"); break;
Dbprintf(" [e] readgap.............%d*8 (%d)", t_config.read_gap / 8, t_config.read_gap); case T55xx_DLMode_Leading0 : Dbprintf("r 2 leading zero"); break;
case T55xx_DLMode_1of4 : Dbprintf("r 3 1 of 4 coding reference"); break;
}
// Save 36 bytes by not showing dec. all data sheets and entry is the x * 8 value, so not sure what we get for the 36 bytes dec?
Dbprintf(" [a] startgap............%d*8", T55xx_Timing.m[DLMode].start_gap );//, T55xx_Timing.start_gap[DLMode]);
Dbprintf(" [b] writegap............%d*8", T55xx_Timing.m[DLMode].write_gap );//, T55xx_Timing.write_gap[DLMode]);
Dbprintf(" [c] write_0.............%d*8", T55xx_Timing.m[DLMode].write_0 );//, T55xx_Timing.write_0 [DLMode]);
Dbprintf(" [d] write_1.............%d*8", T55xx_Timing.m[DLMode].write_1 );//, T55xx_Timing.write_1 [DLMode]);
if (DLMode == T55xx_DLMode_1of4) {
Dbprintf(" [e] write_2.............%d*8", T55xx_Timing.m[DLMode].write_2 );//, T55xx_Timing.write_2 [DLMode]);
Dbprintf(" [f] write_3.............%d*8", T55xx_Timing.m[DLMode].write_3 );//, T55xx_Timing.write_3 [DLMode]);
}
Dbprintf(" [g] readgap.............%d*8", T55xx_Timing.m[DLMode].read_gap );//, T55xx_Timing.read_gap [DLMode]);
}
} }
void setT55xxConfig(uint8_t arg0, t55xx_config *c) { void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
uint8_t DLMode;
if (c->start_gap != 0) t_config.start_gap = c->start_gap;
if (c->write_gap != 0) t_config.write_gap = c->write_gap; for (DLMode = 0; DLMode < 4; DLMode++) {
if (c->write_0 != 0) t_config.write_0 = c->write_0; if (c->m[DLMode].start_gap != 0) T55xx_Timing.m[DLMode].start_gap = c->m[DLMode].start_gap;
if (c->write_1 != 0) t_config.write_1 = c->write_1; if (c->m[DLMode].write_gap != 0) T55xx_Timing.m[DLMode].write_gap = c->m[DLMode].write_gap;
if (c->read_gap != 0) t_config.read_gap = c->read_gap; if (c->m[DLMode].write_0 != 0) T55xx_Timing.m[DLMode].write_0 = c->m[DLMode].write_0 ;
if (c->m[DLMode].write_1 != 0) T55xx_Timing.m[DLMode].write_1 = c->m[DLMode].write_1 ;
if (DLMode == T55xx_DLMode_1of4) {
if (c->m[DLMode].write_2 != 0) T55xx_Timing.m[DLMode].write_2 = c->m[DLMode].write_2 ;
if (c->m[DLMode].write_3 != 0) T55xx_Timing.m[DLMode].write_3 = c->m[DLMode].write_3 ;
}
else{
T55xx_Timing.m[DLMode].write_2 = 0x00;
T55xx_Timing.m[DLMode].write_3 = 0x00;
}
if (c->m[DLMode].read_gap != 0) T55xx_Timing.m[DLMode].read_gap = c->m[DLMode].read_gap ;
}
printT55xxConfig(); printT55xxConfig();
@ -93,27 +195,32 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
return; return;
} }
memcpy(buf, &t_config, T55XX_CONFIG_LEN); memcpy(buf, &T55xx_Timing, T55XX_CONFIG_LEN);
Flash_CheckBusy(BUSY_TIMEOUT); Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable(); Flash_WriteEnable();
Flash_Erase4k(3, 0xD); Flash_Erase4k(3, 0xD);
res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN);
if (res == T55XX_CONFIG_LEN && DBGLEVEL > 1) { // if not a settings erase, write data
if (buf[0] != 0xff) {
res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN);
if (res == T55XX_CONFIG_LEN && DBGLEVEL > 1) {
DbpString("T55XX Config save success"); DbpString("T55XX Config save success");
} }
}
BigBuf_free(); BigBuf_free();
#endif #endif
} }
t55xx_config *getT55xxConfig(void) { t55xx_config *getT55xxConfig(void) {
return &t_config; return &T55xx_Timing;//_FixedBit;
} }
void loadT55xxConfig(void) { void loadT55xxConfig(void) {
#ifdef WITH_FLASH #ifdef WITH_FLASH
if (!FlashInit()) { if (!FlashInit()) {
return; return;
} }
@ -135,7 +242,7 @@ void loadT55xxConfig(void) {
return; return;
} }
memcpy((uint8_t *)&t_config, buf, T55XX_CONFIG_LEN); memcpy((uint8_t *)&T55xx_Timing, buf, T55XX_CONFIG_LEN);
if (isok == T55XX_CONFIG_LEN) { if (isok == T55XX_CONFIG_LEN) {
if (DBGLEVEL > 1) DbpString("T55XX Config load success"); if (DBGLEVEL > 1) DbpString("T55XX Config load success");
@ -1354,187 +1461,302 @@ void TurnReadLF_off(uint32_t delay) {
WaitUS(delay); WaitUS(delay);
} }
// Write one bit to card // Macro for code readability
void T55xxWriteBit(int bit) { #define BitStream_Byte(X) ((X) >> 3)
if (!bit) #define BitStream_Bit(X) ((X) & 7)
TurnReadLFOn(t_config.write_0); #define t55_send_PwdMode (arg & 0x01)
else #define t55_send_Page ((arg & 0x02) >> 1)
TurnReadLFOn(t_config.write_1); #define t55_send_TestMode ((arg & 0x04) >> 2)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); #define t55_send_RegReadMode ((arg & 0x20) >> 5)
WaitUS(t_config.write_gap); #define t55_send_ReadCmd ((arg & 0x40) >> 6)
#define t55_send_Reset ((arg & 0x80) >> 7)
// Write one bit to chip
void T55xxWriteBit(uint8_t bit, uint8_t downlink_idx) {
// Dbprintf ("%d",bit);
// If bit = 4 Send Long Leading Reference which is (138*8) + WRITE_0
switch (bit){
case 0 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_0 * 8); break; // Send bit 0/00
case 1 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_1 * 8); break; // Send bit 1/01
case 2 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_2 * 8); break; // Send bits 10 (1 of 4)
case 3 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_3 * 8); break; // Send bits 11 (1 of 4)
case 4 : TurnReadLFOn((T55xx_Timing.m[downlink_idx].write_0 + 136) * 8); break; // Send Long Leading Reference
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(T55xx_Timing.m[downlink_idx].write_gap * 8);
}
// 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)
uint8_t 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, uint8_t Block, uint32_t Pwd, uint8_t arg) {
void T55xx_SendCMD (uint32_t Data, uint32_t Pwd, uint16_t arg) {
/*
arg bits
xxxx xxxxxxx1 0x001 PwdMode
xxxx xxxxxx1x 0x002 Page
xxxx xxxxx1xx 0x004 testMode
xxxx xxx11xxx 0x018 downlink mode
xxxx xx1xxxxx 0x020 !reg_readmode
xxxx x1xxxxxx 0x040 called for a read, so no data packet
xxxx 1xxxxxxx 0x080 reset
xxx1 xxxxxxxx 0x100 brute force
111x xxxxxxxx 0xE00 Block
*/
uint8_t downlink_mode = (arg >> 3) & 0x03;
uint8_t i = 0;
uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits)
uint8_t BitStreamLen = 0;
uint8_t SendBits;
uint8_t start_wait = 4;
bool brute_mem = (arg & 0x100);
uint8_t Block = (arg >> 9) & 0x07;
if (brute_mem) start_wait = 0;
// 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 (t55_send_Reset) {
// Reset : r*) 00
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
}
else {
if (t55_send_TestMode) Dbprintf("TestMODE");
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,t55_send_TestMode ? 0 : 1 , 1,sizeof(BitStream));
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,t55_send_TestMode ? 1 : t55_send_Page , 1,sizeof(BitStream));
//if (PwdMode) {
if (t55_send_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 (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
// Add Data if a write command
if (!t55_send_ReadCmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream));
// Add Address
if (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream));
}
// Send Bits to T55xx
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
// make sure tag is fully powered up...
WaitMS(start_wait);
// Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(T55xx_Timing.m[downlink_mode].start_gap * 8);
// If long leading 0 send long reference pulse
if (downlink_mode == T55xx_DLMode_LLR)
T55xxWriteBit (T55xx_LongLeadingReference,downlink_mode);//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,downlink_mode);//Timing);
}
}
else {
for (i = 0; i < BitStreamLen; i++) {
SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i));
T55xxWriteBit (SendBits & 1,downlink_mode);//Timing);
}
}
} }
// Send T5577 reset command then read stream (see if we can identify the start of the stream) // Send T5577 reset command then read stream (see if we can identify the start of the stream)
void T55xxResetRead(void) { void T55xxResetRead(uint8_t flags) {
uint8_t downlink_mode = ((flags >> 3) & 3);
uint8_t arg = 0x80 | downlink_mode;
LED_A_ON(); LED_A_ON();
//clear buffer now so it does not interfere with timing later //clear buffer now so it does not interfere with timing later
BigBuf_Clear_keep_EM(); BigBuf_Clear_keep_EM();
// Set up FPGA, 125kHz T55xx_SendCMD (0, 0, arg);
LFSetupFPGAForADC(95, true);
// make sure tag is fully powered up...
WaitMS(4);
// Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(t_config.start_gap);
// reset tag - op code 00
T55xxWriteBit(0);
T55xxWriteBit(0);
TurnReadLFOn(t_config.read_gap);
TurnReadLFOn(T55xx_Timing.m[downlink_mode].read_gap * 8);
// Acquisition // Acquisition
DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0);
// Turn the field off // Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
reply_mix(CMD_ACK, 0, 0, 0, 0, 0); reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
LED_A_OFF(); LED_A_OFF();
} }
// Write one card block in page 0, no lock // Write one card block in page 0, no lock
void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags) { //void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags) {
LED_A_ON(); void T55xxWriteBlock(uint8_t *data) {
bool pwd_mode = (flags & 0x1);
uint8_t page = (flags & 0x2) >> 1;
bool test_mode = (flags & 0x4) >> 2;
uint32_t i = 0;
// Set up FPGA, 125kHz /*
LFSetupFPGAForADC(95, true); flag 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
*/
t55xx_write_block_t *c = (t55xx_write_block_t *)data;
// c->data, c->blockno, c->pwd, c->flags
// make sure tag is fully powered up... bool testMode = ((c->flags & 0x04) == 0x04);
WaitMS(4);
// Trigger T55x7 in mode. c->flags &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(t_config.start_gap); LED_A_ON ();
T55xx_SendCMD (c->data, c->pwd, c->flags | (c->blockno << 9)) ;//, false);
if (test_mode) { // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
Dbprintf("T55xx writing with %s", _YELLOW_("test mode enabled")); // so wait a little more)
// undocmented testmode opcode 01
T55xxWriteBit(0);
T55xxWriteBit(1);
} else {
// std opcode 10 == page 0
// std opcode 11 == page 1
T55xxWriteBit(1);
T55xxWriteBit(page);
}
if (pwd_mode) { // "there is a clock delay before programming"
// Send pwd // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567
for (i = 0x80000000; i != 0; i >>= 1) // so we should wait 1 clock + 5.6ms then read response?
T55xxWriteBit(pwd & i); // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow...
} if (testMode) {
// Send lock bit //TESTMODE TIMING TESTS:
T55xxWriteBit(0); // <566us does nothing
// 566-568 switches between wiping to 0s and doing nothing
// 5184 wipes and allows 1 block to be programmed.
// indefinite power on wipes and then programs all blocks with bitshifted data sent.
TurnReadLFOn(5184);
// Send data } else {
for (i = 0x80000000; i != 0; i >>= 1) TurnReadLFOn(20 * 1000);
T55xxWriteBit(data & i); //could attempt to do a read to confirm write took
// as the tag should repeat back the new block
// until it is reset, but to confirm it we would
// need to know the current block 0 config mode for
// modulation clock an other details to demod the response...
// response should be (for t55x7) a 0 bit then (ST if on)
// block data written in on repeat until reset.
// Send block number //DoPartialAcquisition(20, true, 12000);
for (i = 0x04; i != 0; i >>= 1) }
T55xxWriteBit(blockno & i); // turn field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, // cmd_send(CMD_ACK,0,0,0,0,0);
// so wait a little more) reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0);
LED_A_OFF ();
// "there is a clock delay before programming"
// - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567
// so we should wait 1 clock + 5.6ms then read response?
// but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow...
if (test_mode) {
//TESTMODE TIMING TESTS:
// <566us does nothing
// 566-568 switches between wiping to 0s and doing nothing
// 5184 wipes and allows 1 block to be programmed.
// indefinite power on wipes and then programs all blocks with bitshifted data sent.
TurnReadLFOn(5184);
} else {
TurnReadLFOn(20 * 1000);
//could attempt to do a read to confirm write took
// as the tag should repeat back the new block
// until it is reset, but to confirm it we would
// need to know the current block 0 config mode for
// modulation clock an other details to demod the response...
// response should be (for t55x7) a 0 bit then (ST if on)
// block data written in on repeat until reset.
//DoPartialAcquisition(20, true, 12000);
}
// turn field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_A_OFF();
} }
// Write one card block in page 0, no lock /*
// uses NG format // uses NG format
void T55xxWriteBlock(uint8_t *data) { void T55xxWriteBlock(uint8_t *data) {
t55xx_write_block_t *c = (t55xx_write_block_t *)data; t55xx_write_block_t *c = (t55xx_write_block_t *)data;
T55xxWriteBlockExt(c->data, c->blockno, c->pwd, c->flags); T55xxWriteBlockExt(c->data, c->blockno, c->pwd, c->flags);
reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0); // reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0);
} }
*/
/*
// Read one card block in page [page] // Read one card block in page [page]
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd) { void T55xxReadBlockExt (uint16_t flags, uint8_t block, uint32_t pwd) {
LED_A_ON(); / *
bool regular_readmode = (block == 0xFF); flag bits
uint8_t start_wait = 4; xxxx xxxxxxx1 0x0001 PwdMode
size_t samples = 12000; xxxx xxxxxx1x 0x0002 Page
uint32_t i; xxxx xxxxx1xx 0x0004 testMode
xxxx xxx11xxx 0x0018 downlink mode
xxxx xx1xxxxx 0x0020 !reg_readmode
xxxx x1xxxxxx 0x0040 called for a read, so no data packet
xxxx 1xxxxxxx 0x0080 reset
xxx1 xxxxxxxx 0x0100 brute/leave field on
* /
size_t samples = 12000;
bool brute_mem = (flags & 0x0100) >> 8;
LED_A_ON();
if (brute_mem) { if (brute_mem) samples = 1024;
start_wait = 0;
samples = 1024; // Set Read Flag to ensure SendCMD does not add "data" to the packet
} flags |= 0x40;
//clear buffer now so it does not interfere with timing later // RegRead Mode true block = 0xff, so read without an address
BigBuf_Clear_keep_EM(); if (block == 0xff) flags |= 0x20;
//make sure block is at max 7
block &= 0x7;
//make sure block is at max 7 //clear buffer now so it does not interfere with timing later
block &= 0x7; BigBuf_Clear_keep_EM();
// Set up FPGA, 125kHz to power up the tag T55xx_SendCMD (0, pwd, flags | (block << 9)); //, true);
LFSetupFPGAForADC(95, true);
// make sure tag is fully powered up...
WaitMS(start_wait);
// Trigger T55x7 Direct Access Mode with start gap // Turn field on to read the response
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // 137*8 seems to get to the start of data pretty well...
WaitUS(t_config.start_gap); // but we want to go past the start and let the repeating data settle in...
// Opcode 1[page] // TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
T55xxWriteBit(1); TurnReadLFOn(137*8);
T55xxWriteBit(page); //Page 0
if (pwd_mode) { // Acquisition
// Send Pwd // Now do the acquisition
for (i = 0x80000000; i != 0; i >>= 1) DoPartialAcquisition(0, true, samples, 0);
T55xxWriteBit(pwd & i);
}
// Send a zero bit separation
T55xxWriteBit(0);
// Send Block number (if direct access mode)
if (!regular_readmode)
for (i = 0x04; i != 0; i >>= 1)
T55xxWriteBit(block & i);
// Turn field on to read the response
// 137*8 seems to get to the start of data pretty well...
// but we want to go past the start and let the repeating data settle in...
TurnReadLFOn(150 * 8);
// Acquisition
// Now do the acquisition
DoPartialAcquisition(0, true, samples, 0);
// Turn the field off // Turn the field off
if (!brute_mem) { if (!brute_mem) {
@ -1543,25 +1765,84 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
LED_A_OFF(); LED_A_OFF();
} }
} }
*/
// Read one card block in page [page]
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd, uint8_t downlink_mode) {
/*
flag bits
xxxxxxx1 0x0001 PwdMode
xxxxxx1x 0x0002 Page
xxxxx1xx 0x0004 testMode
xxx11xxx 0x0018 downlink mode
xx1xxxxx 0x0020 !reg_readmode
x1xxxxxx 0x0040 called for a read, so no data packet
1xxxxxxx 0x0080 reset
1xxxxxxxx 0x0100 brute/leave field on
*/
uint16_t flags = 0x0040; // read packet
if (pwd_mode) flags |= 0x0001;
if (page) flags |= 0x0002;
flags |= (downlink_mode & 3) << 3;
if (brute_mem) flags |= 0x0100;
// T55xxReadBlockExt (flags,block,pwd);
size_t samples = 12000;
// bool brute_mem = (flags & 0x0100) >> 8;
LED_A_ON();
void T55xx_ChkPwds() { if (brute_mem) samples = 1024;
//-- Set Read Flag to ensure SendCMD does not add "data" to the packet
//-- flags |= 0x40;
// RegRead Mode true block = 0xff, so read without an address
if (block == 0xff) flags |= 0x20;
//make sure block is at max 7
block &= 0x7;
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_keep_EM();
T55xx_SendCMD (0, pwd, flags | (block << 9)); //, true);
// Turn field on to read the response
// 137*8 seems to get to the start of data pretty well...
// but we want to go past the start and let the repeating data settle in...
// TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
TurnReadLFOn(137*8);
// Acquisition
// Now do the acquisition
DoPartialAcquisition(0, true, samples, 0);
// Turn the field off
if (!brute_mem) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_T55XX_READ_BLOCK, PM3_SUCCESS, NULL, 0);
LED_A_OFF();
}
}
void T55xx_ChkPwds(uint8_t flags) {
DbpString("[+] T55XX Check pwds using flashmemory starting"); DbpString("[+] T55XX Check pwds using flashmemory starting");
uint8_t ret = 0; uint8_t ret = 0;
// First get baseline and setup LF mode. // First get baseline and setup LF mode.
// tends to mess up BigBuf // tends to mess up BigBuf
uint8_t *buf = BigBuf_get_addr(); uint8_t *buf = BigBuf_get_addr();
uint32_t b1, baseline = 0;
uint32_t b1, baseline = 0; uint8_t downlink_mode = (flags >> 3) & 0x03;
// collect baseline for failed attempt // collect baseline for failed attempt
uint8_t x = 32; uint8_t x = 32;
while (x--) { while (x--) {
b1 = 0; b1 = 0;
T55xxReadBlock(0, 0, true, 1, 0,downlink_mode);
// T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd)
T55xxReadBlock(0, 0, true, 1, 0);
for (uint16_t j = 0; j < 1024; ++j) for (uint16_t j = 0; j < 1024; ++j)
b1 += buf[j]; b1 += buf[j];
@ -1576,8 +1857,8 @@ void T55xx_ChkPwds() {
uint8_t *pwds = BigBuf_get_EM_addr(); uint8_t *pwds = BigBuf_get_EM_addr();
uint16_t pwdCount = 0; uint16_t pwdCount = 0;
uint32_t candidate = 0; uint32_t candidate = 0;
#ifdef WITH_FLASH #ifdef WITH_FLASH
BigBuf_Clear_EM(); BigBuf_Clear_EM();
uint16_t isok = 0; uint16_t isok = 0;
uint8_t counter[2] = {0x00, 0x00}; uint8_t counter[2] = {0x00, 0x00};
@ -1606,7 +1887,7 @@ void T55xx_ChkPwds() {
pwd = bytes_to_num(pwds + i * 4, 4); pwd = bytes_to_num(pwds + i * 4, 4);
T55xxReadBlock(0, true, true, 0, pwd); T55xxReadBlock(0, true, true, 0, pwd,downlink_mode);
// calc mean of BigBuf 1024 samples. // calc mean of BigBuf 1024 samples.
uint32_t sum = 0; uint32_t sum = 0;
@ -1623,9 +1904,7 @@ void T55xx_ChkPwds() {
Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr); Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr);
if (curr > prev) { if (curr > prev) {
Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd);
Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd);
candidate = pwd; candidate = pwd;
prev = curr; prev = curr;
} }
@ -1640,36 +1919,31 @@ OUT:
LEDsoff(); LEDsoff();
} }
void T55xxWakeUp(uint32_t Pwd) { void T55xxWakeUp(uint32_t Pwd, uint8_t flags) {
flags |= 0x01 | 0x40 | 0x20; //Password | Read Call (no data) | reg_read no block
LED_B_ON(); LED_B_ON();
uint32_t i = 0;
// Set up FPGA, 125kHz T55xx_SendCMD (0, Pwd, flags);
LFSetupFPGAForADC(95, true);
// make sure tag is fully powered up... //-- Turn and leave field on to let the begin repeating transmission
WaitMS(4);
// Trigger T55x7 Direct Access Mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(t_config.start_gap);
// Opcode 10
T55xxWriteBit(1);
T55xxWriteBit(0); //Page 0
// Send Pwd
for (i = 0x80000000; i != 0; i >>= 1)
T55xxWriteBit(Pwd & i);
// Turn and leave field on to let the begin repeating transmission
TurnReadLFOn(20 * 1000); TurnReadLFOn(20 * 1000);
} }
/*-------------- Cloning routines -----------*/ /*-------------- Cloning routines -----------*/
void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { 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--) t55xx_write_block_t cmd;
T55xxWriteBlockExt(blockdata[i - 1], i - 1, 0, 0); cmd.pwd = 0;
cmd.flags = 0;
for (uint8_t i = numblocks + startblock; i > startblock; i--) {
cmd.data = blockdata[i - 1];
cmd.blockno = i - 1;
T55xxWriteBlock ((uint8_t *)&cmd);
}
} }
// Copy HID id to card and setup block 0 config // Copy HID id to card and setup block 0 config

File diff suppressed because it is too large Load diff

View file

@ -148,9 +148,9 @@ char *GetModelStrFromCID(uint32_t cid);
char *GetSelectedModulationStr(uint8_t id); char *GetSelectedModulationStr(uint8_t id);
void printT5xxHeader(uint8_t page); void printT5xxHeader(uint8_t page);
void printT55xxBlock(uint8_t blockNum); void printT55xxBlock(uint8_t blockNum);
int printConfiguration(t55xx_conf_block_t b); int printConfiguration(t55xx_conf_block_t b);
int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password); int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode);
bool GetT55xxBlockData(uint32_t *blockdata); bool GetT55xxBlockData(uint32_t *blockdata);
bool DecodeT55xxBlock(void); bool DecodeT55xxBlock(void);
bool tryDetectModulation(void); bool tryDetectModulation(void);
@ -158,9 +158,9 @@ bool testKnownConfigBlock(uint32_t block0);
bool tryDetectP1(bool getData); bool tryDetectP1(bool getData);
bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5);
int special(const char *Cmd); int special(const char *Cmd);
bool AquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password); bool AquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode);
int tryOnePassword(uint32_t password); uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode);
void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat); void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat);
void printT5555Trace(t5555_tracedata_t data, uint8_t repeat); void printT5555Trace(t5555_tracedata_t data, uint8_t repeat);

View file

@ -903,7 +903,7 @@ static int l_T55xx_readblock(lua_State *L) {
// try reading the config block and verify that PWD bit is set before doing this! // try reading the config block and verify that PWD bit is set before doing this!
if (!override) { if (!override) {
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0)) { if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,0)) {
return returnToLuaWithError(L, "Failed to read config block"); return returnToLuaWithError(L, "Failed to read config block");
} }
@ -920,7 +920,7 @@ static int l_T55xx_readblock(lua_State *L) {
} }
} }
if (!AquireData(usepage1, block, usepwd, password)) { if (!AquireData(usepage1, block, usepwd, password,0)) {
return returnToLuaWithError(L, "Failed to aquire data from card"); return returnToLuaWithError(L, "Failed to aquire data from card");
} }
@ -977,7 +977,7 @@ static int l_T55xx_detect(lua_State *L) {
if (!useGB) { if (!useGB) {
isok = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password); isok = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,0);
if (isok == false) { if (isok == false) {
return returnToLuaWithError(L, "Failed to aquire LF signal data"); return returnToLuaWithError(L, "Failed to aquire LF signal data");
} }

View file

@ -119,7 +119,7 @@ typedef struct {
int divisor; int divisor;
int trigger_threshold; int trigger_threshold;
} sample_config; } sample_config;
/*
typedef struct { typedef struct {
uint16_t start_gap; uint16_t start_gap;
uint16_t write_gap; uint16_t write_gap;
@ -127,7 +127,34 @@ typedef struct {
uint16_t write_1; uint16_t write_1;
uint16_t read_gap; uint16_t read_gap;
} t55xx_config; } t55xx_config;
*/
// Extended to support 1 of 4 timing
typedef struct {
uint8_t start_gap ;
uint8_t write_gap ;
uint8_t write_0 ;
uint8_t write_1 ;
uint8_t write_2 ;
uint8_t write_3 ;
uint8_t read_gap ;
} t55xx_config_t;
// This setup will allow for the 4 downlink modes "m" as well as other items if needed.
// Given the one struct we can then read/write to flash/client in one go.
typedef struct {
t55xx_config_t m[4]; // mode
} t55xx_config;
/*typedef struct {
uint16_t start_gap [4];
uint16_t write_gap [4];
uint16_t write_0 [4];
uint16_t write_1 [4];
uint16_t write_2 [4];
uint16_t write_3 [4];
uint16_t read_gap [4];
} t55xx_config;
*/
typedef struct { typedef struct {
uint8_t version; uint8_t version;
uint32_t baudrate; uint32_t baudrate;