diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5c645062d..248346b4f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -804,6 +804,10 @@ static void PacketReceived(PacketCommandNG *packet) { T55xxWriteBlock(packet->data.asBytes); break; } + case CMD_LF_T55XX_DANGERRAW: { + T55xxDangerousRawTest(packet->data.asBytes); + break; + } case CMD_LF_T55XX_WAKEUP: { struct p { uint32_t password; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 862f31626..5ff1867de 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1703,6 +1703,45 @@ void T55xxResetRead(uint8_t flags) { LED_A_OFF(); } +void T55xxDangerousRawTest(uint8_t *data) { + // supports only default downlink mode + t55xx_test_block_t *c = (t55xx_test_block_t *)data; + + uint8_t start_wait = 4; + uint8_t bs[128/8]; + memset(bs, 0x00, sizeof(bs)); + uint8_t len = 0; + if (c->bitlen == 0 || c->bitlen > 128 || c->time == 0) + reply_ng(CMD_LF_T55XX_DANGERRAW, PM3_EINVARG, NULL, 0); + for (uint8_t i=0; ibitlen; i++) + len = T55xx_SetBits(bs, len, c->data[i], 1, sizeof(bs)); + + if (DBGLEVEL > 1) { + Dbprintf("LEN %i, TIMING %i", len, c->time); + for (uint8_t i = 0; i < len; i++) { + uint8_t sendbits = (bs[BITSTREAM_BYTE(i)] >> BITSTREAM_BIT(i)); + Dbprintf("%02i: %i", i, sendbits & 1); + } + } + + LED_A_ON(); + LFSetupFPGAForADC(LF_DIVISOR_125, true); + // make sure tag is fully powered up... + WaitMS(start_wait); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(T55xx_Timing.m[0].start_gap); + uint8_t sendbits; + for (uint8_t i = 0; i < len; i++) { + sendbits = (bs[BITSTREAM_BYTE(i)] >> BITSTREAM_BIT(i)); + T55xxWriteBit(sendbits & 1, 0); + } + TurnReadLFOn(c->time); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_T55XX_DANGERRAW, PM3_SUCCESS, NULL, 0); + LED_A_OFF(); +} + // Write one card block in page 0, no lock //void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags) { void T55xxWriteBlock(uint8_t *data) { diff --git a/armsrc/lfops.h b/armsrc/lfops.h index bf246b529..f81d1e7ab 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -52,6 +52,7 @@ void T55xxWriteBlock(uint8_t *data); 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, uint8_t flags); void T55xx_ChkPwds(uint8_t flags); +void T55xxDangerousRawTest(uint8_t *data); void TurnReadLFOn(uint32_t delay); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 8053c2e76..b96dd4cb8 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -1672,6 +1672,69 @@ static int CmdT55xxWriteBlock(const char *Cmd) { return PM3_SUCCESS; } +static int CmdT55xxDangerousRaw(const char *Cmd) { + // supports only default downlink mode + t55xx_test_block_t ng; + ng.time = 0; + ng.bitlen = 0; + memset(ng.data, 0x00, sizeof(ng.data)); + bool errors = false; + uint8_t cmdp = 0; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 't': + ng.time = param_get32ex(Cmd, cmdp + 1, 0, 10); + if (ng.time == 0 || ng.time > 200000) { + PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time); + errors = true; + break; + } + cmdp += 2; + break; + case 'b': { + uint32_t n = param_getlength(Cmd, cmdp + 1); + if (n > 128) { + PrintAndLogEx(ERR, "Bitstream too long, max 128 bits, got %i", n); + errors = true; + break; + } + for (uint8_t i = 0; i < n; i++) { + char c = param_getchar_indx(Cmd, i, cmdp + 1); + if (c == '0') + ng.data[i] = 0; + else if (c == '1') + ng.data[i] = 1; + else { + PrintAndLogEx(ERR, "Unknown bit char '%c'", c); + errors = true; + break; + } + } + ng.bitlen = n; + cmdp += 2; + break; + } + default: + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + if (errors || ng.bitlen == 0 || ng.time == 0) { + PrintAndLogEx(ERR, "Error occurred, abort. " _RED_("DANGEROUS COMMAND, DO NOT USE!")); + return PM3_EINVARG; + } + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng)); + if (!WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000)) { + PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation."); + return PM3_ETIMEOUT; + } + return resp.status; +} + static int CmdT55xxReadTrace(const char *Cmd) { bool frombuff = false; @@ -3400,6 +3463,7 @@ static command_t CommandTable[] = { {"bruteforce", CmdT55xxBruteForce, IfPm3Lf, " Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, AlwaysAvailable, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"chk", CmdT55xxChkPwds, IfPm3Lf, "Check passwords from dictionary/flash"}, + {"dangerraw", CmdT55xxDangerousRaw, IfPm3Lf, "Sends raw bitstream. Dangerous, do not use!! b t "}, {"detect", CmdT55xxDetect, AlwaysAvailable, "[1] Try detecting the tag modulation from reading the configuration block."}, {"deviceconfig", CmdT55xxSetDeviceConfig, IfPm3Lf, "Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap"}, {"dump", CmdT55xxDump, IfPm3Lf, "[password] [o] Dump T55xx card Page 0 block 0-7. Optional [password], [override]"}, diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index ca778a495..a6d59aa05 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -198,6 +198,12 @@ typedef struct { uint8_t flags; } PACKED t55xx_write_block_t; +typedef struct { + uint8_t data[128]; + uint8_t bitlen; + uint32_t time; +} PACKED t55xx_test_block_t; + // For CMD_LF_HID_SIMULATE (FSK) typedef struct { uint32_t hi2; @@ -376,6 +382,7 @@ typedef struct { #define CMD_LF_SAMPLING_GET_CONFIG 0x0227 #define CMD_LF_T55XX_CHK_PWDS 0x0230 +#define CMD_LF_T55XX_DANGERRAW 0x0231 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */