From e435d8a6ff865a29bf001307b3f186a67b968135 Mon Sep 17 00:00:00 2001
From: mwalker33 <mwal5099@bigpond.net.au>
Date: Thu, 10 Oct 2019 21:27:48 +1100
Subject: [PATCH 1/3] 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 <mode>] [p <password> [o]]");
     PrintAndLogEx(NORMAL, "Options:");
-    PrintAndLogEx(NORMAL, "     p <password>   - OPTIONAL password 4bytes (8 hex symbols)");
-    PrintAndLogEx(NORMAL, "     o              - OPTIONAL override, force pwd read despite danger to card");
+    PrintAndLogEx(NORMAL, "     p <password> - OPTIONAL password 4bytes (8 hex symbols)");
+    PrintAndLogEx(NORMAL, "     o            - OPTIONAL override, force pwd read despite danger to card");
+    PrintAndLogEx(NORMAL, "     f <prefix>   - 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 <filename> [p password]");
+    PrintAndLogEx(NORMAL, "Options:");
+    PrintAndLogEx(NORMAL, "     f <filename> - filename of the dump file (.bin/.eml)");
+    PrintAndLogEx(NORMAL, "     p <password> - 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 <mode>] [p <password>]");
     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 <filename> [p <password>] -- 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);

From 92639c9df8b52acf5cf95d493c7e21120e2f4f7b Mon Sep 17 00:00:00 2001
From: mwalker33 <mwal5099@bigpond.net.au>
Date: Thu, 10 Oct 2019 21:38:53 +1100
Subject: [PATCH 2/3] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f6996545..140c072c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
 This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
 
 ## [unreleased][unreleased]
+ - Added lf t55xx dump save and lf t55xx restore for .bin and .eml files (@mwalker33)
  - Added lf t55xx detected to try without password first (@mwalker33)
  - Display high bit for detected Kastle HIDs to allow `lf hid clone [id]` to work properly (@swg0101)
  - Add option `-n` to scripts pm3* (@doegox)

From 18520a5dfd3eeb1b3855e44b8235f83d3a16bdda Mon Sep 17 00:00:00 2001
From: mwalker33 <mwal5099@bigpond.net.au>
Date: Thu, 10 Oct 2019 22:07:57 +1100
Subject: [PATCH 3/3] Update cmdlft55xx.c

---
 client/cmdlft55xx.c | 195 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 157 insertions(+), 38 deletions(-)

diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c
index 98767eda3..796179ad9 100644
--- a/client/cmdlft55xx.c
+++ b/client/cmdlft55xx.c
@@ -340,7 +340,8 @@ static int usage_t55xx_deviceconfig() {
     return PM3_SUCCESS;
 }
 static int usage_t55xx_protect() {
-    PrintAndLogEx(NORMAL, "This command set or unsets the pwd bit on T5577.");
+    PrintAndLogEx(NORMAL, "This command sets the pwd bit on T5577.");
+    PrintAndLogEx(NORMAL, _RED_("WARNING:") " this locks the tag!");
     PrintAndLogEx(NORMAL, "Usage:  lf t55xx protect [r <mode>] [p <password>] [o] [n <new_password>]");
     PrintAndLogEx(NORMAL, "Options:");
     PrintAndLogEx(NORMAL, "     p <password>        - OPTIONAL password (8 hex characters)");
@@ -371,8 +372,8 @@ void T55x7_ClearAllBlockData (void) {
 }
 
 int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) {
-    
-    if (blockdata == NULL) 
+
+    if (blockdata == NULL)
         return PM3_EINVARG;
     if (numblocks < 1 || numblocks > 8)
         return PM3_EINVARG;
@@ -403,7 +404,7 @@ int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) {
             return PM3_ETIMEOUT;
         }
     }
- 
+
    uint8_t res = 0;
     for (int8_t i = 0; i < numblocks; i++) {
 
@@ -419,7 +420,7 @@ int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) {
 
     if (res == 0)
         PrintAndLogEx(SUCCESS, "Success writing to tag");
-    
+
     return PM3_SUCCESS;
 }
 
@@ -496,7 +497,7 @@ bool t55xxAquireAndCompareBlock0(bool usepwd, uint32_t password, uint32_t known_
         PrintAndLogEx(INFO, "Block0 write detected, running `detect` to see if validation is possible");
 
     for (uint8_t m = 0; m < 4; m++) {
-        if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false) {
+        if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false) {
             continue;
         }
 
@@ -529,7 +530,7 @@ bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0,
         config.pwd = 0x00;
 
     for (uint8_t m = 0; m < 4; m++) {
-        if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
+        if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
             continue;
 
         if (tryDetectModulationEx(m, verbose, known_block0) == false)
@@ -793,7 +794,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u
         // override = 1 (override and display)
         // override = 2 (override and no display)
         if (override == 0) {
-            if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
+            if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
                 return PM3_ERFTRANS;
 
             if (tryDetectModulation(downlink_mode, false) == false) {
@@ -809,7 +810,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u
         }
     }
 
-    if (AquireData(page1, block, usepwd, password, downlink_mode) == false)
+    if (AcquireData(page1, block, usepwd, password, downlink_mode) == false)
         return PM3_ERFTRANS;
 
     if (DecodeT55xxBlock() == false)
@@ -1033,7 +1034,7 @@ static int CmdT55xxDetect(const char *Cmd) {
             if (try_all_dl_modes) {
                 for (uint8_t m = downlink_mode; m < 4; m++) {
                             
-                    if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, try_with_pwd & usepwd, password, m) == false)
+                    if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, try_with_pwd & usepwd, password, m) == false)
                         continue;
 
                     // pre fill to save passing in.
@@ -1056,7 +1057,7 @@ static int CmdT55xxDetect(const char *Cmd) {
                 else    
                     config.pwd = 0x00;
 
-                if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
+                if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
                     found = tryDetectModulation(downlink_mode, T55XX_PrintConfig);
                 }
             }
@@ -1694,6 +1695,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;
@@ -1733,7 +1797,7 @@ static int CmdT55xxReadTrace(const char *Cmd) {
         uint32_t password = 0;
 
         // REGULAR_READ_MODE_BLOCK - yeilds correct Page 1 Block 2 data i.e. + 32 bit offset.
-        if (!AquireData(T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password, downlink_mode))
+        if (!AcquireData(T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password, downlink_mode))
             return PM3_ENODATA;
     }
 
@@ -2036,7 +2100,7 @@ static int CmdT55xxInfo(const char *Cmd) {
         // sanity check.
         if (SanityOfflineCheck(false) != PM3_SUCCESS) return PM3_ENODATA;
 
-        if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode))
+        if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode))
             return PM3_ENODATA;
     }
 
@@ -2327,7 +2391,60 @@ static int CmdT55xxRestore(const char *Cmd) {
     return PM3_SUCCESS;
 }
 
-bool AquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode) {
+static int CmdT55xxRestore(const char *Cmd) {
+
+    uint32_t password = 0;
+    uint8_t override = 0;
+    uint8_t downlink_mode = config.downlink_mode;;
+    bool usepwd = false;
+    bool errors = false;
+    uint8_t cmdp = 0;
+
+    while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
+        switch (tolower(param_getchar(Cmd, cmdp))) {
+            case 'h':
+                return usage_t55xx_restore();
+            case 'r':
+                downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
+                if (downlink_mode > 3)
+                    downlink_mode = 0;
+
+                cmdp += 2;
+                break;
+            case 'p':
+                password = param_get32ex(Cmd, cmdp + 1, 0, 16);
+                usepwd = true;
+                cmdp += 2;
+                break;
+            case 'o':
+                override = 1;
+                cmdp++;
+                break;
+            default:
+                PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+                errors = true;
+                break;
+        }
+    }
+    if (errors) return usage_t55xx_restore();
+
+    PrintAndLogEx(INFO,  "Work in progress.  To be implemented");
+    if (usepwd || password || override ) {
+
+    }
+    // load file name  (json/eml/bin)
+
+    // Print dump data?
+
+    uint32_t res = PM3_SUCCESS;
+
+// page0.
+//    res = clone_t55xx_tag(blockdata, numblocks);
+
+    return res;
+}
+
+bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode) {
     // arg0 bitmodes:
     //  b0 = pwdmode
     //  b1 = page to read from
@@ -2670,18 +2787,19 @@ static int CmdResetRead(const char *Cmd) {
 
     if (resp.status == PM3_SUCCESS) {
 
-        uint8_t *got = calloc(BIGBUF_SIZE - 1, sizeof(uint8_t));
+        uint16_t gotsize = BIGBUF_SIZE - 1;
+        uint8_t *got = calloc(gotsize, sizeof(uint8_t));
         if (got == NULL) {
             PrintAndLogEx(WARNING, "failed to allocate memory");
             return PM3_EMALLOC;
         }
 
-        if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) {
+        if (!GetFromDevice(BIG_BUF, got, gotsize, 0, NULL, 0, NULL, 2500, false)) {
             PrintAndLogEx(WARNING, "command execution time out");
             free(got);
             return PM3_ETIMEOUT;
         }
-        setGraphBuf(got, sizeof(got));
+        setGraphBuf(got, gotsize);
         free(got);
     }
     return PM3_SUCCESS;
@@ -2826,7 +2944,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
         }
     }
 
-    if (errors) return usage_t55xx_chk();
+    if (errors || cmdp == 0) return usage_t55xx_chk();
 
     /*
     // block 7,  page1 = false, usepwd = false, override = false, pwd = 00000000
@@ -2859,10 +2977,10 @@ static int CmdT55xxChkPwds(const char *Cmd) {
         if (resp.oldarg[0]) {
             PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX64) " ]. Trying to validate", resp.oldarg[1]);
 
-            if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.oldarg[1], downlink_mode)) {
+            if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.oldarg[1], downlink_mode)) {
                 found = tryDetectModulation(downlink_mode, T55XX_PrintConfig);
                 if (found) {
-                    PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX64) " ]", resp.oldarg[1]);
+                    PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX64) "]", resp.oldarg[1]);
 
                 } else {
                     PrintAndLogEx(WARNING, "Check pwd failed");
@@ -2908,13 +3026,13 @@ static int CmdT55xxChkPwds(const char *Cmd) {
             PrintAndLogEx(INFO, "Testing %08"PRIX64, curr_password);
             for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
 
-                if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
+                if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
                     continue;
                 }
 
                 found = tryDetectModulation(dl_mode, T55XX_PrintConfig);
                 if (found) {
-                    PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX64) " ]", curr_password);
+                    PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX64) "]", curr_password);
                     dl_mode = 4; // Exit other downlink mode checks
                     c = keycount; // Exit loop
                 }
@@ -2970,11 +3088,11 @@ static int CmdT55xxBruteForce(const char *Cmd) {
                 break;
         }
     }
-    if (start_password >= end_password) {
-        return usage_t55xx_bruteforce();
-    }
 
-    if (errors) return usage_t55xx_bruteforce();
+    if (start_password >= end_password)
+        errors = true;
+
+    if (errors || cmdp == 0) return usage_t55xx_bruteforce();
 
     uint64_t t1 = msclock();
 
@@ -3005,7 +3123,7 @@ static int CmdT55xxBruteForce(const char *Cmd) {
         PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") "]", curr - 1);
         T55xx_Print_DownlinkMode((found >> 1) & 3);
     } else
-        PrintAndLogEx(WARNING, "Bruteforce failed, last tried: [ " _YELLOW_("%08X") " ]", curr);
+        PrintAndLogEx(WARNING, "Bruteforce failed, last tried: [ " _YELLOW_("%08X") "]", curr);
 
     t1 = msclock() - t1;
     PrintAndLogEx(SUCCESS, "\nTime in bruteforce: %.0f seconds\n", (float)t1 / 1000.0);
@@ -3026,14 +3144,14 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) {
     // check if dl mode 4 and loop if needed
     for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
 
-        AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode);
-
-        //  if (getSignalProperties()->isnoise == false) {
-        //  } else {
-        if (tryDetectModulation(dl_mode, T55XX_PrintConfig)) {
-            return 1 + (dl_mode << 1);
+        if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) {
+            //  if (getSignalProperties()->isnoise == false) {
+            //  } else {
+            if (tryDetectModulation(dl_mode, T55XX_PrintConfig)) {
+                return 1 + (dl_mode << 1);
+            }
+            //  }
         }
-        //  }
         if (!try_all_dl_modes) dl_mode = 4;
     }
     return 0;
@@ -3073,8 +3191,7 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
         }
     }
 
-    if (errors) return usage_t55xx_recoverpw();
-
+    if (errors || cmdp == 0) return usage_t55xx_recoverpw();
 
     // first try fliping each bit in the expected password
     while (bit < 32) {
@@ -3161,7 +3278,7 @@ bool tryDetectP1(bool getData) {
     bool     st         = true;
 
     if (getData) {
-        if (!AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, false, 0, 0))
+        if (!AcquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, false, 0, 0))
             return false;
     }
 
@@ -3311,7 +3428,7 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
 
     if (!useGB) {
         for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
-            found = AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password, dl_mode);
+            found = AcquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password, dl_mode);
             //return PM3_ENODATA;
             if (tryDetectP1(false)) { //tryDetectModulation())
                 found = true;
@@ -3515,6 +3632,7 @@ static command_t CommandTable[] = {
     {"bruteforce",   CmdT55xxBruteForce,      IfPm3Lf,         "<start password> <end password> 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 <bitstream> t <timing>"},
     {"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]"},
@@ -3524,6 +3642,7 @@ static command_t CommandTable[] = {
     {"protect",      CmdT55xxProtect,         IfPm3Lf,         "Password protect tag"},
     {"read",         CmdT55xxReadBlock,       IfPm3Lf,         "b <block> p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]"},
     {"resetread",    CmdResetRead,            IfPm3Lf,         "Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)"},
+    {"restore",      CmdT55xxRestore,         IfPm3Lf,         "[password] Restore T55xx card Page 0 / Page 1 blocks"},
     {"recoverpw",    CmdT55xxRecoverPW,       IfPm3Lf,         "[password] Try to recover from bad password write from a cloner. Only use on PW protected chips!"},
     {"special",      special,                 IfPm3Lf,         "Show block changes with 64 different offsets"},
     {"trace",        CmdT55xxReadTrace,       AlwaysAvailable, "[1] Show T55x7 traceability data (page 1/ blk 0-1)"},