add lf em 410x clone --htu to support Hitag µ/8265 tag

This commit is contained in:
douniwan5788 2025-03-15 04:21:43 +08:00
commit 2ff92c3b5c

View file

@ -624,11 +624,12 @@ static int CmdEM410xSpoof(const char *Cmd) {
static int CmdEM410xClone(const char *Cmd) { static int CmdEM410xClone(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x clone", CLIParserInit(&ctx, "lf em 410x clone",
"clone a EM410x ID to a T55x7, Q5/T5555, EM4305/4469 or Hitag S/8211/8268/8310 tag.", "clone a EM410x ID to a T55x7, Q5/T5555, EM4305/4469, Hitag S/8211/8268/8310 or Hitag µ/8265 tag.",
"lf em 410x clone --id 0F0368568B -> encode for T55x7 tag\n" "lf em 410x clone --id 0F0368568B -> encode for T55x7 tag\n"
"lf em 410x clone --id 0F0368568B --q5 -> encode for Q5/T5555 tag\n" "lf em 410x clone --id 0F0368568B --q5 -> encode for Q5/T5555 tag\n"
"lf em 410x clone --id 0F0368568B --em -> encode for EM4305/4469\n" "lf em 410x clone --id 0F0368568B --em -> encode for EM4305/4469\n"
"lf em 410x clone --id 0F0368568B --hts -> encode for Hitag S/8211/8268/8310" "lf em 410x clone --id 0F0368568B --hts -> encode for Hitag S/8211/8268/8310\n"
"lf em 410x clone --id 0F0368568B --htu -> encode for Hitag µ/8265 tag"
); );
void *argtable[] = { void *argtable[] = {
@ -638,6 +639,7 @@ static int CmdEM410xClone(const char *Cmd) {
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
arg_lit0(NULL, "hts", "optional - specify writing to Hitag S/8211/8268/8310 tag"), arg_lit0(NULL, "hts", "optional - specify writing to Hitag S/8211/8268/8310 tag"),
arg_lit0(NULL, "htu", "optional - specify writing to Hitag µ/8265 tag"),
arg_lit0(NULL, "electra", "optional - add Electra blocks to tag"), arg_lit0(NULL, "electra", "optional - add Electra blocks to tag"),
arg_param_end arg_param_end
}; };
@ -651,24 +653,24 @@ static int CmdEM410xClone(const char *Cmd) {
bool q5 = arg_get_lit(ctx, 3); bool q5 = arg_get_lit(ctx, 3);
bool em = arg_get_lit(ctx, 4); bool em = arg_get_lit(ctx, 4);
bool hts = arg_get_lit(ctx, 5); bool hts = arg_get_lit(ctx, 5);
bool add_electra = arg_get_lit(ctx, 6); bool htu = arg_get_lit(ctx, 6);
bool add_electra = arg_get_lit(ctx, 7);
CLIParserFree(ctx); CLIParserFree(ctx);
if (q5 + em + hts > 1) { if (q5 + em + hts + htu > 1) {
PrintAndLogEx(FAILED, "Only specify one tag Type"); PrintAndLogEx(FAILED, "Only specify one tag Type");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (hts) { if ((hts || htu) && IfPm3Hitag() == false) {
if (IfPm3Hitag() == false) {
PrintAndLogEx(FAILED, "Device not compiled to support Hitag"); PrintAndLogEx(FAILED, "Device not compiled to support Hitag");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (clk == 40) {
if ((hts || htu) && clk == 40) {
PrintAndLogEx(FAILED, "supported clock rates for Hitag are " _YELLOW_("16, 32, 64")); PrintAndLogEx(FAILED, "supported clock rates for Hitag are " _YELLOW_("16, 32, 64"));
return PM3_EINVARG; return PM3_EINVARG;
} }
}
// Allowed clock rates: 16, 32, 40 and 64 // Allowed clock rates: 16, 32, 40 and 64
if ((clk != 16) && (clk != 32) && (clk != 64) && (clk != 40)) { if ((clk != 16) && (clk != 32) && (clk != 64) && (clk != 40)) {
@ -678,9 +680,9 @@ static int CmdEM410xClone(const char *Cmd) {
uint64_t id = bytes_to_num(uid, uid_len); uint64_t id = bytes_to_num(uid, uid_len);
PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with EM Tag ID " _GREEN_("%010" PRIX64) " (RF/%d)", PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with EM Tag ID " _GREEN_("%010" PRIX64) " (RF/%d)",
q5 ? "Q5/T5555" : (em ? "EM4305/4469" : (hts ? "Hitag S/82xx" : "T55x7")), id, clk); q5 ? "Q5/T5555" : (em ? "EM4305/4469" : (hts ? "Hitag S/82xx" : (htu ? "Hitag µ/82xx" : "T55x7"))), id, clk);
uint8_t data[HITAG_BLOCK_SIZE * 2] = {0xFF, 0x80}; // EM410X_HEADER 9 bits of one uint8_t data[8] = {0xFF, 0x80}; // EM410X_HEADER 9 bits of one
uint32_t databits = 9; uint32_t databits = 9;
uint8_t c_parity = 0; uint8_t c_parity = 0;
@ -706,35 +708,45 @@ static int CmdEM410xClone(const char *Cmd) {
lf_hitag_data_t packet; lf_hitag_data_t packet;
memset(&packet, 0, sizeof(packet)); memset(&packet, 0, sizeof(packet));
for (size_t steps = 0; steps < 3; steps++) { for (size_t step = 0; step < 3; step++) {
switch (steps) { switch (step) {
case 0: case 0: {
packet.data[0] = 0xCA; //compatiable for 82xx, no impact on Hitag S hitags_config_t config = {0};
// clk -> TTFDR1 TTFDR0 config.MEMT = 0x02; // compatiable for 82xx, no impact on Hitag S
// 32 -> 0x00 4 kBit/s config.TTFM = 0x01; // 0 = "Block 0, Block 1, Block 2, Block 3", 1 = "Block 0, Block 1"
// 16 -> 0x10 8 kBit/s config.TTFC = 0x00; // Manchester
// 64 -> 0x20 2 kBit/s config.auth = 0x00; // Plain
packet.data[1] = 0x04;
//compatiable for 82xx, no impact on Hitag S
config.RES1 = 0x01;
config.RES4 = 0x01;
config.RES5 = 0x01;
switch (clk) { switch (clk) {
case 64:
// 2 kBit/s
config.TTFDR = 0x02;
break;
case 32: case 32:
// 4 kBit/s
config.TTFDR = 0x00;
break; break;
case 16: case 16:
packet.data[1] |= 0x10; // 8 kBit/s
break; config.TTFDR = 0x01;
case 64:
packet.data[1] |= 0x20;
break; break;
} }
packet.data[2] = 0; //TODO: keep other fields?
packet.data[3] = 0; //TODO: keep PWDH0? memcpy(packet.data, &config, sizeof(config));
// PrintAndLogEx(INFO, "packet.data: %s", sprint_hex(packet.data, sizeof(packet.data)));
packet.page = 1; packet.page = 1;
break; break;
}
case 1: case 1:
memcpy(packet.data, &data[HITAG_BLOCK_SIZE * 0], HITAG_BLOCK_SIZE); memcpy(packet.data, &data[HITAGS_PAGE_SIZE * 0], HITAGS_PAGE_SIZE);
packet.page = 4; packet.page = 4;
break; break;
case 2: case 2:
memcpy(packet.data, &data[HITAG_BLOCK_SIZE * 1], HITAG_BLOCK_SIZE); memcpy(packet.data, &data[HITAGS_PAGE_SIZE * 1], HITAGS_PAGE_SIZE);
packet.page = 5; packet.page = 5;
break; break;
} }
@ -748,10 +760,78 @@ static int CmdEM410xClone(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
if (resp.status != PM3_SUCCESS) { if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Something went wrong"); PrintAndLogEx(WARNING, "Something went wrong in step %zu", step);
return resp.status; return resp.status;
} }
} }
} else if (htu) {
lf_hitag_data_t packet;
memset(&packet, 0, sizeof(packet));
// Use password auth with default password
packet.cmd = HTUF_82xx;
memcpy(packet.pwd, "\x00\x00\x00\x00", HITAG_PASSWORD_SIZE);
// memcpy(packet.pwd, "\x9A\xC4\x99\x9C", HITAGU_BLOCK_SIZE);
for (size_t step = 0; step < 3; step++) {
switch (step) {
case 0: {
// Configure datarate based on clock
// clk -> datarate
// 64 -> 0x00 2 kBit/s
// 32 -> 0x01 4 kBit/s
// 16 -> 0x10 8 kBit/s
hitagu82xx_config_t config = {0};
config.datarate_override = 0x00; // no datarate override
config.encoding = 0x00; // Manchester
config.ttf_mode = 0x01; // 01 = "Block 0, Block 1"
config.ttf = 0x01; // enable TTF
switch (clk) {
case 64:
break;
case 32:
config.datarate = 0x01;
break;
case 16:
config.datarate = 0x02;
break;
}
packet.data[0] = reflect8(*(uint8_t*)&config);
packet.page = HITAGU_CONFIG_PADR; // Config block
break;
}
case 1:
memcpy(packet.data, &data[HITAGU_BLOCK_SIZE * 0], HITAGU_BLOCK_SIZE);
packet.page = 0; // Start writing EM410x data
break;
case 2:
memcpy(packet.data, &data[HITAGU_BLOCK_SIZE * 1], HITAGU_BLOCK_SIZE);
packet.page = 1; // Continue with second block
break;
}
SendCommandNG(CMD_LF_HITAGU_WRITE, (uint8_t *)&packet, sizeof(packet));
if (WaitForResponseTimeout(CMD_LF_HITAGU_WRITE, &resp, 4000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (resp.status != PM3_ENODATA && resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Something went wrong in step %zu, retrying... Press " _GREEN_("<Enter>") " to exit", step);
// 8265 Often fails during continuous command execution, need to retry
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "Button pressed, user aborted");
return PM3_EOPABORTED;
}
step--;
continue;
}
//TODO: fix this
resp.status = PM3_SUCCESS;
}
} else { } else {
struct { struct {
bool Q5; bool Q5;