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
parent 2e1c906d9e
commit c59d6cdc71
2 changed files with 209 additions and 151 deletions

View file

@ -8,51 +8,64 @@
//-----------------------------------------------------------------------------
#include "cmdlfpresco.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#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 <Card-ID> c <hex-ID> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID");
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
PrintAndLogEx(NORMAL, " <Q5> : 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 <Card-ID> or c <hex-ID>");
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"));
// 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, "<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};
// 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, "<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];
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;
}

View file

@ -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