mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-22 07:04:13 +08:00
Magic gen 3 cards support
This commit is contained in:
parent
7904d962aa
commit
70be7ef4d8
8 changed files with 327 additions and 0 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added `hf mf gen3*`magic gen 3 card operations (@McEloff)
|
||||
- Readded verichip command which seems missing (@iceman1001)
|
||||
- Fix missing t55x7 config block detection (@iceman1001)
|
||||
- Fix missing define on proxspace (@mwalker33)
|
||||
|
|
|
@ -1318,6 +1318,19 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
MifareCIdent();
|
||||
break;
|
||||
}
|
||||
// Gen 3 magic cards
|
||||
case CMD_HF_MIFARE_GEN3UID: {
|
||||
MifareGen3UID(packet->oldarg[0], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_GEN3BLK: {
|
||||
MifareGen3Blk(packet->oldarg[0], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_GEN3FREEZ: {
|
||||
MifareGen3Freez();
|
||||
break;
|
||||
}
|
||||
// mifare sniffer
|
||||
// case CMD_HF_MIFARE_SNIFF: {
|
||||
// SniffMifare(packet->oldarg[0]);
|
||||
|
|
|
@ -2319,6 +2319,154 @@ void OnErrorMagic(uint8_t reason) {
|
|||
OnSuccessMagic();
|
||||
}
|
||||
|
||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
|
||||
LED_B_ON();
|
||||
uint32_t save_iso14a_timeout = iso14a_get_timeout();
|
||||
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 2000); // 2 seconds timeout
|
||||
|
||||
ReaderTransmit(cmd, cmd_len, NULL);
|
||||
int res = ReaderReceive(buf, par);
|
||||
if (res == 4 || memcmp(buf, "\x90\x00\xfd\x07", 4) == 0) {
|
||||
// timeout for card memory reset
|
||||
SpinDelay(1000);
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card operation not completed");
|
||||
retval = PM3_ESOFT;
|
||||
}
|
||||
iso14a_set_timeout(save_iso14a_timeout);
|
||||
LED_B_OFF();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void MifareGen3UID(uint8_t uidlen, uint8_t *uid) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t uid_cmd[5] = { 0x90, 0xfb, 0xcc, 0xcc, 0x07 };
|
||||
uint8_t *old_uid = BigBuf_malloc(10);
|
||||
uint8_t *cmd = BigBuf_malloc(sizeof(uid_cmd) + uidlen + 2);
|
||||
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(old_uid, card_info, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
if (card_info->uidlen != uidlen) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID length");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
memcpy(cmd, uid_cmd, sizeof(uid_cmd));
|
||||
memcpy(&cmd[sizeof(uid_cmd)], uid, uidlen);
|
||||
AddCrc14A(cmd, sizeof(uid_cmd) + uidlen);
|
||||
|
||||
retval = DoGen3Cmd(cmd, sizeof(uid_cmd) + uidlen + 2);
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3UID, retval, old_uid, uidlen);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
|
||||
#define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2)
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 };
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
uint8_t *cmd = BigBuf_malloc(sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
|
||||
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(uid, card_info, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
bool doReselect = false;
|
||||
if (block_len < MIFARE_BLOCK_SIZE) {
|
||||
if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read manufacturer block failed");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
doReselect = true;
|
||||
}
|
||||
|
||||
if (block_len > 0) {
|
||||
memcpy(cmd, block_cmd, sizeof(block_cmd));
|
||||
memcpy(&cmd[sizeof(block_cmd)], block, block_len);
|
||||
int ofs = sizeof(block_cmd);
|
||||
if (card_info->uidlen == 4) {
|
||||
cmd[ofs + 4] = cmd[ofs + 0] ^ cmd[ofs + 1] ^ cmd[ofs + 2] ^ cmd[ofs + 3];
|
||||
ofs += 5;
|
||||
} else if (card_info->uidlen == 7) {
|
||||
ofs += 7;
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong Card UID length");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
cmd[ofs++] = card_info->sak;
|
||||
cmd[ofs++] = card_info->atqa[0];
|
||||
cmd[ofs++] = card_info->atqa[1];
|
||||
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);
|
||||
|
||||
if (doReselect) {
|
||||
if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
}
|
||||
|
||||
retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
|
||||
}
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3BLK, retval, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareGen3Freez(void) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t freeze_cmd[7] = { 0x90, 0xfd, 0x11, 0x11, 0x00, 0xe7, 0x91 };
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
retval = DoGen3Cmd(freeze_cmd, sizeof(freeze_cmd));
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3FREEZ, retval, NULL, 0);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareSetMod(uint8_t *datain) {
|
||||
|
||||
uint8_t mod = datain[0];
|
||||
|
|
|
@ -44,6 +44,11 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
|
|||
void MifareCIdent(void); // is "magic chinese" card?
|
||||
void MifareHasStaticNonce(void); // Has the tag a static nonce?
|
||||
|
||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
|
||||
void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block
|
||||
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
|
||||
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
|
||||
|
||||
void MifareSetMod(uint8_t *datain);
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||
|
||||
|
|
|
@ -500,6 +500,48 @@ static int usage_hf14_nack(void) {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf nack"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_gen3uid(void) {
|
||||
PrintAndLogEx(NORMAL, "Set UID for magic GEN 3 card without manufacturer block changing");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3uid [h] <uid>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " <uid> UID 8/14 hex symbols");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304050607"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_gen3blk(void) {
|
||||
PrintAndLogEx(NORMAL, "Overwrite full manufacturer block for magic GEN 3 card");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3blk [h] [block data (up to 32 hex symbols)]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " [block] manufacturer block data up to 32 hex symbols to write");
|
||||
PrintAndLogEx(NORMAL, " - If block data not specified, it prints current");
|
||||
PrintAndLogEx(NORMAL, " data without changes");
|
||||
PrintAndLogEx(NORMAL, " - You can specify part of manufacturer block as");
|
||||
PrintAndLogEx(NORMAL, " 4/7-bytes for UID change only for example");
|
||||
PrintAndLogEx(NORMAL, " NOTE: BCC, SAK, ATQA will be calculated automatically");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304FFFFFFFF0102030405060708"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304050607"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_gen3freez(void) {
|
||||
PrintAndLogEx(NORMAL, "Lock further UID changes. No more UID changes available after operation completed");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3freez [h] <Y>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " <Y> confirm UID locks operation");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freez Y"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetHFMF14AUID(uint8_t *uid, int *uidlen) {
|
||||
clearCommandBuffer();
|
||||
|
@ -5086,6 +5128,69 @@ static int CmdHF14AMfList(const char *Cmd) {
|
|||
return CmdTraceList("mf");
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3UID(const char *Cmd) {
|
||||
uint8_t uid[7] = {0x00};
|
||||
uint8_t oldUid[10] = {0x00};
|
||||
uint8_t uidlen;
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hf14_gen3uid();
|
||||
|
||||
if (param_gethex(Cmd, 0, uid, 8))
|
||||
if (param_gethex(Cmd, 0, uid, 14))
|
||||
return usage_hf14_gen3uid();
|
||||
else
|
||||
uidlen = 7;
|
||||
else
|
||||
uidlen = 4;
|
||||
|
||||
int res = mfGen3UID(uid, uidlen, oldUid);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't set UID. Error=%d", res);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, uidlen));
|
||||
PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, uidlen));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3Blk(const char *Cmd) {
|
||||
uint8_t block[16] = {0x00};
|
||||
int blocklen = 0;
|
||||
uint8_t newBlock[16] = {0x00};
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hf14_gen3blk();
|
||||
|
||||
if (ctmp != '\0' && param_gethex_to_eol(Cmd, 0, block, sizeof(block), &blocklen))
|
||||
return usage_hf14_gen3blk();
|
||||
|
||||
int res = mfGen3Blk(block, blocklen, newBlock);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't change manufacturer block data. Error=%d", res);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Current Block : %s", sprint_hex(newBlock, 16));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3Freez(const char *Cmd) {
|
||||
char ctmp = param_getchar(Cmd, 0);
|
||||
if (tolower(ctmp) == 'h') return usage_hf14_gen3freez();
|
||||
if (ctmp != 'Y') return usage_hf14_gen3freez();
|
||||
|
||||
int res = mfGen3Freez();
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't lock UID changes. Error=%d", res);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Gen 3 UID locked");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
|
||||
|
@ -5131,6 +5236,10 @@ static command_t CommandTable[] = {
|
|||
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"},
|
||||
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"},
|
||||
{"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
|
||||
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block (magic gen3 card)"},
|
||||
{"gen3blk", CmdHf14AGen3Blk, IfPm3Iso14443a, "Overwrite full manufacturer block (magic gen 3 card)"},
|
||||
{"gen3freez", CmdHf14AGen3Freez, IfPm3Iso14443a, "Lock further UID changes (magic gen 3 card)"},
|
||||
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
|
||||
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||
|
|
|
@ -944,6 +944,48 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_GEN3UID, uidlen, 0, 0, uid, uidlen);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3UID, &resp, 3500)) {
|
||||
if (resp.status == PM3_SUCCESS && oldUid) {
|
||||
memcpy(oldUid, resp.data.asBytes, uidlen);
|
||||
}
|
||||
return resp.status;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_GEN3BLK, blockLen, 0, 0, block, 16);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3BLK, &resp, 3500)) {
|
||||
if (resp.status == PM3_SUCCESS && newBlock) {
|
||||
memcpy(newBlock, resp.data.asBytes, 16);
|
||||
}
|
||||
return resp.status;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
int mfGen3Freez(void) {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_GEN3FREEZ, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3FREEZ, &resp, 3500)) {
|
||||
return resp.status;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
// SNIFFER
|
||||
// [iceman] so many global variables....
|
||||
|
||||
|
|
|
@ -80,6 +80,10 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak);
|
|||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
||||
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||
|
||||
int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid);
|
||||
int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock);
|
||||
int mfGen3Freez(void);
|
||||
|
||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
|
||||
int detect_classic_prng(void);
|
||||
|
|
|
@ -648,6 +648,11 @@ typedef struct {
|
|||
//For Atmel CryptoRF
|
||||
#define CMD_HF_CRYPTORF_SIM 0x0820
|
||||
|
||||
// Gen 3 magic cards
|
||||
#define CMD_HF_MIFARE_GEN3UID 0x0850
|
||||
#define CMD_HF_MIFARE_GEN3BLK 0x0851
|
||||
#define CMD_HF_MIFARE_GEN3FREEZ 0x0852
|
||||
|
||||
#define CMD_UNKNOWN 0xFFFF
|
||||
|
||||
//Mifare simulation flags
|
||||
|
|
Loading…
Reference in a new issue