lf presco - now uses cliparser, continuous mode and clone to EM (untested)

This commit is contained in:
iceman1001 2020-11-26 19:42:24 +01:00
commit c59d6cdc71
2 changed files with 209 additions and 151 deletions

View file

@ -8,51 +8,64 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfpresco.h" #include "cmdlfpresco.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions #include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_lf_presco_clone(void) { // find presco preamble 0x10D in already demoded data
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag."); static int detectPresco(uint8_t *dest, size_t *size) {
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> c <hex-ID> <Q5>"); if (*size < 128 * 2) return -1; //make sure buffer has data
PrintAndLogEx(NORMAL, "Options:"); size_t startIdx = 0;
PrintAndLogEx(NORMAL, " h : this help"); uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID"); if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number"); return -2; //preamble not found
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag"); if (*size != 128) return -3; //wrong demoded size
PrintAndLogEx(NORMAL, ""); //return start position
PrintAndLogEx(NORMAL, "Examples:"); return (int)startIdx;
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789")); }
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) {
char *s = (char*)arr;
uint8_t val = 0;
for (int i = 0; i < strlen(s); ++i) {
// Get value from number string.
if (s[i] == '*')
val = 10;
if (s[i] == '#')
val = 11;
if (s[i] >= 0x30 && s[i] <= 0x39)
val = s[i] - 0x30;
*fullcode += val;
// last digit is only added, not multipled.
if (i < strlen(s) - 1)
*fullcode *= 12;
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_presco_sim(void) { // calc not certain - intended to get bitstream for programming / sim
PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number."); static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); num_to_bytebits(0x10D00000, 32, prescoBits);
PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); num_to_bytebits(0x00000000, 32, prescoBits + 32);
PrintAndLogEx(NORMAL, ""); num_to_bytebits(0x00000000, 32, prescoBits + 64);
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or c <hex-ID>"); num_to_bytebits(fullcode, 32, prescoBits + 96);
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card number");
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco sim d 123456789"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -85,15 +98,16 @@ int demodPresco(bool verbose) {
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
uint32_t cardid = raw4; uint32_t fullcode = raw4;
PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); uint32_t usercode = fullcode & 0x0000FFFF;
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
uint32_t sitecode = 0, usercode = 0, fullcode = 0; PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
bool Q5 = false; , sitecode
char cmd[12] = {0}; , usercode
sprintf(cmd, "H %08X", cardid); , fullcode
getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); , raw1, raw2, raw3, raw4
PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode); );
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -103,35 +117,108 @@ static int CmdPrescoDemod(const char *Cmd) {
} }
//see ASKDemod for what args are accepted //see ASKDemod for what args are accepted
static int CmdPrescoRead(const char *Cmd) { static int CmdPrescoReader(const char *Cmd) {
// Presco Number: 123456789 --> Sitecode 30 | usercode 8665 CLIParserContext *ctx;
(void)Cmd; // Cmd is not used so far CLIParserInit(&ctx, "lf presco reader",
lf_read(false, 12000); "read a presco tag",
return demodPresco(true); "lf presco reader -@ -> continuous reader mode"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool cm = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
do {
lf_read(false, 12000);
demodPresco(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
} }
// takes base 12 ID converts to hex // takes base 12 ID converts to hex
// Or takes 8 digit hex ID // Or takes 8 digit hex ID
static int CmdPrescoClone(const char *Cmd) { static int CmdPrescoClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf presco clone",
"clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
"lf presco clone -d 018363467\n"
"lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag\n"
"lf presco clone -d 018363467 --em -> encode for EM4305/4469"
);
void *argtable[] = {
arg_param_begin,
arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int hex_len = 0;
uint8_t hex[4] = {0,0,0,0};
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
uint8_t idstr[11];
int slen = 9;
memset(idstr, 0x00, sizeof(idstr));
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
bool q5 = arg_get_lit(ctx, 3);
bool em = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
uint32_t fullcode = 0;
if (hex_len) {
fullcode = bytes_to_num(hex, hex_len);
} else {
//param get string int param_getstr(const char *line, int paramnum, char * str)
if (slen < 2) {
PrintAndLogEx(ERR, "Must contain atleast 2 digits");
return PM3_EINVARG;
}
getWiegandFromPrintedPresco(idstr, &fullcode);
}
uint32_t usercode = fullcode & 0x0000FFFF; //% 65566
uint32_t sitecode = (fullcode >> 24) & 0x000000FF; // /= 16777216;
bool Q5 = false;
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR, 0, 0, 0, 0}; uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR, 0, 0, 0, 0};
// get wiegand from printed number. char cardtype[16] = {"T55x7"};
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone(); // Q5
if (q5) {
if (Q5)
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR; blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
// EM4305
if (em) {
blocks[0] = EM4305_PRESCO_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
}
if ((sitecode & 0xFF) != sitecode) { if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF; sitecode &= 0xFF;
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode); PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
} }
if ((usercode & 0xFFFF) != usercode) { if ((usercode & 0xFFFF) != usercode) {
usercode &= 0xFFFF; usercode &= 0xFFFF;
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode); PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
} }
blocks[1] = 0x10D00000; //preamble blocks[1] = 0x10D00000; //preamble
@ -139,25 +226,84 @@ static int CmdPrescoClone(const char *Cmd) {
blocks[3] = 0x00000000; blocks[3] = 0x00000000;
blocks[4] = fullcode; blocks[4] = fullcode;
PrintAndLogEx(INFO, "Preparing to clone Presco to " _YELLOW_("%s") " with SiteCode: %u, UserCode: %u, FullCode: %08x", (Q5) ? "Q5/T5555" : "T55x7", sitecode, usercode, fullcode); PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x")
, cardtype
, sitecode
, usercode
, fullcode
);
print_blocks(blocks, ARRAYLEN(blocks)); print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify");
return res; return res;
} }
// takes base 12 ID converts to hex // takes base 12 ID converts to hex
// Or takes 8 digit hex ID // Or takes 8 digit hex ID
static int CmdPrescoSim(const char *Cmd) { static int CmdPrescoSim(const char *Cmd) {
uint32_t sitecode = 0, usercode = 0, fullcode = 0; CLIParserContext *ctx;
bool Q5 = false; CLIParserInit(&ctx, "lf presco sim",
// get wiegand from printed number. "Enables simulation of presco card with specified card number.\n"
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) "Simulation runs until the button is pressed or another USB command is issued.\n"
return usage_lf_presco_sim(); "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.",
"lf presco sim -d 018363467"
);
PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X", sitecode, usercode, fullcode); void *argtable[] = {
arg_param_begin,
arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int hex_len = 0;
uint8_t hex[4] = {0,0,0,0};
CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
uint8_t idstr[11];
int slen = 9;
memset(idstr, 0x00, sizeof(idstr));
CLIGetStrWithReturn(ctx, 2, idstr, &slen);
CLIParserFree(ctx);
uint32_t fullcode = 0;
if (hex_len) {
fullcode = bytes_to_num(hex, hex_len);
} else {
if (slen < 2) {
PrintAndLogEx(ERR, "Must contain atleast 2 digits");
return PM3_EINVARG;
}
getWiegandFromPrintedPresco(idstr, &fullcode);
}
uint32_t usercode = fullcode & 0x0000FFFF;
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF;
PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
}
if ((usercode & 0xFFFF) != usercode) {
usercode &= 0xFFFF;
PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
}
PrintAndLogEx(SUCCESS, "Simulating Presco - Site Code: " _GREEN_("%u") " User Code: " _GREEN_("%u") " Full Code: " _GREEN_("%08X")
, sitecode
, usercode
, fullcode)
;
uint8_t bs[128]; uint8_t bs[128];
getPrescoBits(fullcode, bs); getPrescoBits(fullcode, bs);
@ -185,9 +331,9 @@ static int CmdPrescoSim(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"}, {"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"},
{"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"}, {"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"},
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -201,86 +347,3 @@ int CmdLFPresco(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
// find presco preamble 0x10D in already demoded data
int detectPresco(uint8_t *dest, size_t *size) {
if (*size < 128 * 2) return -1; //make sure buffer has data
size_t startIdx = 0;
uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
return -2; //preamble not found
if (*size != 128) return -3; //wrong demoded size
//return start position
return (int)startIdx;
}
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) {
bool hex = false, errors = false;
uint8_t cmdp = 0;
char id[11];
int stringlen = 0;
memset(id, 0x00, sizeof(id));
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return PM3_EINVARG;
case 'c':
hex = true;
//get hex
*fullcode = param_get32ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2;
break;
case 'd':
//param get string int param_getstr(const char *line, int paramnum, char * str)
stringlen = param_getstr(Cmd, cmdp + 1, id, sizeof(id));
if (stringlen < 2) return PM3_EINVARG;
cmdp += 2;
break;
case 'q':
*Q5 = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = 1;
break;
}
}
//Validations
if (errors || cmdp == 0) return PM3_EINVARG;
if (!hex) {
uint8_t val = 0;
for (int index = 0; index < strlen(id); ++index) {
// Get value from number string.
if (id[index] == '*')
val = 10;
if (id[index] == '#')
val = 11;
if (id[index] >= 0x30 && id[index] <= 0x39)
val = id[index] - 0x30;
*fullcode += val;
// last digit is only added, not multipled.
if (index < strlen(id) - 1)
*fullcode *= 12;
}
}
*usercode = *fullcode & 0x0000FFFF; //% 65566
*sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216;
return PM3_SUCCESS;
}
// calc not certain - intended to get bitstream for programming / sim
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
num_to_bytebits(0x10D00000, 32, prescoBits);
num_to_bytebits(0x00000000, 32, prescoBits + 32);
num_to_bytebits(0x00000000, 32, prescoBits + 64);
num_to_bytebits(fullcode, 32, prescoBits + 96);
return PM3_SUCCESS;
}

View file

@ -12,11 +12,6 @@
#include "common.h" #include "common.h"
int CmdLFPresco(const char *Cmd); int CmdLFPresco(const char *Cmd);
int demodPresco(bool verbose); int demodPresco(bool verbose);
int detectPresco(uint8_t *dest, size_t *size);
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits);
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5);
#endif #endif