Merge branch 'master' into allin
update
This commit is contained in:
@@ -1638,6 +1638,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
bool isMifareDESFire = false;
|
||||
bool isMifarePlus = false;
|
||||
bool isMifareUltralight = false;
|
||||
bool isST = false;
|
||||
int nxptype = MTNONE;
|
||||
|
||||
if (card.uidlen <= 4) {
|
||||
@@ -1657,6 +1658,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
|
||||
|
||||
switch (card.uid[0]) {
|
||||
case 0x02: // ST
|
||||
isST = true;
|
||||
break;
|
||||
case 0x04: // NXP
|
||||
nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]));
|
||||
|
||||
@@ -1679,9 +1683,13 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
} else if ((card.uid[1] & 0xF0) == 0x70) {
|
||||
printTag("my-d(tm) move lean SLE 66R01L");
|
||||
}
|
||||
isMifareUltralight = true;
|
||||
isMifareClassic = false;
|
||||
|
||||
if (card.sak == 0x88) {
|
||||
printTag("Infineon MIFARE CLASSIC 1K");
|
||||
isMifareUltralight = false;
|
||||
isMifareClassic = true;
|
||||
}
|
||||
getTagLabel(card.uid[0], card.uid[1]);
|
||||
break;
|
||||
@@ -2018,6 +2026,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
if (isMifareDESFire && isMagic == 0)
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
|
||||
|
||||
if (isST)
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
|
||||
|
||||
DropField();
|
||||
return select_status;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||
// Modified 2018 iceman
|
||||
// Modified 2018, 2020 iceman
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
@@ -32,7 +32,7 @@ static int usage_hf_14b_info(void) {
|
||||
PrintAndLogEx(NORMAL, " s silently");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b info"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_reader(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b reader [h] [s]");
|
||||
@@ -41,7 +41,7 @@ static int usage_hf_14b_reader(void) {
|
||||
PrintAndLogEx(NORMAL, " s silently");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b reader"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_raw(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b raw [-h] [-r] [-c] [-p] [-s / -ss] [-t] <0A 0B 0C ... hex>");
|
||||
@@ -55,7 +55,7 @@ static int usage_hf_14b_raw(void) {
|
||||
PrintAndLogEx(NORMAL, " -t timeout in ms");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b raw -s -c -p 0200a40400"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer.");
|
||||
@@ -65,7 +65,7 @@ static int usage_hf_14b_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sniff"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Emulating ISO/IEC 14443 type B tag with 4 UID / PUPI");
|
||||
@@ -76,7 +76,7 @@ static int usage_hf_14b_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sim"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sim u 11223344"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_read_srx(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b sriread [h] <1|2>");
|
||||
@@ -86,45 +86,38 @@ static int usage_hf_14b_read_srx(void) {
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriread 1"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriread 2"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_write_srx(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> <BLOCK> <DATA>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> <block> <data>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512");
|
||||
PrintAndLogEx(NORMAL, " <block> BLOCK number depends on tag, special block == FF");
|
||||
PrintAndLogEx(NORMAL, " <block> (hex) block number depends on tag, special block == FF");
|
||||
PrintAndLogEx(NORMAL, " <data> hex bytes of data to be written");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 1 7F 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 1 FF 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 2 15 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 2 FF 11223344"));
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_14b_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n"
|
||||
"If memory size defaults to SRI4K if auto detect fails.\n"
|
||||
"\n"
|
||||
"Usage: hf 14b dump [h] [card memory] <f filename> \n"
|
||||
"Usage: hf 14b dump [h] <f filename> \n"
|
||||
"Options:\n"
|
||||
"\th this help\n"
|
||||
"\t[card memory] 1 = SRIX4K (default), 2 = SRI512\n"
|
||||
"\tf <name> filename, if no <name> UID will be used as filename\n"
|
||||
"\tf <name> (optional) filename, if no <name> UID will be used as filename\n"
|
||||
"\n"
|
||||
"Example:\n"
|
||||
_YELLOW_("\thf 14b dump f\n")
|
||||
_YELLOW_("\thf 14b dump 2 f mydump")
|
||||
_YELLOW_("\thf 14b dump\n")
|
||||
_YELLOW_("\thf 14b dump f mydump")
|
||||
);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
static void switch_on_field_14b(void) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT, 0, 0, NULL, 0);
|
||||
}
|
||||
*/
|
||||
|
||||
static int switch_off_field_14b(void) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
@@ -311,12 +304,14 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
||||
if (card == NULL)
|
||||
return false;
|
||||
|
||||
int status = 0;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
|
||||
uint8_t status = resp.oldarg[0];
|
||||
status = resp.oldarg[0];
|
||||
if (status == 0) {
|
||||
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
return true;
|
||||
@@ -328,7 +323,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
|
||||
uint8_t status = resp.oldarg[0];
|
||||
status = resp.oldarg[0];
|
||||
if (status == 0) {
|
||||
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
return true;
|
||||
@@ -345,7 +340,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
||||
// 4 = bit rate capacity
|
||||
// 5 = max frame size / -4 info
|
||||
// 6 = FWI / Coding options
|
||||
static void print_atqb_resp(uint8_t *data, uint8_t cid) {
|
||||
static int print_atqb_resp(uint8_t *data, uint8_t cid) {
|
||||
//PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(data+1,4));
|
||||
PrintAndLogEx(SUCCESS, " App Data: %s", sprint_hex(data, 4));
|
||||
PrintAndLogEx(SUCCESS, " Protocol: %s", sprint_hex(data + 4, 3));
|
||||
@@ -387,7 +382,7 @@ static void print_atqb_resp(uint8_t *data, uint8_t cid) {
|
||||
PrintAndLogEx(SUCCESS, "Tag :");
|
||||
PrintAndLogEx(SUCCESS, " Max Buf Length: %u (MBLI) %s", cid >> 4, (cid & 0xF0) ? "" : "chained frames not supported");
|
||||
PrintAndLogEx(SUCCESS, " CID : %u", cid & 0x0f);
|
||||
return;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// get SRx chip model (from UID) // from ST Microelectronics
|
||||
@@ -425,66 +420,209 @@ static char *get_ST_Chip_Model(uint8_t data) {
|
||||
return retStr;
|
||||
}
|
||||
|
||||
// REMAKE:
|
||||
/*
|
||||
static int print_ST_Lock_info(uint8_t model) {
|
||||
static char *get_st_lock_info(uint8_t model, uint8_t *lockbytes, uint8_t blk) {
|
||||
|
||||
PrintAndLogEx(NORMAL, "Chip Write Protection Bits:");
|
||||
// now interpret the data
|
||||
switch (model){
|
||||
case 0x0: //fall through (SRIX4K special)
|
||||
case 0x3: //fall through (SRIx4K)
|
||||
case 0x7: // (SRI4K)
|
||||
//only need data[3]
|
||||
blk1 = 9;
|
||||
PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+3, 1));
|
||||
PrintAndLogEx(NORMAL, " 07/08:%slocked", (data[3] & 1) ? " not " : " " );
|
||||
for (uint8_t i = 1; i<8; i++){
|
||||
PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[3] & (1 << i)) ? " not " : " " );
|
||||
blk1++;
|
||||
static char str[16];
|
||||
char *s = str;
|
||||
sprintf(s, " ");
|
||||
|
||||
if (blk > 15) {
|
||||
return s;
|
||||
}
|
||||
break;
|
||||
case 0x4: //fall through (SRIX512)
|
||||
case 0x6: //fall through (SRI512)
|
||||
case 0xC: // (SRT512)
|
||||
//need data[2] and data[3]
|
||||
blk1 = 0;
|
||||
PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 2));
|
||||
for (uint8_t b=2; b<4; b++){
|
||||
for (uint8_t i=0; i<8; i++){
|
||||
PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " );
|
||||
blk1++;
|
||||
|
||||
uint8_t mask = 0;
|
||||
switch (model) {
|
||||
case 0x0: // SRIX4K special
|
||||
case 0x3: // SRIx4K
|
||||
case 0x7: { // SRI4K
|
||||
//only need data[3]
|
||||
switch(blk) {
|
||||
case 7:
|
||||
case 8:
|
||||
mask = 0x01;
|
||||
break;
|
||||
case 9:
|
||||
mask = 0x02;
|
||||
break;
|
||||
case 10:
|
||||
mask = 0x04;
|
||||
break;
|
||||
case 11:
|
||||
mask = 0x08;
|
||||
break;
|
||||
case 12:
|
||||
mask = 0x10;
|
||||
break;
|
||||
case 13:
|
||||
mask = 0x20;
|
||||
break;
|
||||
case 14:
|
||||
mask = 0x40;
|
||||
break;
|
||||
case 15:
|
||||
mask = 0x80;
|
||||
break;
|
||||
default:
|
||||
return s;
|
||||
}
|
||||
if ((lockbytes[1] & mask) == 0) {
|
||||
sprintf(s, _RED_("1"));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
case 0x4: // SRIX512
|
||||
case 0x6: // SRI512
|
||||
case 0xC: { // SRT512
|
||||
//need data[2] and data[3]
|
||||
uint8_t b = 1;
|
||||
switch(blk) {
|
||||
case 0:
|
||||
mask = 0x01;
|
||||
break;
|
||||
case 1:
|
||||
mask = 0x02;
|
||||
break;
|
||||
case 2:
|
||||
mask = 0x04;
|
||||
break;
|
||||
case 3:
|
||||
mask = 0x08;
|
||||
break;
|
||||
case 4:
|
||||
mask = 0x10;
|
||||
break;
|
||||
case 5:
|
||||
mask = 0x20;
|
||||
break;
|
||||
case 6:
|
||||
mask = 0x40;
|
||||
break;
|
||||
case 7:
|
||||
mask = 0x80;
|
||||
break;
|
||||
case 8:
|
||||
mask = 0x01;
|
||||
b = 0;
|
||||
break;
|
||||
case 9:
|
||||
mask = 0x02;
|
||||
b = 0;
|
||||
break;
|
||||
case 10:
|
||||
mask = 0x04;
|
||||
b = 0;
|
||||
break;
|
||||
case 11:
|
||||
mask = 0x08;
|
||||
b = 0;
|
||||
break;
|
||||
case 12:
|
||||
mask = 0x10;
|
||||
b = 0;
|
||||
break;
|
||||
case 13:
|
||||
mask = 0x20;
|
||||
b = 0;
|
||||
break;
|
||||
case 14:
|
||||
mask = 0x40;
|
||||
b = 0;
|
||||
break;
|
||||
case 15:
|
||||
mask = 0x80;
|
||||
b = 0;
|
||||
break;
|
||||
}
|
||||
if ((lockbytes[b] & mask) == 0) {
|
||||
sprintf(s, _RED_("1"));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
case 0x2: { // SR176
|
||||
//need data[2]
|
||||
switch(blk) {
|
||||
case 0:
|
||||
case 1:
|
||||
mask = 0x1;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
mask = 0x2;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
mask = 0x4;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
mask = 0x8;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
mask = 0x10;
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
mask = 0x20;
|
||||
break;
|
||||
case 12:
|
||||
case 13:
|
||||
mask = 0x40;
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
mask = 0x80;
|
||||
break;
|
||||
}
|
||||
// iceman: this is opposite! need sample to test with.
|
||||
if ((lockbytes[0] & mask)) {
|
||||
sprintf(s, _RED_("1"));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2: // (SR176)
|
||||
//need data[2]
|
||||
blk1 = 0;
|
||||
PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 1));
|
||||
for (uint8_t i = 0; i<8; i++){
|
||||
PrintAndLogEx(NORMAL, " %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " );
|
||||
blk1+=2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return rawClose();
|
||||
}
|
||||
return 1;
|
||||
return s;
|
||||
}
|
||||
*/
|
||||
|
||||
static uint8_t get_st_chipid(uint8_t *uid) {
|
||||
return uid[5] >> 2;
|
||||
}
|
||||
|
||||
static uint8_t get_st_cardsize(uint8_t *uid) {
|
||||
uint8_t chipid = get_st_chipid(uid);
|
||||
switch(chipid) {
|
||||
case 0x0:
|
||||
case 0x3:
|
||||
case 0x7:
|
||||
return 1;
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
case 0xC:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// print UID info from SRx chips (ST Microelectronics)
|
||||
static void print_st_general_info(uint8_t *data, uint8_t len) {
|
||||
//uid = first 8 bytes in data
|
||||
uint8_t mfgid = data[6];
|
||||
uint8_t chipid = get_st_chipid(data);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(SwapEndian64(data, 8, 8), len));
|
||||
PrintAndLogEx(SUCCESS, " MFG: %02X, " _YELLOW_("%s"), data[6], getTagInfo(data[6]));
|
||||
PrintAndLogEx(SUCCESS, "Chip: %02X, " _YELLOW_("%s"), data[5] >> 2, get_ST_Chip_Model(data[5] >> 2));
|
||||
PrintAndLogEx(SUCCESS, " MFG: %02X, " _YELLOW_("%s"), mfgid, getTagInfo(mfgid));
|
||||
PrintAndLogEx(SUCCESS, "Chip: %02X, " _YELLOW_("%s"), chipid, get_ST_Chip_Model(chipid));
|
||||
}
|
||||
|
||||
//05 00 00 = find one tag in field
|
||||
//1d xx xx xx xx 00 08 01 00 = attrib xx=UID (resp 10 [f9 e0])
|
||||
//a3 = ? (resp 03 [e2 c2])
|
||||
//02 = ? (resp 02 [6a d3])
|
||||
// iceman, some 14B APDU break down
|
||||
// 05 00 00 = find one tag in field
|
||||
// 1d xx xx xx xx 00 08 01 00 = attrib xx=UID (resp 10 [f9 e0])
|
||||
// a3 = ? (resp 03 [e2 c2])
|
||||
// 02 = ? (resp 02 [6a d3])
|
||||
// 022b (resp 02 67 00 [29 5b])
|
||||
// 0200a40400 (resp 02 67 00 [29 5b])
|
||||
// 0200a4040c07a0000002480300 (resp 02 67 00 [29 5b])
|
||||
@@ -494,31 +632,31 @@ static void print_st_general_info(uint8_t *data, uint8_t len) {
|
||||
// 0200a404000cd2760001354b414e4d30310000 (resp 02 6a 82 [4b 4c])
|
||||
// 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c])
|
||||
// 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c])
|
||||
//03 = ? (resp 03 [e3 c2])
|
||||
//c2 = ? (resp c2 [66 15])
|
||||
//b2 = ? (resp a3 [e9 67])
|
||||
//a2 = ? (resp 02 [6a d3])
|
||||
// 03 = ? (resp 03 [e3 c2])
|
||||
// c2 = ? (resp c2 [66 15])
|
||||
// b2 = ? (resp a3 [e9 67])
|
||||
// a2 = ? (resp 02 [6a d3])
|
||||
|
||||
// 14b get and print Full Info (as much as we know)
|
||||
static bool HF14B_Std_Info(bool verbose) {
|
||||
|
||||
bool isSuccess = false;
|
||||
bool is_success = false;
|
||||
|
||||
// 14b get and print UID only (general info)
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
return is_success;
|
||||
}
|
||||
|
||||
iso14b_card_select_t card;
|
||||
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
|
||||
uint64_t status = resp.oldarg[0];
|
||||
int status = resp.oldarg[0];
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
@@ -527,12 +665,12 @@ static bool HF14B_Std_Info(bool verbose) {
|
||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
|
||||
print_atqb_resp(card.atqb, card.cid);
|
||||
isSuccess = true;
|
||||
is_success = true;
|
||||
break;
|
||||
case 2:
|
||||
case -1:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
|
||||
break;
|
||||
case 3:
|
||||
case -2:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
|
||||
break;
|
||||
default:
|
||||
@@ -540,15 +678,14 @@ static bool HF14B_Std_Info(bool verbose) {
|
||||
break;
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
return is_success;
|
||||
}
|
||||
|
||||
// SRx get and print full info (needs more info...)
|
||||
static bool HF14B_ST_Info(bool verbose) {
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
@@ -558,33 +695,11 @@ static bool HF14B_ST_Info(bool verbose) {
|
||||
iso14b_card_select_t card;
|
||||
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
|
||||
uint64_t status = resp.oldarg[0];
|
||||
if (status > 0)
|
||||
int status = resp.oldarg[0];
|
||||
if (status < 0)
|
||||
return false;
|
||||
|
||||
print_st_general_info(card.uid, card.uidlen);
|
||||
|
||||
//add locking bit information here. uint8_t data[16] = {0x00};
|
||||
// uint8_t datalen = 2;
|
||||
// uint8_t resplen;
|
||||
// uint8_t blk1;
|
||||
// data[0] = 0x08;
|
||||
|
||||
//
|
||||
// if (model == 0x2) { //SR176 has special command:
|
||||
// data[1] = 0xf;
|
||||
// resplen = 4;
|
||||
// } else {
|
||||
// data[1] = 0xff;
|
||||
// resplen = 6;
|
||||
// }
|
||||
|
||||
// //std read cmd
|
||||
// if (HF14BCmdRaw(true, true, data, &datalen, false)==0)
|
||||
// return rawClose();
|
||||
|
||||
// if (datalen != resplen || !crc) return rawClose();
|
||||
//print_ST_Lock_info(data[5]>>2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -599,52 +714,53 @@ static int CmdHF14Binfo(const char *Cmd) {
|
||||
|
||||
static bool HF14B_ST_Reader(bool verbose) {
|
||||
|
||||
bool isSuccess = false;
|
||||
bool is_success = false;
|
||||
|
||||
// SRx get and print general info about SRx chip from UID
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
return false;
|
||||
return is_success;
|
||||
}
|
||||
|
||||
iso14b_card_select_t card;
|
||||
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
|
||||
uint64_t status = resp.oldarg[0];
|
||||
int status = resp.oldarg[0];
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
print_st_general_info(card.uid, card.uidlen);
|
||||
isSuccess = true;
|
||||
is_success = true;
|
||||
break;
|
||||
case 1:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 random chip id fail");
|
||||
break;
|
||||
case 2:
|
||||
case -1:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
|
||||
break;
|
||||
case 3:
|
||||
case -2:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
|
||||
break;
|
||||
case -3:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 random chip id fail");
|
||||
break;
|
||||
default:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select SRx failed");
|
||||
break;
|
||||
}
|
||||
return isSuccess;
|
||||
return is_success;
|
||||
}
|
||||
|
||||
static bool HF14B_Std_Reader(bool verbose) {
|
||||
|
||||
bool isSuccess = false;
|
||||
bool is_success = false;
|
||||
|
||||
// 14b get and print UID only (general info)
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
return false;
|
||||
@@ -653,7 +769,7 @@ static bool HF14B_Std_Reader(bool verbose) {
|
||||
iso14b_card_select_t card;
|
||||
memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||
|
||||
uint64_t status = resp.oldarg[0];
|
||||
int status = resp.oldarg[0];
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
@@ -662,72 +778,104 @@ static bool HF14B_Std_Reader(bool verbose) {
|
||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
|
||||
print_atqb_resp(card.atqb, card.cid);
|
||||
isSuccess = true;
|
||||
is_success = true;
|
||||
break;
|
||||
case 2:
|
||||
case -1:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
|
||||
break;
|
||||
case 3:
|
||||
case -2:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail");
|
||||
break;
|
||||
default:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed");
|
||||
break;
|
||||
}
|
||||
return isSuccess;
|
||||
return is_success;
|
||||
}
|
||||
|
||||
// test for other 14b type tags (mimic another reader - don't have tags to identify)
|
||||
static bool HF14B_Other_Reader(void) {
|
||||
static bool HF14B_Other_Reader(bool verbose) {
|
||||
|
||||
// uint8_t data[] = {0x00, 0x0b, 0x3f, 0x80};
|
||||
// uint8_t datalen = 4;
|
||||
uint8_t data[] = {0x00, 0x0b, 0x3f, 0x80};
|
||||
uint8_t datalen = 4;
|
||||
|
||||
// // 14b get and print UID only (general info)
|
||||
// uint32_t flags = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_RAW | ISO14B_APPEND_CRC;
|
||||
// 14b get and print UID only (general info)
|
||||
uint32_t flags = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_RAW | ISO14B_APPEND_CRC;
|
||||
|
||||
// clearCommandBuffer();
|
||||
// SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen);
|
||||
// PacketResponseNG resp;
|
||||
// WaitForResponse(CMD_HF_ISO14443B_COMMAND,&resp);
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen);
|
||||
|
||||
// if (datalen > 2 ) {
|
||||
// PrintAndLogEx(NORMAL, "\n14443-3b tag found:");
|
||||
// PrintAndLogEx(NORMAL, "unknown tag type answered to a 0x000b3f80 command ans:");
|
||||
// //PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen));
|
||||
// rawclose();
|
||||
// return true;
|
||||
// }
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
int status = resp.oldarg[0];
|
||||
PrintAndLogEx(DEBUG, "status %d", status);
|
||||
|
||||
// data[0] = ISO14443B_AUTHENTICATE;
|
||||
// clearCommandBuffer();
|
||||
// SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
// PacketResponseNG resp;
|
||||
// WaitForResponse(CMD_HF_ISO14443B_COMMAND, &resp);
|
||||
if (status == 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "unknown tag type answered to a 0x000b3f80 command ans:");
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
} else if (status > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "unknown tag type answered to a 0x000b3f80 command ans:");
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (datalen > 0) {
|
||||
// PrintAndLogEx(NORMAL, "\n14443-3b tag found:");
|
||||
// PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0A command ans:");
|
||||
// // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen));
|
||||
// rawClose();
|
||||
// return true;
|
||||
// }
|
||||
data[0] = ISO14443B_AUTHENTICATE;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
status = resp.oldarg[0];
|
||||
PrintAndLogEx(DEBUG, "status %d", status);
|
||||
|
||||
// data[0] = ISO14443B_RESET;
|
||||
// clearCommandBuffer();
|
||||
// SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
// PacketResponseNG resp;
|
||||
// WaitForResponse(CMD_HF_ISO14443B_COMMAND, &resp);
|
||||
if (status == 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "Unknown tag type answered to a 0x0A command ans:");
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
} else if (status > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "unknown tag type answered to a 0x0A command ans:");
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (datalen > 0) {
|
||||
// PrintAndLogEx(NORMAL, "\n14443-3b tag found:");
|
||||
// PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0C command ans:");
|
||||
// PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen));
|
||||
// rawClose();
|
||||
// return true;
|
||||
// }
|
||||
data[0] = ISO14443B_RESET;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
status = resp.oldarg[0];
|
||||
PrintAndLogEx(DEBUG, "status %d", status);
|
||||
|
||||
// rawClose();
|
||||
if (status == 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "Unknown tag type answered to a 0x0C command ans:");
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
} else if (status > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\n14443-3b tag found:");
|
||||
PrintAndLogEx(SUCCESS, "unknown tag type answered to a 0x0C command ans:");
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, status));
|
||||
switch_off_field_14b();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -832,10 +980,6 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0, cardtype = 1;
|
||||
uint16_t cardsize = 0;
|
||||
uint8_t blocks = 0;
|
||||
iso14b_card_select_t card;
|
||||
|
||||
if (strlen(Cmd) < 1) return usage_hf_14b_dump();
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
@@ -846,20 +990,27 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
if (cmdp == 0) {
|
||||
cardtype = param_get8ex(Cmd, cmdp, 1, 10);
|
||||
cmdp++;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors) return usage_hf_14b_dump();
|
||||
|
||||
iso14b_card_select_t card;
|
||||
if (get_14b_UID(&card) == false) {
|
||||
PrintAndLogEx(WARNING, "No tag found.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// detect cardsize
|
||||
// 1 = 4096
|
||||
// 2 = 512
|
||||
cardtype = get_st_cardsize(card.uid);
|
||||
|
||||
uint8_t blocks = 0;
|
||||
switch (cardtype) {
|
||||
case 2:
|
||||
cardsize = (512 / 8) + 4;
|
||||
@@ -872,25 +1023,22 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_14b_UID(&card) == false) {
|
||||
PrintAndLogEx(WARNING, "No tag found.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
fptr += sprintf(fptr, "hf-14b-");
|
||||
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
|
||||
FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), "-dump", card.uidlen);
|
||||
}
|
||||
|
||||
// detect blocksize from card :)
|
||||
PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprint_hex(card.uid, card.uidlen));
|
||||
uint8_t chipid = get_st_chipid(card.uid);
|
||||
PrintAndLogEx(SUCCESS, "Found a " _GREEN_("%s") " tag", get_ST_Chip_Model(chipid));
|
||||
|
||||
// detect blocksize from card :)
|
||||
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(card.uid, card.uidlen, 8), card.uidlen));
|
||||
|
||||
uint8_t data[cardsize];
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
int blocknum = 0;
|
||||
uint8_t *recv = NULL;
|
||||
int status = 0;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
@@ -898,14 +1046,17 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
|
||||
//select
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
|
||||
if (resp.oldarg[0]) {
|
||||
PrintAndLogEx(INFO, "failed to select %" PRId64 " | %" PRId64, resp.oldarg[0], resp.oldarg[1]);
|
||||
status = resp.oldarg[0];
|
||||
if (status < 0) {
|
||||
PrintAndLogEx(FAILED, "failed to select arg0[%" PRId64 "] arg1 [%" PRId64 "]", resp.oldarg[0], resp.oldarg[1]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t req[2] = {ISO14443B_READ_BLK};
|
||||
PrintAndLogEx(INFO, "." NOLF);
|
||||
|
||||
uint8_t req[2] = {ISO14443B_READ_BLK};
|
||||
int blocknum = 0;
|
||||
for (int retry = 0; retry < 5; retry++) {
|
||||
|
||||
req[1] = blocknum;
|
||||
@@ -915,8 +1066,9 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
|
||||
|
||||
uint8_t status = resp.oldarg[0] & 0xFF;
|
||||
if (status > 0) {
|
||||
status = resp.oldarg[0];
|
||||
if (status < 0) {
|
||||
PrintAndLogEx(FAILED, "retrying one more time");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -930,8 +1082,8 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
|
||||
memcpy(data + (blocknum * 4), resp.data.asBytes, 4);
|
||||
|
||||
// last read.
|
||||
if (blocknum == 0xFF) {
|
||||
//last read.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -943,31 +1095,46 @@ static int CmdHF14BDump(const char *Cmd) {
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (blocknum != 0xFF) {
|
||||
PrintAndLogEx(NORMAL, "Dump failed");
|
||||
PrintAndLogEx(FAILED, "Dump failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "block# | data | ascii");
|
||||
PrintAndLogEx(NORMAL, "---------+--------------+----------");
|
||||
PrintAndLogEx(DEBUG, "systemblock : %s", sprint_hex(data + (blocknum * 4), 4));
|
||||
PrintAndLogEx(DEBUG, " otp lock : %02x %02x", data[(blocknum * 4)], data[(blocknum * 4) + 1]);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, " block# | data |lck| ascii");
|
||||
PrintAndLogEx(INFO, "---------+--------------+---+----------");
|
||||
|
||||
for (int i = 0; i <= blocks; i++) {
|
||||
PrintAndLogEx(NORMAL,
|
||||
"%3d/0x%02X | %s | %s",
|
||||
PrintAndLogEx(INFO,
|
||||
"%3d/0x%02X | %s | %s | %s",
|
||||
i,
|
||||
i,
|
||||
sprint_hex(data + (i * 4), 4),
|
||||
get_st_lock_info(chipid, data + (blocknum * 4), i),
|
||||
sprint_ascii(data + (i * 4), 4)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
PrintAndLogEx(INFO,
|
||||
"%3d/0x%02X | %s | %s | %s",
|
||||
0xFF,
|
||||
0xFF,
|
||||
sprint_hex(data + (0xFF * 4), 4),
|
||||
get_st_lock_info(chipid, data + (blocknum * 4), 0xFF),
|
||||
sprint_ascii(data + (0xFF * 4), 4)
|
||||
);
|
||||
PrintAndLogEx(INFO, "---------+--------------+---+----------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
|
||||
// save to file
|
||||
size_t datalen = (blocks + 1) * 4;
|
||||
saveFileEML(filename, data, datalen, 4);
|
||||
saveFile(filename, ".bin", data, datalen);
|
||||
@@ -1112,10 +1279,12 @@ int CmdHF14B(const char *Cmd) {
|
||||
int infoHF14B(bool verbose) {
|
||||
|
||||
// try std 14b (atqb)
|
||||
if (HF14B_Std_Info(verbose)) return 1;
|
||||
if (HF14B_Std_Info(verbose))
|
||||
return 1;
|
||||
|
||||
// try ST 14b
|
||||
if (HF14B_ST_Info(verbose)) return 1;
|
||||
if (HF14B_ST_Info(verbose))
|
||||
return 1;
|
||||
|
||||
// try unknown 14b read commands (to be identified later)
|
||||
// could be read of calypso, CEPAS, moneo, or pico pass.
|
||||
@@ -1127,14 +1296,17 @@ int infoHF14B(bool verbose) {
|
||||
int readHF14B(bool verbose) {
|
||||
|
||||
// try std 14b (atqb)
|
||||
if (HF14B_Std_Reader(verbose)) return 1;
|
||||
if (HF14B_Std_Reader(verbose))
|
||||
return 1;
|
||||
|
||||
// try ST Microelectronics 14b
|
||||
if (HF14B_ST_Reader(verbose)) return 1;
|
||||
if (HF14B_ST_Reader(verbose))
|
||||
return 1;
|
||||
|
||||
// try unknown 14b read commands (to be identified later)
|
||||
// could be read of calypso, CEPAS, moneo, or pico pass.
|
||||
if (HF14B_Other_Reader()) return 1;
|
||||
if (HF14B_Other_Reader(verbose))
|
||||
return 1;
|
||||
|
||||
if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found");
|
||||
return 0;
|
||||
|
||||
@@ -321,6 +321,7 @@ typedef enum {
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
NTAG413DNA,
|
||||
} nxp_cardtype_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -347,9 +348,9 @@ static char *getCardSizeStr(uint8_t fsize) {
|
||||
|
||||
// is LSB set?
|
||||
if (fsize & 1)
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize);
|
||||
snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -377,18 +378,22 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
|
||||
char *retStr = buf;
|
||||
|
||||
if (major == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor);
|
||||
else if (major == 0x01 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor);
|
||||
else if (major == 0x12 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor);
|
||||
else if (major == 0x33 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor);
|
||||
else if (major == 0x30 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor);
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor);
|
||||
else if (major == 0x10 && minor == 0x00)
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("NTAG413DNA") ")", major, minor);
|
||||
else
|
||||
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor);
|
||||
return buf;
|
||||
|
||||
//04 01 01 01 00 1A 05
|
||||
}
|
||||
|
||||
static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) {
|
||||
@@ -648,9 +653,10 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
||||
return DESFIRE_EV3;
|
||||
if (major == 0x30 && minor == 0x00)
|
||||
return DESFIRE_LIGHT;
|
||||
if (major == 0x11 && minor == 0x00)
|
||||
if (major == 0x11 && minor == 0x00)
|
||||
return PLUS_EV1;
|
||||
|
||||
if (major == 0x10 && minor == 0x00)
|
||||
return NTAG413DNA;
|
||||
return DESFIRE_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -3318,7 +3324,10 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||
if (major == 0 && minor == 2)
|
||||
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
|
||||
|
||||
if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) {
|
||||
if (cardtype == DESFIRE_EV2 ||
|
||||
cardtype == DESFIRE_LIGHT ||
|
||||
cardtype == DESFIRE_EV3 ||
|
||||
cardtype == NTAG413DNA) {
|
||||
// Signature originality check
|
||||
uint8_t signature[56] = {0};
|
||||
size_t signature_len = 0;
|
||||
|
||||
@@ -272,14 +272,16 @@ uint32_t UL_TYPES_ARRAY[] = {
|
||||
UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG,
|
||||
NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216,
|
||||
MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL,
|
||||
UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT
|
||||
UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT,
|
||||
NTAG_213_C
|
||||
};
|
||||
|
||||
uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
|
||||
MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203,
|
||||
MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, MAX_NTAG_215, MAX_NTAG_216,
|
||||
MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS,
|
||||
MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213
|
||||
MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213,
|
||||
MAX_NTAG_213
|
||||
};
|
||||
|
||||
//------------------------------------
|
||||
@@ -685,6 +687,8 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_F)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_C)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, "");
|
||||
else if (tagtype & NTAG_213_TT)
|
||||
PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, "");
|
||||
else if (tagtype & NTAG_215)
|
||||
@@ -1112,6 +1116,7 @@ uint32_t GetHF14AMfU_Type(void) {
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = NTAG_210; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; }
|
||||
else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213_F; break; }
|
||||
@@ -1338,7 +1343,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
}
|
||||
|
||||
// NTAG counters?
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if (ntag_print_counter()) {
|
||||
// failed - re-select
|
||||
if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
@@ -1346,7 +1351,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
}
|
||||
|
||||
// Read signature
|
||||
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) {
|
||||
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) {
|
||||
uint8_t ulev1_signature[32] = {0x00};
|
||||
status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature));
|
||||
if (status == -1) {
|
||||
@@ -1461,12 +1466,20 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||
if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
if (len < 1) PrintAndLogEx(WARNING, _YELLOW_("password not known"));
|
||||
if (len < 1) {
|
||||
PrintAndLogEx(WARNING, _YELLOW_("password not known"));
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
}
|
||||
out:
|
||||
DropField();
|
||||
if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info");
|
||||
if (locked) {
|
||||
PrintAndLogEx(INFO, "\nTag appears to be locked, try using the key to get more info");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -2032,7 +2045,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||
uint8_t n = 0;
|
||||
|
||||
// NTAG has 1 counter, at 0x02
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) {
|
||||
n = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef enum TAGTYPE_UL {
|
||||
UL_EV1 = 0x1000000,
|
||||
UL_NANO_40 = 0x2000000,
|
||||
NTAG_213_TT = 0x4000000,
|
||||
NTAG_213_C = 0x8000000,
|
||||
UL_MAGIC = UL | MAGIC,
|
||||
UL_C_MAGIC = UL_C | MAGIC,
|
||||
UL_ERROR = 0xFFFFFF,
|
||||
|
||||
@@ -715,18 +715,20 @@ void pm3_version(bool verbose, bool oneliner) {
|
||||
PrintAndLogEx(NORMAL, "%s", temp);
|
||||
PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
|
||||
|
||||
if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) {
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4") " ]");
|
||||
PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4 Extras") " ]");
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
|
||||
if (IfPm3FpcUsartDevFromUsb()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present"));
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
|
||||
if (IfPm3Rdv4Fw() == false ){
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3OTHER"));
|
||||
if (IfPm3FpcUsartHost()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", _GREEN_("present"));
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3RDV4"));
|
||||
PrintAndLogEx(NORMAL, " external flash...................%s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader.................%s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
}
|
||||
if (IfPm3FpcUsartDevFromUsb()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer..........%s", _GREEN_("present"));
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "fileutils.h" // loadDictionary
|
||||
#include "util_posix.h"
|
||||
#include "cmdlf.h" // for lf sniff
|
||||
#include "generator.h"
|
||||
|
||||
// Some defines for readability
|
||||
#define T55XX_DLMODE_FIXED 0 // Default Mode
|
||||
@@ -254,16 +255,18 @@ static int usage_t55xx_chk(void) {
|
||||
PrintAndLogEx(NORMAL, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may brick non-password protected chips!");
|
||||
PrintAndLogEx(NORMAL, "Try to reading block 7 before\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx chk [h] [m] [r <mode>] [f <*.dic>]");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx chk [h] [m] [r <mode>] [f <*.dic>] [e <em4100 id>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " m - use dictionary from flashmemory\n");
|
||||
print_usage_t55xx_downloadlink(T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
|
||||
PrintAndLogEx(NORMAL, " f <*.dic> - loads a default keys dictionary file <*.dic>");
|
||||
PrintAndLogEx(NORMAL, " e <EM4100> - will try the calculated password from some cloners based on EM4100 ID");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk m"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk f t55xx_default_pwds"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx chk e aa11223344"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
@@ -3003,6 +3006,9 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
int dl_mode; // to try each downlink mode for each password
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool useCardPassword = false;
|
||||
uint32_t cardPassword = 0x00;
|
||||
uint64_t cardID = 0x00;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
@@ -3028,6 +3034,14 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
use_pwd_file = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'e':
|
||||
// White cloner password based on EM4100 ID
|
||||
useCardPassword = true;
|
||||
cardID = param_get64ex(Cmd,cmdp + 1,0,16);
|
||||
uint32_t card32Bit = cardID & 0xFFFFFFFF;
|
||||
cardPassword = lf_t55xx_white_pwdgen (card32Bit);
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
@@ -3090,7 +3104,28 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (use_pwd_file) {
|
||||
// try calculated password
|
||||
if (useCardPassword) {
|
||||
|
||||
PrintAndLogEx(INFO, "Testing %08"PRIX32" generated ", cardPassword);
|
||||
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
|
||||
|
||||
if (!AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, cardPassword, dl_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
}
|
||||
|
||||
if (!try_all_dl_modes) // Exit loop if not trying all downlink modes
|
||||
dl_mode = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!found) && (use_pwd_file)) {
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
@@ -3135,9 +3170,10 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||
dl_mode = 4;
|
||||
}
|
||||
}
|
||||
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
}
|
||||
|
||||
if (!found) PrintAndLogEx(WARNING, "Check pwd failed");
|
||||
|
||||
free(keyBlock);
|
||||
|
||||
out:
|
||||
|
||||
@@ -26,6 +26,12 @@ bool IfPm3Present(void) {
|
||||
return session.pm3_present;
|
||||
}
|
||||
|
||||
bool IfPm3Rdv4Fw(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
return (pm3_capabilities.compiled_with_flash) || (pm3_capabilities.compiled_with_smartcard);
|
||||
}
|
||||
|
||||
bool IfPm3Flash(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef struct command_s {
|
||||
// helpers for command_t IsAvailable
|
||||
bool AlwaysAvailable(void);
|
||||
bool IfPm3Present(void);
|
||||
bool IfPm3Rdv4Fw(void);
|
||||
bool IfPm3Flash(void);
|
||||
bool IfPm3Smartcard(void);
|
||||
bool IfPm3FpcUsart(void);
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "flash.h"
|
||||
#include "preferences.h"
|
||||
|
||||
#define BANNERMSG1 ""
|
||||
#define BANNERMSG2 " :snowflake: bleeding edge :coffee:"
|
||||
#define BANNERMSG1 " Iceman :coffee:"
|
||||
#define BANNERMSG2 " :snowflake: bleeding edge"
|
||||
#define BANNERMSG3 " https://github.com/rfidresearchgroup/proxmark3/"
|
||||
|
||||
typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode;
|
||||
|
||||
Reference in New Issue
Block a user