textual
[RRG-proxmark3.git] / client / src / cmdlft55xx.c
blobe7ae82ed332aaa41d3d90c79fb939debece33847
1 //-----------------------------------------------------------------------------
2 //
3 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
4 // at your option, any later version. See the LICENSE.txt file for the text of
5 // the license.
6 //-----------------------------------------------------------------------------
7 // Low frequency T55xx commands
8 //-----------------------------------------------------------------------------
10 // ensure localtime_r is available even with -std=c99; must be included before
11 #if !defined(_WIN32)
12 #define _POSIX_C_SOURCE 200112L
13 #endif
15 #include "cmdlft55xx.h"
16 #include <ctype.h>
17 #include <time.h> // MingW
18 #include "cmdparser.h" // command_t
19 #include "comms.h"
20 #include "commonutil.h"
21 #include "protocols.h"
22 #include "proxgui.h"
23 #include "graph.h"
24 #include "cmddata.h"
25 #include "lfdemod.h"
26 #include "cmdhf14a.h" // for getTagInfo
27 #include "fileutils.h" // loadDictionary
28 #include "util_posix.h"
29 #include "cmdlf.h" // for lf sniff
30 #include "generator.h"
31 #include "cliparser.h" // cliparsing
33 // Some defines for readability
34 #define T55XX_DLMODE_FIXED 0 // Default Mode
35 #define T55XX_DLMODE_LLR 1 // Long Leading Reference
36 #define T55XX_DLMODE_LEADING_ZERO 2 // Leading Zero
37 #define T55XX_DLMODE_1OF4 3 // 1 of 4
38 // #define T55XX_LONGLEADINGREFERENCE 4 // Value to tell Write Bit to send long reference
39 #define T55XX_DLMODE_ALL 4 // Tell help to show 'r 4' for all dl modes
40 #define T55XX_DLMODE_SINGLE 5 // Tell help file NOT to show 'r 4' (not available)
42 #define T55XX_PrintConfig true
43 #define T55XX_DontPrintConfig false
45 //static uint8_t bit_rates[9] = {8, 16, 32, 40, 50, 64, 100, 128, 0};
47 // Default configuration
48 t55xx_conf_block_t config = {
49 .modulation = DEMOD_ASK,
50 .inverted = false,
51 .offset = 0x00,
52 .block0 = 0x00,
53 .block0Status = NOTSET,
54 .Q5 = false,
55 .usepwd = false,
56 .downlink_mode = refFixedBit
59 static t55xx_memory_item_t cardmem[T55x7_BLOCK_COUNT] = {{0}};
61 t55xx_conf_block_t Get_t55xx_Config(void) {
62 return config;
65 void Set_t55xx_Config(t55xx_conf_block_t conf) {
66 config = conf;
69 static int CmdHelp(const char *Cmd);
71 static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, uint8_t dl_mode_def) {
73 char *r0 = (char *)calloc(56, sizeof(uint8_t));
74 char *r1 = (char *)calloc(56, sizeof(uint8_t));
75 char *r2 = (char *)calloc(56, sizeof(uint8_t));
76 char *r3 = (char *)calloc(56, sizeof(uint8_t));
78 sprintf(r0, "downlink - fixed bit length %s", (dl_mode_def == 0) ? "(detected def)" : "");
79 sprintf(r1, "downlink - long leading reference %s", (dl_mode_def == 1) ? "(detected def)" : "");
80 sprintf(r2, "downlink - leading zero %s", (dl_mode_def == 2) ? "(detected def)" : "");
81 sprintf(r3, "downlink - 1 of 4 coding reference %s", (dl_mode_def == 3) ? "(detected def)" : "");
83 uint8_t n = *idx;
84 at[n++] = arg_lit0(NULL, "r0", r0);
85 at[n++] = arg_lit0(NULL, "r1", r1);
86 at[n++] = arg_lit0(NULL, "r2", r2);
87 at[n++] = arg_lit0(NULL, "r3", r3);
89 if (show == T55XX_DLMODE_ALL) {
90 char *r4 = (char *)calloc(56, sizeof(uint8_t));
91 sprintf(r4, "try all downlink modes %s", (dl_mode_def == 4) ? "(def)" : "");
92 at[n++] = arg_lit0(NULL, "all", r4);
94 at[n++] = arg_param_end;
95 *idx = n;
98 static int CmdT55xxCloneHelp(const char *Cmd) {
99 CLIParserContext *ctx;
100 CLIParserInit(&ctx, "lf t55xx clonehelp",
101 "Display a list of available commands for cloning specific techs on T5xx tags",
102 "lf t55xx clonehelp"
104 void *argtable[] = {
105 arg_param_begin,
106 arg_param_end
108 CLIExecWithReturn(ctx, Cmd, argtable, true);
109 CLIParserFree(ctx);
110 PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
111 PrintAndLogEx(NORMAL, _GREEN_("lf awid clone"));
112 PrintAndLogEx(NORMAL, _GREEN_("lf destron clone"));
113 PrintAndLogEx(NORMAL, _GREEN_("lf em 410x clone"));
114 // todo: implement restore
115 // PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05 write"));
116 // PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50 write"));
117 PrintAndLogEx(NORMAL, _GREEN_("lf fdxb clone"));
118 PrintAndLogEx(NORMAL, _GREEN_("lf gallagher clone"));
119 PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone"));
120 PrintAndLogEx(NORMAL, _GREEN_("lf hid clone"));
121 PrintAndLogEx(NORMAL, _GREEN_("lf indala clone"));
122 PrintAndLogEx(NORMAL, _GREEN_("lf io clone"));
123 PrintAndLogEx(NORMAL, _GREEN_("lf jablotron clone"));
124 PrintAndLogEx(NORMAL, _GREEN_("lf keri clone"));
125 PrintAndLogEx(NORMAL, _GREEN_("lf motorola clone"));
126 PrintAndLogEx(NORMAL, _GREEN_("lf nedap clone"));
127 PrintAndLogEx(NORMAL, _GREEN_("lf nexwatch clone"));
128 PrintAndLogEx(NORMAL, _GREEN_("lf noralsy clone"));
129 PrintAndLogEx(NORMAL, _GREEN_("lf pac clone"));
130 PrintAndLogEx(NORMAL, _GREEN_("lf paradox clone"));
131 PrintAndLogEx(NORMAL, _GREEN_("lf presco clone"));
132 PrintAndLogEx(NORMAL, _GREEN_("lf pyramid clone"));
133 PrintAndLogEx(NORMAL, _GREEN_("lf securakey clone"));
134 PrintAndLogEx(NORMAL, _GREEN_("lf viking clone"));
135 PrintAndLogEx(NORMAL, _GREEN_("lf visa2000 clone"));
136 return PM3_SUCCESS;
139 static void T55x7_SaveBlockData(uint8_t idx, uint32_t data) {
140 if (idx < T55x7_BLOCK_COUNT) {
141 cardmem[idx].valid = true;
142 cardmem[idx].blockdata = data;
145 static void T55x7_ClearAllBlockData(void) {
146 for (uint8_t idx = 0; idx < T55x7_BLOCK_COUNT; idx++) {
147 cardmem[idx].valid = false;
148 cardmem[idx].blockdata = 0x00;
152 int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) {
154 if (blockdata == NULL)
155 return PM3_EINVARG;
156 if (numblocks < 1 || numblocks > 8)
157 return PM3_EINVARG;
159 PacketResponseNG resp;
161 // fast push mode
162 conn.block_after_ACK = true;
164 for (int8_t i = 0; i < numblocks; i++) {
166 // Disable fast mode on last packet
167 if (i == numblocks - 1) {
168 conn.block_after_ACK = false;
171 clearCommandBuffer();
173 t55xx_write_block_t ng;
174 ng.data = blockdata[i];
175 ng.pwd = 0;
176 ng.blockno = i;
177 ng.flags = 0;
179 SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
180 if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) {
181 PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
182 return PM3_ETIMEOUT;
186 uint8_t res = 0;
187 for (int8_t i = 0; i < numblocks; i++) {
189 if (i == 0) {
190 SetConfigWithBlock0(blockdata[0]);
191 if (t55xxAquireAndCompareBlock0(false, 0, blockdata[0], false))
192 continue;
195 if (t55xxVerifyWrite(i, 0, false, false, 0, 0xFF, blockdata[i]) == false)
196 res++;
199 if (res == 0)
200 PrintAndLogEx(SUCCESS, "Data written and verified");
202 return PM3_SUCCESS;
205 static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t new_password) {
207 PrintAndLogEx(INFO, "Checking current configuration");
209 bool testmode = false;
210 uint32_t block0 = 0;
212 int res = T55xxReadBlockEx(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, override, password, downlink_mode, false);
213 if (res != PM3_SUCCESS) {
214 PrintAndLogEx(WARNING, "Failed to read block0, use " _YELLOW_("`p`") " password parameter?");
215 return false;
218 if (GetT55xxBlockData(&block0) == false) {
219 PrintAndLogEx(DEBUG, "ERROR decoded block0 == %08x", block0);
220 return false;
222 PrintAndLogEx(DEBUG, "OK read block0 == %08x", block0);
225 bool isPwdBitAlreadySet = (block0 >> (32 - 28) & 1);
226 if (isPwdBitAlreadySet) {
227 PrintAndLogEx(INFO, "PWD bit is already set");
228 usepwd = true;
231 // set / clear pwd bit
232 if (lock) {
233 block0 |= 1 << 4;
234 } else {
235 block0 &= ~(1 << 4);
238 // write new password
239 if (t55xxWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, testmode, password, downlink_mode, new_password) != PM3_SUCCESS) {
240 PrintAndLogEx(ERR, "Failed to write new password");
241 return false;
242 } else {
243 PrintAndLogEx(SUCCESS, "Wrote new password");
246 // validate new password
247 uint32_t curr_password = (isPwdBitAlreadySet) ? new_password : password;
249 if (t55xxVerifyWrite(T55x7_PWD_BLOCK, T55x7_PAGE0, usepwd, override, curr_password, downlink_mode, new_password) == false) {
250 PrintAndLogEx(WARNING, "Failed to validate the password write. aborting.");
251 return false;
252 } else {
253 PrintAndLogEx(SUCCESS, "Validated new password");
256 // write config
257 if (t55xxWrite(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, testmode, curr_password, downlink_mode, block0) != PM3_SUCCESS) {
258 PrintAndLogEx(ERR, "Failed to write modified configuration block %08X", block0);
259 return false;
260 } else {
261 PrintAndLogEx(SUCCESS, "Wrote modified configuration block");
264 // validate new config. If all went well, card should now demand pwd, hence override = 0.
265 override = 0;
266 if (t55xxVerifyWrite(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, true, override, new_password, downlink_mode, block0) == false) {
267 PrintAndLogEx(WARNING, "Failed to validate pwd bit set on configuration block. aborting.");
268 return false;
269 } else {
270 PrintAndLogEx(SUCCESS, "New configuration block " _YELLOW_("%08X")" password " _YELLOW_("%08X"), block0, new_password);
271 PrintAndLogEx(SUCCESS, "Success, tag is locked");
272 return true;
276 bool t55xxAquireAndCompareBlock0(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose) {
278 if (verbose)
279 PrintAndLogEx(INFO, "Block0 write detected, running `detect` to see if validation is possible");
281 for (uint8_t m = 0; m < 4; m++) {
282 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false) {
283 continue;
286 if (DecodeT55xxBlock() == false) {
287 continue;
290 for (uint16_t i = 0; i < DemodBufferLen - 32; i++) {
291 uint32_t tmp = PackBits(i, 32, DemodBuffer);
292 if (tmp == known_block0) {
293 config.offset = i;
294 config.downlink_mode = m;
295 return true;
299 return false;
302 bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0, bool verbose) {
304 if (verbose)
305 PrintAndLogEx(INFO, "Block0 write detected, running `detect` to see if validation is possible");
307 for (uint8_t m = 0; m < 4; m++) {
308 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
309 continue;
311 if (t55xxTryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
312 continue;
314 config.downlink_mode = m;
315 return true;
317 config.usepwd = false; // unknown so assume no password
318 config.pwd = 0x00;
319 return false;
322 bool t55xxVerifyWrite(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, uint32_t data) {
324 uint32_t read_data = 0;
326 if (downlink_mode == 0xFF)
327 downlink_mode = config.downlink_mode;
329 int res = T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, false);
330 if (res == PM3_SUCCESS) {
332 if (GetT55xxBlockData(&read_data) == false)
333 return false;
335 } else if (res == PM3_EWRONGANSWER) {
337 // could't decode. Lets see if this was a block 0 write and try read/detect it auto.
338 // this messes up with ppls config..
339 if (block == 0 && page1 == false) {
341 if (t55xxAquireAndDetect(usepwd, password, data, true) == false)
342 return false;
344 return t55xxVerifyWrite(block, page1, usepwd, 2, password, config.downlink_mode, data);
348 return (read_data == data);
351 int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t password, uint8_t downlink_mode, uint32_t data) {
353 uint8_t flags;
354 flags = (usepwd) ? 0x1 : 0;
355 flags |= (page1) ? 0x2 : 0;
356 flags |= (testMode) ? 0x4 : 0;
357 flags |= (downlink_mode << 3);
360 OLD style
361 arg0 = data, (4 bytes)
362 arg1 = block (1 byte)
363 arg2 = password (4 bytes)
364 flags = data[0] (1 byte)
366 new style
367 uses struct in pm3_cmd.h
369 t55xx_write_block_t ng;
370 ng.data = data;
371 ng.pwd = password;
372 ng.blockno = block;
373 ng.flags = flags;
375 PacketResponseNG resp;
376 clearCommandBuffer();
377 SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng));
378 if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000)) {
379 PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation.");
380 return PM3_ETIMEOUT;
382 return resp.status;
385 void printT5xxHeader(uint8_t page) {
386 PrintAndLogEx(SUCCESS, "Reading Page %d:", page);
387 PrintAndLogEx(SUCCESS, "blk | hex data | binary | ascii");
388 PrintAndLogEx(SUCCESS, "----+----------+----------------------------------+-------");
391 void SetConfigWithBlock0(uint32_t block0) {
392 SetConfigWithBlock0Ex(block0, 0, false);
394 void SetConfigWithBlock0Ex(uint32_t block0, uint8_t offset, bool Q5) {
395 // T55x7
396 uint32_t extend = (block0 >> (32 - 15)) & 0x01;
397 uint32_t dbr;
398 if (extend)
399 dbr = (block0 >> (32 - 14)) & 0x3F;
400 else
401 dbr = (block0 >> (32 - 14)) & 0x07;
403 uint32_t datamod = (block0 >> (32 - 20)) & 0x1F;
404 bool pwd = (bool)((block0 >> (32 - 28)) & 0x01);
405 bool sst = (bool)((block0 >> (32 - 29)) & 0x01);
406 bool inv = (bool)((block0 >> (32 - 31)) & 0x01);
408 config.modulation = datamod;
409 config.bitrate = dbr;
411 // FSK1a, FSK2a
412 if (datamod == DEMOD_FSK1a || datamod == DEMOD_FSK2a || datamod == DEMOD_BIa)
413 config.inverted = 1;
414 else
415 config.inverted = inv;
417 config.Q5 = Q5;
418 config.ST = sst;
419 config.usepwd = pwd;
420 config.offset = offset;
421 config.block0 = block0;
424 static int CmdT55xxSetConfig(const char *Cmd) {
425 // No args
426 if (strlen(Cmd) == 0) {
427 PrintAndLogEx(INFO, "--- " _CYAN_("current t55xx config") " --------------------------");
428 return printConfiguration(config);
431 CLIParserContext *ctx;
432 CLIParserInit(&ctx, "lf t55xx config",
433 "Set/Get T55XX configuration of the pm3 client. Like modulation, inverted, offset, rate etc.\n"
434 "Offset is start position to decode data.",
435 "lf t55xx config --FSK --> FSK demodulation\n"
436 "lf t55xx config --FSK -i --> FSK demodulation, inverse data\n"
437 "lf t55xx config --FSK -i -o 3 --> FSK demodulation, inverse data, offset 3\n"
440 // 1 (help) + 19 (user specified params) + (5 T55XX_DLMODE_SINGLE)
441 void *argtable[1 + 12 + 6 + 5] = {
442 arg_param_begin,
443 arg_lit0(NULL, "FSK", "set demodulation FSK"),
444 arg_lit0(NULL, "FSK1", "set demodulation FSK 1"),
445 arg_lit0(NULL, "FSK1A", "set demodulation FSK 1a (inv)"),
446 arg_lit0(NULL, "FSK2", "set demodulation FSK 2"),
447 arg_lit0(NULL, "FSK2A", "set demodulation FSK 2a (inv)"),
448 arg_lit0(NULL, "ASK", "set demodulation ASK"),
449 arg_lit0(NULL, "PSK1", "set demodulation PSK 1"),
450 arg_lit0(NULL, "PSK2", "set demodulation PSK 2"),
451 arg_lit0(NULL, "PSK3", "set demodulation PSK 3"),
452 arg_lit0(NULL, "NRZ", "set demodulation NRZ"),
453 arg_lit0(NULL, "BI", "set demodulation Biphase"),
454 arg_lit0(NULL, "BIA", "set demodulation Diphase (inverted biphase)"),
455 arg_lit0("i", "inv", "set/reset data signal inversion"),
456 arg_lit0(NULL, "q5", "set/reset as Q5/T5555 chip instead of T55x7"),
457 arg_lit0(NULL, "st", "set/reset Sequence Terminator on"),
458 arg_int0(NULL, "rate", "<dec>", "set bitrate <8|16|32|40|50|64|100|128>"),
459 arg_str0("c", "blk0", "<hex>", "set configuration from a block0 (4 hex bytes)"),
460 arg_int0("o", "offset", "<0-255>", "set offset, where data should start decode in bitstream "),
463 uint8_t idx = 19;
464 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
465 CLIExecWithReturn(ctx, Cmd, argtable, true);
467 idx = 1;
468 bool mods[12];
469 int verify_mods = 0;
470 while (idx - 1 < sizeof(mods)) {
471 mods[idx - 1] = arg_get_lit(ctx, idx);
472 verify_mods += mods[idx - 1];
473 idx++;
476 // Not these flags are used to Toggle the values.
477 // If not flag then dont set or reset, leave as is since the call may just be be setting a different value.
478 bool invert = arg_get_lit(ctx, idx++);
479 bool use_q5 = arg_get_lit(ctx, idx++);
480 bool use_st = arg_get_lit(ctx, idx++);
482 int bitrate = arg_get_int_def(ctx, idx, -1);
483 idx++;
485 bool gotconf = false;
486 uint32_t block0 = 0;
487 int res = arg_get_u32_hexstr_def_nlen(ctx, idx++, 0, &block0, 4, true);
488 if (res == 0 || res == 2) {
489 PrintAndLogEx(ERR, "block0 data must be 4 hex bytes");
490 CLIParserFree(ctx);
491 return PM3_EINVARG;
493 if (res == 1) {
494 gotconf = true;
497 int offset = arg_get_int_def(ctx, idx, -1);
498 idx++;
500 bool r0 = arg_get_lit(ctx, idx++);
501 bool r1 = arg_get_lit(ctx, idx++);
502 bool r2 = arg_get_lit(ctx, idx++);
503 bool r3 = arg_get_lit(ctx, idx++);
504 CLIParserFree(ctx);
506 // validate user specified downlink mode
507 if ((r0 + r1 + r2 + r3) > 1) {
508 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
509 return PM3_EINVARG;
512 // validate user specified modulation FSK,FSK1,...BIA
513 if (verify_mods > 1) {
514 PrintAndLogEx(FAILED, "Error multiple demodulations, select one");
515 return PM3_EINVARG;
518 // validate user specified bitrate
520 if (bitrate != -1) {
521 uint8_t rates[9] = {8, 16, 32, 40, 50, 64, 100, 128, 0};
522 uint8_t i = 0;
523 for (; i < ARRAYLEN(rates); i++) {
524 if (rates[i] == bitrate) {
525 config.bitrate = i;
526 config.block0 = ((config.block0 & ~(0x1c0000)) | (i << 18));
527 break;
530 if (i == 9) {
531 PrintAndLogEx(FAILED, "Error select a valid bitrate");
532 return PM3_EINVARG;
536 // validate user specified offset
537 if (offset > -1 && offset < 0x100) {
538 config.offset = offset;
541 // validate user specific T5555 / Q5 - use the flag to toggle between T5577 and Q5
542 config.Q5 ^= use_q5;
544 // validate user specific sequence terminator
545 // if use_st flag was supplied, then toggle and update the config block0; if not supplied skip the config block0 update.
546 if (use_st) {
547 config.ST ^= use_st;
548 config.block0 = ((config.block0 & ~(0x8)) | (config.ST << 3));
551 // validate user specific invert
552 // In theory this should also be set in the config block 0; butit requries the extend mode config, which will change other things.
553 // as such, leave in user config for decoding the data until a full fix can be added.
554 // use the flag to toggle if invert is on or off.
555 config.inverted ^= invert;
557 // validate user specific downlink mode
558 uint8_t downlink_mode = config.downlink_mode;
559 if (r0)
560 downlink_mode = refFixedBit;
561 else if (r1)
562 downlink_mode = refLongLeading;
563 else if (r2)
564 downlink_mode = refLeading0;
565 else if (r3)
566 downlink_mode = ref1of4;
568 config.downlink_mode = downlink_mode;
570 // validate user specific modulation
571 if (mods[0]) {
572 config.modulation = DEMOD_FSK;
573 } else if (mods[1]) {
574 config.modulation = DEMOD_FSK1;
575 config.inverted = 0;
576 } else if (mods[2]) {
577 config.modulation = DEMOD_FSK1a;
578 config.inverted = 1;
579 } else if (mods[3]) {
580 config.modulation = DEMOD_FSK2;
581 config.inverted = 0;
582 } else if (mods[4]) {
583 config.modulation = DEMOD_FSK2a;
584 config.inverted = 1;
585 } else if (mods[5]) {
586 config.modulation = DEMOD_ASK;
587 } else if (mods[6]) {
588 config.modulation = DEMOD_PSK1;
589 } else if (mods[7]) {
590 config.modulation = DEMOD_PSK2;
591 } else if (mods[8]) {
592 config.modulation = DEMOD_PSK3;
593 } else if (mods[9]) {
594 config.modulation = DEMOD_NRZ;
595 } else if (mods[10]) {
596 config.modulation = DEMOD_BI;
597 config.inverted = 0;
598 } else if (mods[11]) {
599 config.modulation = DEMOD_BIa;
600 config.inverted = 1;
603 config.block0 = ((config.block0 & ~(0x1f000)) | (config.modulation << 12));
605 config.block0Status = USERSET;
606 if (gotconf) {
607 SetConfigWithBlock0Ex(block0, config.offset, config.Q5);
610 PrintAndLogEx(INFO, "--- " _CYAN_("current t55xx config") " --------------------------");
611 return printConfiguration(config);
613 int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode) {
614 return T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, true);
617 int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, bool verbose) {
618 //Password mode
619 if (usepwd) {
620 // try reading the config block and verify that PWD bit is set before doing this!
621 // override = 1 (override and display)
622 // override = 2 (override and no display)
623 if (override == 0) {
624 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
625 return PM3_ERFTRANS;
627 if (t55xxTryDetectModulationEx(downlink_mode, false, 0, password) == false) {
628 PrintAndLogEx(WARNING, "Safety check: Could not detect if PWD bit is set in config block. Exits.");
629 PrintAndLogEx(HINT, "Consider using the override parameter to force read.");
630 return PM3_EWRONGANSWER;
631 } else {
632 PrintAndLogEx(WARNING, "Safety check: PWD bit is NOT set in config block. Reading without password...");
633 usepwd = false;
634 page1 = false; // ??
636 } else if (override == 1) {
637 PrintAndLogEx(INFO, "Safety check overridden - proceeding despite risk");
641 if (AcquireData(page1, block, usepwd, password, downlink_mode) == false)
642 return PM3_ERFTRANS;
644 if (DecodeT55xxBlock() == false)
645 return PM3_EWRONGANSWER;
647 if (verbose)
648 printT55xxBlock(block, page1);
650 return PM3_SUCCESS;
653 static int CmdT55xxReadBlock(const char *Cmd) {
654 CLIParserContext *ctx;
655 CLIParserInit(&ctx, "lf t55xx read",
656 "Read T55xx block data. This commands defaults to page 0.\n\n"
657 _RED_(" * * * WARNING * * *") "\n"
658 _CYAN_("Use of read with password on a tag not configured") "\n"
659 _CYAN_("for a password can damage the tag") "\n"
660 _RED_(" * * * * * * * * * *"),
661 "lf t55xx read -b 0 --> read data from block 0\n"
662 "lf t55xx read -b 0 --pwd 01020304 --> read data from block 0, pwd 01020304\n"
663 "lf t55xx read -b 0 --pwd 01020304 -o --> read data from block 0, pwd 01020304, override\n"
666 // 1 (help) + 4(four user specified params) + (5 T55XX_DLMODE_SINGLE)
667 void *argtable[5 + 5] = {
668 arg_param_begin,
669 arg_int1("b", "blk", "<0-7>", "block number to read"),
670 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
671 arg_lit0("o", "override", "override safety check"),
672 arg_lit0(NULL, "pg1", "read page 1"),
674 uint8_t idx = 5;
675 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
676 CLIExecWithReturn(ctx, Cmd, argtable, true);
678 int block = arg_get_int_def(ctx, 1, REGULAR_READ_MODE_BLOCK);
680 bool usepwd = false;
681 uint32_t password = 0;
682 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true);
683 if (res == 0 || res == 2) {
684 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
685 CLIParserFree(ctx);
686 return PM3_EINVARG;
688 if (res == 1) {
689 usepwd = true;
692 uint8_t override = arg_get_lit(ctx, 3);
693 bool page1 = arg_get_lit(ctx, 4);
695 bool r0 = arg_get_lit(ctx, 5);
696 bool r1 = arg_get_lit(ctx, 6);
697 bool r2 = arg_get_lit(ctx, 7);
698 bool r3 = arg_get_lit(ctx, 8);
699 CLIParserFree(ctx);
701 if ((r0 + r1 + r2 + r3) > 1) {
702 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
703 return PM3_EINVARG;
706 uint8_t downlink_mode = config.downlink_mode;
707 if (r0)
708 downlink_mode = refFixedBit;
709 else if (r1)
710 downlink_mode = refLongLeading;
711 else if (r2)
712 downlink_mode = refLeading0;
713 else if (r3)
714 downlink_mode = ref1of4;
716 if (block > 7 && block != REGULAR_READ_MODE_BLOCK) {
717 PrintAndLogEx(NORMAL, "Block must be between 0 and 7");
718 return PM3_ESOFT;
721 printT5xxHeader(page1);
722 return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode);
725 bool DecodeT55xxBlock(void) {
727 int ans = 0;
728 bool ST = config.ST;
729 uint8_t bitRate[8] = {8, 16, 32, 40, 50, 64, 100, 128};
730 DemodBufferLen = 0x00;
732 switch (config.modulation) {
733 case DEMOD_FSK:
734 ans = FSKrawDemod(bitRate[config.bitrate], config.inverted, 0, 0, false);
735 break;
736 case DEMOD_FSK1:
737 case DEMOD_FSK1a:
738 ans = FSKrawDemod(bitRate[config.bitrate], config.inverted, 8, 5, false);
739 break;
740 case DEMOD_FSK2:
741 case DEMOD_FSK2a:
742 ans = FSKrawDemod(bitRate[config.bitrate], config.inverted, 10, 8, false);
743 break;
744 case DEMOD_ASK:
745 ans = ASKDemod_ext(bitRate[config.bitrate], config.inverted, 1, 0, false, false, false, 1, &ST);
746 break;
747 case DEMOD_PSK1:
748 ans = PSKDemod(bitRate[config.bitrate], config.inverted, 6, false);
749 break;
750 case DEMOD_PSK2: //inverted won't affect this
751 case DEMOD_PSK3: //not fully implemented
752 ans = PSKDemod(bitRate[config.bitrate], 0, 6, false);
753 psk1TOpsk2(DemodBuffer, DemodBufferLen);
754 break;
755 case DEMOD_NRZ:
756 ans = NRZrawDemod(bitRate[config.bitrate], config.inverted, 1, false);
757 break;
758 case DEMOD_BI:
759 case DEMOD_BIa:
760 ans = ASKbiphaseDemod(0, bitRate[config.bitrate], config.inverted, 1, false);
761 break;
762 default:
763 return false;
765 return (ans == PM3_SUCCESS);
768 static bool DecodeT5555TraceBlock(void) {
769 DemodBufferLen = 0x00;
771 // According to datasheet. Always: RF/64, not inverted, Manchester
772 bool st = false;
773 return (ASKDemod_ext(64, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS);
776 // sanity check. Don't use proxmark if it is offline and you didn't specify useGraphbuf
777 static int SanityOfflineCheck(bool useGraphBuffer) {
778 if (!useGraphBuffer && !session.pm3_present) {
779 PrintAndLogEx(WARNING, "Your proxmark3 device is offline. Specify [1] to use graphbuffer data instead");
780 return PM3_ENODATA;
782 return PM3_SUCCESS;
785 static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
786 char msg[80];
787 snprintf(msg, sizeof(msg), "Downlink Mode used : ");
789 switch (downlink_mode) {
790 case 1 :
791 strcat(msg, _YELLOW_("long leading reference"));
792 break;
793 case 2 :
794 strcat(msg, _YELLOW_("leading zero reference"));
795 break;
796 case 3 :
797 strcat(msg, _YELLOW_("1 of 4 coding reference"));
798 break;
799 default :
800 strcat(msg, _YELLOW_("default/fixed bit length"));
801 break;
804 PrintAndLogEx(NORMAL, msg);
807 static int CmdT55xxWakeUp(const char *Cmd) {
808 CLIParserContext *ctx;
809 CLIParserInit(&ctx, "lf t55xx wakeup",
810 "This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards",
811 "lf t55xx wakeup -p 11223344 --> send wakeup with password\n"
814 // 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
815 void *argtable[3 + 5] = {
816 arg_param_begin,
817 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
818 arg_lit0("v", "verbose", "verbose output"),
820 uint8_t idx = 3;
821 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
822 CLIExecWithReturn(ctx, Cmd, argtable, true);
824 uint32_t password = 0;
825 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true);
826 if (res == 0 || res == 2) {
827 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
828 CLIParserFree(ctx);
829 return PM3_EINVARG;
832 bool verbose = arg_get_lit(ctx, 2);
833 bool r0 = arg_get_lit(ctx, 3);
834 bool r1 = arg_get_lit(ctx, 4);
835 bool r2 = arg_get_lit(ctx, 5);
836 bool r3 = arg_get_lit(ctx, 6);
837 CLIParserFree(ctx);
839 if ((r0 + r1 + r2 + r3) > 1) {
840 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
841 return PM3_EINVARG;
844 uint8_t downlink_mode = config.downlink_mode;
845 if (r0)
846 downlink_mode = refFixedBit;
847 else if (r1)
848 downlink_mode = refLongLeading;
849 else if (r2)
850 downlink_mode = refLeading0;
851 else if (r3)
852 downlink_mode = ref1of4;
854 struct p {
855 uint32_t password;
856 uint8_t flags;
857 } PACKED payload;
859 payload.password = password;
860 payload.flags = (downlink_mode << 3);
862 clearCommandBuffer();
863 SendCommandNG(CMD_LF_T55XX_WAKEUP, (uint8_t *)&payload, sizeof(payload));
864 if (WaitForResponseTimeout(CMD_LF_T55XX_WAKEUP, NULL, 1000) == false) {
865 PrintAndLogEx(WARNING, "command execution time out");
866 return PM3_ETIMEOUT;
869 if (verbose)
870 PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
872 return PM3_SUCCESS;
875 static int CmdT55xxDetect(const char *Cmd) {
876 CLIParserContext *ctx;
877 CLIParserInit(&ctx, "lf t55xx detect",
878 "Try detecting the tag modulation from reading the configuration block",
879 "lf t55xx detect\n"
880 "lf t55xx detect -1\n"
881 "lf t55xx detect -p 11223344\n"
884 // 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL)
885 void *argtable[3 + 6] = {
886 arg_param_begin,
887 arg_lit0("1", NULL, "extract using data from graphbuffer"),
888 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
890 uint8_t idx = 3;
891 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, config.downlink_mode);
892 CLIExecWithReturn(ctx, Cmd, argtable, true);
894 bool use_gb = arg_get_lit(ctx, 1);
896 bool usepwd = false;
897 uint64_t password = -1;
898 uint32_t tmp_pwd = 0;
899 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &tmp_pwd, 4, true);
900 if (res == 0 || res == 2) {
901 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
902 CLIParserFree(ctx);
903 return PM3_EINVARG;
905 if (res == 1) {
906 usepwd = true;
907 password = tmp_pwd;
910 bool r0 = arg_get_lit(ctx, 3);
911 bool r1 = arg_get_lit(ctx, 4);
912 bool r2 = arg_get_lit(ctx, 5);
913 bool r3 = arg_get_lit(ctx, 6);
914 bool ra = arg_get_lit(ctx, 7);
915 CLIParserFree(ctx);
917 if ((r0 + r1 + r2 + r3 + ra) > 1) {
918 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
919 return PM3_EINVARG;
922 bool try_all_dl_modes = false;
923 uint8_t downlink_mode = config.downlink_mode;
924 if (r0)
925 downlink_mode = refFixedBit;
926 else if (r1)
927 downlink_mode = refLongLeading;
928 else if (r2)
929 downlink_mode = refLeading0;
930 else if (r3)
931 downlink_mode = ref1of4;
932 else // This will set the default to user all d/l modes which will cover the ra flag as well.
933 try_all_dl_modes = true;
935 bool found = false;
937 // Setup the 90ms time value to sleep for after the wake, to allow delay init to complete (~70ms)
938 struct timespec sleepperiod;
939 sleepperiod.tv_sec = 0;
940 sleepperiod.tv_nsec = 90000000;
942 // detect called so clear data blocks
943 T55x7_ClearAllBlockData();
945 // sanity check.
946 if (SanityOfflineCheck(use_gb) != PM3_SUCCESS)
947 return PM3_ESOFT;
949 if (use_gb == false) {
951 char wakecmd[20] = { 0x00 };
952 sprintf(wakecmd, "-p %08" PRIx64, password);
954 bool usewake = false;
955 bool try_with_pwd = false;
956 // do ... while not found and not yet tried with wake (for AOR or Init Delay)
957 do {
958 // do ... while to check without password then loop back if password supplied
959 do {
960 if (try_all_dl_modes) {
961 // Loop from 1st d/l mode refFixedBit to the last d/l mode ref1of4
962 for (uint8_t m = refFixedBit; m <= ref1of4; m++) {
963 if (usewake) {
964 // call wake
965 if (try_with_pwd)
966 CmdT55xxWakeUp(wakecmd);
967 else
968 CmdT55xxWakeUp("");
969 // sleep 90 ms
970 nanosleep(&sleepperiod, &sleepperiod);
973 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
974 continue;
976 if (t55xxTryDetectModulationEx(m, T55XX_PrintConfig, 0, (try_with_pwd && usepwd) ? password : -1) == false)
977 continue;
979 found = true;
980 break;
982 } else {
983 if (usewake) {
984 // call wake
985 if (try_with_pwd)
986 CmdT55xxWakeUp(wakecmd);
987 else
988 CmdT55xxWakeUp("");
989 // sleep 90 ms
990 nanosleep(&sleepperiod, &sleepperiod);
993 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
994 found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
998 // toggle so we loop back if not found and try with pwd
999 if (found == false && usepwd)
1000 try_with_pwd = !try_with_pwd;
1002 // force exit as detect block has been found
1003 if (found)
1004 try_with_pwd = false;
1006 } while (try_with_pwd);
1007 // Toggle so we loop back and try with wakeup.
1008 usewake = !usewake;
1009 } while (found == false && usewake);
1010 } else {
1011 found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
1014 if (found == false) {
1015 config.usepwd = false;
1016 config.pwd = 0x00;
1017 PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
1019 return PM3_SUCCESS;
1022 // detect configuration?
1023 bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config) {
1024 return t55xxTryDetectModulationEx(downlink_mode, print_config, 0, -1);
1027 bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd) {
1029 t55xx_conf_block_t tests[15];
1030 int bitRate = 0, clk = 0, firstClockEdge = 0;
1031 uint8_t hits = 0, fc1 = 0, fc2 = 0, ans = 0;
1033 ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
1035 if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) {
1036 if ((FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS) && test(DEMOD_FSK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1037 tests[hits].modulation = DEMOD_FSK;
1038 if (fc1 == 8 && fc2 == 5)
1039 tests[hits].modulation = DEMOD_FSK1a;
1040 else if (fc1 == 10 && fc2 == 8)
1041 tests[hits].modulation = DEMOD_FSK2;
1042 tests[hits].bitrate = bitRate;
1043 tests[hits].inverted = false;
1044 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1045 tests[hits].ST = false;
1046 tests[hits].downlink_mode = downlink_mode;
1047 ++hits;
1049 if ((FSKrawDemod(0, 1, 0, 0, false) == PM3_SUCCESS) && test(DEMOD_FSK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1050 tests[hits].modulation = DEMOD_FSK;
1051 if (fc1 == 8 && fc2 == 5)
1052 tests[hits].modulation = DEMOD_FSK1;
1053 else if (fc1 == 10 && fc2 == 8)
1054 tests[hits].modulation = DEMOD_FSK2a;
1055 tests[hits].bitrate = bitRate;
1056 tests[hits].inverted = true;
1057 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1058 tests[hits].ST = false;
1059 tests[hits].downlink_mode = downlink_mode;
1060 ++hits;
1062 } else {
1063 clk = GetAskClock("", false);
1064 if (clk > 0) {
1065 tests[hits].ST = true;
1066 // "0 0 1 " == clock auto, invert false, maxError 1.
1067 // false = no verbose
1068 // false = no emSearch
1069 // 1 = Ask/Man
1070 // st = true
1071 if ((ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &tests[hits].ST) == PM3_SUCCESS) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1072 tests[hits].modulation = DEMOD_ASK;
1073 tests[hits].bitrate = bitRate;
1074 tests[hits].inverted = false;
1075 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1076 tests[hits].downlink_mode = downlink_mode;
1077 ++hits;
1079 tests[hits].ST = true;
1080 // "0 0 1 " == clock auto, invert true, maxError 1.
1081 // false = no verbose
1082 // false = no emSearch
1083 // 1 = Ask/Man
1084 // st = true
1085 if ((ASKDemod_ext(0, 1, 1, 0, false, false, false, 1, &tests[hits].ST) == PM3_SUCCESS) && test(DEMOD_ASK, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1086 tests[hits].modulation = DEMOD_ASK;
1087 tests[hits].bitrate = bitRate;
1088 tests[hits].inverted = true;
1089 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1090 tests[hits].downlink_mode = downlink_mode;
1091 ++hits;
1093 if ((ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS) && test(DEMOD_BI, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1094 tests[hits].modulation = DEMOD_BI;
1095 tests[hits].bitrate = bitRate;
1096 tests[hits].inverted = false;
1097 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1098 tests[hits].ST = false;
1099 tests[hits].downlink_mode = downlink_mode;
1100 ++hits;
1102 if ((ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS) && test(DEMOD_BIa, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1103 tests[hits].modulation = DEMOD_BIa;
1104 tests[hits].bitrate = bitRate;
1105 tests[hits].inverted = true;
1106 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1107 tests[hits].ST = false;
1108 tests[hits].downlink_mode = downlink_mode;
1109 ++hits;
1112 clk = GetNrzClock("", false);
1113 if (clk > 8) { //clock of rf/8 is likely a false positive, so don't use it.
1114 if ((NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS) && test(DEMOD_NRZ, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1115 tests[hits].modulation = DEMOD_NRZ;
1116 tests[hits].bitrate = bitRate;
1117 tests[hits].inverted = false;
1118 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1119 tests[hits].ST = false;
1120 tests[hits].downlink_mode = downlink_mode;
1121 ++hits;
1124 if ((NRZrawDemod(0, 1, 1, false) == PM3_SUCCESS) && test(DEMOD_NRZ, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1125 tests[hits].modulation = DEMOD_NRZ;
1126 tests[hits].bitrate = bitRate;
1127 tests[hits].inverted = true;
1128 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1129 tests[hits].ST = false;
1130 tests[hits].downlink_mode = downlink_mode;
1131 ++hits;
1135 clk = GetPskClock("", false);
1136 if (clk > 0) {
1137 // allow undo
1138 save_restoreGB(GRAPH_SAVE);
1139 // skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise)
1140 CmdLtrim("-i 160");
1141 if ((PSKDemod(0, 0, 6, false) == PM3_SUCCESS) && test(DEMOD_PSK1, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1142 tests[hits].modulation = DEMOD_PSK1;
1143 tests[hits].bitrate = bitRate;
1144 tests[hits].inverted = false;
1145 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1146 tests[hits].ST = false;
1147 tests[hits].downlink_mode = downlink_mode;
1148 ++hits;
1150 if ((PSKDemod(0, 1, 6, false) == PM3_SUCCESS) && test(DEMOD_PSK1, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1151 tests[hits].modulation = DEMOD_PSK1;
1152 tests[hits].bitrate = bitRate;
1153 tests[hits].inverted = true;
1154 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1155 tests[hits].ST = false;
1156 tests[hits].downlink_mode = downlink_mode;
1157 ++hits;
1159 //ICEMAN: are these PSKDemod calls needed?
1160 // PSK2 - needs a call to psk1TOpsk2.
1161 if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) {
1162 psk1TOpsk2(DemodBuffer, DemodBufferLen);
1163 if (test(DEMOD_PSK2, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1164 tests[hits].modulation = DEMOD_PSK2;
1165 tests[hits].bitrate = bitRate;
1166 tests[hits].inverted = false;
1167 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1168 tests[hits].ST = false;
1169 tests[hits].downlink_mode = downlink_mode;
1170 ++hits;
1172 } // inverse waves does not affect this demod
1173 // PSK3 - needs a call to psk1TOpsk2.
1174 if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) {
1175 psk1TOpsk2(DemodBuffer, DemodBufferLen);
1176 if (test(DEMOD_PSK3, &tests[hits].offset, &bitRate, clk, &tests[hits].Q5)) {
1177 tests[hits].modulation = DEMOD_PSK3;
1178 tests[hits].bitrate = bitRate;
1179 tests[hits].inverted = false;
1180 tests[hits].block0 = PackBits(tests[hits].offset, 32, DemodBuffer);
1181 tests[hits].ST = false;
1182 tests[hits].downlink_mode = downlink_mode;
1183 ++hits;
1185 } // inverse waves does not affect this demod
1186 //undo trim samples
1187 save_restoreGB(GRAPH_RESTORE);
1190 if (hits == 1) {
1191 config.modulation = tests[0].modulation;
1192 config.bitrate = tests[0].bitrate;
1193 config.inverted = tests[0].inverted;
1194 config.offset = tests[0].offset;
1195 config.block0 = tests[0].block0;
1196 config.Q5 = tests[0].Q5;
1197 config.ST = tests[0].ST;
1198 config.downlink_mode = downlink_mode;
1199 if (pwd != -1) {
1200 config.usepwd = true;
1201 config.pwd = pwd & 0xffffffff;
1204 config.block0Status = AUTODETECT;
1205 if (print_config)
1206 printConfiguration(config);
1208 return true;
1211 bool retval = false;
1212 if (hits > 1) {
1213 PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits);
1214 for (int i = 0; i < hits; ++i) {
1216 bool wanted = false;
1217 if (wanted_conf > 0)
1218 wanted = (wanted_conf == tests[i].block0);
1220 retval = testKnownConfigBlock(tests[i].block0);
1221 if (retval || wanted) {
1222 PrintAndLogEx(NORMAL, "--[%d]--------------- << selected this", i + 1);
1223 config.modulation = tests[i].modulation;
1224 config.bitrate = tests[i].bitrate;
1225 config.inverted = tests[i].inverted;
1226 config.offset = tests[i].offset;
1227 config.block0 = tests[i].block0;
1228 config.Q5 = tests[i].Q5;
1229 config.ST = tests[i].ST;
1230 config.downlink_mode = tests[i].downlink_mode;
1232 if (pwd != -1) {
1233 config.usepwd = true;
1234 config.pwd = pwd & 0xffffffff;
1236 } else {
1237 PrintAndLogEx(NORMAL, "--[%d]---------------", i + 1);
1240 config.block0Status = AUTODETECT;
1241 if (print_config)
1242 printConfiguration(tests[i]);
1245 return retval;
1248 bool testKnownConfigBlock(uint32_t block0) {
1249 switch (block0) {
1250 case T55X7_DEFAULT_CONFIG_BLOCK:
1251 case T55X7_RAW_CONFIG_BLOCK:
1252 case T55X7_EM_UNIQUE_CONFIG_BLOCK:
1253 case T55X7_FDXB_CONFIG_BLOCK:
1254 case T55X7_FDXB_2_CONFIG_BLOCK:
1255 case T55X7_HID_26_CONFIG_BLOCK:
1256 case T55X7_PYRAMID_CONFIG_BLOCK:
1257 case T55X7_INDALA_64_CONFIG_BLOCK:
1258 case T55X7_INDALA_224_CONFIG_BLOCK:
1259 case T55X7_GUARDPROXII_CONFIG_BLOCK:
1260 case T55X7_VIKING_CONFIG_BLOCK:
1261 case T55X7_NORALSY_CONFIG_BLOCK:
1262 case T55X7_IOPROX_CONFIG_BLOCK:
1263 case T55X7_PRESCO_CONFIG_BLOCK:
1264 case T55X7_NEDAP_64_CONFIG_BLOCK:
1265 case T55X7_NEDAP_128_CONFIG_BLOCK:
1266 case T55X7_VISA2000_CONFIG_BLOCK:
1267 case T55X7_SECURAKEY_CONFIG_BLOCK:
1268 case T55X7_PAC_CONFIG_BLOCK:
1269 case T55X7_VERICHIP_CONFIG_BLOCK:
1270 case T55X7_KERI_CONFIG_BLOCK:
1271 case T55X7_NEXWATCH_CONFIG_BLOCK:
1272 case T55X7_JABLOTRON_CONFIG_BLOCK:
1273 return true;
1275 return false;
1278 bool GetT55xxBlockData(uint32_t *blockdata) {
1280 if (DemodBufferLen == 0)
1281 return false;
1283 uint8_t idx = config.offset;
1285 if (idx + 32 > DemodBufferLen) {
1286 PrintAndLogEx(WARNING, "The configured offset %d is too big. Possible offset: %zu)", idx, DemodBufferLen - 32);
1287 return false;
1290 *blockdata = PackBits(0, 32, DemodBuffer + idx);
1291 return true;
1294 void printT55xxBlock(uint8_t blockNum, bool page1) {
1296 uint32_t val = 0;
1297 if (GetT55xxBlockData(&val) == false)
1298 return;
1300 uint8_t bytes[4] = {0};
1301 num_to_bytes(val, 4, bytes);
1303 T55x7_SaveBlockData((page1) ? blockNum + 8 : blockNum, val);
1305 PrintAndLogEx(SUCCESS, " %02d | %08X | %s | %s", blockNum, val, sprint_bin(DemodBuffer + config.offset, 32), sprint_ascii(bytes, 4));
1308 static bool testModulation(uint8_t mode, uint8_t modread) {
1309 switch (mode) {
1310 case DEMOD_FSK:
1311 if (modread >= DEMOD_FSK1 && modread <= DEMOD_FSK2a) return true;
1312 break;
1313 case DEMOD_ASK:
1314 if (modread == DEMOD_ASK) return true;
1315 break;
1316 case DEMOD_PSK1:
1317 if (modread == DEMOD_PSK1) return true;
1318 break;
1319 case DEMOD_PSK2:
1320 if (modread == DEMOD_PSK2) return true;
1321 break;
1322 case DEMOD_PSK3:
1323 if (modread == DEMOD_PSK3) return true;
1324 break;
1325 case DEMOD_NRZ:
1326 if (modread == DEMOD_NRZ) return true;
1327 break;
1328 case DEMOD_BI:
1329 if (modread == DEMOD_BI) return true;
1330 break;
1331 case DEMOD_BIa:
1332 if (modread == DEMOD_BIa) return true;
1333 break;
1334 default:
1335 return false;
1337 return false;
1340 static bool testQ5Modulation(uint8_t mode, uint8_t modread) {
1341 switch (mode) {
1342 case DEMOD_FSK:
1343 if (modread >= 4 && modread <= 5) return true;
1344 break;
1345 case DEMOD_ASK:
1346 if (modread == 0) return true;
1347 break;
1348 case DEMOD_PSK1:
1349 if (modread == 1) return true;
1350 break;
1351 case DEMOD_PSK2:
1352 if (modread == 2) return true;
1353 break;
1354 case DEMOD_PSK3:
1355 if (modread == 3) return true;
1356 break;
1357 case DEMOD_NRZ:
1358 if (modread == 7) return true;
1359 break;
1360 case DEMOD_BI:
1361 if (modread == 6) return true;
1362 break;
1363 default:
1364 return false;
1366 return false;
1369 static int convertQ5bitRate(uint8_t bitRateRead) {
1370 uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
1371 for (int i = 0; i < 8; i++)
1372 if (expected[i] == bitRateRead)
1373 return i;
1375 return -1;
1378 static bool testQ5(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk) {
1380 if (DemodBufferLen < 64) return false;
1382 for (uint8_t idx = 28; idx < 64; idx++) {
1383 uint8_t si = idx;
1384 if (PackBits(si, 28, DemodBuffer) == 0x00) continue;
1386 uint8_t safer = PackBits(si, 4, DemodBuffer);
1387 si += 4; //master key
1388 uint8_t resv = PackBits(si, 8, DemodBuffer);
1389 si += 8;
1390 // 2nibble must be zeroed.
1391 if (safer != 0x6 && safer != 0x9) continue;
1392 if (resv > 0x00) continue;
1393 //uint8_t pageSel = PackBits(si, 1, DemodBuffer); si += 1;
1394 //uint8_t fastWrite = PackBits(si, 1, DemodBuffer); si += 1;
1395 si += 1 + 1;
1396 int bitRate = PackBits(si, 6, DemodBuffer) * 2 + 2;
1397 si += 6; //bit rate
1398 if (bitRate > 128 || bitRate < 8) continue;
1400 //uint8_t AOR = PackBits(si, 1, DemodBuffer); si += 1;
1401 //uint8_t PWD = PackBits(si, 1, DemodBuffer); si += 1;
1402 //uint8_t pskcr = PackBits(si, 2, DemodBuffer); si += 2; //could check psk cr
1403 //uint8_t inverse = PackBits(si, 1, DemodBuffer); si += 1;
1404 si += 1 + 1 + 2 + 1;
1405 uint8_t modread = PackBits(si, 3, DemodBuffer);
1406 si += 3;
1407 uint8_t maxBlk = PackBits(si, 3, DemodBuffer);
1408 si += 3;
1409 //uint8_t ST = PackBits(si, 1, DemodBuffer); si += 1;
1410 if (maxBlk == 0) continue;
1412 //test modulation
1413 if (!testQ5Modulation(mode, modread)) continue;
1414 if (bitRate != clk) continue;
1416 *fndBitRate = convertQ5bitRate(bitRate);
1417 if (*fndBitRate < 0) continue;
1419 *offset = idx;
1421 return true;
1423 return false;
1426 static bool testBitRate(uint8_t readRate, uint8_t clk) {
1427 uint8_t expected[] = {8, 16, 32, 40, 50, 64, 100, 128};
1428 if (expected[readRate] == clk)
1429 return true;
1431 return false;
1434 bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5) {
1436 if (DemodBufferLen < 64) return false;
1437 for (uint8_t idx = 28; idx < 64; idx++) {
1438 uint8_t si = idx;
1439 if (PackBits(si, 28, DemodBuffer) == 0x00) continue;
1441 uint8_t safer = PackBits(si, 4, DemodBuffer);
1442 si += 4; //master key
1443 uint8_t resv = PackBits(si, 4, DemodBuffer);
1444 si += 4; //was 7 & +=7+3 //should be only 4 bits if extended mode
1445 // 2nibble must be zeroed.
1446 // moved test to here, since this gets most faults first.
1447 if (resv > 0x00) continue;
1449 int bitRate = PackBits(si, 6, DemodBuffer);
1450 si += 6; //bit rate (includes extended mode part of rate)
1451 uint8_t extend = PackBits(si, 1, DemodBuffer);
1452 si += 1; //bit 15 extended mode
1453 uint8_t modread = PackBits(si, 5, DemodBuffer);
1454 si += 5 + 2 + 1;
1455 //uint8_t pskcr = PackBits(si, 2, DemodBuffer); si += 2+1; //could check psk cr
1456 //uint8_t nml01 = PackBits(si, 1, DemodBuffer); si += 1+5; //bit 24, 30, 31 could be tested for 0 if not extended mode
1457 //uint8_t nml02 = PackBits(si, 2, DemodBuffer); si += 2;
1459 //if extended mode
1460 bool extMode = ((safer == 0x6 || safer == 0x9) && extend) ? true : false;
1462 if (!extMode) {
1463 if (bitRate > 7) continue;
1464 if (!testBitRate(bitRate, clk)) continue;
1465 } else { //extended mode bitrate = same function to calc bitrate as em4x05
1466 if (EM4x05_GET_BITRATE(bitRate) != clk) continue;
1469 //test modulation
1470 if (!testModulation(mode, modread)) continue;
1471 *fndBitRate = bitRate;
1472 *offset = idx;
1473 *Q5 = false;
1474 return true;
1476 if (testQ5(mode, offset, fndBitRate, clk)) {
1477 *Q5 = true;
1478 return true;
1480 return false;
1483 int CmdT55xxSpecial(const char *Cmd) {
1485 CLIParserContext *ctx;
1486 CLIParserInit(&ctx, "lf t55xx special",
1487 "Show block changes with 64 different offsets, data taken from Demod buffer.",
1488 "lf t55xx special\n"
1491 void *argtable[] = {
1492 arg_param_begin,
1493 arg_param_end
1495 CLIExecWithReturn(ctx, Cmd, argtable, true);
1496 CLIParserFree(ctx);
1498 uint8_t bits[32] = {0x00};
1500 PrintAndLogEx(NORMAL, "OFFSET | DATA | BINARY | ASCII");
1501 PrintAndLogEx(NORMAL, "-------+-------+-------------------------------------+------");
1502 int i, j = 0;
1503 for (; j < 64; ++j) {
1505 for (i = 0; i < 32; ++i)
1506 bits[i] = DemodBuffer[j + i];
1508 uint32_t blockData = PackBits(0, 32, bits);
1510 PrintAndLogEx(NORMAL, "%02d | 0x%08X | %s", j, blockData, sprint_bin(bits, 32));
1512 return PM3_SUCCESS;
1515 int printConfiguration(t55xx_conf_block_t b) {
1516 PrintAndLogEx(INFO, " Chip type......... " _GREEN_("%s"), (b.Q5) ? "Q5/T5555" : "T55x7");
1517 PrintAndLogEx(INFO, " Modulation........ " _GREEN_("%s"), GetSelectedModulationStr(b.modulation));
1518 PrintAndLogEx(INFO, " Bit rate.......... %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0 >> 28 == 6 || b.block0 >> 28 == 9))));
1519 PrintAndLogEx(INFO, " Inverted.......... %s", (b.inverted) ? _GREEN_("Yes") : "No");
1520 PrintAndLogEx(INFO, " Offset............ %d", b.offset);
1521 PrintAndLogEx(INFO, " Seq. terminator... %s", (b.ST) ? _GREEN_("Yes") : "No");
1522 PrintAndLogEx(INFO, " Block0............ %08X %s", b.block0, GetConfigBlock0Source(b.block0Status));
1523 PrintAndLogEx(INFO, " Downlink mode..... %s", GetDownlinkModeStr(b.downlink_mode));
1524 PrintAndLogEx(INFO, " Password set...... %s", (b.usepwd) ? _RED_("Yes") : _GREEN_("No"));
1525 if (b.usepwd) {
1526 PrintAndLogEx(INFO, " Password.......... %08X", b.pwd);
1528 PrintAndLogEx(NORMAL, "");
1529 return PM3_SUCCESS;
1532 static int CmdT55xxWriteBlock(const char *Cmd) {
1533 CLIParserContext *ctx;
1534 CLIParserInit(&ctx, "lf t55xx write",
1535 "Write T55xx block data",
1536 "lf t55xx write -b 3 -d 11223344 --> write 11223344 to block 3\n"
1537 "lf t55xx write -b 3 -d 11223344 --pwd 01020304 --> write 11223344 to block 3, pwd 01020304\n"
1538 "lf t55xx write -b 3 -d 11223344 --pwd 01020304 --verify --> write 11223344 to block 3 and try validating write"
1541 // 1 (help) + 6 (six user specified params) + (5 T55XX_DLMODE_SINGLE)
1542 void *argtable[7 + 5] = {
1543 arg_param_begin,
1544 arg_int1("b", "blk", "<0-7>", "block number to write"),
1545 arg_str0("d", "data", "<hex>", "data to write (4 hex bytes)"),
1546 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
1547 arg_lit0("t", "tm", "test mode write ( " _RED_("danger") " )"),
1548 arg_lit0(NULL, "pg1", "write page 1"),
1549 arg_lit0(NULL, "verify", "try validate data afterward"),
1551 uint8_t idx = 7;
1552 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
1553 CLIExecWithReturn(ctx, Cmd, argtable, true);
1555 int block = arg_get_int_def(ctx, 1, REGULAR_READ_MODE_BLOCK);
1557 uint32_t data = 0; // default to blank Block
1558 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &data, 4, true);
1559 if (res == 0 || res == 2) {
1560 PrintAndLogEx(ERR, "data must be 4 hex bytes");
1561 CLIParserFree(ctx);
1562 return PM3_EINVARG;
1565 bool usepwd = false;
1566 uint32_t password = 0; // default to blank Block 7
1567 res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &password, 4, true);
1568 if (res == 0 || res == 2) {
1569 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
1570 CLIParserFree(ctx);
1571 return PM3_EINVARG;
1573 if (res == 1) {
1574 usepwd = true;
1577 bool testmode = arg_get_lit(ctx, 4);
1578 bool page1 = arg_get_lit(ctx, 5);
1579 bool validate = arg_get_lit(ctx, 6);
1581 bool r0 = arg_get_lit(ctx, 7);
1582 bool r1 = arg_get_lit(ctx, 8);
1583 bool r2 = arg_get_lit(ctx, 9);
1584 bool r3 = arg_get_lit(ctx, 10);
1585 CLIParserFree(ctx);
1587 if ((r0 + r1 + r2 + r3) > 1) {
1588 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
1589 return PM3_EINVARG;
1592 uint8_t downlink_mode = config.downlink_mode;
1593 if (r0)
1594 downlink_mode = refFixedBit;
1595 else if (r1)
1596 downlink_mode = refLongLeading;
1597 else if (r2)
1598 downlink_mode = refLeading0;
1599 else if (r3)
1600 downlink_mode = ref1of4;
1602 if (block > 7 && block != REGULAR_READ_MODE_BLOCK) {
1603 PrintAndLogEx(NORMAL, "Block must be between 0 and 7");
1604 return PM3_ESOFT;
1607 char pwdstr[16] = {0};
1608 snprintf(pwdstr, sizeof(pwdstr), "pwd: 0x%08X", password);
1610 PrintAndLogEx(INFO, "Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdstr : "");
1612 if (t55xxWrite(block, page1, usepwd, testmode, password, downlink_mode, data) != PM3_SUCCESS) {
1613 PrintAndLogEx(ERR, "Write failed");
1614 return PM3_ESOFT;
1617 if (validate) {
1618 bool isOK = t55xxVerifyWrite(block, page1, usepwd, 1, password, downlink_mode, data);
1619 if (isOK)
1620 PrintAndLogEx(SUCCESS, "Write OK, validation successful");
1621 else
1622 PrintAndLogEx(WARNING, "Write could not validate the written data");
1625 return PM3_SUCCESS;
1628 static int CmdT55xxDangerousRaw(const char *Cmd) {
1629 CLIParserContext *ctx;
1630 CLIParserInit(&ctx, "lf t55xx dangerraw",
1631 "This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration.\n"
1632 "Uncontrolled usage can easily write an invalid configuration, activate lock bits,\n"
1633 "OTP bit, password protection bit, deactivate test-mode, lock your card forever.\n"
1634 _RED_("WARNING:") _CYAN_(" this may lock definitively the tag in an unusable state!"),
1635 "lf t55xx dangerraw -d 01000000000000010000100000000100000000 -t 3200\n"
1638 void *argtable[] = {
1639 arg_param_begin,
1640 arg_str1("d", "data", NULL, "raw bit string"),
1641 arg_int1("t", "time", "<us>", "<0 - 200000> time in microseconds before dropping the field"),
1642 arg_param_end
1644 CLIExecWithReturn(ctx, Cmd, argtable, true);
1646 // supports only default downlink mode
1647 t55xx_test_block_t ng;
1648 ng.time = 0;
1649 ng.bitlen = 0;
1650 memset(ng.data, 0x00, sizeof(ng.data));
1652 int bin_len = 127;
1653 uint8_t bin[128] = {0};
1654 CLIGetStrWithReturn(ctx, 1, bin, &bin_len);
1656 ng.time = arg_get_int_def(ctx, 2, 0);
1657 CLIParserFree(ctx);
1659 if (ng.time == 0 || ng.time > 200000) {
1660 PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time);
1661 return PM3_EINVARG;
1664 int bs_len = binstring2binarray(ng.data, (char *)bin, bin_len);
1665 if (bs_len == 0) {
1666 return PM3_EINVARG;
1669 ng.bitlen = bs_len;
1671 PacketResponseNG resp;
1672 clearCommandBuffer();
1673 SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng));
1674 if (!WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000)) {
1675 PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation.");
1676 return PM3_ETIMEOUT;
1678 return resp.status;
1681 static int CmdT55xxReadTrace(const char *Cmd) {
1683 CLIParserContext *ctx;
1684 CLIParserInit(&ctx, "lf t55xx trace",
1685 "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block",
1686 "lf t55xx trace\n"
1687 "lf t55xx trace -1"
1690 // 1 (help) + 1 (one user specified params) + (5 T55XX_DLMODE_SINGLE)
1691 void *argtable[2 + 5] = {
1692 arg_param_begin,
1693 arg_lit0("1", NULL, "extract using data from graphbuffer"),
1695 uint8_t idx = 2;
1696 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
1697 CLIExecWithReturn(ctx, Cmd, argtable, true);
1699 bool use_gb = arg_get_lit(ctx, 1);
1701 bool r0 = arg_get_lit(ctx, 2);
1702 bool r1 = arg_get_lit(ctx, 3);
1703 bool r2 = arg_get_lit(ctx, 4);
1704 bool r3 = arg_get_lit(ctx, 5);
1705 CLIParserFree(ctx);
1707 if ((r0 + r1 + r2 + r3) > 1) {
1708 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
1709 return PM3_EINVARG;
1712 uint8_t downlink_mode = config.downlink_mode;
1713 if (r0)
1714 downlink_mode = refFixedBit;
1715 else if (r1)
1716 downlink_mode = refLongLeading;
1717 else if (r2)
1718 downlink_mode = refLeading0;
1719 else if (r3)
1720 downlink_mode = ref1of4;
1722 if (use_gb == false) {
1723 // sanity check.
1724 if (SanityOfflineCheck(false) != PM3_SUCCESS) return PM3_ENODATA;
1726 bool pwdmode = false;
1727 uint32_t password = 0;
1729 // REGULAR_READ_MODE_BLOCK - yeilds correct Page 1 Block 2 data i.e. + 32 bit offset.
1730 if (!AcquireData(T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password, downlink_mode))
1731 return PM3_ENODATA;
1734 if (config.Q5) {
1735 if (DecodeT5555TraceBlock() == false) {
1736 return PM3_ESOFT;
1738 } else {
1739 if (DecodeT55xxBlock() == false) {
1740 return PM3_ESOFT;
1744 if (DemodBufferLen == 0) {
1745 return PM3_ESOFT;
1748 RepaintGraphWindow();
1749 uint8_t repeat = (config.offset > 5) ? 32 : 0;
1751 uint8_t si = config.offset + repeat;
1752 uint32_t bl1 = PackBits(si, 32, DemodBuffer);
1753 uint32_t bl2 = PackBits(si + 32, 32, DemodBuffer);
1755 if (config.Q5) {
1756 uint32_t hdr = PackBits(si, 9, DemodBuffer);
1757 si += 9;
1759 if (hdr != 0x1FF) {
1760 PrintAndLogEx(FAILED, "Invalid Q5/T5555 Trace data header (expected 0x1FF, found %X)", hdr);
1761 return PM3_ESOFT;
1764 t5555_tracedata_t data = {.bl1 = bl1, .bl2 = bl2, .icr = 0, .lotidc = '?', .lotid = 0, .wafer = 0, .dw = 0};
1766 data.icr = PackBits(si, 2, DemodBuffer);
1767 si += 2;
1768 data.lotidc = 'Z' - PackBits(si, 2, DemodBuffer);
1769 si += 3;
1771 data.lotid = PackBits(si, 4, DemodBuffer);
1772 si += 5;
1773 data.lotid <<= 4;
1774 data.lotid |= PackBits(si, 4, DemodBuffer);
1775 si += 5;
1776 data.lotid <<= 4;
1777 data.lotid |= PackBits(si, 4, DemodBuffer);
1778 si += 5;
1779 data.lotid <<= 4;
1780 data.lotid |= PackBits(si, 4, DemodBuffer);
1781 si += 5;
1782 data.lotid <<= 1;
1783 data.lotid |= PackBits(si, 1, DemodBuffer);
1784 si += 1;
1786 data.wafer = PackBits(si, 3, DemodBuffer);
1787 si += 4;
1788 data.wafer <<= 2;
1789 data.wafer |= PackBits(si, 2, DemodBuffer);
1790 si += 2;
1792 data.dw = PackBits(si, 2, DemodBuffer);
1793 si += 3;
1794 data.dw <<= 4;
1795 data.dw |= PackBits(si, 4, DemodBuffer);
1796 si += 5;
1797 data.dw <<= 4;
1798 data.dw |= PackBits(si, 4, DemodBuffer);
1799 si += 5;
1800 data.dw <<= 4;
1801 data.dw |= PackBits(si, 4, DemodBuffer);
1803 printT5555Trace(data, repeat);
1805 } else {
1807 t55x7_tracedata_t data = {.bl1 = bl1, .bl2 = bl2, .acl = 0, .mfc = 0, .cid = 0, .year = 0, .quarter = 0, .icr = 0, .lotid = 0, .wafer = 0, .dw = 0};
1809 data.acl = PackBits(si, 8, DemodBuffer);
1810 si += 8;
1811 if (data.acl != 0xE0) {
1812 PrintAndLogEx(FAILED, "The modulation is most likely wrong since the ACL is not 0xE0. ");
1813 return PM3_ESOFT;
1816 data.mfc = PackBits(si, 8, DemodBuffer);
1817 si += 8;
1818 data.cid = PackBits(si, 5, DemodBuffer);
1819 si += 5;
1820 data.icr = PackBits(si, 3, DemodBuffer);
1821 si += 3;
1822 data.year = PackBits(si, 4, DemodBuffer);
1823 si += 4;
1824 data.quarter = PackBits(si, 2, DemodBuffer);
1825 si += 2;
1826 data.lotid = PackBits(si, 14, DemodBuffer);
1827 si += 14;
1828 data.wafer = PackBits(si, 5, DemodBuffer);
1829 si += 5;
1830 data.dw = PackBits(si, 15, DemodBuffer);
1832 struct tm *ct, tm_buf;
1833 time_t now = time(NULL);
1834 #if defined(_WIN32)
1835 ct = localtime_s(&tm_buf, &now) == 0 ? &tm_buf : NULL;
1836 #else
1837 ct = localtime_r(&now, &tm_buf);
1838 #endif
1840 if (data.year > ct->tm_year - 110)
1841 data.year += 2000;
1842 else
1843 data.year += 2010;
1845 printT55x7Trace(data, repeat);
1847 return PM3_SUCCESS;
1850 void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat) {
1851 PrintAndLogEx(INFO, "--- " _CYAN_("T55x7 Trace Information") " ----------------------------------");
1852 PrintAndLogEx(INFO, " ACL Allocation class (ISO/IEC 15963-1) : 0x%02X ( %d )", data.acl, data.acl);
1853 PrintAndLogEx(INFO, " MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X ( %d ) - %s", data.mfc, data.mfc, getTagInfo(data.mfc));
1854 PrintAndLogEx(INFO, " CID : 0x%02X ( %d ) - %s", data.cid, data.cid, GetModelStrFromCID(data.cid));
1855 PrintAndLogEx(INFO, " ICR IC Revision : %d", data.icr);
1856 PrintAndLogEx(INFO, " Manufactured");
1857 PrintAndLogEx(INFO, " Year/Quarter... %d/%d", data.year, data.quarter);
1858 PrintAndLogEx(INFO, " Lot ID......... %d", data.lotid);
1859 PrintAndLogEx(INFO, " Wafer number... %d", data.wafer);
1860 PrintAndLogEx(INFO, " Die Number..... %d", data.dw);
1861 PrintAndLogEx(INFO, "-------------------------------------------------------------");
1862 PrintAndLogEx(INFO, " Raw Data - Page 1");
1863 PrintAndLogEx(INFO, " Block 1... %08X - %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32));
1864 PrintAndLogEx(INFO, " Block 2... %08X - %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32));
1865 PrintAndLogEx(NORMAL, "");
1868 Trace info.
1869 M1, M2 has the about ATMEL defintion of trace data.
1870 M3 has unique format following industry defacto standard with row/col parity
1872 TRACE - BLOCK O
1873 Bits Definition HEX
1874 1-8 ACL Allocation class (ISO/IEC 15963-1) 0xE0
1875 9-16 MFC Manufacturer ID (ISO/IEC 7816-6) 0x15 Atmel Corporation
1876 17-21 CID 0x1 = Atmel ATA5577M1
1877 0x2 = Atmel ATA5577M2
1878 0x3 = Atmel ATA5577M3
1879 22-24 ICR IC revision
1880 25-28 YEAR (BCD encoded) 9 (= 2009)
1881 29-30 QUARTER 1,2,3,4
1882 31-32 LOT ID
1884 TRACE - BLOCK 1
1885 1-12 LOT ID
1886 13-17 Wafer number
1887 18-32 DW, die number sequential
1890 Startup times (FC)
1891 M1, M2 = 192
1892 M3 = 128
1896 void printT5555Trace(t5555_tracedata_t data, uint8_t repeat) {
1897 PrintAndLogEx(INFO, "--- " _CYAN_("Q5/T5555 Trace Information") " ---------------------------");
1898 PrintAndLogEx(INFO, " ICR IC Revision.... %d", data.icr);
1899 PrintAndLogEx(INFO, " Lot ID......... %c%d", data.lotidc, data.lotid);
1900 PrintAndLogEx(INFO, " Wafer number... %d", data.wafer);
1901 PrintAndLogEx(INFO, " Die Number..... %d", data.dw);
1902 PrintAndLogEx(INFO, "-------------------------------------------------------------");
1903 PrintAndLogEx(INFO, " Raw Data - Page 1");
1904 PrintAndLogEx(INFO, " Block 1... %08X - %s", data.bl1, sprint_bin(DemodBuffer + config.offset + repeat, 32));
1905 PrintAndLogEx(INFO, " Block 2... %08X - %s", data.bl2, sprint_bin(DemodBuffer + config.offset + repeat + 32, 32));
1908 ** Q5 **
1909 TRACE - BLOCK O and BLOCK1
1910 Bits Definition HEX
1911 1-9 Header 0x1FF
1912 10-11 IC Revision
1913 12-13 Lot ID char
1914 15-35 Lot ID (NB parity)
1915 36-41 Wafer number (NB parity)
1916 42-58 DW, die number sequential (NB parity)
1917 60-63 Parity bits
1918 64 Always zero
1922 static void printT5x7KnownBlock0(uint32_t b0) {
1924 char s[40];
1925 memset(s, 0, sizeof(s));
1927 switch (b0) {
1928 case T55X7_DEFAULT_CONFIG_BLOCK:
1929 snprintf(s, sizeof(s) - strlen(s), "T55x7 Default ");
1930 break;
1931 case T55X7_RAW_CONFIG_BLOCK:
1932 snprintf(s + strlen(s), sizeof(s) - strlen(s), "T55x7 Raw ");
1933 break;
1934 case T55X7_EM_UNIQUE_CONFIG_BLOCK:
1935 snprintf(s + strlen(s), sizeof(s) - strlen(s), "EM unique, Paxton ");
1936 break;
1937 case T55X7_FDXB_2_CONFIG_BLOCK:
1938 case T55X7_FDXB_CONFIG_BLOCK:
1939 snprintf(s + strlen(s), sizeof(s) - strlen(s), "FDXB ");
1940 break;
1941 case T55X7_HID_26_CONFIG_BLOCK:
1942 snprintf(s + strlen(s), sizeof(s) - strlen(s), "HID 26b (ProxCard), Paradox, AWID ");
1943 break;
1944 case T55X7_PYRAMID_CONFIG_BLOCK:
1945 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Pyramid ");
1946 break;
1947 case T55X7_INDALA_64_CONFIG_BLOCK:
1948 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Indala 64, Motorola, Idteck");
1949 break;
1950 case T55X7_INDALA_224_CONFIG_BLOCK:
1951 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Indala 224 ");
1952 break;
1953 case T55X7_GUARDPROXII_CONFIG_BLOCK:
1954 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Guard Prox II ");
1955 break;
1956 case T55X7_VIKING_CONFIG_BLOCK:
1957 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Viking ");
1958 break;
1959 case T55X7_NORALSY_CONFIG_BLOCK:
1960 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Noralys ");
1961 break;
1962 case T55X7_IOPROX_CONFIG_BLOCK:
1963 snprintf(s + strlen(s), sizeof(s) - strlen(s), "IO Prox ");
1964 break;
1965 case T55X7_PRESCO_CONFIG_BLOCK:
1966 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Presco ");
1967 break;
1968 case T55X7_NEDAP_64_CONFIG_BLOCK:
1969 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Nedap 64 ");
1970 break;
1971 case T55X7_NEDAP_128_CONFIG_BLOCK:
1972 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Nedap 128 ");
1973 break;
1974 case T55X7_PAC_CONFIG_BLOCK:
1975 snprintf(s + strlen(s), sizeof(s) - strlen(s), "PAC/Stanley ");
1976 break;
1977 case T55X7_VERICHIP_CONFIG_BLOCK:
1978 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Verichip ");
1979 break;
1980 case T55X7_VISA2000_CONFIG_BLOCK:
1981 snprintf(s + strlen(s), sizeof(s) - strlen(s), "VISA2000 ");
1982 break;
1983 case T55X7_JABLOTRON_CONFIG_BLOCK:
1984 snprintf(s + strlen(s), sizeof(s) - strlen(s), "Jablotron ");
1985 break;
1986 case T55X7_KERI_CONFIG_BLOCK:
1987 snprintf(s + strlen(s), sizeof(s) - strlen(s), "KERI ");
1988 break;
1989 case T55X7_SECURAKEY_CONFIG_BLOCK:
1990 snprintf(s + strlen(s), sizeof(s) - strlen(s), "SecuraKey ");
1991 break;
1992 case T55X7_NEXWATCH_CONFIG_BLOCK:
1993 snprintf(s + strlen(s), sizeof(s) - strlen(s), "NexWatch, Quadrakey ");
1994 break;
1995 default:
1996 break;
1999 if (strlen(s) > 0) {
2000 PrintAndLogEx(SUCCESS, "Config block match : " _YELLOW_("%s"), s);
2004 static int CmdT55xxInfo(const char *Cmd) {
2005 CLIParserContext *ctx;
2006 CLIParserInit(&ctx, "lf t55xx info",
2007 "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block\n"
2008 "from tag. Use `-c` to specify a config block data to be used instead of reading tag.",
2009 "lf t55xx info\n"
2010 "lf t55xx info -1\n"
2011 "lf t55xx info -p 11223344\n"
2012 "lf t55xx info -c 00083040\n"
2013 "lf t55xx info -c 6001805A --q5"
2016 // 1 (help) + 4 (four user specified params) + (5 T55XX_DLMODE_SINGLE)
2017 void *argtable[5 + 5] = {
2018 arg_param_begin,
2019 arg_lit0("1", NULL, "extract using data from graphbuffer"),
2020 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
2021 arg_str0("c", "blk0", "<hex>", "use these data instead (4 hex bytes)"),
2022 arg_lit0(NULL, "q5", "interprete provided data as T5555/Q5 config"),
2024 uint8_t idx = 5;
2025 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
2026 CLIExecWithReturn(ctx, Cmd, argtable, true);
2028 bool use_gb = arg_get_lit(ctx, 1);
2030 bool usepwd = false;
2031 uint32_t password = 0;
2032 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true);
2033 if (res == 0 || res == 2) {
2034 PrintAndLogEx(ERR, "Password must be 4 hex bytes");
2035 CLIParserFree(ctx);
2036 return PM3_EINVARG;
2038 if (res == 1) {
2039 usepwd = true;
2042 bool gotdata = false;
2043 uint32_t block0 = 0;
2044 res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &block0, 4, true);
2045 if (res == 0 || res == 2) {
2046 PrintAndLogEx(ERR, "block0 data must be 4 hex bytes");
2047 CLIParserFree(ctx);
2048 return PM3_EINVARG;
2050 if (res == 1) {
2051 gotdata = true;
2054 bool dataasq5 = arg_get_lit(ctx, 4);
2056 bool r0 = arg_get_lit(ctx, 5);
2057 bool r1 = arg_get_lit(ctx, 6);
2058 bool r2 = arg_get_lit(ctx, 7);
2059 bool r3 = arg_get_lit(ctx, 8);
2060 CLIParserFree(ctx);
2062 if (gotdata && use_gb) {
2063 PrintAndLogEx(FAILED, "Must select one of user supplied data and use graphbuffer");
2064 return PM3_EINVARG;
2067 if (dataasq5 && gotdata == false) {
2068 PrintAndLogEx(FAILED, "Must specify user supplied Q5 data");
2069 return PM3_EINVARG;
2072 if ((r0 + r1 + r2 + r3) > 1) {
2073 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
2074 return PM3_EINVARG;
2077 uint8_t downlink_mode = config.downlink_mode;
2078 if (r0)
2079 downlink_mode = refFixedBit;
2080 else if (r1)
2081 downlink_mode = refLongLeading;
2082 else if (r2)
2083 downlink_mode = refLeading0;
2084 else if (r3)
2085 downlink_mode = ref1of4;
2089 Page 0 Block 0 Configuration data.
2090 Normal mode
2091 Extended mode
2094 if (use_gb == false && gotdata == false) {
2095 // sanity check.
2096 if (SanityOfflineCheck(false) != PM3_SUCCESS) {
2097 return PM3_ENODATA;
2100 if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
2101 return PM3_ENODATA;
2105 if (gotdata == false) {
2106 if (DecodeT55xxBlock() == false) {
2107 return PM3_ESOFT;
2110 // too little space to start with
2111 if (DemodBufferLen < 32 + config.offset) {
2112 return PM3_ESOFT;
2115 //PrintAndLogEx(NORMAL, "Offset+32 ==%d\n DemodLen == %d", config.offset + 32, DemodBufferLen);
2116 block0 = PackBits(config.offset, 32, DemodBuffer);
2119 PrintAndLogEx(NORMAL, "");
2120 if (((!gotdata) && config.Q5) || (gotdata && dataasq5)) {
2121 uint32_t header = (block0 >> (32 - 12)) & 0xFFF;
2122 uint32_t ps = (block0 >> (32 - 13)) & 0x01;
2123 uint32_t fw = (block0 >> (32 - 14)) & 0x01;
2124 uint32_t dbr = (block0 >> (32 - 20)) & 0x3F;
2125 uint32_t aor = (block0 >> (32 - 21)) & 0x01;
2126 uint32_t pwd = (block0 >> (32 - 22)) & 0x01;
2127 uint32_t pskcf = (block0 >> (32 - 24)) & 0x03;
2128 uint32_t inv = (block0 >> (32 - 25)) & 0x01;
2129 uint32_t datamod = (block0 >> (32 - 28)) & 0x07;
2130 uint32_t maxblk = (block0 >> (32 - 31)) & 0x07;
2131 uint32_t st = block0 & 0x01;
2132 PrintAndLogEx(INFO, "--- " _CYAN_("Q5 Configuration & Information") " ------------");
2133 PrintAndLogEx(INFO, " Header : 0x%03X%s", header, (header != 0x600) ? _RED_(" - Warning") : "");
2134 PrintAndLogEx(INFO, " Page select : %d", ps);
2135 PrintAndLogEx(INFO, " Fast Write : %s", (fw) ? _GREEN_("Yes") : "No");
2136 PrintAndLogEx(INFO, " Data bit rate : %s", GetBitRateStr(dbr, 1));
2137 PrintAndLogEx(INFO, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No");
2138 PrintAndLogEx(INFO, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No");
2139 PrintAndLogEx(INFO, " PSK clock frequency : %s", GetPskCfStr(pskcf, 1));
2140 PrintAndLogEx(INFO, " Inverse data : %s", (inv) ? _GREEN_("Yes") : "No");
2141 PrintAndLogEx(INFO, " Modulation : %s", GetQ5ModulationStr(datamod));
2142 PrintAndLogEx(INFO, " Max block : %d", maxblk);
2143 PrintAndLogEx(INFO, " Sequence Terminator : %s", (st) ? _GREEN_("Yes") : "No");
2144 } else {
2145 uint32_t safer = (block0 >> (32 - 4)) & 0x0F;
2146 uint32_t extend = (block0 >> (32 - 15)) & 0x01;
2147 uint32_t resv, dbr;
2148 if (extend) {
2149 resv = (block0 >> (32 - 8)) & 0x0F;
2150 dbr = (block0 >> (32 - 14)) & 0x3F;
2151 } else {
2152 resv = (block0 >> (32 - 11)) & 0x7F;
2153 dbr = (block0 >> (32 - 14)) & 0x07;
2155 uint32_t datamod = (block0 >> (32 - 20)) & 0x1F;
2156 uint32_t pskcf = (block0 >> (32 - 22)) & 0x03;
2157 uint32_t aor = (block0 >> (32 - 23)) & 0x01;
2158 uint32_t otp = (block0 >> (32 - 24)) & 0x01;
2159 uint32_t maxblk = (block0 >> (32 - 27)) & 0x07;
2160 uint32_t pwd = (block0 >> (32 - 28)) & 0x01;
2161 uint32_t sst = (block0 >> (32 - 29)) & 0x01;
2162 uint32_t fw = (block0 >> (32 - 30)) & 0x01;
2163 uint32_t inv = (block0 >> (32 - 31)) & 0x01;
2164 uint32_t por = (block0 >> (32 - 32)) & 0x01;
2166 PrintAndLogEx(INFO, "--- " _CYAN_("T55x7 Configuration & Information") " ---------");
2167 PrintAndLogEx(INFO, " Safer key : %s", GetSaferStr(safer));
2168 PrintAndLogEx(INFO, " reserved : %d", resv);
2169 PrintAndLogEx(INFO, " Data bit rate : %s", GetBitRateStr(dbr, extend));
2170 PrintAndLogEx(INFO, " eXtended mode : %s", (extend) ? _YELLOW_("Yes - Warning") : "No");
2171 PrintAndLogEx(INFO, " Modulation : %s", GetModulationStr(datamod, extend));
2172 PrintAndLogEx(INFO, " PSK clock frequency : %s", GetPskCfStr(pskcf, 0));
2173 PrintAndLogEx(INFO, " AOR - Answer on Request : %s", (aor) ? _GREEN_("Yes") : "No");
2174 PrintAndLogEx(INFO, " OTP - One Time Pad : %s", (otp) ? ((extend) ? _YELLOW_("Yes - Warning") : _RED_("Yes - Warning")) : "No");
2175 PrintAndLogEx(INFO, " Max block : %d", maxblk);
2176 PrintAndLogEx(INFO, " Password mode : %s", (pwd) ? _GREEN_("Yes") : "No");
2177 PrintAndLogEx(INFO, " Sequence %-12s : %s", (extend) ? "Start Marker" : "Terminator", (sst) ? _GREEN_("Yes") : "No");
2178 PrintAndLogEx(INFO, " Fast Write : %s", (fw) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No");
2179 PrintAndLogEx(INFO, " Inverse data : %s", (inv) ? ((extend) ? _GREEN_("Yes") : _RED_("Yes - Warning")) : "No");
2180 PrintAndLogEx(INFO, " POR-Delay : %s", (por) ? _GREEN_("Yes") : "No");
2182 PrintAndLogEx(INFO, "-------------------------------------------------------------");
2183 PrintAndLogEx(INFO, " Raw Data - Page 0, block 0");
2184 if (gotdata)
2185 PrintAndLogEx(INFO, " " _GREEN_("%08X"), block0);
2186 else
2187 PrintAndLogEx(INFO, " " _GREEN_("%08X") " - %s", block0, sprint_bin(DemodBuffer + config.offset, 32));
2189 if (((!gotdata) && (!config.Q5)) || (gotdata && (!dataasq5))) {
2190 PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint") " ------------");
2191 printT5x7KnownBlock0(block0);
2194 PrintAndLogEx(NORMAL, "");
2195 //PrintAndLogEx(INFO, "-------------------------------------------------------------");
2196 return PM3_SUCCESS;
2199 static int CmdT55xxDump(const char *Cmd) {
2201 CLIParserContext *ctx;
2202 CLIParserInit(&ctx, "lf t55xx dump",
2203 "This command dumps a T55xx card Page 0 block 0-7.\n"
2204 "It will create three files (bin/eml/json)",
2205 "lf t55xx dump\n"
2206 "lf t55xx dump -p aabbccdd --override\n"
2207 "lf t55xx dump -f my_lf_dump"
2210 // 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
2211 void *argtable[4 + 5] = {
2212 arg_param_begin,
2213 arg_str0("f", "filename", "<fn>", "filename (default is generated on blk 0)"),
2214 arg_lit0("o", "override", "override, force pwd read despite danger to card"),
2215 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
2217 uint8_t idx = 4;
2218 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, T55XX_DLMODE_SINGLE);
2219 CLIExecWithReturn(ctx, Cmd, argtable, true);
2221 int fnlen = 0;
2222 char filename[FILE_PATH_SIZE] = {0};
2223 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, sizeof(filename), &fnlen);
2225 uint8_t override = arg_get_lit(ctx, 2) ? 1 : 0;
2227 bool usepwd = false;
2228 uint32_t password = 0;
2229 int res = arg_get_u32_hexstr_def_nlen(ctx, 3, 0, &password, 4, true);
2230 if (res == 0 || res == 2) {
2231 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
2232 CLIParserFree(ctx);
2233 return PM3_EINVARG;
2235 if (res == 1) {
2236 usepwd = true;
2239 bool r0 = arg_get_lit(ctx, 4);
2240 bool r1 = arg_get_lit(ctx, 5);
2241 bool r2 = arg_get_lit(ctx, 6);
2242 bool r3 = arg_get_lit(ctx, 7);
2243 CLIParserFree(ctx);
2245 if ((r0 + r1 + r2 + r3) > 1) {
2246 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
2247 return PM3_EINVARG;
2250 uint8_t downlink_mode = config.downlink_mode;
2251 if (r0)
2252 downlink_mode = refFixedBit;
2253 else if (r1)
2254 downlink_mode = refLongLeading;
2255 else if (r2)
2256 downlink_mode = refLeading0;
2257 else if (r3)
2258 downlink_mode = ref1of4;
2260 bool success = true;
2262 // Due to the few different T55xx cards and number of blocks supported
2263 // will save the dump file if ALL page 0 is OK
2264 printT5xxHeader(0);
2265 for (uint8_t i = 0; i < 8; ++i) {
2266 if (T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode) != PM3_SUCCESS)
2267 success = false;
2269 // only show override warning on the first block read
2270 if (override == 1) {
2271 override++;
2274 printT5xxHeader(1);
2275 for (uint8_t i = 0; i < 4; i++)
2276 if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS)
2277 T55x7_SaveBlockData(8 + i, 0x00);
2279 // all ok, save dump to file
2280 if (success) {
2282 // set default filename, if not set by user
2283 if (strlen(filename) == 0) {
2284 strcpy(filename, "lf-t55xx");
2285 for (uint8_t i = 1; i <= 7; i++) {
2286 if ((cardmem[i].blockdata != 0x00) && (cardmem[i].blockdata != 0xFFFFFFFF)) {
2287 snprintf(filename + strlen(filename), sizeof(filename) - strlen(filename), "-%08X", cardmem[i].blockdata);
2288 } else {
2289 break;
2292 strcat(filename, "-dump");
2295 // Swap endian so the files match the txt display
2296 uint32_t data[T55x7_BLOCK_COUNT];
2298 for (int i = 0; i < T55x7_BLOCK_COUNT; i++) {
2299 data[i] = BSWAP_32(cardmem[i].blockdata);
2302 // saveFileEML will add .eml extension to filename
2303 // saveFile (binary) passes in the .bin extension.
2304 saveFileJSON(filename, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL);
2305 saveFileEML(filename, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t));
2306 saveFile(filename, ".bin", data, sizeof(data));
2309 return PM3_SUCCESS;
2312 static int CmdT55xxRestore(const char *Cmd) {
2313 CLIParserContext *ctx;
2314 CLIParserInit(&ctx, "lf t55xx restore",
2315 "Restore T55xx card page 0/1 n blocks from (bin/eml/json) dump file",
2316 "lf t55xx restore -f lf-t55xx-00148040-dump.bin"
2319 void *argtable[] = {
2320 arg_param_begin,
2321 arg_str0("f", "file", "<fn>", "filename of dump file"),
2322 arg_str0("p", "pwd", "<hex>", "password if target card has password set (4 hex bytes)"),
2323 arg_param_end
2325 CLIExecWithReturn(ctx, Cmd, argtable, false);
2327 int fnlen = 0;
2328 char filename[FILE_PATH_SIZE] = {0};
2329 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, sizeof(filename), &fnlen);
2331 bool usepwd = false;
2332 uint32_t password = 0;
2333 int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true);
2334 if (res == 0 || res == 2) {
2335 PrintAndLogEx(ERR, "Password should be 4 hex bytes");
2336 CLIParserFree(ctx);
2337 return PM3_EINVARG;
2339 if (res == 1) {
2340 usepwd = true;
2342 CLIParserFree(ctx);
2344 if (fnlen == 0) {
2345 PrintAndLogEx(ERR, "Must specify a filename");
2346 return PM3_EINVARG;
2349 size_t dlen = 0;
2350 void *dump = NULL;
2351 DumpFileType_t dftype = getfiletype(filename);
2352 switch (dftype) {
2353 case BIN: {
2354 res = loadFile_safe(filename, ".bin", (void **)&dump, &dlen);
2355 break;
2357 case EML: {
2358 res = loadFileEML_safe(filename, (void **)&dump, &dlen);
2359 break;
2361 case JSON: {
2362 dump = calloc(T55x7_BLOCK_COUNT * 4, sizeof(uint8_t));
2363 if (dump == NULL) {
2364 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
2365 return PM3_EMALLOC;
2367 res = loadFileJSON(filename, dump, T55x7_BLOCK_COUNT * 4, &dlen, NULL);
2368 break;
2370 case DICTIONARY: {
2371 PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed");
2372 free(dump);
2373 return PM3_EINVARG;
2377 //sanity checks of file processing
2378 if (res != PM3_SUCCESS) {
2379 free(dump);
2380 return res;
2383 if (dlen != T55x7_BLOCK_COUNT * 4) {
2384 free(dump);
2385 PrintAndLogEx(FAILED, "wrong length of dump file. Expected 48 bytes, got %zu", dlen);
2386 return PM3_EFILE;
2389 // 12 blocks * 4 bytes per block
2390 // this part creates strings to call "lf t55 write" command.
2391 PrintAndLogEx(INFO, "Starting to write...");
2393 uint8_t downlink_mode;
2394 char wcmd[100];
2395 char pwdopt [14] = {0}; // p XXXXXXXX
2397 if (usepwd)
2398 snprintf(pwdopt, sizeof(pwdopt), "-p %08X", password);
2400 uint32_t *data = (uint32_t *) dump;
2401 uint8_t idx;
2402 // Restore endien for writing to card
2403 for (idx = 0; idx < 12; idx++) {
2404 data[idx] = BSWAP_32(data[idx]);
2407 // Have data ready, lets write
2408 // Order
2409 // write blocks 1..7 page 0
2410 // write blocks 1..3 page 1
2411 // update downlink mode (if needed) and write b 0
2412 downlink_mode = 0;
2413 if ((((data[11] >> 28) & 0xf) == 6) || (((data[11] >> 28) & 0xf) == 9))
2414 downlink_mode = (data[11] >> 10) & 3;
2416 // write out blocks 1-7 page 0
2417 for (idx = 1; idx <= 7; idx++) {
2418 snprintf(wcmd, sizeof(wcmd), "-b %d -d %08X %s", idx, data[idx], pwdopt);
2420 if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
2421 PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
2425 // if password was set on the "blank" update as we may have just changed it
2426 if (usepwd) {
2427 snprintf(pwdopt, sizeof(pwdopt), "-p %08X", data[7]);
2430 // write out blocks 1-3 page 1
2431 for (idx = 9; idx <= 11; idx++) {
2432 snprintf(wcmd, sizeof(wcmd), "-b %d --pg1 -d %08X %s", idx - 8, data[idx], pwdopt);
2434 if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
2435 PrintAndLogEx(WARNING, "Warning: error writing blk %d", idx);
2439 // Update downlink mode for the page 0 config write.
2440 config.downlink_mode = downlink_mode;
2442 // Write the page 0 config
2443 snprintf(wcmd, sizeof(wcmd), "-b 0 -d %08X %s", data[0], pwdopt);
2444 if (CmdT55xxWriteBlock(wcmd) != PM3_SUCCESS) {
2445 PrintAndLogEx(WARNING, "Warning: error writing blk 0");
2447 free(dump);
2448 PrintAndLogEx(INFO, "Done!");
2449 return PM3_SUCCESS;
2452 static int CmdT55xxRestore(const char *Cmd) {
2454 uint32_t password = 0;
2455 uint8_t override = 0;
2456 uint8_t downlink_mode = config.downlink_mode;
2457 bool usepwd = false;
2458 bool errors = false;
2459 uint8_t cmdp = 0;
2461 while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
2462 switch (tolower(param_getchar(Cmd, cmdp))) {
2463 case 'h':
2464 return usage_t55xx_restore();
2465 case 'r':
2466 downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
2467 if (downlink_mode > 3)
2468 downlink_mode = 0;
2470 cmdp += 2;
2471 break;
2472 case 'p':
2473 password = param_get32ex(Cmd, cmdp + 1, 0, 16);
2474 usepwd = true;
2475 cmdp += 2;
2476 break;
2477 case 'o':
2478 override = 1;
2479 cmdp++;
2480 break;
2481 default:
2482 PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
2483 errors = true;
2484 break;
2487 if (errors) return usage_t55xx_restore();
2489 PrintAndLogEx(INFO, "Work in progress. To be implemented");
2490 if (usepwd || password || override ) {
2493 // load file name (json/eml/bin)
2495 // Print dump data?
2497 uint32_t res = PM3_SUCCESS;
2499 // page0.
2500 // res = clone_t55xx_tag(blockdata, numblocks);
2502 return res;
2505 bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode) {
2506 // arg0 bitmodes:
2507 // b0 = pwdmode
2508 // b1 = page to read from
2509 // b2 = brute_mem (armside function)
2510 // arg1: which block to read
2511 // arg2: password
2512 struct p {
2513 uint32_t password;
2514 uint8_t blockno;
2515 uint8_t page;
2516 bool pwdmode;
2517 uint8_t downlink_mode;
2518 } PACKED;
2519 struct p payload;
2520 payload.password = password;
2521 payload.blockno = block;
2522 payload.page = page & 0x1;
2523 payload.pwdmode = pwdmode;
2524 payload.downlink_mode = downlink_mode;
2526 clearCommandBuffer();
2527 SendCommandNG(CMD_LF_T55XX_READBL, (uint8_t *)&payload, sizeof(payload));
2528 if (!WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500)) {
2529 PrintAndLogEx(WARNING, "command execution time out");
2530 return false;
2533 getSamples(12000, false);
2534 bool ok = !getSignalProperties()->isnoise;
2536 config.usepwd = pwdmode;
2537 return ok;
2540 char *GetPskCfStr(uint32_t id, bool q5) {
2541 static char buf[40];
2542 char *retStr = buf;
2543 switch (id) {
2544 case 0:
2545 snprintf(retStr, sizeof(buf), "%u - RF/2", id);
2546 break;
2547 case 1:
2548 snprintf(retStr, sizeof(buf), "%u - RF/4", id);
2549 break;
2550 case 2:
2551 snprintf(retStr, sizeof(buf), "%u - RF/8", id);
2552 break;
2553 case 3:
2554 if (q5)
2555 snprintf(retStr, sizeof(buf), "%u - RF/8", id);
2556 else
2557 snprintf(retStr, sizeof(buf), "%u - " _RED_("(Unknown)"), id);
2558 break;
2559 default:
2560 snprintf(retStr, sizeof(buf), "%u - " _RED_("(Unknown)"), id);
2561 break;
2563 return buf;
2566 char *GetBitRateStr(uint32_t id, bool xmode) {
2567 static char buf[25];
2569 char *retStr = buf;
2570 if (xmode) { //xmode bitrate calc is same as em4x05 calc
2571 snprintf(retStr, sizeof(buf), "%u - RF/%u", id, EM4x05_GET_BITRATE(id));
2572 } else {
2573 switch (id) {
2574 case 0:
2575 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/8"), id);
2576 break;
2577 case 1:
2578 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/16"), id);
2579 break;
2580 case 2:
2581 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/32"), id);
2582 break;
2583 case 3:
2584 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/40"), id);
2585 break;
2586 case 4:
2587 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/50"), id);
2588 break;
2589 case 5:
2590 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/64"), id);
2591 break;
2592 case 6:
2593 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/100"), id);
2594 break;
2595 case 7:
2596 snprintf(retStr, sizeof(buf), "%u - "_GREEN_("RF/128"), id);
2597 break;
2598 default:
2599 snprintf(retStr, sizeof(buf), "%u - " _RED_("(Unknown)"), id);
2600 break;
2603 return buf;
2606 char *GetSaferStr(uint32_t id) {
2607 static char buf[40];
2608 char *retStr = buf;
2610 snprintf(retStr, sizeof(buf), "%u", id);
2611 if (id == 6) {
2612 snprintf(retStr, sizeof(buf), "%u - " _YELLOW_("passwd"), id);
2614 if (id == 9) {
2615 snprintf(retStr, sizeof(buf), "%u - " _YELLOW_("testmode"), id);
2618 return buf;
2621 char *GetModulationStr(uint32_t id, bool xmode) {
2622 static char buf[60];
2623 char *retStr = buf;
2625 switch (id) {
2626 case 0:
2627 snprintf(retStr, sizeof(buf), "%u - DIRECT (ASK/NRZ)", id);
2628 break;
2629 case 1:
2630 snprintf(retStr, sizeof(buf), "%u - PSK 1 phase change when input changes", id);
2631 break;
2632 case 2:
2633 snprintf(retStr, sizeof(buf), "%u - PSK 2 phase change on bitclk if input high", id);
2634 break;
2635 case 3:
2636 snprintf(retStr, sizeof(buf), "%u - PSK 3 phase change on rising edge of input", id);
2637 break;
2638 case 4:
2639 snprintf(retStr, sizeof(buf), "%u - FSK 1 RF/8 RF/5", id);
2640 break;
2641 case 5:
2642 snprintf(retStr, sizeof(buf), "%u - FSK 2 RF/8 RF/10", id);
2643 break;
2644 case 6:
2645 snprintf(retStr, sizeof(buf), "%u - %s RF/5 RF/8", id, (xmode) ? "FSK 1a" : _YELLOW_("FSK 1a"));
2646 break;
2647 case 7:
2648 snprintf(retStr, sizeof(buf), "%u - %s RF/10 RF/8", id, (xmode) ? "FSK 2a" : _YELLOW_("FSK 2a"));
2649 break;
2650 case 8:
2651 snprintf(retStr, sizeof(buf), "%u - Manchester", id);
2652 break;
2653 case 16:
2654 snprintf(retStr, sizeof(buf), "%u - Biphase", id);
2655 break;
2656 case 24:
2657 snprintf(retStr, sizeof(buf), "%u - %s", id, (xmode) ? "Biphase a - AKA Conditional Dephase Encoding(CDP)" : _YELLOW_("Reserved"));
2658 break;
2659 default:
2660 snprintf(retStr, sizeof(buf), "0x%02X " _RED_("(Unknown)"), id);
2661 break;
2663 return buf;
2666 char *GetDownlinkModeStr(uint8_t downlink_mode) {
2667 static char buf[30];
2668 char *retStr = buf;
2670 switch (downlink_mode) {
2671 case T55XX_DLMODE_FIXED :
2672 snprintf(retStr, sizeof(buf), "default/fixed bit length");
2673 break;
2674 case T55XX_DLMODE_LLR :
2675 snprintf(retStr, sizeof(buf), "long leading reference");
2676 break;
2677 case T55XX_DLMODE_LEADING_ZERO :
2678 snprintf(retStr, sizeof(buf), "leading zero reference");
2679 break;
2680 case T55XX_DLMODE_1OF4 :
2681 snprintf(retStr, sizeof(buf), "1 of 4 coding reference");
2682 break;
2683 default:
2684 snprintf(retStr, sizeof(buf), _RED_("(Unknown)"));
2685 break;
2687 return buf;
2690 char *GetQ5ModulationStr(uint32_t id) {
2691 static char buf[60];
2692 char *retStr = buf;
2694 switch (id) {
2695 case 0:
2696 snprintf(retStr, sizeof(buf), "%u - Manchester", id);
2697 break;
2698 case 1:
2699 snprintf(retStr, sizeof(buf), "%u - PSK 1 phase change when input changes", id);
2700 break;
2701 case 2:
2702 snprintf(retStr, sizeof(buf), "%u - PSK 2 phase change on bitclk if input high", id);
2703 break;
2704 case 3:
2705 snprintf(retStr, sizeof(buf), "%u - PSK 3 phase change on rising edge of input", id);
2706 break;
2707 case 4:
2708 snprintf(retStr, sizeof(buf), "%u - FSK 1a RF/5 RF/8", id);
2709 break;
2710 case 5:
2711 snprintf(retStr, sizeof(buf), "%u - FSK 2a RF/10 RF/8", id);
2712 break;
2713 case 6:
2714 snprintf(retStr, sizeof(buf), "%u - Biphase", id);
2715 break;
2716 case 7:
2717 snprintf(retStr, sizeof(buf), "%u - NRZ / Direct", id);
2718 break;
2720 return buf;
2723 char *GetModelStrFromCID(uint32_t cid) {
2725 static char buf[10];
2726 char *retStr = buf;
2728 if (cid == 1) snprintf(retStr, sizeof(buf), "ATA5577M1");
2729 if (cid == 2) snprintf(retStr, sizeof(buf), "ATA5577M2");
2730 if (cid == 3) snprintf(retStr, sizeof(buf), "ATA5577M3");
2731 return buf;
2734 char *GetConfigBlock0Source(uint8_t id) {
2736 static char buf[40];
2737 char *retStr = buf;
2739 switch (id) {
2740 case AUTODETECT:
2741 snprintf(retStr, sizeof(buf), _YELLOW_("(auto detect)"));
2742 break;
2743 case USERSET:
2744 snprintf(retStr, sizeof(buf), _YELLOW_("(user set)"));
2745 break;
2746 case TAGREAD:
2747 snprintf(retStr, sizeof(buf), _GREEN_("(tag read)"));
2748 break;
2749 default:
2750 snprintf(retStr, sizeof(buf), _RED_("(n/a)"));
2751 break;
2753 return buf;
2756 char *GetSelectedModulationStr(uint8_t id) {
2758 static char buf[20];
2759 char *retStr = buf;
2761 switch (id) {
2762 case DEMOD_FSK:
2763 snprintf(retStr, sizeof(buf), "FSK");
2764 break;
2765 case DEMOD_FSK1:
2766 snprintf(retStr, sizeof(buf), "FSK1");
2767 break;
2768 case DEMOD_FSK1a:
2769 snprintf(retStr, sizeof(buf), "FSK1a");
2770 break;
2771 case DEMOD_FSK2:
2772 snprintf(retStr, sizeof(buf), "FSK2");
2773 break;
2774 case DEMOD_FSK2a:
2775 snprintf(retStr, sizeof(buf), "FSK2a");
2776 break;
2777 case DEMOD_ASK:
2778 snprintf(retStr, sizeof(buf), "ASK");
2779 break;
2780 case DEMOD_NRZ:
2781 snprintf(retStr, sizeof(buf), "DIRECT/NRZ");
2782 break;
2783 case DEMOD_PSK1:
2784 snprintf(retStr, sizeof(buf), "PSK1");
2785 break;
2786 case DEMOD_PSK2:
2787 snprintf(retStr, sizeof(buf), "PSK2");
2788 break;
2789 case DEMOD_PSK3:
2790 snprintf(retStr, sizeof(buf), "PSK3");
2791 break;
2792 case DEMOD_BI:
2793 snprintf(retStr, sizeof(buf), "BIPHASE");
2794 break;
2795 case DEMOD_BIa:
2796 snprintf(retStr, sizeof(buf), "BIPHASEa - (CDP)");
2797 break;
2798 default:
2799 snprintf(retStr, sizeof(buf), _RED_("(Unknown)"));
2800 break;
2802 return buf;
2806 static void t55x7_create_config_block(int tagtype) {
2808 // T55X7_DEFAULT_CONFIG_BLOCK, T55X7_RAW_CONFIG_BLOCK
2809 // T55X7_EM_UNIQUE_CONFIG_BLOCK, T55X7_FDXB_CONFIG_BLOCK,
2810 // T55X7_FDXB_CONFIG_BLOCK, T55X7_HID_26_CONFIG_BLOCK, T55X7_INDALA_64_CONFIG_BLOCK, T55X7_INDALA_224_CONFIG_BLOCK
2811 // T55X7_GUARDPROXII_CONFIG_BLOCK, T55X7_VIKING_CONFIG_BLOCK, T55X7_NORALYS_CONFIG_BLOCK, T55X7_IOPROX_CONFIG_BLOCK
2812 static char buf[60];
2813 char *retStr = buf;
2815 switch (tagtype) {
2816 case 0:
2817 snprintf(retStr, sizeof(buf), "%08X - T55X7 Default", T55X7_DEFAULT_CONFIG_BLOCK);
2818 break;
2819 case 1:
2820 snprintf(retStr, sizeof(buf), "%08X - T55X7 Raw", T55X7_RAW_CONFIG_BLOCK);
2821 break;
2822 case 2:
2823 snprintf(retStr, sizeof(buf), "%08X - Q5/T5555 Default", T5555_DEFAULT_CONFIG_BLOCK);
2824 break;
2825 default:
2826 break;
2828 PrintAndLogEx(NORMAL, buf);
2832 static int CmdResetRead(const char *Cmd) {
2834 CLIParserContext *ctx;
2835 CLIParserInit(&ctx, "lf t55xx resetread",
2836 "Send Reset Cmd then `lf read` the stream to attempt\n"
2837 "to identify the start of it (needs a demod and/or plot after)",
2838 "lf t55xx resetread"
2841 // 1 (help) + 0(one user specified params) + (5 T55XX_DLMODE_SINGLE)
2842 void *argtable[2 + 5] = {
2843 arg_param_begin,
2844 arg_lit0("1", NULL, "extract using data from graphbuffer"),
2846 uint8_t idx = 2;
2847 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
2848 CLIExecWithReturn(ctx, Cmd, argtable, true);
2850 bool r0 = arg_get_lit(ctx, 1);
2851 bool r1 = arg_get_lit(ctx, 2);
2852 bool r2 = arg_get_lit(ctx, 3);
2853 bool r3 = arg_get_lit(ctx, 4);
2854 CLIParserFree(ctx);
2856 if ((r0 + r1 + r2 + r3) > 1) {
2857 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
2858 return PM3_EINVARG;
2861 uint8_t downlink_mode = config.downlink_mode;
2862 if (r0)
2863 downlink_mode = refFixedBit;
2864 else if (r1)
2865 downlink_mode = refLongLeading;
2866 else if (r2)
2867 downlink_mode = refLeading0;
2868 else if (r3)
2869 downlink_mode = ref1of4;
2871 uint8_t flags = downlink_mode << 3;
2873 PrintAndLogEx(INFO, "Sending reset command...");
2875 PacketResponseNG resp;
2876 clearCommandBuffer();
2877 SendCommandNG(CMD_LF_T55XX_RESET_READ, &flags, sizeof(flags));
2878 if (WaitForResponseTimeout(CMD_LF_T55XX_RESET_READ, &resp, 2500) == false) {
2879 PrintAndLogEx(WARNING, "command execution time out");
2880 return PM3_ETIMEOUT;
2883 if (resp.status == PM3_SUCCESS) {
2885 uint16_t gotsize = pm3_capabilities.bigbuf_size - 1;
2886 uint8_t *got = calloc(gotsize, sizeof(uint8_t));
2887 if (got == NULL) {
2888 PrintAndLogEx(WARNING, "failed to allocate memory");
2889 return PM3_EMALLOC;
2892 PrintAndLogEx(INFO, "Downloading samples...");
2893 if (!GetFromDevice(BIG_BUF, got, gotsize, 0, NULL, 0, NULL, 2500, false)) {
2894 PrintAndLogEx(WARNING, "command execution time out");
2895 free(got);
2896 return PM3_ETIMEOUT;
2898 setGraphBuf(got, gotsize);
2899 free(got);
2902 PrintAndLogEx(INFO, "Done");
2903 return PM3_SUCCESS;
2906 static int CmdT55xxWipe(const char *Cmd) {
2907 CLIParserContext *ctx;
2908 CLIParserInit(&ctx, "lf t55xx wipe",
2909 "This commands wipes a tag, fills blocks 1-7 with zeros and a default configuration block",
2910 "lf t55xx wipe -> wipes a T55x7 tag, config block 0x000880E0\n"
2911 "lf t55xx wipe --q5 -> wipes a Q5/T5555 tag, config block 0x6001F004\n"
2912 "lf t55xx wipe -p 11223344 -> wipes a T55x7 tag, config block 0x000880E0, using pwd"
2915 // 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE)
2916 void *argtable[4 + 5] = {
2917 arg_param_begin,
2918 arg_str0("c", "cfg", "<hex>", "configuration block0 (4 hex bytes)"),
2919 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
2920 arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag using dedicated config block"),
2922 uint8_t idx = 4;
2923 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
2924 CLIExecWithReturn(ctx, Cmd, argtable, true);
2926 bool usepwd = false, gotconf = false;
2927 uint32_t block0 = 0;
2928 int res = arg_get_u32_hexstr_def(ctx, 1, 0, &block0);
2929 if (res == 1) {
2930 gotconf = true;
2932 if (res == 2) {
2933 CLIParserFree(ctx);
2934 PrintAndLogEx(WARNING, "config block needs to be 4 hex bytes");
2935 return PM3_EINVARG;
2938 uint32_t password = 0;
2939 res = arg_get_u32_hexstr_def(ctx, 2, 0x51243648, &password);
2940 if (res) {
2941 usepwd = true;
2944 if (res == 2) {
2945 PrintAndLogEx(WARNING, "Password should be 4 bytes, using default pwd");
2948 bool Q5 = arg_get_lit(ctx, 3);
2949 CLIParserFree(ctx);
2951 PrintAndLogEx(INFO, "Target " _YELLOW_("%s")" tag", (Q5) ? "Q5/T5555" : "T55x7");
2953 // default config blocks.
2954 if (gotconf == false) {
2955 block0 = (Q5) ? 0x6001F004 : 0x000880E0;
2958 if (usepwd)
2959 PrintAndLogEx(INFO, "Using password " _GREEN_("%08X"), password);
2961 char msg[80] = {0};
2962 if (gotconf)
2963 snprintf(msg, sizeof(msg), "User provided configuration block " _GREEN_("%08X"), block0);
2964 else
2965 snprintf(msg, sizeof(msg), "Default configuration block " _GREEN_("%08X"), block0);
2967 PrintAndLogEx(INFO, "%s\n", msg);
2969 PrintAndLogEx(INFO, "Begin wiping...");
2971 // Creating cmd string for write block :)
2972 char wcmd[36] = {0};
2973 char *pwcmd = wcmd;
2975 snprintf(pwcmd, sizeof(wcmd), "-b 0 ");
2977 if (usepwd) {
2978 snprintf(pwcmd + strlen(wcmd), sizeof(wcmd) - strlen(wcmd), "-p %08x ", password);
2980 snprintf(pwcmd + strlen(wcmd), sizeof(wcmd) - strlen(wcmd), "-d %08X", block0);
2982 if (CmdT55xxWriteBlock(pwcmd) != PM3_SUCCESS)
2983 PrintAndLogEx(WARNING, "Warning: error writing blk 0");
2985 for (uint8_t blk = 1; blk < 8; blk++) {
2987 snprintf(pwcmd, sizeof(wcmd), "-b %d -d 00000000", blk);
2989 if (CmdT55xxWriteBlock(pwcmd) != PM3_SUCCESS)
2990 PrintAndLogEx(WARNING, "Warning: error writing blk %d", blk);
2992 memset(wcmd, 0x00, sizeof(wcmd));
2995 // Check and rest t55xx downlink mode.
2996 if (config.downlink_mode != T55XX_DLMODE_FIXED) { // Detect found a different mode so card must support
2997 snprintf(pwcmd, sizeof(wcmd), "-b 3 --pg1 -d 00000000");
2998 if (CmdT55xxWriteBlock(pwcmd) != PM3_SUCCESS) {
2999 PrintAndLogEx(WARNING, "Warning: failed writing block 3 page 1 (config)");
3001 memset(wcmd, 0x00, sizeof(wcmd));
3003 return PM3_SUCCESS;
3006 static bool IsCancelled(void) {
3007 if (kbd_enter_pressed()) {
3008 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
3009 return true;
3011 return false;
3014 // load a default pwd file.
3015 static int CmdT55xxChkPwds(const char *Cmd) {
3016 CLIParserContext *ctx;
3017 CLIParserInit(&ctx, "lf t55xx chk",
3018 "This command uses a dictionary attack.\n"
3019 "For some cloners, try '--em' for known pwdgen algo.\n"
3020 "Try to reading Page 0 block 7 before.\n"
3021 _RED_("WARNING:") _CYAN_(" this may brick non-password protected chips!"),
3022 "lf t55xx chk -m -> use dictionary from flash memory (RDV4)\n"
3023 "lf t55xx chk -f my_dictionary_pwds -> loads a default keys dictionary file\n"
3024 "lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on EM4100 ID"
3028 Calculate size of argtable accordingly:
3029 1 (help) + 3 (three user specified params) + ( 5 or 6 T55XX_DLMODE)
3030 start index to call arg_add_t55xx_downloadlink() is 4 (1 + 3) given the above sample
3033 // 1 (help) + 3 (three user specified params) + (6 T55XX_DLMODE_ALL)
3034 void *argtable[4 + 6] = {
3035 arg_param_begin,
3036 arg_lit0("m", "fm", "use dictionary from flash memory (RDV4)"),
3037 arg_str0("f", "file", "<fn>", "file name"),
3038 arg_str0(NULL, "em", "<hex>", "EM4100 ID (5 hex bytes)"),
3040 uint8_t idx = 4;
3041 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
3042 CLIExecWithReturn(ctx, Cmd, argtable, true);
3044 bool from_flash = arg_get_lit(ctx, 1);
3046 int fnlen = 0;
3047 char filename[FILE_PATH_SIZE] = {0};
3048 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, sizeof(filename), &fnlen);
3050 // White cloner password based on EM4100 ID
3051 bool use_calc_password = false;
3052 uint32_t card_password = 0x00;
3053 uint64_t cardid = 0;
3054 int res = arg_get_u64_hexstr_def_nlen(ctx, 3, 0x00, &cardid, 5, true);
3055 if (res == 1) {
3056 use_calc_password = true;
3057 uint32_t calc = cardid & 0xFFFFFFFF;
3058 card_password = lf_t55xx_white_pwdgen(calc);
3060 if (res == 2) {
3061 CLIParserFree(ctx);
3062 PrintAndLogEx(WARNING, "EM4100 ID must be 5 hex bytes");
3063 return PM3_EINVARG;
3065 if (res == 0) {
3066 CLIParserFree(ctx);
3067 return PM3_EINVARG;
3070 bool r0 = arg_get_lit(ctx, 4);
3071 bool r1 = arg_get_lit(ctx, 5);
3072 bool r2 = arg_get_lit(ctx, 6);
3073 bool r3 = arg_get_lit(ctx, 7);
3074 bool ra = arg_get_lit(ctx, 8);
3075 CLIParserFree(ctx);
3077 if ((r0 + r1 + r2 + r3 + ra) > 1) {
3078 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3079 return PM3_EINVARG;
3082 uint8_t downlink_mode = refFixedBit; // Password checks should always start with default/fixed bit unluess requested by user for specific mode
3083 // if (r0 || ra) // ra should start downlink mode ad fixed bit to loop through all modes correctly
3084 // downlink_mode = refFixedBit;
3085 // else
3086 if (r1)
3087 downlink_mode = refLongLeading;
3088 else if (r2)
3089 downlink_mode = refLeading0;
3090 else if (r3)
3091 downlink_mode = ref1of4;
3093 bool use_pwd_file = true; // Assume we are going to use a file, unless turned off later.
3095 if (strlen(filename) == 0) {
3096 snprintf(filename, sizeof(filename), "t55xx_default_pwds");
3099 PrintAndLogEx(INFO, "press " _GREEN_("<Enter>") " to exit");
3100 PrintAndLogEx(NORMAL, "");
3102 // block 7, page1 = false, usepwd = false, override = false, pwd = 00000000
3103 if ( T55xxReadBlock(7, false, false, false, 0x00000000) == PM3_SUCCESS) {
3105 // now try to validate it..
3106 PrintAndLogEx(WARNING, "\n Block 7 was readable");
3107 return PM3_SUCCESS;
3111 bool found = false;
3113 uint64_t t1 = msclock();
3114 uint8_t flags = downlink_mode << 3;
3116 if (from_flash) {
3117 use_pwd_file = false; // turn of local password file since we are checking from flash.
3118 clearCommandBuffer();
3119 SendCommandNG(CMD_LF_T55XX_CHK_PWDS, &flags, sizeof(flags));
3120 PacketResponseNG resp;
3122 uint8_t timeout = 0;
3123 while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) {
3124 timeout++;
3125 PrintAndLogEx(NORMAL, "." NOLF);
3126 if (timeout > 180) {
3127 PrintAndLogEx(WARNING, "\nno response from Proxmark3. Aborting...");
3128 return PM3_ENODATA;
3131 PrintAndLogEx(NORMAL, "");
3132 struct p {
3133 bool found;
3134 uint32_t candidate;
3135 } PACKED;
3136 struct p *packet = (struct p *)resp.data.asBytes;
3138 if (packet->found) {
3139 PrintAndLogEx(SUCCESS, "\nfound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
3141 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) {
3142 found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
3143 if (found) {
3144 PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
3146 } else {
3147 PrintAndLogEx(WARNING, "check pwd failed");
3149 } else {
3150 PrintAndLogEx(WARNING, "check pwd failed");
3152 } else {
3153 PrintAndLogEx(WARNING, "check pwd failed");
3155 goto out;
3158 // to try each downlink mode for each password
3159 int dl_mode;
3161 // try calculated password
3162 if (use_calc_password) {
3164 PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", card_password);
3165 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
3167 if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, card_password, dl_mode)) {
3168 continue;
3171 found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, card_password);
3172 if (found) {
3173 PrintAndLogEx(SUCCESS, "found valid password : [ " _GREEN_("%08"PRIX32) " ]", card_password);
3174 break;
3177 if (ra == false)
3178 break;
3182 if ((found == false) && use_pwd_file) {
3183 uint32_t keycount = 0;
3184 uint8_t *keyblock = NULL;
3186 res = loadFileDICTIONARY_safe(filename, (void **) &keyblock, 4, &keycount);
3187 if (res != PM3_SUCCESS || keycount == 0 || keyblock == NULL) {
3188 PrintAndLogEx(WARNING, "no keys found in file");
3189 if (keyblock != NULL)
3190 free(keyblock);
3192 return PM3_ESOFT;
3195 PrintAndLogEx(INFO, "press " _GREEN_("<Enter>") " to exit");
3197 for (uint32_t c = 0; c < keycount && found == false; ++c) {
3199 if (!session.pm3_present) {
3200 PrintAndLogEx(WARNING, "device offline\n");
3201 free(keyblock);
3202 return PM3_ENODATA;
3205 if (IsCancelled()) {
3206 free(keyblock);
3207 return PM3_EOPABORTED;
3210 uint32_t curr_password = bytes_to_num(keyblock + 4 * c, 4);
3212 PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
3213 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
3214 // If aquire fails, then we still need to check if we are only trying a single downlink mode.
3215 // If we continue on fail, it will skip that test and try the next downlink mode; thus slowing down the check
3216 // when on a single downlink mode is wanted.
3217 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
3218 found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
3219 if (found) {
3220 PrintAndLogEx(SUCCESS, "found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
3221 break;
3224 if (ra == false) // Exit loop if not trying all downlink modes
3225 break;
3229 free(keyblock);
3232 if (found == false)
3233 PrintAndLogEx(WARNING, "failed to find password");
3235 out:
3236 t1 = msclock() - t1;
3237 PrintAndLogEx(SUCCESS, "\ntime in check pwd " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
3238 return PM3_SUCCESS;
3241 // Bruteforce - incremental password range search
3242 static int CmdT55xxBruteForce(const char *Cmd) {
3243 CLIParserContext *ctx;
3244 CLIParserInit(&ctx, "lf t55xx bruteforce",
3245 "This command uses bruteforce to scan a number range.\n"
3246 "Try reading Page 0, block 7 before.\n\n"
3247 _RED_("WARNING") _CYAN_(" this may brick non-password protected chips!"),
3248 "lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99\n"
3251 // 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL)
3252 void *argtable[3 + 6] = {
3253 arg_param_begin,
3254 arg_str1("s", "start", "<hex>", "search start password (4 hex bytes)"),
3255 arg_str1("e", "end", "<hex>", "search end password (4 hex bytes)"),
3257 uint8_t idx = 3;
3258 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
3259 CLIExecWithReturn(ctx, Cmd, argtable, true);
3261 uint32_t start_password = 0;
3262 int res = arg_get_u32_hexstr_def(ctx, 1, 0, &start_password);
3263 if (res == 2) {
3264 CLIParserFree(ctx);
3265 PrintAndLogEx(FAILED, "start password should be 4 bytes");
3266 return PM3_EINVARG;
3269 uint32_t end_password = 0xFFFFFFFF;
3270 res = arg_get_u32_hexstr_def(ctx, 2, 0xFFFFFFFF, &end_password);
3271 if (res == 2) {
3272 CLIParserFree(ctx);
3273 PrintAndLogEx(FAILED, "end password should be 4 bytes");
3274 return PM3_EINVARG;
3277 bool r0 = arg_get_lit(ctx, 3);
3278 bool r1 = arg_get_lit(ctx, 4);
3279 bool r2 = arg_get_lit(ctx, 5);
3280 bool r3 = arg_get_lit(ctx, 6);
3281 bool ra = arg_get_lit(ctx, 7);
3282 CLIParserFree(ctx);
3284 if ((r0 + r1 + r2 + r3 + ra) > 1) {
3285 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3286 return PM3_EINVARG;
3289 uint8_t downlink_mode = refFixedBit; // if no downlink mode suppliled use fixed bit/default as the is the most common
3290 // Since we dont know the password the config.downlink mode is of little value.
3291 // if (r0 || ra) // if try all (ra) then start at fixed bit for correct try all
3292 // downlink_mode = refFixedBit;
3293 // else
3294 if (r1)
3295 downlink_mode = refLongLeading;
3296 else if (r2)
3297 downlink_mode = refLeading0;
3298 else if (r3)
3299 downlink_mode = ref1of4;
3301 uint32_t curr = 0;
3302 uint8_t found = 0; // > 0 if found xx1 xx downlink needed, 1 found
3304 if (start_password >= end_password) {
3305 PrintAndLogEx(FAILED, "Error, start larger then end password");
3306 return PM3_EINVARG;
3309 PrintAndLogEx(INFO, "press " _GREEN_("<Enter>") " to exit");
3310 PrintAndLogEx(INFO, "Search password range [%08X -> %08X]", start_password, end_password);
3312 uint64_t t1 = msclock();
3313 curr = start_password;
3315 while (found == 0) {
3317 PrintAndLogEx(NORMAL, "." NOLF);
3319 if (IsCancelled()) {
3320 return PM3_EOPABORTED;
3323 found = t55xx_try_one_password(curr, downlink_mode, ra);
3325 if (curr == end_password)
3326 break;
3328 curr++;
3331 PrintAndLogEx(NORMAL, "");
3333 if (found) {
3334 PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", curr - 1);
3335 T55xx_Print_DownlinkMode((found >> 1) & 3);
3336 } else
3337 PrintAndLogEx(WARNING, "Bruteforce failed, last tried: [ " _YELLOW_("%08X") " ]", curr);
3339 t1 = msclock() - t1;
3340 PrintAndLogEx(SUCCESS, "\ntime in bruteforce " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
3341 return PM3_SUCCESS;
3344 uint8_t t55xx_try_one_password(uint32_t password, uint8_t downlink_mode, bool try_all_dl_modes) {
3346 PrintAndLogEx(INFO, "Trying password %08X", password);
3348 // ensure 0-3
3349 downlink_mode = (downlink_mode & 3);
3351 // check if dl mode 4 and loop if needed
3352 for (uint8_t dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
3354 if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) {
3355 // if (getSignalProperties()->isnoise == false) {
3356 // } else {
3357 if (t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
3358 return 1 + (dl_mode << 1);
3360 // }
3362 if (try_all_dl_modes == false) {
3363 break;
3366 return 0;
3369 static int CmdT55xxRecoverPW(const char *Cmd) {
3370 CLIParserContext *ctx;
3371 CLIParserInit(&ctx, "lf t55xx recoverpw",
3372 "This command uses a few tricks to try to recover mangled password.\n"
3373 "Try reading Page 0, block 7 before.\n\n"
3374 _RED_("WARNING") _CYAN_(" this may brick non-password protected chips!"),
3375 "lf t55xx recoverpw\n"
3376 "lf t55xx recoverpw -p 11223344\n"
3377 "lf t55xx recoverpw -p 11223344 --r3\n"
3380 // 1 (help) + 1 (one user specified params) + (6 T55XX_DLMODE_ALL)
3381 void *argtable[2 + 6] = {
3382 arg_param_begin,
3383 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
3385 uint8_t idx = 2;
3386 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
3387 CLIExecWithReturn(ctx, Cmd, argtable, true);
3389 uint32_t orig_password = 0;
3390 int res = arg_get_u32_hexstr_def(ctx, 1, 0x51243648, &orig_password);
3391 if (res == 2) {
3392 PrintAndLogEx(INFO, "Password should be 4 bytes, using default pwd instead");
3395 bool r0 = arg_get_lit(ctx, 2);
3396 bool r1 = arg_get_lit(ctx, 3);
3397 bool r2 = arg_get_lit(ctx, 4);
3398 bool r3 = arg_get_lit(ctx, 5);
3399 bool ra = arg_get_lit(ctx, 6);
3400 CLIParserFree(ctx);
3402 if ((r0 + r1 + r2 + r3 + ra) > 1) {
3403 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3404 return PM3_EINVARG;
3407 uint8_t downlink_mode = config.downlink_mode;
3408 if (r0)
3409 downlink_mode = refFixedBit;
3410 else if (r1)
3411 downlink_mode = refLongLeading;
3412 else if (r2)
3413 downlink_mode = refLeading0;
3414 else if (r3)
3415 downlink_mode = ref1of4;
3417 PrintAndLogEx(INFO, "press " _GREEN_("<Enter>") " to exit");
3419 int bit = 0;
3420 uint32_t curr_password = 0x0;
3421 uint32_t prev_password = 0xffffffff;
3422 uint32_t mask = 0x0;
3423 uint8_t found = 0;
3425 // first try fliping each bit in the expected password
3426 while (bit < 32) {
3427 curr_password = orig_password ^ (1u << bit);
3428 found = t55xx_try_one_password(curr_password, downlink_mode, ra);
3429 if (found > 0) // xx1 for found xx = dl mode used
3430 goto out;
3432 bit++;
3434 if (IsCancelled())
3435 return PM3_EOPABORTED;
3438 // now try to use partial original password, since block 7 should have been completely
3439 // erased during the write sequence and it is possible that only partial password has been
3440 // written
3441 // not sure from which end the bit bits are written, so try from both ends
3442 // from low bit to high bit
3443 bit = 0;
3444 while (bit < 32) {
3445 mask += (1u << bit);
3446 curr_password = orig_password & mask;
3447 // if updated mask didn't change the password, don't try it again
3448 if (prev_password == curr_password) {
3449 bit++;
3450 continue;
3453 found = t55xx_try_one_password(curr_password, downlink_mode, ra);
3454 if (found > 0)
3455 goto out;
3457 bit++;
3458 prev_password = curr_password;
3460 if (IsCancelled())
3461 return PM3_EOPABORTED;
3464 // from high bit to low
3465 bit = 0;
3466 mask = 0xffffffff;
3467 while (bit < 32) {
3468 mask -= (1u << bit);
3469 curr_password = orig_password & mask;
3470 // if updated mask didn't change the password, don't try it again
3471 if (prev_password == curr_password) {
3472 bit++;
3473 continue;
3475 found = t55xx_try_one_password(curr_password, downlink_mode, ra);
3476 if (found > 0)
3477 goto out;
3479 bit++;
3480 prev_password = curr_password;
3482 if (IsCancelled())
3483 return PM3_EOPABORTED;
3486 out:
3487 PrintAndLogEx(NORMAL, "");
3489 if (found > 0) {
3490 PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", curr_password);
3491 T55xx_Print_DownlinkMode((found >> 1) & 3);
3492 } else {
3493 PrintAndLogEx(FAILED, "Recover password failed");
3495 return PM3_SUCCESS;
3498 // note length of data returned is different for different chips.
3499 // some return all page 1 (64 bits) and others return just that block (32 bits)
3500 // unfortunately the 64 bits makes this more likely to get a false positive...
3501 bool tryDetectP1(bool getData) {
3502 uint8_t preamble[] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1};
3503 size_t startIdx = 0;
3504 uint8_t fc1 = 0, fc2 = 0, ans = 0;
3505 int clk = 0, firstClockEdge = 0;
3506 bool st = true;
3508 if (getData) {
3509 if (!AcquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, false, 0, 0))
3510 return false;
3513 // try fsk clock detect. if successful it cannot be any other type of modulation... (in theory...)
3514 ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
3515 if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) {
3516 if ((FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS) &&
3517 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3518 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3519 return true;
3521 if ((FSKrawDemod(0, 1, 0, 0, false) == PM3_SUCCESS) &&
3522 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3523 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3524 return true;
3526 return false;
3529 // try ask clock detect. it could be another type even if successful.
3530 clk = GetAskClock("", false);
3531 if (clk > 0) {
3532 if ((ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) &&
3533 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3534 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3535 return true;
3538 st = true;
3539 if ((ASKDemod_ext(0, 1, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) &&
3540 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3541 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3542 return true;
3545 if ((ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS) &&
3546 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3547 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3548 return true;
3551 if ((ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS) &&
3552 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3553 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3554 return true;
3558 // try NRZ clock detect. it could be another type even if successful.
3559 clk = GetNrzClock("", false); //has the most false positives :(
3560 if (clk > 0) {
3561 if ((NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS) &&
3562 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3563 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3564 return true;
3566 if ((NRZrawDemod(0, 1, 1, false) == PM3_SUCCESS) &&
3567 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3568 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3569 return true;
3573 // Fewer card uses PSK
3574 // try psk clock detect. if successful it cannot be any other type of modulation... (in theory...)
3575 clk = GetPskClock("", false);
3576 if (clk > 0) {
3577 // allow undo
3578 // save_restoreGB(GRAPH_SAVE);
3579 // skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise)
3580 //CmdLtrim("-i 160");
3581 if ((PSKDemod(0, 0, 6, false) == PM3_SUCCESS) &&
3582 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3583 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3584 //save_restoreGB(GRAPH_RESTORE);
3585 return true;
3587 if ((PSKDemod(0, 1, 6, false) == PM3_SUCCESS) &&
3588 preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3589 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3590 //save_restoreGB(GRAPH_RESTORE);
3591 return true;
3593 // PSK2 - needs a call to psk1TOpsk2.
3594 if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) {
3595 psk1TOpsk2(DemodBuffer, DemodBufferLen);
3596 if (preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &DemodBufferLen, &startIdx, false) &&
3597 (DemodBufferLen == 32 || DemodBufferLen == 64)) {
3598 //save_restoreGB(GRAPH_RESTORE);
3599 return true;
3601 } // inverse waves does not affect PSK2 demod
3602 //undo trim samples
3603 //save_restoreGB(GRAPH_RESTORE);
3604 // no other modulation clocks = 2 or 4 so quit searching
3605 if (fc1 != 8) return false;
3608 return false;
3610 // does this need to be a callable command?
3611 static int CmdT55xxDetectPage1(const char *Cmd) {
3612 CLIParserContext *ctx;
3613 CLIParserInit(&ctx, "lf t55xx p1detect",
3614 "Detect Page 1 of a T55xx chip",
3615 "lf t55xx p1detect\n"
3616 "lf t55xx p1detect -1\n"
3617 "lf t55xx p1detect -p 11223344 --r3\n"
3620 // 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
3621 void *argtable[3 + 5] = {
3622 arg_param_begin,
3623 arg_lit0("1", NULL, "extract using data from graphbuffer"),
3624 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
3626 uint8_t idx = 3;
3627 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
3628 CLIExecWithReturn(ctx, Cmd, argtable, true);
3630 bool use_graphbuf = arg_get_lit(ctx, 1);
3632 bool usepwd = false;
3633 uint32_t password = 0;
3634 int res = arg_get_u32_hexstr_def(ctx, 2, 0, &password);
3635 if (res == 2) {
3636 PrintAndLogEx(INFO, "Password should be 4 hex bytes");
3637 CLIParserFree(ctx);
3638 return PM3_EINVARG;
3639 } else if (res == 1) {
3640 usepwd = true;
3643 bool r0 = arg_get_lit(ctx, 3);
3644 bool r1 = arg_get_lit(ctx, 4);
3645 bool r2 = arg_get_lit(ctx, 5);
3646 bool r3 = arg_get_lit(ctx, 6);
3647 CLIParserFree(ctx);
3649 if ((r0 + r1 + r2 + r3) > 1) {
3650 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3651 return PM3_EINVARG;
3654 uint8_t downlink_mode = config.downlink_mode;
3655 if (r0)
3656 downlink_mode = refFixedBit;
3657 else if (r1)
3658 downlink_mode = refLongLeading;
3659 else if (r2)
3660 downlink_mode = refLeading0;
3661 else if (r3)
3662 downlink_mode = ref1of4;
3664 bool try_all_dl_modes = true;
3666 //ICEMAN STRANGE
3667 if (downlink_mode == 4)
3668 try_all_dl_modes = true;
3669 if (downlink_mode < 4)
3670 try_all_dl_modes = false;
3672 if (downlink_mode > 3)
3673 downlink_mode = 0;
3675 bool found = false;
3676 uint8_t found_mode = 0;
3678 if (use_graphbuf == false) {
3679 for (uint8_t dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
3681 if (AcquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password, dl_mode) == false)
3682 continue;
3684 if (tryDetectP1(false)) {
3685 found = true;
3686 found_mode = dl_mode;
3687 break;
3688 } else {
3689 found = false;
3692 if (try_all_dl_modes == false) {
3693 break;
3696 } else {
3697 found = tryDetectP1(false);
3700 if (found) {
3701 PrintAndLogEx(SUCCESS, "T55xx chip found!");
3702 T55xx_Print_DownlinkMode(found_mode);
3703 } else
3704 PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
3706 return PM3_SUCCESS;
3709 static int CmdT55xxSetDeviceConfig(const char *Cmd) {
3710 CLIParserContext *ctx;
3711 CLIParserInit(&ctx, "lf t55xx deviceconfig",
3712 "Sets t55x7 timings for direct commands.\n"
3713 "The timings are set here in Field Clocks (FC) which is converted to (US) on device.",
3714 "lf t55xx deviceconfig -a 29 -b 17 -c 15 -d 47 -e 15 -> default T55XX\n"
3715 "lf t55xx deviceconfig -a 55 -b 14 -c 21 -d 30 -> default EM4305"
3718 // 1 (help) + 9 (nine user specified params) + (5 T55XX_DLMODE_SINGLE)
3719 void *argtable[10 + 5] = {
3720 arg_param_begin,
3721 arg_int0("a", NULL, "<8..255>", "Set start gap"),
3722 arg_int0("b", NULL, "<8..255>", "Set write gap"),
3723 arg_int0("c", NULL, "<8..255>", "Set write ZERO gap"),
3724 arg_int0("d", NULL, "<8..255>", "Set write ONE gap"),
3725 arg_int0("e", NULL, "<8..255>", "Set read gap"),
3726 arg_int0("f", NULL, "<8..255>", "Set write TWO gap (1 of 4 only)"),
3727 arg_int0("g", NULL, "<8..255>", "Set write THREE gap (1 of 4 only)"),
3728 arg_lit0("p", "persist", "persist to flash memory (RDV4)"),
3729 arg_lit0("z", NULL, "Set default t55x7 timings (use `-p` to save if required)"),
3731 uint8_t idx = 10;
3732 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
3733 CLIExecWithReturn(ctx, Cmd, argtable, false);
3735 uint8_t startgap = arg_get_int(ctx, 1);
3736 uint8_t writegap = arg_get_int(ctx, 2);
3737 uint8_t write0 = arg_get_int(ctx, 3);
3738 uint8_t write1 = arg_get_int(ctx, 4);
3739 uint8_t readgap = arg_get_int(ctx, 5);
3740 uint8_t write2 = arg_get_int(ctx, 6);
3741 uint8_t write3 = arg_get_int(ctx, 7);
3742 bool shall_persist = arg_get_lit(ctx, 8);
3743 bool set_defaults = arg_get_lit(ctx, 9);
3744 bool r0 = arg_get_lit(ctx, 10);
3745 bool r1 = arg_get_lit(ctx, 11);
3746 bool r2 = arg_get_lit(ctx, 12);
3747 bool r3 = arg_get_lit(ctx, 13);
3748 CLIParserFree(ctx);
3750 if ((r0 + r1 + r2 + r3) > 1) {
3751 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3752 return PM3_EINVARG;
3755 uint8_t downlink_mode = 0;
3756 if (r0)
3757 downlink_mode = refFixedBit;
3758 else if (r1)
3759 downlink_mode = refLongLeading;
3760 else if (r2)
3761 downlink_mode = refLeading0;
3762 else if (r3)
3763 downlink_mode = ref1of4;
3765 t55xx_configurations_t configurations = {{{0}, {0}, {0}, {0}}};
3767 if (set_defaults) {
3768 // fixed bit length
3769 configurations.m[T55XX_DLMODE_FIXED].start_gap = 29 * 8;
3770 configurations.m[T55XX_DLMODE_FIXED].write_gap = 17 * 8;
3771 configurations.m[T55XX_DLMODE_FIXED].write_0 = 15 * 8;
3772 configurations.m[T55XX_DLMODE_FIXED].write_1 = 47 * 8;
3773 configurations.m[T55XX_DLMODE_FIXED].read_gap = 15 * 8;
3774 configurations.m[T55XX_DLMODE_FIXED].write_2 = 0;
3775 configurations.m[T55XX_DLMODE_FIXED].write_3 = 0;
3777 // long leading reference
3778 configurations.m[T55XX_DLMODE_LLR].start_gap = 29 * 8;
3779 configurations.m[T55XX_DLMODE_LLR].write_gap = 17 * 8;
3780 configurations.m[T55XX_DLMODE_LLR].write_0 = 15 * 8;
3781 configurations.m[T55XX_DLMODE_LLR].write_1 = 47 * 8;
3782 configurations.m[T55XX_DLMODE_LLR].read_gap = 15 * 8;
3783 configurations.m[T55XX_DLMODE_LLR].write_2 = 0;
3784 configurations.m[T55XX_DLMODE_LLR].write_3 = 0;
3786 // leading zero
3787 configurations.m[T55XX_DLMODE_LEADING_ZERO].start_gap = 29 * 8;
3788 configurations.m[T55XX_DLMODE_LEADING_ZERO].write_gap = 17 * 8;
3789 configurations.m[T55XX_DLMODE_LEADING_ZERO].write_0 = 15 * 8;
3790 configurations.m[T55XX_DLMODE_LEADING_ZERO].write_1 = 40 * 8;
3791 configurations.m[T55XX_DLMODE_LEADING_ZERO].read_gap = 15 * 8;
3792 configurations.m[T55XX_DLMODE_LEADING_ZERO].write_2 = 0;
3793 configurations.m[T55XX_DLMODE_LEADING_ZERO].write_3 = 0;
3795 // 1 of 4 coding reference
3796 configurations.m[T55XX_DLMODE_1OF4].start_gap = 29 * 8;
3797 configurations.m[T55XX_DLMODE_1OF4].write_gap = 17 * 8;
3798 configurations.m[T55XX_DLMODE_1OF4].write_0 = 15 * 8;
3799 configurations.m[T55XX_DLMODE_1OF4].write_1 = 31 * 8;
3800 configurations.m[T55XX_DLMODE_1OF4].read_gap = 15 * 8;
3801 configurations.m[T55XX_DLMODE_1OF4].write_2 = 47 * 8;
3802 configurations.m[T55XX_DLMODE_1OF4].write_3 = 63 * 8;
3804 } else {
3805 configurations.m[downlink_mode].start_gap = startgap * 8;
3806 configurations.m[downlink_mode].write_gap = writegap * 8;
3807 configurations.m[downlink_mode].write_0 = write0 * 8;
3808 configurations.m[downlink_mode].write_1 = write1 * 8;
3809 configurations.m[downlink_mode].read_gap = readgap * 8;
3810 configurations.m[downlink_mode].write_2 = write2 * 8;
3811 configurations.m[downlink_mode].write_3 = write3 * 8;
3814 clearCommandBuffer();
3815 SendCommandMIX(CMD_LF_T55XX_SET_CONFIG, shall_persist, 0, 0, &configurations, sizeof(t55xx_configurations_t));
3816 return PM3_SUCCESS;
3819 static int CmdT55xxProtect(const char *Cmd) {
3821 CLIParserContext *ctx;
3822 CLIParserInit(&ctx, "lf t55xx protect",
3823 "This command sets the pwd bit on T5577.\n"
3824 _RED_("WARNING") _CYAN_(" this locks the tag!"),
3825 "lf t55xx protect -n 01020304 -> sets new pwd 01020304\n"
3826 "lf t55xx protect -p 11223344 -n 00000000 -> use pwd 11223344, sets new pwd 00000000"
3829 // 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE)
3830 void *argtable[4 + 5] = {
3831 arg_param_begin,
3832 arg_lit0("o", "override", "override safety check"),
3833 arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
3834 arg_str1("n", "new", "<hex>", "new password (4 hex bytes)"),
3836 uint8_t idx = 4;
3837 arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
3838 CLIExecWithReturn(ctx, Cmd, argtable, true);
3840 uint8_t override = 0;
3841 if (arg_get_lit(ctx, 1))
3842 override = 2;
3844 uint32_t password = 0;
3845 bool usepwd = false;
3846 int res = arg_get_u32_hexstr_def(ctx, 2, 0, &password);
3847 if (res == 2) {
3848 CLIParserFree(ctx);
3849 PrintAndLogEx(FAILED, "Error parsing password bytes");
3850 return PM3_EINVARG;
3851 } else if (res == 1) {
3852 usepwd = true;
3853 override = 1;
3856 uint32_t new_password = 0;
3857 res = arg_get_u32_hexstr_def(ctx, 3, 0, &new_password);
3858 if (res == 2) {
3859 CLIParserFree(ctx);
3860 PrintAndLogEx(FAILED, "Error parsing new password bytes");
3861 return PM3_EINVARG;
3862 } else if (res == 0) {
3863 PrintAndLogEx(FAILED, "Must specify new password param");
3864 CLIParserFree(ctx);
3865 return PM3_EINVARG;
3868 bool r0 = arg_get_lit(ctx, 4);
3869 bool r1 = arg_get_lit(ctx, 5);
3870 bool r2 = arg_get_lit(ctx, 6);
3871 bool r3 = arg_get_lit(ctx, 7);
3872 CLIParserFree(ctx);
3874 if ((r0 + r1 + r2 + r3) > 1) {
3875 PrintAndLogEx(FAILED, "Error multiple downlink encoding");
3876 return PM3_EINVARG;
3879 uint8_t downlink_mode = config.downlink_mode;
3880 if (r0)
3881 downlink_mode = refFixedBit;
3882 else if (r1)
3883 downlink_mode = refLongLeading;
3884 else if (r2)
3885 downlink_mode = refLeading0;
3886 else if (r3)
3887 downlink_mode = ref1of4;
3889 // sanity check.
3890 if (SanityOfflineCheck(false) != PM3_SUCCESS)
3891 return PM3_ESOFT;
3893 // lock
3894 if (t55xxProtect(true, usepwd, override, password, downlink_mode, new_password) == false) {
3895 PrintAndLogEx(WARNING, "Command failed. Did you run " _YELLOW_("`lf t55xx detect`") " before?");
3896 return PM3_ESOFT;
3898 return PM3_SUCCESS;
3901 // if the difference between a and b is less then or eq to d i.e. does a = b +/- d
3902 #define APPROX_EQ(a, b, d) ((abs(a - b) <= d) ? true : false)
3904 static uint8_t t55sniff_get_packet(int *pulseBuffer, char *data, uint8_t width0, uint8_t width1, uint8_t tolerance) {
3905 int i = 0;
3906 bool ok = true;
3907 uint8_t len = 0;
3909 while (ok && (i < 73)) { // 70 bits max Fixed bit packet
3910 if (APPROX_EQ(width0, pulseBuffer[i], tolerance)) {
3911 data[len++] = '0';
3912 i++;
3913 continue;
3915 if (APPROX_EQ(width1, pulseBuffer[i], tolerance)) {
3916 data[len++] = '1';
3917 i++;
3918 continue;
3921 ok = false;
3923 data[len] = 0x00;
3924 return len;
3927 static uint8_t t55sniff_trim_samples(int *pulseBuffer, int *pulseIdx, uint8_t len) {
3928 for (uint8_t i = 0; i < (80 - len); i++) {
3929 pulseBuffer[i] = pulseBuffer[i + len];
3932 *pulseIdx -= len;
3933 return PM3_SUCCESS;
3936 static int CmdT55xxSniff(const char *Cmd) {
3937 CLIParserContext *ctx;
3938 CLIParserInit(&ctx, "lf t55xx sniff",
3939 "Sniff LF t55xx based trafic and decode possible cmd / blocks.\n"
3940 "Lower tolerance means tighter pulses. ",
3941 "lf t55xx sniff\n"
3942 "lf t55xx sniff -1 -t 2 -> use buffer with tolerance of 2\n"
3943 "lf t55xx sniff -1 --zero 7 --one 14 -> use buffer, zero pulse width 7, one pulse width 15"
3946 void *argtable[] = {
3947 arg_param_begin,
3948 arg_lit0("1", NULL, "extract using data from graphbuffer"),
3949 arg_int0("t", "tol", "<dec>", "set tolerance level (default 5)"),
3950 // arg_int0(NULL, "signal", "<dec>", "set minimum signal level (default 20)"),
3951 arg_int0("o", "one", "<dec>", "set samples width for ONE pulse (default auto)"),
3952 arg_int0("z", "zero", "<dec>", "set samples width for ZERO pulse (default auto)"),
3953 arg_param_end
3955 CLIExecWithReturn(ctx, Cmd, argtable, true);
3956 bool use_graphbuf = arg_get_lit(ctx, 1);
3957 uint8_t tolerance = arg_get_int_def(ctx, 2, 5);
3958 int opt_width1 = arg_get_int_def(ctx, 3, -1);
3959 int opt_width0 = arg_get_int_def(ctx, 4, -1);
3960 CLIParserFree(ctx);
3962 if (opt_width0 == 0) {
3963 PrintAndLogEx(ERR, "Must call with --zero larger than 0");
3964 return PM3_EINVARG;
3966 if (opt_width1 == 0) {
3967 PrintAndLogEx(ERR, "Must call with --one larger than 0");
3968 return PM3_EINVARG;
3971 if (opt_width0 > 0 && opt_width1 == -1) {
3972 PrintAndLogEx(ERR, _RED_("Missing sample width for ONE"));
3973 return PM3_EINVARG;
3976 if (opt_width1 > 0 && opt_width0 == -1) {
3977 PrintAndLogEx(ERR, _RED_("Missing sample width for ZERO"));
3978 return PM3_EINVARG;
3981 uint8_t width1 = 0;
3982 uint8_t width0 = 0;
3984 if (opt_width0 > -1)
3985 width0 = (uint8_t)opt_width0 & 0xFF;
3987 if (opt_width1 > -1)
3988 width1 = (uint8_t)opt_width1 & 0xFF;
3993 Notes:
3994 T55xx packet lengths (1 of 4 needs to be checked)
3995 -----------------------------------------------
3996 | Default | LL 0 | Leading 0 | 1 of 4 |
3997 ----------------------------------------------------------------|
3998 | Standard Write | 38 | 39 | 39 | 40 |
3999 | Protect Write | 70 | 71 | 73 | 74 |
4000 | AOR | 34 | 35 | 37 | 38 |
4001 | Standard Read | 5 | 6 | 7 | 8 |
4002 | Protect Read | 38 | 39 | 41 | 42 |
4003 | Regular Read | 2 | 3 | 3 | 4 |
4004 | Reset | 2 | 3 | 3 | 4 |
4005 ----------------------------------------------------------------
4007 T55xx bit widths (decimation 1) - Expected, but may vary a little
4008 Reference 0 for LL0 and Leading 0 can be longer
4009 -----------------------------------------------
4010 | Default | LL 0 | Leading 0 | 1 of 4 |
4011 ----------------------------------------------------|
4012 | 0 | 16 - 32 | 9 - 33 | 5 - 80 | tbc |
4013 | 1 | 48 - 64 | 41 - 72 | 21 - 96 | tbc |
4014 ----------------------------------------------------
4015 00 01 10 11
4018 uint8_t page, blockAddr;
4019 size_t idx = 0;
4020 uint32_t usedPassword, blockData;
4021 int pulseSamples = 0, pulseIdx = 0;
4022 char modeText[100];
4023 char pwdText[100];
4024 char dataText[100];
4025 int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths
4026 char data[80]; // linked to pulseBuffer. - Holds 0/1 from pulse widths
4028 // setup and sample data from Proxmark
4029 // if not directed to existing sample/graphbuffer
4030 if (use_graphbuf == false) {
4031 CmdLFSniff("");
4034 // Headings
4035 PrintAndLogEx(NORMAL, "");
4036 PrintAndLogEx(INFO, _CYAN_("T55xx command detection"));
4037 PrintAndLogEx(SUCCESS, "Downlink mode | password | Data | blk | page | 0 | 1 | raw");
4038 PrintAndLogEx(SUCCESS, "----------------------+----------+----------+-----+------+-----+-----+-------------------------------------------------------------------------------");
4040 idx = 0;
4041 // loop though sample buffer
4042 while (idx < GraphTraceLen) {
4044 int minWidth = 1000;
4045 int maxWidth = 0;
4046 uint16_t dataLen = 0;
4047 data[0] = 0;
4048 bool have_data = false;
4049 sprintf(modeText, "Default");
4050 sprintf(pwdText, " ");
4051 sprintf(dataText, " ");
4053 if (pulseSamples == 0) {
4054 idx++;
4057 // find high
4058 while ((idx < GraphTraceLen) && (GraphBuffer[idx] < 0)) {
4059 idx++;
4062 // count high samples
4063 pulseSamples = 0;
4064 while ((idx < GraphTraceLen) && (GraphBuffer[idx] > 0)) { // last bit seems to be high to zero, but can vary in width..
4065 pulseSamples++;
4066 idx++;
4069 if (pulseSamples > 0) {
4070 pulseBuffer[pulseIdx++] = pulseSamples;
4071 if (pulseIdx > 79) { // make room for next sample - if not used by now, it wont be.
4072 t55sniff_trim_samples(pulseBuffer, &pulseIdx, 1);
4075 // Check Samples for valid packets;
4076 // We should find (outside of leading bits) we have a packet of "1" and "0" at same widths.
4077 if (pulseIdx >= 6) {// min size for a read - ignoring 1of4 10 0 <adr>
4079 // We auto find widths
4080 if ((width0 == 0) && (width1 == 0)) {
4081 // We ignore bit 0 for the moment as it may be a ref. pulse, so check last
4082 uint8_t ii = 2;
4083 minWidth = pulseBuffer[1];
4084 maxWidth = pulseBuffer[1];
4085 bool done = false;
4087 while ((!done) && (ii < pulseIdx) && ((maxWidth <= minWidth) || (APPROX_EQ(minWidth, maxWidth, tolerance)))) { // min should be 8, 16-32 more normal
4088 if (pulseBuffer[ii] + 3 < minWidth) {
4089 minWidth = pulseBuffer[ii];
4090 done = true;
4092 if (pulseBuffer[ii] - 1 > maxWidth) {
4093 maxWidth = pulseBuffer[ii];
4094 done = true;
4096 ii++;
4098 } else {
4099 minWidth = width0;
4100 maxWidth = width1;
4104 // out of bounds... min max far enough appart and minWidth is large enough
4105 if (((maxWidth - minWidth) < 6) || (minWidth < 6)) // min 8 +/-
4106 continue;
4108 // At this point we should have
4109 // - a min of 6 samples
4110 // - the 0 and 1 sample widths
4111 // - min 0 and min seperations (worst case)
4112 // No max checks done (yet) as have seen samples > then specs in use.
4114 // Check first bit.
4116 // Long leading 0
4117 if (have_data == false && (APPROX_EQ(pulseBuffer[0], 136 + minWidth, tolerance) && APPROX_EQ(pulseBuffer[1], maxWidth, tolerance))) {
4118 // printf ("Long Leading 0 - not yet hanled | have 1 Fisrt bit | Min : %-3d - Max : %-3d : diff : %d\n",minWidth,maxWidth, maxWidth-minWidth);
4119 continue;
4122 // Fixed bit - Default
4123 if (have_data == false && (APPROX_EQ(pulseBuffer[0], maxWidth, tolerance))) {
4124 dataLen = t55sniff_get_packet(pulseBuffer, data, minWidth, maxWidth, tolerance);
4126 // if ((dataLen == 39) )
4127 // printf ("Fixed | Data end of 80 samples | offset : %llu - datalen %-2d - data : %s --- - Bit 0 width : %d\n",idx,dataLen,data,pulseBuffer[0]);
4129 if (data[0] == '0') { // should never get here..
4130 data[0] = 0;
4131 } else {
4133 // Default Read
4134 if (dataLen == 6) {
4135 t55sniff_trim_samples(pulseBuffer, &pulseIdx, 4); // left 1 or 2 samples seemed to help
4137 page = data[1] - '0';
4138 blockAddr = 0;
4139 for (uint8_t i = 3; i < 6; i++) {
4140 blockAddr <<= 1;
4141 if (data[i] == '1')
4142 blockAddr |= 1;
4144 blockData = 0;
4145 have_data = true;
4146 sprintf(modeText, "Default Read");
4149 // Password Write
4150 if (dataLen == 70) {
4151 t55sniff_trim_samples(pulseBuffer, &pulseIdx, 70);
4153 page = data[1] - '0';
4154 usedPassword = 0;
4155 for (uint8_t i = 2; i <= 33; i++) {
4156 usedPassword <<= 1;
4157 if (data[i] == '1')
4158 usedPassword |= 1;
4160 // Lock bit 34
4161 blockData = 0;
4162 for (uint8_t i = 35; i <= 66; i++) {
4163 blockData <<= 1;
4164 if (data[i] == '1')
4165 blockData |= 1;
4167 blockAddr = 0;
4168 for (uint8_t i = 67; i <= 69; i++) {
4169 blockAddr <<= 1;
4170 if (data[i] == '1')
4171 blockAddr |= 1;
4173 have_data = true;
4174 sprintf(modeText, "Default pwd write");
4175 sprintf(pwdText, "%08X", usedPassword);
4176 sprintf(dataText, "%08X", blockData);
4179 // Default Write (or password read ??)
4180 if (dataLen == 38) {
4181 t55sniff_trim_samples(pulseBuffer, &pulseIdx, 38);
4183 page = data[1] - '0';
4184 usedPassword = 0;
4185 blockData = 0;
4186 for (uint8_t i = 3; i <= 34; i++) {
4187 blockData <<= 1;
4188 if (data[i] == '1')
4189 blockData |= 1;
4191 blockAddr = 0;
4192 for (uint8_t i = 35; i <= 37; i++) {
4193 blockAddr <<= 1;
4194 if (data[i] == '1')
4195 blockAddr |= 1;
4197 have_data = true;
4198 sprintf(modeText, "Default write");
4199 sprintf(dataText, "%08X", blockData);
4204 // Leading 0
4205 if (have_data == false && (APPROX_EQ(pulseBuffer[0], minWidth, tolerance))) {
4206 // leading 0 (should = 0 width)
4207 // 1 of 4 (leads with 00)
4208 dataLen = t55sniff_get_packet(pulseBuffer, data, minWidth, maxWidth, tolerance);
4209 // **** Should check to 0 to be actual 0 as well i.e. 01 .... data ....
4210 if ((data[0] == '0') && (data[1] == '1')) {
4211 if (dataLen == 73) {
4212 t55sniff_trim_samples(pulseBuffer, &pulseIdx, 73);
4214 page = data[2] - '0';
4215 usedPassword = 0;
4216 for (uint8_t i = 5; i <= 36; i++) {
4217 usedPassword <<= 1;
4218 if (data[i] == '1')
4219 usedPassword |= 1;
4221 blockData = 0;
4222 for (uint8_t i = 38; i <= 69; i++) {
4223 blockData <<= 1;
4224 if (data[i] == '1')
4225 blockData |= 1;
4227 blockAddr = 0;
4228 for (uint8_t i = 70; i <= 72; i++) {
4229 blockAddr <<= 1;
4230 if (data[i] == '1')
4231 blockAddr |= 1;
4233 have_data = true;
4234 sprintf(modeText, "Leading 0 pwd write");
4235 sprintf(pwdText, "%08X", usedPassword);
4236 sprintf(dataText, "%08X", blockData);
4242 // Print results
4243 if (have_data) {
4244 if (blockAddr == 7)
4245 PrintAndLogEx(SUCCESS, "%-20s | "_GREEN_("%8s")" | "_YELLOW_("%8s")" | "_YELLOW_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, dataText, blockAddr, page, minWidth, maxWidth, data);
4246 else
4247 PrintAndLogEx(SUCCESS, "%-20s | "_GREEN_("%8s")" | "_GREEN_("%8s")" | "_GREEN_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, dataText, blockAddr, page, minWidth, maxWidth, data);
4251 // footer
4252 PrintAndLogEx(SUCCESS, "-----------------------------------------------------------------------------------------------------------------------------------------------------");
4253 PrintAndLogEx(NORMAL, "");
4254 return PM3_SUCCESS;
4257 static command_t CommandTable[] = {
4258 {"-----------", CmdHelp, AlwaysAvailable, "---------------------------- " _CYAN_("notice") " -----------------------------"},
4259 {"", CmdHelp, AlwaysAvailable, "Remember to run `" _YELLOW_("lf t55xx detect") "` first whenever a new card"},
4260 {"", CmdHelp, AlwaysAvailable, "is placed on the Proxmark3 or the config block changed."},
4261 {"", CmdHelp, AlwaysAvailable, ""},
4262 {"help", CmdHelp, AlwaysAvailable, "This help"},
4263 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
4264 {"clonehelp", CmdT55xxCloneHelp, IfPm3Lf, "Shows the available clone commands"},
4265 {"config", CmdT55xxSetConfig, AlwaysAvailable, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"},
4266 {"dangerraw", CmdT55xxDangerousRaw, IfPm3Lf, "Sends raw bitstream. Dangerous, do not use!!"},
4267 {"detect", CmdT55xxDetect, AlwaysAvailable, "Try detecting the tag modulation from reading the configuration block"},
4268 {"deviceconfig", CmdT55xxSetDeviceConfig, IfPm3Lf, "Set/Get T55XX device configuration"},
4269 {"dump", CmdT55xxDump, IfPm3Lf, "Dump T55xx card Page 0 block 0-7"},
4270 {"info", CmdT55xxInfo, AlwaysAvailable, "Show T55x7 configuration data (page 0/ blk 0)"},
4271 {"p1detect", CmdT55xxDetectPage1, IfPm3Lf, "Try detecting if this is a t55xx tag by reading page 1"},
4272 {"read", CmdT55xxReadBlock, IfPm3Lf, "Read T55xx block data"},
4273 {"resetread", CmdResetRead, IfPm3Lf, "Send Reset Cmd then lf read the stream to attempt to identify the start of it"},
4274 {"restore", CmdT55xxRestore, IfPm3Lf, "Restore T55xx card Page 0 / Page 1 blocks"},
4275 {"trace", CmdT55xxReadTrace, AlwaysAvailable, "Show T55x7 traceability data (page 1/ blk 0-1)"},
4276 {"wakeup", CmdT55xxWakeUp, IfPm3Lf, "Send AOR wakeup command"},
4277 {"write", CmdT55xxWriteBlock, IfPm3Lf, "Write T55xx block data"},
4278 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"},
4279 {"bruteforce", CmdT55xxBruteForce, IfPm3Lf, "Simple bruteforce attack to find password"},
4280 {"chk", CmdT55xxChkPwds, IfPm3Lf, "Check passwords from dictionary/flash"},
4281 {"protect", CmdT55xxProtect, IfPm3Lf, "Password protect tag"},
4282 {"recoverpw", CmdT55xxRecoverPW, IfPm3Lf, "Try to recover from bad password write from a cloner"},
4283 {"sniff", CmdT55xxSniff, AlwaysAvailable, "Attempt to recover T55xx commands from sample buffer"},
4284 {"special", CmdT55xxSpecial, IfPm3Lf, "Show block changes with 64 different offsets"},
4285 {"wipe", CmdT55xxWipe, IfPm3Lf, "Wipe a T55xx tag and set defaults (will destroy any data on tag)"},
4286 {NULL, NULL, NULL, NULL}
4289 static int CmdHelp(const char *Cmd) {
4290 (void)Cmd; // Cmd is not used so far
4291 CmdsHelp(CommandTable);
4292 return PM3_SUCCESS;
4295 int CmdLFT55XX(const char *Cmd) {
4296 clearCommandBuffer();
4297 return CmdsParse(CommandTable, Cmd);