diff --git a/client/src/cmdlfpresco.c b/client/src/cmdlfpresco.c index d8bca9c19..3857cdd83 100644 --- a/client/src/cmdlfpresco.c +++ b/client/src/cmdlfpresco.c @@ -8,51 +8,64 @@ //----------------------------------------------------------------------------- #include "cmdlfpresco.h" - #include #include #include #include - -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" #include "cmddata.h" #include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest -#include "cmdlft55xx.h" // verifywrite +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "cmdlft55xx.h" // verifywrite +#include "cmdlfem4x05.h" // +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_presco_clone(void) { - PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d c "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " d : 9 digit presco card ID"); - PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789")); +// find presco preamble 0x10D in already demoded data +static 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 +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; } -static int usage_lf_presco_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d or c "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " d : 9 digit presco card number"); - PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf presco sim d 123456789")); +// calc not certain - intended to get bitstream for programming / sim +static 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; } @@ -85,15 +98,16 @@ int demodPresco(bool verbose) { uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); - uint32_t cardid = raw4; - PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); + uint32_t fullcode = raw4; + uint32_t usercode = fullcode & 0x0000FFFF; + uint32_t sitecode = (fullcode >> 24) & 0x000000FF; - uint32_t sitecode = 0, usercode = 0, fullcode = 0; - bool Q5 = false; - char cmd[12] = {0}; - sprintf(cmd, "H %08X", cardid); - getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); - PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode); + PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X") + , sitecode + , usercode + , fullcode + , raw1, raw2, raw3, raw4 + ); return PM3_SUCCESS; } @@ -103,35 +117,108 @@ static int CmdPrescoDemod(const char *Cmd) { } //see ASKDemod for what args are accepted -static int CmdPrescoRead(const char *Cmd) { - // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 - (void)Cmd; // Cmd is not used so far - lf_read(false, 12000); - return demodPresco(true); +static int CmdPrescoReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf presco reader", + "read a presco tag", + "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 // Or takes 8 digit hex ID 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, "", "8 digit hex card number"), + arg_str0("d", NULL, "", "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}; - // get wiegand from printed number. - if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone(); - - if (Q5) + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { 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) { 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) { 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 @@ -139,25 +226,84 @@ static int CmdPrescoClone(const char *Cmd) { blocks[3] = 0x00000000; 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)); - 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(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify"); return res; } // takes base 12 ID converts to hex // Or takes 8 digit hex ID static int CmdPrescoSim(const char *Cmd) { - uint32_t sitecode = 0, usercode = 0, fullcode = 0; - bool Q5 = false; - // get wiegand from printed number. - if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) - return usage_lf_presco_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf presco sim", + "Enables simulation of presco card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "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, "", "8 digit hex card number"), + arg_str0("d", NULL, "", "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]; getPrescoBits(fullcode, bs); @@ -185,9 +331,9 @@ static int CmdPrescoSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"}, - {"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"}, - {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, - {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, + {"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"}, + {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, + {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, {NULL, NULL, NULL, NULL} }; @@ -201,86 +347,3 @@ int CmdLFPresco(const char *Cmd) { clearCommandBuffer(); 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; -} diff --git a/client/src/cmdlfpresco.h b/client/src/cmdlfpresco.h index d90d6c573..961830ab2 100644 --- a/client/src/cmdlfpresco.h +++ b/client/src/cmdlfpresco.h @@ -12,11 +12,6 @@ #include "common.h" int CmdLFPresco(const char *Cmd); - 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