mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-09-11 18:29:22 -07:00
Add ISO15693 magic 'V3' tag support (hf 15 csetuid --v3 / hf 15 cfinalize)
This commit is contained in:
+181
-13
@@ -3309,6 +3309,79 @@ static int CmdHF15Restore(const char *Cmd) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// ISO15693 magic "V3" tag support
|
||||
#define ISO15_MAGIC_V3_BLK_UID_LO 0x10
|
||||
#define ISO15_MAGIC_V3_BLK_UID_HI 0x11
|
||||
#define ISO15_MAGIC_V3_BLK_SIG_A 0x14
|
||||
#define ISO15_MAGIC_V3_BLK_SIG_B 0x15
|
||||
|
||||
// signature check in block 0x14/0x15
|
||||
static const uint8_t iso15_magic_v3_sig_a[4] = {0xA5, 0x2B, 0x44, 0x2C};
|
||||
static const uint8_t iso15_magic_v3_sig_b[4] = {0x21, 0xAE, 0x93, 0x00};
|
||||
|
||||
// finalize command write in block 0x14/0x15
|
||||
// hf 15 raw -wac -d 022114A52B442C
|
||||
// hf 15 raw -wac -d 02211569E25D00
|
||||
static const uint8_t iso15_magic_v3_fin_a[4] = {0xA5, 0x2B, 0x44, 0x2C};
|
||||
static const uint8_t iso15_magic_v3_fin_b[4] = {0x69, 0xE2, 0x5D, 0x00};
|
||||
|
||||
// Read one 4-byte block from a magic V3 tag in unaddressed mode.
|
||||
static int hf15_magic_v3_read_blk(uint8_t blockno, uint8_t out[4]) {
|
||||
|
||||
uint16_t approxlen = 2 + 1 + 2;
|
||||
iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen);
|
||||
if (packet == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// enforce OPTION flag so we get the lock byte, keeping data at offset 2
|
||||
packet->raw[packet->rawlen++] = arg_get_raw_flag(0, true, false, true);
|
||||
packet->raw[packet->rawlen++] = ISO15693_READBLOCK;
|
||||
packet->raw[packet->rawlen++] = blockno;
|
||||
AddCrc15(packet->raw, packet->rawlen);
|
||||
packet->rawlen += 2;
|
||||
packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen));
|
||||
free(packet);
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
|
||||
PrintAndLogEx(DEBUG, "iso15693 timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
ISO15_ERROR_HANDLING_RESPONSE
|
||||
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
|
||||
ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length)
|
||||
|
||||
memcpy(out, d + 2, 4);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// Write one 4-byte block to a magic V3 tag in unaddressed mode.
|
||||
static int hf15_magic_v3_write_blk(uint8_t blockno, const uint8_t *data) {
|
||||
uint16_t flags = arg_get_raw_flag(0, true, false, false);
|
||||
return hf_15_write_blk(NULL, flags, NULL, true, blockno, data, 4);
|
||||
}
|
||||
|
||||
// Detect an un-finalized magic V3 tag by its configuration-mode signature.
|
||||
static bool hf15_magic_v3_is_config_mode(void) {
|
||||
uint8_t a[4] = {0};
|
||||
uint8_t b[4] = {0};
|
||||
if (hf15_magic_v3_read_blk(ISO15_MAGIC_V3_BLK_SIG_A, a) != PM3_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
if (hf15_magic_v3_read_blk(ISO15_MAGIC_V3_BLK_SIG_B, b) != PM3_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
return (memcmp(a, iso15_magic_v3_sig_a, 4) == 0) && (memcmp(b, iso15_magic_v3_sig_b, 4) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commandline handling: HF15 CMD CSETUID
|
||||
* Set UID for magic Chinese card
|
||||
@@ -3317,15 +3390,19 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 csetuid",
|
||||
"Set UID for magic Chinese card (only works with such cards)\n",
|
||||
"Set UID for magic Chinese card (only works with such cards)\n"
|
||||
"For magic 'V3' tags this writes the UID configuration only and is repeatable;\n"
|
||||
"run `" _YELLOW_("hf 15 cfinalize") "` afterwards to lock the UID permanently.",
|
||||
"hf 15 csetuid -u E011223344556677 -> use gen1 command\n"
|
||||
"hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command"
|
||||
"hf 15 csetuid -u E011223344556677 --v2 -> use gen2 command\n"
|
||||
"hf 15 csetuid -u E011223344556677 --v3 -> use gen3 (V3) magic tag"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<hex>", "UID, 8 hex bytes"),
|
||||
arg_lit0("2", "v2", "Use gen2 magic command"),
|
||||
arg_lit0("3", "v3", "Use gen3 (V3) magic tag (repeatable, needs cfinalize)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
@@ -3337,8 +3414,14 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||
int uidlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
bool use_v2 = arg_get_lit(ctx, 2);
|
||||
bool use_v3 = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_v2 && use_v3) {
|
||||
PrintAndLogEx(WARNING, "Select only one of " _YELLOW_("--v2") " / " _YELLOW_("--v3"));
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (uidlen != ISO15693_UID_LENGTH) {
|
||||
PrintAndLogEx(WARNING, "UID must include 8 hex bytes, got " _RED_("%i"), uidlen);
|
||||
return PM3_EINVARG;
|
||||
@@ -3360,19 +3443,40 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Writing...");
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
||||
uint16_t cmd = CMD_HF_ISO15693_CSETUID;
|
||||
if (use_v2) {
|
||||
cmd = CMD_HF_ISO15693_CSETUID_V2;
|
||||
}
|
||||
if (use_v3) {
|
||||
/*
|
||||
for example id: E011223344556677
|
||||
[=] 16 | 77 66 55 44 | 0 | wfUD
|
||||
[=] 17 | 33 22 11 E0 | 0 | 3"..
|
||||
*/
|
||||
uint8_t blk_lo[4] = {0};
|
||||
uint8_t blk_hi[4] = {0};
|
||||
reverse_array_copy(payload.uid + 4, 4, blk_lo);
|
||||
reverse_array_copy(payload.uid, 4, blk_hi);
|
||||
|
||||
SendCommandNG(cmd, (uint8_t *)&payload, sizeof(payload));
|
||||
if (WaitForResponseTimeout(cmd, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
if (hf15_magic_v3_write_blk(ISO15_MAGIC_V3_BLK_UID_LO, blk_lo) != PM3_SUCCESS ||
|
||||
hf15_magic_v3_write_blk(ISO15_MAGIC_V3_BLK_UID_HI, blk_hi) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Setting new UID ( " _RED_("fail") " )");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
} else {
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
||||
uint16_t cmd = CMD_HF_ISO15693_CSETUID;
|
||||
if (use_v2) {
|
||||
cmd = CMD_HF_ISO15693_CSETUID_V2;
|
||||
}
|
||||
|
||||
SendCommandNG(cmd, (uint8_t *)&payload, sizeof(payload));
|
||||
if (WaitForResponseTimeout(cmd, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Verifying...");
|
||||
@@ -3397,6 +3501,69 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commandline handling: HF15 CMD CFINALIZE
|
||||
* Finalize a magic 'V3' tag - irreversible
|
||||
*/
|
||||
static int CmdHF15CFinalize(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 cfinalize",
|
||||
"Finalize a magic ISO15693 'V3' tag.\n"
|
||||
_RED_("This operation is irreversible.") " After finalize the configuration\n"
|
||||
"area is erased and the UID can no longer be changed. Set the UID with\n"
|
||||
"`" _YELLOW_("hf 15 csetuid --v3") "` first, then lock it in with this command.",
|
||||
"hf 15 cfinalize -y"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("y", "yes", "Confirm the irreversible finalize operation"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool confirmed = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(INFO, "Get current tag");
|
||||
|
||||
uint8_t carduid[ISO15693_UID_LENGTH] = {0x00};
|
||||
if (getUID(true, false, carduid) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "no tag found");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// Safety: only proceed on a tag that is actually an un-finalized magic V3.
|
||||
// Writing the finalize values to any other tag may permanently brick it.
|
||||
if (hf15_magic_v3_is_config_mode() == false) {
|
||||
PrintAndLogEx(FAILED, "tag is not an un-finalized magic " _YELLOW_("V3") " tag");
|
||||
PrintAndLogEx(HINT, "Hint: signature in blocks 0x14/0x15 not found - already finalized or not a V3 tag");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Magic " _GREEN_("V3") " tag in configuration mode ( " _GREEN_("ok") " )");
|
||||
|
||||
if (confirmed == false) {
|
||||
PrintAndLogEx(WARNING, _RED_("This operation is irreversible!") " The UID will be locked permanently.");
|
||||
PrintAndLogEx(WARNING, "Add " _YELLOW_("-y") " to confirm and proceed.");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Finalizing...");
|
||||
|
||||
if (hf15_magic_v3_write_blk(ISO15_MAGIC_V3_BLK_SIG_A, iso15_magic_v3_fin_a) != PM3_SUCCESS ||
|
||||
hf15_magic_v3_write_blk(ISO15_MAGIC_V3_BLK_SIG_B, iso15_magic_v3_fin_b) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "Finalize ( " _RED_("fail") " )");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Finalize ( " _GREEN_("ok") " )");
|
||||
PrintAndLogEx(HINT, "Hint: UID is now locked; the tag behaves like a normal ISO15693 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF15SlixEASEnable(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
@@ -4146,6 +4313,7 @@ static command_t CommandTable[] = {
|
||||
{"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO-15693 tag"},
|
||||
{"-----------", CmdHF15Help, IfPm3Iso15693, "------------------------- " _CYAN_("Magic") " -----------------------"},
|
||||
{"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic card"},
|
||||
{"cfinalize", CmdHF15CFinalize, IfPm3Iso15693, "Finalize a magic V3 tag (irreversible)"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user