mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
commit
3f84bf4bce
12 changed files with 714 additions and 399 deletions
|
@ -970,6 +970,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_LOGIN: {
|
||||
struct p {
|
||||
uint32_t password;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
EM4xLogin(payload->password);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_READWORD: {
|
||||
struct p {
|
||||
uint32_t password;
|
||||
|
|
|
@ -2501,7 +2501,7 @@ static void SendForward(uint8_t fwd_bit_count) {
|
|||
}
|
||||
}
|
||||
|
||||
static void EM4xLogin(uint32_t pwd) {
|
||||
static void EM4xLoginEx(uint32_t pwd) {
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN);
|
||||
len += Prepare_Data(pwd & 0xFFFF, pwd >> 16);
|
||||
|
@ -2512,6 +2512,29 @@ static void EM4xLogin(uint32_t pwd) {
|
|||
// 0000 0001 fail
|
||||
}
|
||||
|
||||
void EM4xLogin(uint32_t pwd) {
|
||||
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitMS(20);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
EM4xLoginEx(pwd);
|
||||
|
||||
WaitUS(400);
|
||||
// We need to acquire more than needed, to help demodulators finding the proper modulation
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_LOGIN, PM3_SUCCESS, NULL, 0);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
||||
|
||||
StartTicks();
|
||||
|
@ -2529,7 +2552,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
|||
* 0000 1010 ok
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
if (usepwd) EM4xLoginEx(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_READ);
|
||||
|
@ -2539,7 +2562,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
|||
|
||||
WaitUS(400);
|
||||
|
||||
DoPartialAcquisition(20, false, 6000, 1000);
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
@ -2564,7 +2587,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
* 0000 1010 ok.
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
if (usepwd) EM4xLoginEx(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_WRITE);
|
||||
|
@ -2607,7 +2630,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
* 0000 1010 ok.
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
if (usepwd) EM4xLoginEx(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT);
|
||||
|
|
|
@ -56,6 +56,7 @@ void T55xxDangerousRawTest(uint8_t *data);
|
|||
|
||||
void TurnReadLFOn(uint32_t delay);
|
||||
|
||||
void EM4xLogin(uint32_t pwd);
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
|
|
|
@ -203,34 +203,33 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
|
|||
int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
||||
*datalen = 0;
|
||||
|
||||
int ibuf = 0;
|
||||
uint8_t tmp_buf[512] = {0};
|
||||
int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX
|
||||
int tmplen = 0;
|
||||
uint8_t tmpstr[(256 * 2) + 1] = {0};
|
||||
|
||||
// concat all strings in argstr into tmpstr[]
|
||||
//
|
||||
int res = CLIParamStrToBuf(argstr, tmpstr, sizeof(tmpstr), &tmplen);
|
||||
if (res) {
|
||||
printf("Parameter error: buffer overflow.\n");
|
||||
fflush(stdout);
|
||||
return res;
|
||||
}
|
||||
if (ibuf == 0) {
|
||||
if (tmplen == 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (param_gethex_to_eol((char *)tmp_buf, 0, data, maxdatalen, datalen)) {
|
||||
res = param_gethex_to_eol((char*)tmpstr, 0, data, maxdatalen, datalen);
|
||||
switch (res) {
|
||||
case 1:
|
||||
printf("Parameter error: Invalid HEX value.\n");
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
printf("Parameter error: Invalid HEX value\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("Parameter error: parameter too large.\n");
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
printf("Parameter error: parameter too large\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("Parameter error: Hex string must have even number of digits.\n");
|
||||
fflush(stdout);
|
||||
return 3;
|
||||
printf("Parameter error: Hex string must have EVEN number of digits\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fflush(stdout);
|
||||
return res;
|
||||
}
|
||||
|
||||
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
||||
|
@ -238,26 +237,37 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
if (!argstr->count)
|
||||
return 0;
|
||||
|
||||
uint8_t tmp_buf[512] = {0};
|
||||
uint8_t tmpstr[(256 * 2) + 1] = {0};
|
||||
int ibuf = 0;
|
||||
|
||||
for (int i = 0; i < argstr->count; i++) {
|
||||
|
||||
int len = strlen(argstr->sval[i]);
|
||||
memcpy(&tmp_buf[ibuf], argstr->sval[i], len);
|
||||
|
||||
if (len > ( (sizeof(tmpstr) / 2 ) - ibuf)) {
|
||||
printf("Parameter error: string too long (%i chars), expect MAX %zu chars\n", len + ibuf, (sizeof(tmpstr) / 2));
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(&tmpstr[ibuf], argstr->sval[i], len);
|
||||
|
||||
ibuf += len;
|
||||
}
|
||||
tmp_buf[ibuf] = 0;
|
||||
|
||||
ibuf = MIN(ibuf, (sizeof(tmpstr) / 2));
|
||||
tmpstr[ibuf] = 0;
|
||||
|
||||
if (!ibuf)
|
||||
if (ibuf == 0)
|
||||
return 0;
|
||||
|
||||
if (ibuf + 1 > maxdatalen) {
|
||||
printf("Parameter error: string too long, expect max %i chars\n", maxdatalen - 1);
|
||||
if (ibuf > maxdatalen) {
|
||||
printf("Parameter error: string too long (%i chars), expected MAX %i chars\n", ibuf, maxdatalen);
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(data, tmp_buf, ibuf + 1);
|
||||
memcpy(data, tmpstr, ibuf + 1);
|
||||
*datalen = ibuf;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -130,7 +130,6 @@ static int CmdHF14BSim(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sim",
|
||||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim\n"
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
|
||||
|
@ -139,7 +138,7 @@ static int CmdHF14BSim(const char *Cmd) {
|
|||
arg_strx0("u", "uid", "hex", "4byte UID/PUPI"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
|
@ -150,6 +149,9 @@ static int CmdHF14BSim(const char *Cmd) {
|
|||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi)));
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "crc16.h" // iso15 crc
|
||||
#include "cmddata.h" // getsamples
|
||||
#include "fileutils.h" // savefileEML
|
||||
#include "cliparser.h"
|
||||
|
||||
#define FrameSOF Iso15693FrameSOF
|
||||
#define Logic0 Iso15693Logic0
|
||||
|
@ -209,16 +210,6 @@ const productName_t uidmapping[] = {
|
|||
|
||||
static int CmdHF15Help(const char *Cmd);
|
||||
|
||||
static int usage_15_demod(void) {
|
||||
PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n"
|
||||
"Gather samples with 'hf 15 read' / 'hf 15 record'");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_samples(void) {
|
||||
PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n"
|
||||
"and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n"
|
||||
"command may fail, depending on tag.\n"
|
||||
|
@ -235,36 +226,7 @@ static int usage_15_info(void) {
|
|||
_YELLOW_("\thf 15 info u"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_record(void) {
|
||||
PrintAndLogEx(NORMAL, "Record activity without enabling carrier");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_reader(void) {
|
||||
PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n"
|
||||
"\n"
|
||||
"Usage: hf 15 reader [h]\n"
|
||||
"Options:\n"
|
||||
"\th this help\n"
|
||||
"\t1 read once\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
_YELLOW_("\thf 15 reader\n")
|
||||
_YELLOW_("\thf 15 reader 1\n"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 15 sim <UID>\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
_YELLOW_("\thf 15 sim E016240000000000"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_findafi(void) {
|
||||
PrintAndLogEx(NORMAL, "This command attempts to brute force AFI of an ISO15693 tag\n"
|
||||
"\n"
|
||||
"Usage: hf 15 findafi");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_15_writeafi(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi <uid|u|*> <afi>\n"
|
||||
"\tuid (either): \n"
|
||||
|
@ -358,17 +320,6 @@ static int usage_15_readmulti(void) {
|
|||
"\t <count> 1-6, number of pages");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_15_csetuid(void) {
|
||||
PrintAndLogEx(NORMAL, "Set UID for magic Chinese card (only works with such cards)\n"
|
||||
"\n"
|
||||
"Usage: hf 15 csetuid <uid>\n"
|
||||
"Options:\n"
|
||||
"\tuid : <8B hex> full UID eg E011223344556677\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
_YELLOW_("\thf 15 csetuid E011223344556677"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
||||
|
||||
|
@ -691,17 +642,31 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
|
|||
}
|
||||
|
||||
// Mode 3
|
||||
//helptext
|
||||
static int CmdHF15Demod(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_demod();
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 demod",
|
||||
"Tries to demodulate / decode ISO15693, from downloaded samples.\n"
|
||||
"Gather samples with 'hf 15 samples' / 'hf 15 sniff'",
|
||||
"hf 15 demod\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// The sampling rate is 106.353 ksps/s, for T = 18.8 us
|
||||
int i, j;
|
||||
int max = 0, maxPos = 0;
|
||||
int skip = 4;
|
||||
|
||||
if (GraphTraceLen < 1000) return PM3_ESOFT;
|
||||
if (GraphTraceLen < 1000) {
|
||||
PrintAndLogEx(FAILED, "Too few samples in GraphBuffer. Need more than 1000");
|
||||
PrintAndLogEx(HINT, "Run " _YELLOW_("`hf 15 samples`") " to collect and download data");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// First, correlate for SOF
|
||||
for (i = 0; i < 1000; i++) {
|
||||
|
@ -719,7 +684,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
|||
|
||||
i = maxPos + ARRAYLEN(FrameSOF) / skip;
|
||||
int k = 0;
|
||||
uint8_t outBuf[20];
|
||||
uint8_t outBuf[2048] = {0};
|
||||
memset(outBuf, 0, sizeof(outBuf));
|
||||
uint8_t mask = 0x01;
|
||||
for (;;) {
|
||||
|
@ -746,40 +711,80 @@ static int CmdHF15Demod(const char *Cmd) {
|
|||
} else {
|
||||
i += ARRAYLEN(Logic0) / skip;
|
||||
}
|
||||
|
||||
mask <<= 1;
|
||||
if (mask == 0) {
|
||||
k++;
|
||||
mask = 0x01;
|
||||
}
|
||||
|
||||
if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) {
|
||||
PrintAndLogEx(INFO, "ran off end!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (k > 2048) {
|
||||
PrintAndLogEx(INFO, "ran out of buffer");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask != 0x01) {
|
||||
PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)");
|
||||
PrintAndLogEx(INFO, " mask = %02x", mask);
|
||||
}
|
||||
PrintAndLogEx(INFO, "%d octets", k);
|
||||
|
||||
if ( k == 0 ) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
for (i = 0; i < k; i++)
|
||||
PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]);
|
||||
i = 0;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Got %d octets, decoded as following", k);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " idx | data");
|
||||
PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------");
|
||||
if ( k / 16 > 0) {
|
||||
for (; i < k; i += 16) {
|
||||
PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, 16));
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2));
|
||||
uint8_t mod = (k % 16);
|
||||
if (mod > 0) {
|
||||
PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, mod));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------");
|
||||
if (k > 2) {
|
||||
PrintAndLogEx(SUCCESS, "--> CRC %04x", Crc15(outBuf, k - 2));
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// * Acquire Samples as Reader (enables carrier, sends inquiry)
|
||||
//helptext
|
||||
static int CmdHF15Samples(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_samples();
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 samples",
|
||||
"Acquire samples as Reader (enables carrier, send inquiry\n"
|
||||
"and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal",
|
||||
"hf 15 samples");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0);
|
||||
|
||||
getSamples(0, true);
|
||||
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 demod") "` to decode signal");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1040,12 +1045,20 @@ static int CmdHF15Info(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// Record Activity without enabling carrier
|
||||
//helptext
|
||||
// Sniff Activity without enabling carrier
|
||||
static int CmdHF15Sniff(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_record();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 sniff",
|
||||
"Sniff activity without enabling carrier",
|
||||
"hf 15 sniff\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0);
|
||||
|
@ -1058,30 +1071,58 @@ static int CmdHF15Sniff(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHF15Reader(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_reader();
|
||||
bool loop_read = (cmdp == '1') ? false : true;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 reader",
|
||||
"Act as a ISO15693 reader. Look for ISO15693 tags until Enter or the pm3 button is pressed\n",
|
||||
"hf 15 reader\n"
|
||||
"hf 15 reader -1");
|
||||
|
||||
readHF15Uid(loop_read, true);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", "one", "read once"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool read_once = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(INFO, "Starting ISO15 reader mode");
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
||||
readHF15Uid(!read_once, true);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// Simulation is still not working very good
|
||||
// helptext
|
||||
static int CmdHF15Sim(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim();
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 sim",
|
||||
"Simulate a ISO15693 tag\n",
|
||||
"hf 15 sim -u E011223344556677");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
struct {
|
||||
uint8_t uid[8];
|
||||
} PACKED payload;
|
||||
|
||||
int uidlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (param_gethex(Cmd, 0, payload.uid, 16)) {
|
||||
if (uidlen != 9) {
|
||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid));
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
@ -1094,17 +1135,25 @@ static int CmdHF15Sim(const char *Cmd) {
|
|||
// (There is no standard way of reading the AFI, although some tags support this)
|
||||
// helptext
|
||||
static int CmdHF15FindAfi(const char *Cmd) {
|
||||
PacketResponseNG resp;
|
||||
uint32_t timeout = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 findafi",
|
||||
"This command attempts to brute force AFI of an ISO15693 tag\n",
|
||||
"hf 15 findafi");
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_15_findafi();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "press pm3-button to cancel");
|
||||
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0);
|
||||
|
||||
uint32_t timeout = 0;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
timeout++;
|
||||
|
||||
|
@ -1840,16 +1889,28 @@ static int CmdHF15Restore(const char *Cmd) {
|
|||
*/
|
||||
static int CmdHF15CSetUID(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_csetuid();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 csetuid",
|
||||
"Set UID for magic Chinese card (only works with such cards)\n",
|
||||
"hf 15 csetuid -u E011223344556677");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
struct {
|
||||
uint8_t uid[8];
|
||||
} PACKED payload;
|
||||
|
||||
if (param_gethex(Cmd, 0, payload.uid, 16)) {
|
||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols");
|
||||
|
||||
int uidlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (uidlen != 8) {
|
||||
PrintAndLogEx(WARNING, "UID must include 16 HEX symbols got ");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -1872,9 +1933,10 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "getting updated card details...");
|
||||
|
|
|
@ -272,17 +272,6 @@ static int usage_hf_iclass_managekeys(void) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_reader(void) {
|
||||
PrintAndLogEx(NORMAL, "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass reader [h] [1]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h Show this help");
|
||||
PrintAndLogEx(NORMAL, " 1 read only 1 tag");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass reader 1"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_loclass(void) {
|
||||
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
|
||||
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
|
||||
|
@ -435,57 +424,55 @@ uint8_t get_pagemap(const picopass_hdr *hdr) {
|
|||
}
|
||||
|
||||
static void fuse_config(const picopass_hdr *hdr) {
|
||||
|
||||
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
|
||||
|
||||
PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t*)&hdr->conf, 8));
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... App limit", hdr->conf.app_limit);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ Block write lock", hdr->conf.block_writelock);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... Chip", hdr->conf.chip_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... Mem", hdr->conf.mem_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " Fuses", hdr->conf.fuses);
|
||||
|
||||
uint8_t fuses = hdr->conf.fuses;
|
||||
|
||||
PrintAndLogEx(INFO, " Fuses:");
|
||||
if (isset(fuses, FUSE_FPERS))
|
||||
PrintAndLogEx(SUCCESS, " Mode: " _GREEN_("Personalization (programmable)"));
|
||||
PrintAndLogEx(SUCCESS, " mode..... " _GREEN_("Personalization (programmable)"));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, " Mode: " _YELLOW_("Application (locked)"));
|
||||
PrintAndLogEx(SUCCESS, " mode..... " _YELLOW_("Application (locked)"));
|
||||
|
||||
if (isset(fuses, FUSE_CODING1)) {
|
||||
PrintAndLogEx(SUCCESS, "Coding: RFU");
|
||||
PrintAndLogEx(SUCCESS, " coding.. RFU");
|
||||
} else {
|
||||
if (isset(fuses, FUSE_CODING0))
|
||||
PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-2 B / 15693"));
|
||||
PrintAndLogEx(SUCCESS, " coding... " _YELLOW_("ISO 14443-2 B / 15693"));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-B only"));
|
||||
PrintAndLogEx(SUCCESS, " coding... " _YELLOW_("ISO 14443-B only"));
|
||||
}
|
||||
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
switch (pagemap) {
|
||||
case 0x0:
|
||||
PrintAndLogEx(INFO, " Crypt: No auth possible. Read only if RA is enabled");
|
||||
PrintAndLogEx(INFO, " crypt.... No auth possible. Read only if RA is enabled");
|
||||
break;
|
||||
case 0x1:
|
||||
PrintAndLogEx(SUCCESS, " Crypt: Non secured page");
|
||||
PrintAndLogEx(SUCCESS, " crypt.... Non secured page");
|
||||
break;
|
||||
case 0x2:
|
||||
PrintAndLogEx(INFO, " Crypt: Secured page, keys locked");
|
||||
PrintAndLogEx(INFO, " crypt.... Secured page, keys locked");
|
||||
break;
|
||||
case 0x03:
|
||||
PrintAndLogEx(SUCCESS, " Crypt: Secured page, " _GREEN_("keys not locked"));
|
||||
PrintAndLogEx(SUCCESS, " crypt.... Secured page, " _GREEN_("keys not locked"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset(fuses, FUSE_RA))
|
||||
PrintAndLogEx(SUCCESS, " RA: Read access enabled");
|
||||
PrintAndLogEx(SUCCESS, " RA....... Read access enabled (non-secure mode)");
|
||||
else
|
||||
PrintAndLogEx(INFO, " RA: Read access not enabled");
|
||||
|
||||
PrintAndLogEx(INFO,
|
||||
"App limit " _YELLOW_("0x%02X") ", OTP " _YELLOW_("0x%02X%02X") ", Block write lock " _YELLOW_("0x%02X")
|
||||
, hdr->conf.app_limit
|
||||
, hdr->conf.otp[1]
|
||||
, hdr->conf.otp[0]
|
||||
, hdr->conf.block_writelock
|
||||
);
|
||||
PrintAndLogEx(INFO,
|
||||
" Chip " _YELLOW_("0x%02X") ", Mem " _YELLOW_("0x%02X") ", EAS " _YELLOW_("0x%02X") ", Fuses " _YELLOW_("0x%02X")
|
||||
, hdr->conf.chip_config
|
||||
, hdr->conf.mem_config
|
||||
, hdr->conf.eas
|
||||
, hdr->conf.fuses
|
||||
);
|
||||
PrintAndLogEx(INFO, " RA....... Read access not enabled");
|
||||
}
|
||||
|
||||
static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) {
|
||||
|
@ -546,19 +533,19 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
|||
uint8_t app2_limit = card_app2_limit[type];
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
|
||||
PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------");
|
||||
PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Memory") " --------------------------");
|
||||
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
PrintAndLogEx(INFO, " %u KBits (%u bytes)", kb, app2_limit * 8);
|
||||
PrintAndLogEx(INFO, " %u KBits ( " _YELLOW_("%u") " bytes )", kb, app2_limit * 8);
|
||||
PrintAndLogEx(INFO, " Tag has not App Areas");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, (app2_limit + 1) * 8);
|
||||
PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )", kb, app_areas, (app2_limit + 1) * 8);
|
||||
PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit, app1_limit + 5, app1_limit + 5);
|
||||
PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit);
|
||||
|
||||
PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------");
|
||||
PrintAndLogEx(INFO, "------------------------ " _CYAN_("KeyAccess") " -------------------------");
|
||||
PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)");
|
||||
uint8_t book = isset(mem, 0x20);
|
||||
if (book) {
|
||||
|
@ -579,18 +566,18 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
|||
}
|
||||
|
||||
static void print_picopass_info(const picopass_hdr *hdr) {
|
||||
PrintAndLogEx(INFO, "------ " _CYAN_("card configuration") " ------");
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------");
|
||||
fuse_config(hdr);
|
||||
mem_app_config(hdr);
|
||||
}
|
||||
static void print_picopass_header(const picopass_hdr *hdr) {
|
||||
PrintAndLogEx(INFO, "------------ " _CYAN_("card") " -------------");
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
||||
PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
|
||||
PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
|
||||
PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------");
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
||||
PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
PrintAndLogEx(SUCCESS, " Kd: %s Debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
|
||||
PrintAndLogEx(SUCCESS, " Kc: %s Credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s Application Issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
|
||||
}
|
||||
|
||||
static int CmdHFiClassList(const char *Cmd) {
|
||||
|
@ -816,6 +803,8 @@ static int CmdHFiClassSim(const char *Cmd) {
|
|||
case ICLASS_SIM_MODE_CSN_DEFAULT:
|
||||
case ICLASS_SIM_MODE_FULL:
|
||||
default: {
|
||||
PrintAndLogEx(INFO, "Starting iCLASS simulation");
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
||||
uint8_t numberOfCSNs = 0;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, CSN, 8);
|
||||
|
@ -873,11 +862,25 @@ int read_iclass_csn(bool loop, bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHFiClassReader(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_iclass_reader();
|
||||
bool loop_read = (cmdp == '1') ? false : true;
|
||||
|
||||
return read_iclass_csn(loop_read, true);
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass reader",
|
||||
"Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n",
|
||||
"hf iclass reader\n"
|
||||
"hf iclass reader -1");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", "one", "read once"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool read_once = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(INFO, "Starting iCLASS reader mode");
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel");
|
||||
return read_iclass_csn(!read_once, true);
|
||||
}
|
||||
|
||||
static int CmdHFiClassELoad(const char *Cmd) {
|
||||
|
@ -1116,22 +1119,7 @@ static int CmdHFiClassEView(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
uint8_t *csn = dump;
|
||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
||||
PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8));
|
||||
printIclassDumpContents(dump, 1, blocks, bytes);
|
||||
|
||||
/*
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "----+-------------------------+---------");
|
||||
PrintAndLogEx(INFO, "blk | data | ascii");
|
||||
PrintAndLogEx(INFO, "----+-------------------------+---------");
|
||||
for (uint16_t i = 0; i < blocks; i++){
|
||||
PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 8) , 8) );
|
||||
}
|
||||
PrintAndLogEx(INFO, "----+-------------------------+---------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
*/
|
||||
free(dump);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1285,7 +1273,6 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
saveFileEML(fptr, decrypted, decryptedlen, 8);
|
||||
saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen, NULL);
|
||||
|
||||
PrintAndLogEx(INFO, "Following output skips CSN / block0");
|
||||
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -1561,7 +1548,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((use_replay + rawkey + elite) > 0) {
|
||||
if ((use_replay + rawkey + elite) > 1) {
|
||||
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||
errors = true;
|
||||
}
|
||||
|
@ -1780,9 +1767,6 @@ write_dump:
|
|||
PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file");
|
||||
|
||||
// print the dump
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
||||
PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8));
|
||||
printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got);
|
||||
|
||||
// use CSN as filename
|
||||
|
@ -1918,7 +1902,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
if (got_blockno == false)
|
||||
errors = true;
|
||||
|
||||
if ((use_replay + rawkey + elite) > 0) {
|
||||
if ((use_replay + rawkey + elite) > 1) {
|
||||
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||
errors = true;
|
||||
}
|
||||
|
@ -2250,7 +2234,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
if (got_blockno == false)
|
||||
errors = true;
|
||||
|
||||
if ((use_replay + rawkey + elite) > 0) {
|
||||
if ((use_replay + rawkey + elite) > 1) {
|
||||
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||
errors = true;
|
||||
}
|
||||
|
@ -2411,9 +2395,20 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
|
|||
, filemaxblock
|
||||
);
|
||||
*/
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
|
||||
|
||||
|
||||
int i = startblock;
|
||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, " blk| data | ascii |lck| info");
|
||||
PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------");
|
||||
PrintAndLogEx(INFO, "0x00| " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump, 8));
|
||||
|
||||
if (i != 1)
|
||||
PrintAndLogEx(INFO, "....");
|
||||
|
||||
while (i <= endblock) {
|
||||
uint8_t *blk = iclass_dump + (i * 8);
|
||||
|
||||
|
@ -2453,10 +2448,28 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
|
|||
bl_lock = true;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " %c |0x%02X| %s", (bl_lock) ? 'x' : ' ', i, sprint_hex_ascii(blk, 8));
|
||||
const char *lockstr = (bl_lock) ? _RED_("x") : " ";
|
||||
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
const char *info_nonks[] = {"CSN", "Config", "AIA", "User"};
|
||||
const char *s = info_nonks[3];
|
||||
if (i < 3) {
|
||||
s = info_nonks[i];
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s);
|
||||
} else {
|
||||
const char *info_ks[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User"};
|
||||
const char *s = info_ks[6];
|
||||
if (i < 6) {
|
||||
s = info_ks[i];
|
||||
}
|
||||
PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
||||
PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
static int CmdHFiClassView(const char *Cmd) {
|
||||
|
@ -2500,13 +2513,9 @@ static int CmdHFiClassView(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "start " _YELLOW_("0x%02x") " end " _YELLOW_("0x%02x"), (startblock == 0) ? 6 : startblock, endblock);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
print_picopass_header((picopass_hdr *) dump);
|
||||
print_picopass_info((picopass_hdr *) dump);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
uint8_t *csn = dump;
|
||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
||||
PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8));
|
||||
printIclassDumpContents(dump, startblock, endblock, bytes_read);
|
||||
free(dump);
|
||||
return PM3_SUCCESS;
|
||||
|
@ -2682,12 +2691,15 @@ static int saveKeys(char *filename) {
|
|||
|
||||
static int printKeys(void) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "idx| key");
|
||||
PrintAndLogEx(INFO, "---+------------------------");
|
||||
for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) {
|
||||
if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)
|
||||
PrintAndLogEx(INFO, "%u: %s", i, sprint_hex(iClass_Key_Table[i], 8));
|
||||
PrintAndLogEx(INFO, " %u |", i);
|
||||
else
|
||||
PrintAndLogEx(INFO, "%u: "_YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8));
|
||||
PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8));
|
||||
}
|
||||
PrintAndLogEx(INFO, "---+------------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -2805,105 +2817,15 @@ static void add_key(uint8_t *key) {
|
|||
}
|
||||
}
|
||||
|
||||
static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||
|
||||
// empty string
|
||||
if (strlen(Cmd) == 0) return usage_hf_iclass_chk();
|
||||
|
||||
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
// elite key, raw key, standard key
|
||||
bool use_elite = false;
|
||||
bool use_raw = false;
|
||||
bool use_credit_key = false;
|
||||
bool found_key = false;
|
||||
//bool found_credit = false;
|
||||
bool got_csn = false;
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0x00;
|
||||
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
uint8_t fileNameLen = 0;
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_hf_iclass_chk();
|
||||
case 'f':
|
||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLogEx(WARNING, _RED_("no filename found after f"));
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'e':
|
||||
use_elite = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'c':
|
||||
use_credit_key = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'r':
|
||||
use_raw = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errors) return usage_hf_iclass_chk();
|
||||
|
||||
uint8_t *keyBlock = NULL;
|
||||
uint32_t keycount = 0;
|
||||
|
||||
// load keys
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0) {
|
||||
free(keyBlock);
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
static int iclass_chk_keys(uint8_t *keyBlock, uint32_t keycount) {
|
||||
|
||||
iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
|
||||
if (!pre) {
|
||||
free(keyBlock);
|
||||
if (pre == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// Get CSN / UID and CCNR
|
||||
PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR...");
|
||||
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) {
|
||||
got_csn = select_only(CSN, CCNR, false);
|
||||
if (got_csn == false)
|
||||
PrintAndLogEx(WARNING, "one more try");
|
||||
}
|
||||
|
||||
if (got_csn == false) {
|
||||
PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting...");
|
||||
free(keyBlock);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN)));
|
||||
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : "");
|
||||
if (use_elite)
|
||||
PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo"));
|
||||
if (use_raw)
|
||||
PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode"));
|
||||
|
||||
GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT");
|
||||
|
||||
// max 42 keys inside USB_COMMAND. 512/4 = 103 mac
|
||||
uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount;
|
||||
bool lastChunk = false;
|
||||
|
@ -2987,7 +2909,195 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
|
||||
} // end chunks of keys
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||
|
||||
// empty string
|
||||
if (strlen(Cmd) == 0) return usage_hf_iclass_chk();
|
||||
|
||||
uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
// elite key, raw key, standard key
|
||||
bool use_elite = false;
|
||||
bool use_raw = false;
|
||||
bool use_credit_key = false;
|
||||
bool found_key = false;
|
||||
//bool found_credit = false;
|
||||
bool got_csn = false;
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0x00;
|
||||
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
uint8_t fileNameLen = 0;
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_hf_iclass_chk();
|
||||
case 'f':
|
||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLogEx(WARNING, _RED_("no filename found after f"));
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'e':
|
||||
use_elite = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'c':
|
||||
use_credit_key = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'r':
|
||||
use_raw = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errors) return usage_hf_iclass_chk();
|
||||
|
||||
uint8_t *keyBlock = NULL;
|
||||
uint32_t keycount = 0;
|
||||
|
||||
// load keys
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0) {
|
||||
free(keyBlock);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Get CSN / UID and CCNR
|
||||
PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR...");
|
||||
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) {
|
||||
got_csn = select_only(CSN, CCNR, false);
|
||||
if (got_csn == false)
|
||||
PrintAndLogEx(WARNING, "one more try");
|
||||
}
|
||||
|
||||
if (got_csn == false) {
|
||||
PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting...");
|
||||
free(keyBlock);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
|
||||
if (pre == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN)));
|
||||
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : "");
|
||||
if (use_elite)
|
||||
PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo"));
|
||||
if (use_raw)
|
||||
PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode"));
|
||||
|
||||
GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT");
|
||||
|
||||
|
||||
// max 42 keys inside USB_COMMAND. 512/4 = 103 mac
|
||||
uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount;
|
||||
bool lastChunk = false;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
|
||||
// keep track of position of found key
|
||||
uint8_t found_offset = 0;
|
||||
uint32_t key_offset = 0;
|
||||
// main keychunk loop
|
||||
for (key_offset = 0; key_offset < keycount; key_offset += chunksize) {
|
||||
|
||||
uint64_t t2 = msclock();
|
||||
uint8_t timeout = 0;
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Aborted via keyboard!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
uint32_t keys = ((keycount - key_offset) > chunksize) ? chunksize : keycount - key_offset;
|
||||
|
||||
// last chunk?
|
||||
if (keys == keycount - key_offset) {
|
||||
lastChunk = true;
|
||||
// Disable fast mode on last command
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
uint32_t flags = lastChunk << 8;
|
||||
// bit 16
|
||||
// - 1 indicates credit key
|
||||
// - 0 indicates debit key (default)
|
||||
flags |= (use_credit_key << 16);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys);
|
||||
PacketResponseNG resp;
|
||||
|
||||
bool looped = false;
|
||||
while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) {
|
||||
timeout++;
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
if (timeout > 120) {
|
||||
PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting...");
|
||||
goto out;
|
||||
}
|
||||
looped = true;
|
||||
}
|
||||
|
||||
if (looped)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
found_offset = resp.oldarg[1] & 0xFF;
|
||||
uint8_t isOK = resp.oldarg[0] & 0xFF;
|
||||
|
||||
t2 = msclock() - t2;
|
||||
switch (isOK) {
|
||||
case 1: {
|
||||
found_key = true;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s")
|
||||
, sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 0: {
|
||||
PrintAndLogEx(INPLACE, "Chunk [%d/%d]", key_offset, keycount);
|
||||
break;
|
||||
}
|
||||
case 99: {
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// both keys found.
|
||||
if (found_key) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
t1 = msclock() - t1;
|
||||
|
@ -3288,7 +3398,6 @@ static int CmdHFiClassPermuteKey(const char *Cmd) {
|
|||
|
||||
uint8_t key[8] = {0};
|
||||
uint8_t data[16] = {0};
|
||||
bool isReverse = false;
|
||||
int len = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -3305,7 +3414,7 @@ static int CmdHFiClassPermuteKey(const char *Cmd) {
|
|||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
isReverse = arg_get_lit(ctx, 1);
|
||||
bool isReverse = arg_get_lit(ctx, 1);
|
||||
|
||||
CLIGetHexWithReturn(ctx, 2, data, &len);
|
||||
|
||||
|
@ -3327,6 +3436,28 @@ static int CmdHFiClassPermuteKey(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFiClassAutopwn(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass autopwn",
|
||||
"Tries to check keys, if found, dump card and save file",
|
||||
"hf iclass autopwn\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// Check keys.
|
||||
|
||||
// dump
|
||||
|
||||
PrintAndLogEx(INFO, "to be implemented");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
|
@ -3341,7 +3472,8 @@ static command_t CommandTable[] = {
|
|||
{"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write Picopass / iCLASS block"},
|
||||
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"},
|
||||
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
|
||||
{"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "[options..] Automatic key recovery tool for iCLASS"},
|
||||
{"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "[options..] Check keys"},
|
||||
{"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"},
|
||||
{"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
|
||||
|
|
|
@ -215,15 +215,20 @@ int infoHF_ST(void) {
|
|||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (resplen < 2)
|
||||
if (resplen < 2) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -235,12 +240,15 @@ int infoHF_ST(void) {
|
|||
int aSELECT_FILE_CC_n = 0;
|
||||
param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
|
||||
res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -248,12 +256,15 @@ int infoHF_ST(void) {
|
|||
int aREAD_CC_n = 0;
|
||||
param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
|
||||
res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -265,12 +276,15 @@ int infoHF_ST(void) {
|
|||
int aSELECT_FILE_SYS_n = 0;
|
||||
param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
|
||||
res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -280,12 +294,15 @@ int infoHF_ST(void) {
|
|||
int aREAD_SYS_n = 0;
|
||||
param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
|
||||
res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
print_st_system_info(response, resplen - 2);
|
||||
|
@ -377,15 +394,20 @@ static int cmd_hf_st_ndef(const char *Cmd) {
|
|||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (resplen < 2)
|
||||
if (resplen < 2) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -397,12 +419,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
|
|||
int aSELECT_FILE_NDEF_n = 0;
|
||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -412,8 +437,10 @@ static int cmd_hf_st_ndef(const char *Cmd) {
|
|||
int aVERIFY_n = 0;
|
||||
param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw == 0x6300) {
|
||||
|
@ -421,12 +448,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
|
|||
param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
@ -437,12 +467,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
|
|||
int aREAD_NDEF_n = 0;
|
||||
param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
|
||||
res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -490,25 +523,23 @@ static int cmd_hf_st_protect(const char *Cmd) {
|
|||
if (enable_protection && disable_protection) {
|
||||
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
if (enable_protection) {
|
||||
state[0] = 0x28;
|
||||
}
|
||||
if (disable_protection) {
|
||||
state[0] = 0x26;
|
||||
}
|
||||
}
|
||||
if (enable_protection) {
|
||||
state[0] = 0x28;
|
||||
}
|
||||
|
||||
if (disable_protection) {
|
||||
state[0] = 0x26;
|
||||
}
|
||||
|
||||
if (read_protection && write_protection) {
|
||||
PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
if (read_protection) {
|
||||
state[2] = 0x01;
|
||||
}
|
||||
if (write_protection) {
|
||||
state[2] = 0x02;
|
||||
}
|
||||
}
|
||||
if (read_protection) {
|
||||
state[2] = 0x01;
|
||||
}
|
||||
if (write_protection) {
|
||||
state[2] = 0x02;
|
||||
}
|
||||
|
||||
if (pwdlen != 16) {
|
||||
|
@ -526,15 +557,20 @@ static int cmd_hf_st_protect(const char *Cmd) {
|
|||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (resplen < 2)
|
||||
if (resplen < 2) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -546,12 +582,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
|
|||
int aSELECT_FILE_NDEF_n = 0;
|
||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -562,12 +601,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
|
|||
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -578,12 +620,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
|
|||
param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
|
||||
memcpy(aPROTECT + aPROTECT_n, state, statelen);
|
||||
res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -629,15 +674,14 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
if (change_read_password && change_write_password) {
|
||||
PrintAndLogEx(ERR, "Must specify either read or write, not both");
|
||||
return PM3_EINVARG;
|
||||
} else {
|
||||
if (change_read_password) {
|
||||
changePwd[2] = 0x01;
|
||||
}
|
||||
if (change_write_password) {
|
||||
changePwd[2] = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if (change_read_password) {
|
||||
changePwd[2] = 0x01;
|
||||
}
|
||||
if (change_write_password) {
|
||||
changePwd[2] = 0x02;
|
||||
}
|
||||
|
||||
if (pwdlen != 16) {
|
||||
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
|
||||
return PM3_EINVARG;
|
||||
|
@ -657,15 +701,20 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (resplen < 2)
|
||||
if (resplen < 2) {
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -677,12 +726,15 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
int aSELECT_FILE_NDEF_n = 0;
|
||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -693,12 +745,15 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
|
||||
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
|
||||
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -711,12 +766,15 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
|
||||
memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
|
||||
res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res)
|
||||
if (res) {
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
|
||||
|
|
|
@ -147,7 +147,7 @@ static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t col
|
|||
return true;
|
||||
}
|
||||
|
||||
#define EM_PREAMBLE_LEN 6
|
||||
#define EM_PREAMBLE_LEN 8
|
||||
// download samples from device and copy to Graphbuffer
|
||||
static bool downloadSamplesEM(void) {
|
||||
|
||||
|
@ -178,15 +178,15 @@ static int doPreambleSearch(size_t *startIdx) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// set size to 9 to only test first 3 positions for the preamble
|
||||
// set size to 11 to only test first 3 positions for the preamble
|
||||
// do not set it too long else an error preamble followed by 010 could be seen as success.
|
||||
size_t size = (9 > DemodBufferLen) ? DemodBufferLen : 9;
|
||||
size_t size = (11 > DemodBufferLen) ? DemodBufferLen : 11;
|
||||
*startIdx = 0;
|
||||
// skip first two 0 bits as they might have been missed in the demod
|
||||
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 1, 0, 1, 0};
|
||||
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 1, 0, 1, 0};
|
||||
|
||||
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
uint8_t errpreamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 0, 1};
|
||||
uint8_t errpreamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 0, 0, 0, 1};
|
||||
if (!preambleSearchEx(DemodBuffer, errpreamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
|
||||
return PM3_ESOFT;
|
||||
|
@ -361,6 +361,29 @@ static int demodEM4x05resp(uint32_t *word, bool onlyPreamble) {
|
|||
|
||||
//////////////// 4205 / 4305 commands
|
||||
|
||||
static int EM4x05Login_ext(uint32_t pwd) {
|
||||
|
||||
struct {
|
||||
uint32_t password;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_LOGIN, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_LOGIN, &resp, 10000)) {
|
||||
PrintAndLogEx(WARNING, "(EM4x05Login_ext) timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (downloadSamplesEM() == false) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
uint32_t word;
|
||||
return demodEM4x05resp(&word, true);
|
||||
}
|
||||
|
||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) {
|
||||
|
||||
struct {
|
||||
|
@ -438,7 +461,6 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
if (EM4x05IsBlock0(&block0) == false)
|
||||
return PM3_ESOFT;
|
||||
|
||||
bool needReadPwd = true;
|
||||
uint8_t bytes[4] = {0};
|
||||
uint32_t data[16];
|
||||
|
||||
|
@ -456,28 +478,32 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
em_tech_type_t card_type = em_get_card_type(block0);
|
||||
|
||||
PrintAndLogEx(INFO, "Found a " _GREEN_("%s") " tag", em_get_card_str(block0));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if the password is correct
|
||||
status = EM4x05Login_ext(pwd);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Password is " _GREEN_("correct"));
|
||||
} else if (status == PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "Password is " _RED_("incorrect") ", will try without password");
|
||||
usePwd = false;
|
||||
} else if (status != PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "Login attempt: No answer from tag");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Addr | data | ascii |lck| info");
|
||||
PrintAndLogEx(INFO, "-----+----------+-------+---+-----");
|
||||
|
||||
if ( card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
|
@ -503,14 +529,9 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else {
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
|
@ -550,21 +571,10 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
} else if (card_type == EM_4X69) {
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
|
@ -580,14 +590,9 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||
}
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||
} else {
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||
|
@ -1100,8 +1105,6 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
uint8_t addr = 4;
|
||||
uint32_t word = 0;
|
||||
bool found = false;
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
|
@ -1111,10 +1114,12 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
uint32_t pwd = lf_t55xx_white_pwdgen(card_id & 0xFFFFFFFF);
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", pwd);
|
||||
|
||||
int status = EM4x05ReadWord_ext(addr, pwd, true, &word);
|
||||
int status = EM4x05Login_ext(pwd);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
|
||||
found = true;
|
||||
} else if (status != PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "No answer from tag");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1129,6 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
|
||||
word = 0;
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
|
@ -1153,11 +1157,13 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
|
||||
|
||||
int status = EM4x05ReadWord_ext(addr, curr_password, 1, &word);
|
||||
int status = EM4x05Login_ext(curr_password);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
found = true;
|
||||
break;
|
||||
} else if (status != PM3_EFAILED) {
|
||||
PrintAndLogEx(WARNING, "No answer from tag");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1351,7 +1357,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
uint32_t soon = 0;
|
||||
uint32_t late = 0;
|
||||
|
||||
em4x05_unlock_item_t flipped[64];
|
||||
em4x05_unlock_item_t flipped[64] ={{0,0}};
|
||||
|
||||
//
|
||||
// main loop
|
||||
|
|
|
@ -156,26 +156,36 @@ static int CmdMotorolaClone(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola clone",
|
||||
"Enables cloning of Motorola card with specified uid onto T55x7\n"
|
||||
"defaults to 64.",
|
||||
"lf motorola clone a0000000a0002021"
|
||||
"clone Motorola UID to T55x7 or Q5/T5555 tag\n"
|
||||
"defaults to 64 bit format",
|
||||
"lf motorola clone -r a0000000a0002021"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
|
||||
arg_strx1("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIGetHexWithReturn(ctx, 1, data, &datalen);
|
||||
bool is_t5555 = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
// data[0] = T5555_FIXED | T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
|
||||
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
|
||||
|
||||
// config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag with RawID %s", sprint_hex(data, datalen));
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag");
|
||||
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
else
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
|
||||
|
||||
blocks[1] = bytes_to_num(data, 4);
|
||||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
|
||||
|
|
|
@ -60,7 +60,9 @@ extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, char
|
|||
if (getenv("DISPLAY") == NULL)
|
||||
return;
|
||||
#endif
|
||||
#if QT_VERSION >= 0x050100
|
||||
qunsetenv("SESSION_MANAGER");
|
||||
#endif
|
||||
main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, stayInCommandLoop);
|
||||
gui = new ProxGuiQT(argc, argv, main_loop_thread);
|
||||
}
|
||||
|
|
|
@ -496,6 +496,7 @@ typedef struct {
|
|||
#define CMD_LF_T55XX_RESET_READ 0x0216
|
||||
#define CMD_LF_PCF7931_READ 0x0217
|
||||
#define CMD_LF_PCF7931_WRITE 0x0223
|
||||
#define CMD_LF_EM4X_LOGIN 0x0229
|
||||
#define CMD_LF_EM4X_READWORD 0x0218
|
||||
#define CMD_LF_EM4X_WRITEWORD 0x0219
|
||||
#define CMD_LF_EM4X_PROTECTWORD 0x021B
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue