From e435d8a6ff865a29bf001307b3f186a67b968135 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Thu, 10 Oct 2019 21:27:48 +1100 Subject: [PATCH] t55x7 save and restore eml/bin --- client/cmdlft55xx.c | 199 ++++++++++++++++++++++++++++++++++++++++++-- client/cmdlft55xx.h | 5 +- 2 files changed, 195 insertions(+), 9 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 0fbf348d7..86ec6d0e2 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -51,12 +51,15 @@ t55xx_conf_block_t config = { .block0 = 0x00, .Q5 = false, .usepwd = false, - .downlink_mode = refFixedBit + .downlink_mode = refFixedBit, + .blockData = {0}, // array to hold data blocks + .blockValid = {0} // array to hold data valid status }; t55xx_conf_block_t Get_t55xx_Config() { return config; } + void Set_t55xx_Config(t55xx_conf_block_t conf) { config = conf; } @@ -179,8 +182,9 @@ static int usage_t55xx_info() { static int usage_t55xx_dump() { PrintAndLogEx(NORMAL, "Usage: lf t55xx dump [r ] [p [o]]"); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " p - OPTIONAL password 4bytes (8 hex symbols)"); - PrintAndLogEx(NORMAL, " o - OPTIONAL override, force pwd read despite danger to card"); + PrintAndLogEx(NORMAL, " p - OPTIONAL password 4bytes (8 hex symbols)"); + PrintAndLogEx(NORMAL, " o - OPTIONAL override, force pwd read despite danger to card"); + PrintAndLogEx(NORMAL, " f - overide filename prefix (optional). Default is based on blk 0"); print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE,config.downlink_mode); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -189,6 +193,20 @@ static int usage_t55xx_dump() { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_t55xx_restore() { + PrintAndLogEx(NORMAL, "Usage: lf t55xx restore f [p password]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " f - filename of the dump file (.bin/.eml)"); + PrintAndLogEx(NORMAL, " p - optional password if target card has password set"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, _YELLOW_(" Assumes lf t55 detect has been run first!")); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf t55xx restore f lf-t55xx-00148040-data.bin"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + static int usage_t55xx_detect() { PrintAndLogEx(NORMAL, "Usage: lf t55xx detect [1] [r ] [p ]"); PrintAndLogEx(NORMAL, "Options:"); @@ -339,6 +357,19 @@ static int usage_t55xx_protect() { static int CmdHelp(const char *Cmd); +void T55x7_SaveBlockData (uint8_t idx,uint32_t data) { + if (idx < T55x7_BLOCK_COUNT) { + config.blockValid[idx] = true; + config.blockData[idx] = data; + } +} +void T55x7_ClearAllBlockData (void) { + for (uint8_t idx = 0; idx < T55x7_BLOCK_COUNT; idx++) { + config.blockValid[idx] = false; + config.blockData[idx] = 0x00; + } +} + int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) { if (blockdata == NULL) @@ -785,7 +816,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u return PM3_EWRONGANSVER; if (verbose) - printT55xxBlock(block); + printT55xxBlock(block,page1); return PM3_SUCCESS; } @@ -988,6 +1019,9 @@ static int CmdT55xxDetect(const char *Cmd) { } if (errors) return usage_t55xx_detect(); + // detect called so clear data blocks + T55x7_ClearAllBlockData (); + // sanity check. if (SanityOfflineCheck(useGB) != PM3_SUCCESS) return PM3_ESOFT; @@ -1300,7 +1334,7 @@ bool GetT55xxBlockData(uint32_t *blockdata) { return true; } -void printT55xxBlock(uint8_t blockNum) { +void printT55xxBlock(uint8_t blockNum, bool page1) { uint32_t blockData = 0; uint8_t bytes[4] = {0}; @@ -1310,6 +1344,8 @@ void printT55xxBlock(uint8_t blockNum) { num_to_bytes(blockData, 4, bytes); + T55x7_SaveBlockData ((page1)?blockNum+8 : blockNum,blockData); + PrintAndLogEx(SUCCESS, " %02d | %08X | %s | %s", blockNum, blockData, sprint_bin(DemodBuffer + config.offset, 32), sprint_ascii(bytes, 4)); } @@ -2091,6 +2127,8 @@ static int CmdT55xxDump(const char *Cmd) { bool usepwd = false; bool errors = false; uint8_t cmdp = 0; + char preferredName[FILE_PATH_SIZE] = {0}; + bool success = true; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -2112,6 +2150,12 @@ static int CmdT55xxDump(const char *Cmd) { override = 1; cmdp++; break; + case 'f': + param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); + cmdp+=2; + if (strlen (preferredName) == 0) + errors = true; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -2120,16 +2164,154 @@ static int CmdT55xxDump(const char *Cmd) { } if (errors) return usage_t55xx_dump(); + // Due to the few different T55xx cards and number of blocks supported + // will save the dump file if ALL page 0 is OK printT5xxHeader(0); for (uint8_t i = 0; i < 8; ++i) { - T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode); + if (T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode) != PM3_SUCCESS) + success = false; // idea for better user experience and display. // only show override warning on the first block read if (override == 1) override++; // flag not to show safty for 2nd and on. } printT5xxHeader(1); - for (uint8_t i = 0; i < 4; i++) - T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode); + for (uint8_t i = 0; i < 4; i++) + if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS) + T55x7_SaveBlockData (8+i,0x00); + + + if (success) { // all ok save dump to file + // saveFileEML will add .eml extension to filename + // saveFile (binary) passes in the .bin extension. + if (strcmp (preferredName,"") == 0) { // Set default filename, if not set by user + strcpy (preferredName,"lf-t55xx"); + for (uint8_t i = 1; i <= 7; i++) { + if ((config.blockData[i] != 0x00) && (config.blockData[i] != 0xFFFFFFFF)) + sprintf (preferredName,"%s-%08X",preferredName,config.blockData[i]); + else + break; + } + sprintf (preferredName,"%s-data",preferredName); + } + + // Swap endian so the files match the txt display + uint32_t data[T55x7_BLOCK_COUNT]; + + for (int i = 0; i < T55x7_BLOCK_COUNT; i++) + data[i] = BSWAP_32(config.blockData[i]); + + saveFileEML(preferredName, (uint8_t *)data, T55x7_BLOCK_COUNT*sizeof(uint32_t), sizeof(uint32_t)); + saveFile (preferredName, ".bin", data, sizeof(data)); + } + + return PM3_SUCCESS; +} + +static int CmdT55xxRestore(const char *Cmd) { + bool errors = false; + uint8_t cmdp = 0; + char preferredName[FILE_PATH_SIZE] = {0}; + char ext[FILE_PATH_SIZE] = {0}; + int success = PM3_ESOFT; + uint32_t password = 0x00; + bool usepwd = false; + uint32_t data[12] = {0}; + size_t datalen = 0; + uint8_t blockidx; + uint8_t downlink_mode; + char writeCmdOpt[100]; + char pwdOpt [11] = {0}; // p XXXXXXXX + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_t55xx_restore(); + case 'f': + param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); + if (strlen (preferredName) == 0) + errors = true; + cmdp+=2; + break; + case 'p': + password = param_get32ex(Cmd, cmdp + 1, 0, 16); + usepwd = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + // File name expected to be .eml .bin or .json so sould be at least 4 + if (errors || (strlen (preferredName) == 0)) return usage_t55xx_restore(); + + // split file name into prefix and ext. + int fnLength; + + fnLength = strlen (preferredName); + + if (fnLength > 4) { // Holds .EXT [.bin|.eml] + memcpy (ext,&preferredName[fnLength - 4],4); + ext[5] = 0x00; + + if (memcmp (ext,".bin",4) == 0) { + preferredName[fnLength-4] = 0x00; + success = loadFile (preferredName, ".bin", data, sizeof(data),&datalen); + } + if (memcmp (ext,".eml",4) == 0) { + preferredName[fnLength-4] = 0x00; + datalen = 12; + success = loadFileEML(preferredName, (uint8_t *)data, &datalen); + } + } + + if (success == PM3_SUCCESS) { // Got data, so write to cards + if (datalen == T55x7_BLOCK_COUNT * 4) { // 12 blocks * 4 bytes per block + if (usepwd) + sprintf (pwdOpt,"p %08X",password); + + // Restore endien for writing to card + for (blockidx = 0; blockidx < 12; blockidx++) + data[blockidx] = BSWAP_32(data[blockidx]); + + // Have data ready, lets write + // Order + // write blocks 1..7 page 0 + // write blocks 1..3 page 1 + // update downlink mode (if needed) and write b 0 + downlink_mode = 0; + if ((((data[11] >> 28) & 0xf) == 6) || (((data[11] >> 28) & 0xf) == 9)) + downlink_mode = (data[11] >> 10) & 3; + + // write out blocks 1-7 page 0 + for (blockidx = 1; blockidx <= 7; blockidx++) { + sprintf (writeCmdOpt,"b %d d %08X %s",blockidx,data[blockidx],pwdOpt); + if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) + PrintAndLogEx(WARNING, "Warning: error writing blk %d",blockidx); + } + + // if password was set on the "blank" update as we may have just changed it + if (usepwd) + sprintf (pwdOpt,"p %08X",data[7]); + + // write out blocks 1-3 page 1 + for (blockidx = 9; blockidx <= 11; blockidx++) { + sprintf (writeCmdOpt,"b %d 1 d %08X %s",blockidx-8,data[blockidx],pwdOpt); + if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) + PrintAndLogEx(WARNING, "Warning: error writing blk %d",blockidx); + } + + // Update downlink mode for the page 0 config write. + config.downlink_mode = downlink_mode; + + // Write the page 0 config + sprintf (writeCmdOpt,"b 0 d %08X %s",data[0],pwdOpt); + if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) + PrintAndLogEx(WARNING, "Warning: error writing blk 0"); + } + } return PM3_SUCCESS; } @@ -3324,6 +3506,7 @@ static command_t CommandTable[] = { {"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 block 0-7. Optional [password], [override]"}, + {"restore", CmdT55xxRestore, IfPm3Lf, "f [p ] -- Restore a dump file of a T55xx card"}, {"info", CmdT55xxInfo, AlwaysAvailable, "[1] Show T55x7 configuration data (page 0/ blk 0)"}, {"p1detect", CmdT55xxDetectPage1, IfPm3Lf, "[1] Try detecting if this is a t55xx tag by reading page 1"}, {"protect", CmdT55xxProtect, IfPm3Lf, "Password protect tag"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index d7791466c..06c9399f1 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -20,6 +20,7 @@ #define T55x7_PAGE1 0x01 #define T55x7_PWD 0x00000010 #define REGULAR_READ_MODE_BLOCK 0xFF +#define T55x7_BLOCK_COUNT 12 // config blocks #define T55X7_DEFAULT_CONFIG_BLOCK 0x000880E8 // ASK, compat mode, data rate 32, manchester, STT, 7 data blocks @@ -125,6 +126,8 @@ typedef struct { refLeading0 = 0x02, ref1of4 = 0x03, } downlink_mode; + uint32_t blockData [T55x7_BLOCK_COUNT]; // the dump/read will save data here. + bool blockValid [T55x7_BLOCK_COUNT]; // this will allow easy access to the data for display etc. } t55xx_conf_block_t; t55xx_conf_block_t Get_t55xx_Config(void); @@ -144,7 +147,7 @@ char *GetModelStrFromCID(uint32_t cid); char *GetSelectedModulationStr(uint8_t id); char *GetDownlinkModeStr(uint8_t dlmode); void printT5xxHeader(uint8_t page); -void printT55xxBlock(uint8_t blockNum); +void printT55xxBlock(uint8_t blockNum,bool page1); int printConfiguration(t55xx_conf_block_t b); bool t55xxAquireAndCompareBlock0(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose);