From 6d7fcc642a6e9cf74f78e83bcc9cf97ad2602b8a Mon Sep 17 00:00:00 2001 From: nvx Date: Sat, 2 Nov 2024 22:22:13 +1000 Subject: [PATCH 1/2] add gdm flag to hf mf c* commands this enables the use of hf mf c* commands with gdm/uscuid cards when the alt wake up mode 20(7)/23 is enabled rather than gen1 wake up --- armsrc/Standalone/hf_young.c | 4 ++-- armsrc/mifarecmd.c | 33 +++++++++++++++++++++++++++ client/src/cmdhfmf.c | 41 ++++++++++++++++++++++++++-------- client/src/mifare/mifarehost.c | 10 ++++----- client/src/mifare/mifarehost.h | 4 ++-- include/protocols.h | 5 ++++- 6 files changed, 78 insertions(+), 19 deletions(-) diff --git a/armsrc/Standalone/hf_young.c b/armsrc/Standalone/hf_young.c index 1356e29543..ea47e06f85 100644 --- a/armsrc/Standalone/hf_young.c +++ b/armsrc/Standalone/hf_young.c @@ -55,7 +55,7 @@ void RunMod(void) { card_clone_t uids[OPTS]; iso14a_card_select_t card[OPTS]; - uint8_t params = (MAGIC_SINGLE | MAGIC_DATAIN); + uint8_t params = (MAGIC_SINGLE | MAGIC_WUPC | MAGIC_DATAIN); LED(selected + 1, 0); @@ -184,7 +184,7 @@ void RunMod(void) { // Mifare UID BCC block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5 Bytes 5-7 are reserved SAK and ATQA for mifare classic - -Use mfCSetBlock(0, block0, oldUID, wantWipe, MAGIC_SINGLE) to write it + -Use mfCSetBlock(0, block0, oldUID, wantWipe, MAGIC_SINGLE | MAGIC_WUPC) to write it */ uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}; // arg0 = Flags, arg1=blockNo diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index e2d9850967..167e1d6408 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2552,6 +2552,7 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype, uint8_t *key) { // bit 4 - need turn off FPGA // bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) // bit 6 - wipe tag. +// bit 7 - use USCUID/GDM (20/23) magic wakeup //----------------------------------------------------------------------------- void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { @@ -2620,6 +2621,22 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { mifare_classic_halt(NULL); } + if (workFlags & MAGIC_GDM_ALT_WUPC) { + ReaderTransmitBitsPar(wupGDM1, 7, NULL, NULL); + if ((ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) == 0) || (receivedAnswer[0] != 0x0a)) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("wupGDM1 error"); + errormsg = MAGIC_WUPC; + break; + } + + ReaderTransmit(wupGDM2, sizeof(wupC2), NULL); + if ((ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) == 0) || (receivedAnswer[0] != 0x0a)) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("wupGDM2 error"); + errormsg = MAGIC_WUPC; + break; + } + } + // write block if (workFlags & MAGIC_WUPC) { ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); @@ -2706,6 +2723,22 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { //loop doesn't loop just breaks out if error or done while (true) { + if (workFlags & MAGIC_GDM_ALT_WUPC) { + ReaderTransmitBitsPar(wupGDM1, 7, NULL, NULL); + if ((ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) == 0) || (receivedAnswer[0] != 0x0a)) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("wupGDM1 error"); + errormsg = MAGIC_WUPC; + break; + } + + ReaderTransmit(wupGDM2, sizeof(wupC2), NULL); + if ((ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) == 0) || (receivedAnswer[0] != 0x0a)) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("wupGDM2 error"); + errormsg = MAGIC_WUPC; + break; + } + } + if (workFlags & MAGIC_WUPC) { ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); if ((ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) == 0) || (receivedAnswer[0] != 0x0a)) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 765bb53cfc..235dcb1bf2 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -5166,6 +5166,7 @@ static int CmdHF14AMfCSetUID(const char *Cmd) { arg_str0("u", "uid", "", "UID, 4/7 hex bytes"), arg_str0("a", "atqa", "", "ATQA, 2 hex bytes"), arg_str0("s", "sak", "", "SAK, 1 hex byte"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -5183,6 +5184,7 @@ static int CmdHF14AMfCSetUID(const char *Cmd) { int slen = 0; uint8_t sak[1] = {0x00}; CLIGetHexWithReturn(ctx, 4, sak, &slen); + uint8_t gdm = arg_get_lit(ctx, 5); CLIParserFree(ctx); // sanity checks @@ -5209,7 +5211,8 @@ static int CmdHF14AMfCSetUID(const char *Cmd) { (slen) ? sak : NULL, old_uid, verify_uid, - wipe_card + wipe_card, + gdm ); if (res) { @@ -5240,6 +5243,7 @@ static int CmdHF14AMfCWipe(const char *cmd) { arg_str0("u", "uid", "", "UID, 4 hex bytes"), arg_str0("a", "atqa", "", "ATQA, 2 hex bytes"), arg_str0("s", "sak", "", "SAK, 1 hex byte"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, cmd, argtable, true); @@ -5255,6 +5259,7 @@ static int CmdHF14AMfCWipe(const char *cmd) { int slen = 0; uint8_t sak[1] = {0x00}; CLIGetHexWithReturn(ctx, 3, sak, &slen); + uint8_t gdm = arg_get_lit(ctx, 4); CLIParserFree(ctx); if (uidlen && uidlen != 4) { @@ -5270,7 +5275,7 @@ static int CmdHF14AMfCWipe(const char *cmd) { return PM3_EINVARG; } - int res = mfCWipe((uidlen) ? uid : NULL, (alen) ? atqa : NULL, (slen) ? sak : NULL); + int res = mfCWipe((uidlen) ? uid : NULL, (alen) ? atqa : NULL, (slen) ? sak : NULL, gdm); if (res) { PrintAndLogEx(ERR, "Can't wipe card. error %d", res); return PM3_ESOFT; @@ -5292,6 +5297,7 @@ static int CmdHF14AMfCSetBlk(const char *Cmd) { arg_int1("b", "blk", "", "block number"), arg_str0("d", "data", "", "bytes to write, 16 hex bytes"), arg_lit0("w", "wipe", "wipes card with backdoor cmd before writing"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5303,6 +5309,7 @@ static int CmdHF14AMfCSetBlk(const char *Cmd) { CLIGetHexWithReturn(ctx, 2, data, &datalen); uint8_t wipe_card = arg_get_lit(ctx, 3); + uint8_t gdm = arg_get_lit(ctx, 4); CLIParserFree(ctx); if (b < 0 || b >= MIFARE_1K_MAXBLOCK) { @@ -5316,6 +5323,12 @@ static int CmdHF14AMfCSetBlk(const char *Cmd) { } uint8_t params = MAGIC_SINGLE; + if (gdm) { + params |= MAGIC_GDM_ALT_WUPC; + } else { + params |= MAGIC_WUPC; + } + if (wipe_card) { params |= MAGIC_WIPE; } @@ -5347,6 +5360,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), arg_lit0(NULL, "emu", "from emulator memory"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -5360,6 +5374,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { bool m2 = arg_get_lit(ctx, 4); bool m4 = arg_get_lit(ctx, 5); bool fill_from_emulator = arg_get_lit(ctx, 6); + bool gdm = arg_get_lit(ctx, 7); CLIParserFree(ctx); @@ -5393,7 +5408,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { if (fill_from_emulator) { - PrintAndLogEx(INFO, "Start upload to emulator memory"); + PrintAndLogEx(INFO, "Start upload from emulator memory"); PrintAndLogEx(INFO, "." NOLF); for (int b = 0; b < block_cnt; b++) { @@ -5408,7 +5423,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { // switch on field and send magic sequence if (b == 0) { - flags = MAGIC_INIT + MAGIC_WUPC; + flags = MAGIC_INIT | (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); } // just write @@ -5456,7 +5471,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { // switch on field and send magic sequence if (blockno == 0) { - flags = MAGIC_INIT + MAGIC_WUPC; + flags = MAGIC_INIT | (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); } // write @@ -5511,11 +5526,13 @@ static int CmdHF14AMfCGetBlk(const char *Cmd) { arg_param_begin, arg_int1("b", "blk", "", "block number"), arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); int b = arg_get_int_def(ctx, 1, 0); bool verbose = arg_get_lit(ctx, 2); + bool gdm = arg_get_lit(ctx, 3); CLIParserFree(ctx); if (b > 255) { @@ -5524,7 +5541,7 @@ static int CmdHF14AMfCGetBlk(const char *Cmd) { uint8_t blockno = (uint8_t)b; uint8_t data[16] = {0}; - int res = mfCGetBlock(blockno, data, MAGIC_SINGLE); + int res = mfCGetBlock(blockno, data, MAGIC_SINGLE | (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC)); if (res) { PrintAndLogEx(ERR, "Can't read block. error=%d", res); return PM3_ESOFT; @@ -5553,11 +5570,13 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { arg_param_begin, arg_int1("s", "sec", "", "sector number"), arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); int s = arg_get_int_def(ctx, 1, 0); bool verbose = arg_get_lit(ctx, 2); + bool gdm = arg_get_lit(ctx, 3); CLIParserFree(ctx); if (s >= MIFARE_4K_MAXSECTOR) { @@ -5575,7 +5594,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { start = 128 + (sector - 32) * 16; } - int flags = MAGIC_INIT + MAGIC_WUPC; + int flags = MAGIC_INIT + (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); uint8_t data[16] = {0}; for (int i = 0; i < blocks; i++) { if (i == 1) flags = 0; @@ -5612,6 +5631,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), arg_lit0(NULL, "emu", "to emulator memory"), + arg_lit0(NULL, "gdm", "to emulator memory"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -5625,6 +5645,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { bool m2 = arg_get_lit(ctx, 4); bool m4 = arg_get_lit(ctx, 5); bool fill_emulator = arg_get_lit(ctx, 6); + bool gdm = arg_get_lit(ctx, 7); CLIParserFree(ctx); // validations @@ -5692,7 +5713,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { } // switch on field and send magic sequence - uint8_t flags = MAGIC_INIT + MAGIC_WUPC; + uint8_t flags = MAGIC_INIT + (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); for (uint16_t i = 0; i < block_cnt; i++) { // read @@ -5766,6 +5787,7 @@ static int CmdHF14AMfCView(const char *Cmd) { arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "gdm", "use gdm alt (20/23) magic wakeup"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -5774,6 +5796,7 @@ static int CmdHF14AMfCView(const char *Cmd) { bool m2 = arg_get_lit(ctx, 3); bool m4 = arg_get_lit(ctx, 4); bool verbose = arg_get_lit(ctx, 5); + bool gdm = arg_get_lit(ctx, 6); CLIParserFree(ctx); // validations @@ -5840,7 +5863,7 @@ static int CmdHF14AMfCView(const char *Cmd) { } // switch on field and send magic sequence - uint8_t flags = MAGIC_INIT + MAGIC_WUPC; + uint8_t flags = MAGIC_INIT + (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); for (uint16_t i = 0; i < block_cnt; i++) { // read if (i == 1) { diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index ebe119a780..d24fe35ce3 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1058,9 +1058,9 @@ int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidt } // "MAGIC" CARD -int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t *sak, uint8_t *old_uid, uint8_t *verifed_uid, uint8_t wipecard) { +int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t *sak, uint8_t *old_uid, uint8_t *verifed_uid, uint8_t wipecard, uint8_t gdm) { - uint8_t params = MAGIC_SINGLE; + uint8_t params = MAGIC_SINGLE | (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); uint8_t block0[MFBLOCK_SIZE]; memset(block0, 0x00, sizeof(block0)); @@ -1111,7 +1111,7 @@ int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t * res = mfCSetBlock(0, block0, NULL, params); if (res == PM3_SUCCESS) { - params = MAGIC_SINGLE; + params = MAGIC_SINGLE | MAGIC_WUPC; memset(block0, 0, sizeof(block0)); res = mfCGetBlock(0, block0, params); if (res == 0) { @@ -1123,13 +1123,13 @@ int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t * return res; } -int mfCWipe(uint8_t *uid, const uint8_t *atqa, const uint8_t *sak) { +int mfCWipe(uint8_t *uid, const uint8_t *atqa, const uint8_t *sak, uint8_t gdm) { uint8_t block0[MFBLOCK_SIZE] = {0x00, 0x56, 0x78, 0xBB, 0x95, 0x08, 0x04, 0x00, 0x02, 0xB2, 0x1E, 0x24, 0x23, 0x27, 0x1E, 0x1D}; // uint8_t block0[MFBLOCK_SIZE] = {0x04, 0x03, 0x02, 0x01, 0x04, 0x08, 0x04, 0x00, 0x64, 0xB9, 0x95, 0x11, 0x4D, 0x20, 0x42, 0x09}; uint8_t blockD[MFBLOCK_SIZE] = {0x00}; // default transport ACL uint8_t blockK[MFBLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t params = MAGIC_SINGLE; + uint8_t params = MAGIC_SINGLE | (gdm ? MAGIC_GDM_ALT_WUPC : MAGIC_WUPC); if (uid != NULL) { memcpy(block0, uid, 4); diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 22460b1700..facb6c0076 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -92,8 +92,8 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); -int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t *sak, uint8_t *old_uid, uint8_t *verifed_uid, uint8_t wipecard); -int mfCWipe(uint8_t *uid, const uint8_t *atqa, const uint8_t *sak); +int mfCSetUID(uint8_t *uid, uint8_t uidlen, const uint8_t *atqa, const uint8_t *sak, uint8_t *old_uid, uint8_t *verifed_uid, uint8_t wipecard, uint8_t gdm); +int mfCWipe(uint8_t *uid, const uint8_t *atqa, const uint8_t *sak, uint8_t gdm); 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); diff --git a/include/protocols.h b/include/protocols.h index 58c857a6ff..3aa40ea796 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -250,6 +250,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. // bit 3 - turn on FPGA // bit 4 - turn off FPGA // bit 5 - set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) +// bit 6 - wipe tag. +// bit 7 - use USCUID/GDM (20/23) magic wakeup #define MAGIC_UID 0x01 #define MAGIC_WUPC 0x02 #define MAGIC_HALT 0x04 @@ -257,7 +259,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MAGIC_OFF 0x10 #define MAGIC_DATAIN 0x20 #define MAGIC_WIPE 0x40 -#define MAGIC_SINGLE (MAGIC_WUPC | MAGIC_HALT | MAGIC_INIT | MAGIC_OFF) //0x1E +#define MAGIC_GDM_ALT_WUPC 0x80 +#define MAGIC_SINGLE (MAGIC_HALT | MAGIC_INIT | MAGIC_OFF) //0x1E // by CMD_HF_MIFARE_CIDENT / Flags #define MAGIC_FLAG_NONE 0x0000 From 1157ef0b3815870ee9000ff86c9a42bb1ca955de Mon Sep 17 00:00:00 2001 From: nvx Date: Sat, 2 Nov 2024 22:24:45 +1000 Subject: [PATCH 2/2] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7299d70eb1..6431af575e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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] +- Changed `hf mf c*` - now accepts a --gdm flag to write using uscuid/gdm 20/23 alt magic wakeup (@nvx) - Changed `pm3_console()` - Python/Lua/C: replace `passthru` by `capture` and `quiet` (@doegox) - Fixed `hf iclass list` - annotation crc handled better (@iceman1001) - Fixed `hf_mf_uscuid_prog.lua` - bad divisions and code style fixes (@iceman1001)