static uint8_t mf_nr_ar3;
uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET);
- traceLen = 0;
+ iso14a_clear_trace();
tracing = false;
byte_t nt_diff = 0;
LED_B_OFF();
LED_C_OFF();
-
+
for(uint16_t i = 0; TRUE; i++) {
WDT_HIT();
tracing = TRUE;
}
-//-----------------------------------------------------------------------------
-// MIFARE 1K simulate.
-//
-//-----------------------------------------------------------------------------
-void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
+/**
+ *MIFARE 1K simulate.
+ *
+ *@param flags :
+ * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK
+ * 4B_FLAG_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that
+ * 7B_FLAG_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that
+ * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later
+ *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite
+ */
+void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain)
{
int cardSTATE = MFEMUL_NOFIELD;
int _7BUID = 0;
int vHf = 0; // in mV
- //int nextCycleTimeout = 0;
int res;
-// uint32_t timer = 0;
uint32_t selTimer = 0;
uint32_t authTimer = 0;
uint32_t par = 0;
uint8_t cardWRBL = 0;
uint8_t cardAUTHSC = 0;
uint8_t cardAUTHKEY = 0xff; // no authentication
- //uint32_t cardRn = 0;
uint32_t cardRr = 0;
uint32_t cuid = 0;
- uint32_t rn_enc = 0;
+ //uint32_t rn_enc = 0;
uint32_t ans = 0;
uint32_t cardINTREG = 0;
uint8_t cardINTBLOCK = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
-
+ uint32_t numReads = 0;//Counts numer of times reader read a block
uint8_t* receivedCmd = eml_get_bigbufptr_recbuf();
uint8_t *response = eml_get_bigbufptr_sendbuf();
- static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID
+ uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID
+ uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62};
+ uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!!
+ uint8_t rSAK[] = {0x08, 0xb6, 0xdd};
+ uint8_t rSAK1[] = {0x04, 0xda, 0x17};
- static uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62};
- static uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!!
-
- static uint8_t rSAK[] = {0x08, 0xb6, 0xdd};
- static uint8_t rSAK1[] = {0x04, 0xda, 0x17};
+ uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
+ uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
- static uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
-// static uint8_t rAUTH_NT[] = {0x1a, 0xac, 0xff, 0x4f};
- static uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
+ //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
+ // This can be used in a reader-only attack.
+ // (it can also be retrieved via 'hf 14a list', but hey...
+ uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0};
+ uint8_t ar_nr_collected = 0;
// clear trace
- traceLen = 0;
+ iso14a_clear_trace();
+
tracing = true;
// Authenticate response - nonce
uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
-
- // get UID from emul memory
- emlGetMemBt(receivedCmd, 7, 1);
- _7BUID = !(receivedCmd[0] == 0x00);
- if (!_7BUID) { // ---------- 4BUID
- rATQA[0] = 0x04;
- emlGetMemBt(rUIDBCC1, 0, 4);
+ //-- Determine the UID
+ // Can be set from emulator memory, incoming data
+ // and can be 7 or 4 bytes long
+ if(flags & FLAG_4B_UID_IN_DATA)
+ {
+ // 4B uid comes from data-portion of packet
+ memcpy(rUIDBCC1,datain,4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
- } else { // ---------- 7BUID
- rATQA[0] = 0x44;
+ }else if(flags & FLAG_7B_UID_IN_DATA)
+ {
+ // 7B uid comes from data-portion of packet
+ memcpy(&rUIDBCC1[1],datain,3);
+ memcpy(rUIDBCC2, datain+3, 4);
+ _7BUID = true;
+ }
+ else
+ {
+ // get UID from emul memory
+ emlGetMemBt(receivedCmd, 7, 1);
+ _7BUID = !(receivedCmd[0] == 0x00);
+ if (!_7BUID) { // ---------- 4BUID
+ emlGetMemBt(rUIDBCC1, 0, 4);
+ } else { // ---------- 7BUID
+ emlGetMemBt(&rUIDBCC1[1], 0, 3);
+ emlGetMemBt(rUIDBCC2, 3, 4);
+ }
+ }
+ /*
+ * Regardless of what method was used to set the UID, set fifth byte and modify
+ * the ATQA for 4 or 7-byte UID
+ */
+
+ rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
+ if(_7BUID)
+ {
+ rATQA[0] = 0x44;
rUIDBCC1[0] = 0x88;
- emlGetMemBt(&rUIDBCC1[1], 0, 3);
- rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
- emlGetMemBt(rUIDBCC2, 3, 4);
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
}
-// -------------------------------------- test area
-
-// -------------------------------------- END test area
// start mkseconds counter
StartCountUS();
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
- FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
SpinDelay(200);
- if (MF_DBGLEVEL >= 1) Dbprintf("Started. 7buid=%d", _7BUID);
+ if (MF_DBGLEVEL >= 1) {
+ if (!_7BUID) {
+ Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]);
+ }else
+ {
+ Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]);
+ }
+ }
// calibrate mkseconds counter
GetDeltaCountUS();
- while (true) {
+ bool finished = false;
+ while (!BUTTON_PRESS() && !finished) {
WDT_HIT();
- if(BUTTON_PRESS()) {
- break;
- }
-
// find reader field
// Vref = 3300mV, and an 10:1 voltage divider on the input
// can measure voltages up to 33000 mV
LED_A_ON();
}
}
+ if(cardSTATE == MFEMUL_NOFIELD) continue;
- if (cardSTATE != MFEMUL_NOFIELD) {
- res = EmGetCmd(receivedCmd, &len, RECV_CMD_SIZE); // (+ nextCycleTimeout)
- if (res == 2) {
- cardSTATE = MFEMUL_NOFIELD;
- LEDsoff();
- continue;
- }
- if(res) break;
- }
-
- //nextCycleTimeout = 0;
-
-// if (len) Dbprintf("len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]);
-
- if (len != 4 && cardSTATE != MFEMUL_NOFIELD) { // len != 4 <---- speed up the code 4 authentication
- // REQ or WUP request in ANY state and WUP in HALTED state
- if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) {
- selTimer = GetTickCount();
- EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52));
- cardSTATE = MFEMUL_SELECT1;
-
- // init crypto block
- LED_B_OFF();
- LED_C_OFF();
- crypto1_destroy(pcs);
- cardAUTHKEY = 0xff;
- }
+ //Now, get data
+
+ res = EmGetCmd(receivedCmd, &len, RECV_CMD_SIZE); // (+ nextCycleTimeout)
+ if (res == 2) { //Field is off!
+ cardSTATE = MFEMUL_NOFIELD;
+ LEDsoff();
+ continue;
+ }else if(res == 1) break;//return value 1 means button press
+
+
+ // REQ or WUP request in ANY state and WUP in HALTED state
+ if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) {
+ selTimer = GetTickCount();
+ EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52));
+ cardSTATE = MFEMUL_SELECT1;
+
+ // init crypto block
+ LED_B_OFF();
+ LED_C_OFF();
+ crypto1_destroy(pcs);
+ cardAUTHKEY = 0xff;
+ continue;
}
-
+
switch (cardSTATE) {
- case MFEMUL_NOFIELD:{
- break;
- }
- case MFEMUL_HALTED:{
- break;
- }
+ case MFEMUL_NOFIELD:
+ case MFEMUL_HALTED:
case MFEMUL_IDLE:{
break;
}
case MFEMUL_SELECT1:{
// select all
if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) {
+ if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received");
EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1));
break;
}
+ if (MF_DBGLEVEL >= 4 && len == 9 && receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 )
+ {
+ Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
+ }
// select card
if (len == 9 &&
(receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) {
+
if (!_7BUID)
EmSendCmd(rSAK, sizeof(rSAK));
else
break;
}
+ case MFEMUL_AUTH1:{
+ if( len != 8)
+ {
+ cardSTATE_TO_IDLE();
+ break;
+ }
+ uint32_t ar = bytes_to_num(receivedCmd, 4);
+ uint32_t nr= bytes_to_num(&receivedCmd[4], 4);
+
+ //Collect AR/NR
+ if(ar_nr_collected < 2){
+ if(ar_nr_responses[ar_nr_collected*4+2] != ar)
+ {// Avoid duplicates
+ ar_nr_collected++;
+ ar_nr_responses[ar_nr_collected*4] = cuid;
+ ar_nr_responses[ar_nr_collected*4+1] = nonce;
+ ar_nr_responses[ar_nr_collected*4+2] = ar;
+ ar_nr_responses[ar_nr_collected*4+3] = nr;
+ }
+ }
+
+ // --- crypto
+ crypto1_word(pcs, ar , 1);
+ cardRr = nr ^ crypto1_word(pcs, 0, 0);
+
+ // test if auth OK
+ if (cardRr != prng_successor(nonce, 64)){
+ if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64));
+ //Shouldn't we respond anything here?
+ // Right now, we don't nack or anything, which causes the
+ // reader to do a WUPA after a while. /Martin
+ cardSTATE_TO_IDLE();
+ break;
+ }
+
+ ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
+
+ num_to_bytes(ans, 4, rAUTH_AT);
+ // --- crypto
+ EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
+ LED_C_ON();
+ cardSTATE = MFEMUL_WORK;
+ if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sector=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer);
+ break;
+ }
case MFEMUL_SELECT2:{
if (!len) break;
// i guess there is a command). go into the work state.
if (len != 4) break;
cardSTATE = MFEMUL_WORK;
- goto lbWORK;
- }
- case MFEMUL_AUTH1:{
- if (len == 8) {
- // --- crypto
- rn_enc = bytes_to_num(receivedCmd, 4);
- crypto1_word(pcs, rn_enc , 1);
- cardRr = bytes_to_num(&receivedCmd[4], 4) ^ crypto1_word(pcs, 0, 0);
- // test if auth OK
- if (cardRr != prng_successor(nonce, 64)){
- if (MF_DBGLEVEL >= 4) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x", cardRr, prng_successor(nonce, 64));
- cardSTATE_TO_IDLE();
- break;
- }
- ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
- num_to_bytes(ans, 4, rAUTH_AT);
- // --- crypto
- EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
- cardSTATE = MFEMUL_AUTH2;
- } else {
- cardSTATE_TO_IDLE();
- }
- if (cardSTATE != MFEMUL_AUTH2) break;
- }
- case MFEMUL_AUTH2:{
- LED_C_ON();
- cardSTATE = MFEMUL_WORK;
- if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sec=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer);
- break;
+ //goto lbWORK;
+ //intentional fall-through to the next case-stmt
}
case MFEMUL_WORK:{
-lbWORK: if (len == 0) break;
-
- if (cardAUTHKEY == 0xff) {
- // first authentication
- if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
- authTimer = GetTickCount();
-
- cardAUTHSC = receivedCmd[1] / 4; // received block num
- cardAUTHKEY = receivedCmd[0] - 0x60;
-
- // --- crypto
- crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
- ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
- num_to_bytes(nonce, 4, rAUTH_AT);
- EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
- // --- crypto
-
-// last working revision
-// EmSendCmd14443aRaw(resp1, resp1Len, 0);
-// LogTrace(NULL, 0, GetDeltaCountUS(), 0, true);
+ if (len == 0) break;
- cardSTATE = MFEMUL_AUTH1;
- //nextCycleTimeout = 10;
- break;
- }
- } else {
+ bool encrypted_data = (cardAUTHKEY != 0xFF) ;
+
+ if(encrypted_data)
+ {
// decrypt seqence
mf_crypto1_decrypt(pcs, receivedCmd, len);
-
- // nested authentication
- if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
- authTimer = GetTickCount();
+ }
- cardAUTHSC = receivedCmd[1] / 4; // received block num
- cardAUTHKEY = receivedCmd[0] - 0x60;
+ if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
+ authTimer = GetTickCount();
+ cardAUTHSC = receivedCmd[1] / 4; // received block num
+ cardAUTHKEY = receivedCmd[0] - 0x60;
+ crypto1_destroy(pcs);//Added by martin
+ crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
- // --- crypto
- crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
- ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
- num_to_bytes(ans, 4, rAUTH_AT);
- EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
- // --- crypto
+ if (!encrypted_data) { // first authentication
+ if (MF_DBGLEVEL >= 2) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
- cardSTATE = MFEMUL_AUTH1;
- //nextCycleTimeout = 10;
- break;
+ crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state
+ num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce
+ }
+ else{ // nested authentication
+ if (MF_DBGLEVEL >= 2) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
+ ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
+ num_to_bytes(ans, 4, rAUTH_AT);
}
+ EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
+ //Dbprintf("Sending rAUTH %02x%02x%02x%02x", rAUTH_AT[0],rAUTH_AT[1],rAUTH_AT[2],rAUTH_AT[3]);
+ cardSTATE = MFEMUL_AUTH1;
+ break;
}
-
+
// rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued
// BUT... ACK --> NACK
if (len == 1 && receivedCmd[0] == CARD_ACK) {
break;
}
- // read block
- if (len == 4 && receivedCmd[0] == 0x30) {
- if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
+ if(len != 4) break;
+
+ if(receivedCmd[0] == 0x30 // read block
+ || receivedCmd[0] == 0xA0 // write block
+ || receivedCmd[0] == 0xC0
+ || receivedCmd[0] == 0xC1
+ || receivedCmd[0] == 0xC2 // inc dec restore
+ || receivedCmd[0] == 0xB0) // transfer
+ {
+ if (receivedCmd[1] >= 16 * 4)
+ {
+
+ EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
+ if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
+ break;
+ }
+
+ if (receivedCmd[1] / 4 != cardAUTHSC)
+ {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
+ if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
break;
}
+ }
+ // read block
+ if (receivedCmd[0] == 0x30) {
+ if (MF_DBGLEVEL >= 2) {
+ Dbprintf("Reader reading block %d (0x%02x)",receivedCmd[1],receivedCmd[1]);
+ }
emlGetMem(response, receivedCmd[1], 1);
AppendCrc14443a(response, 16);
mf_crypto1_encrypt(pcs, response, 18, &par);
EmSendCmdPar(response, 18, par);
+ numReads++;
+ if(exitAfterNReads > 0 && numReads == exitAfterNReads)
+ {
+ Dbprintf("%d reads done, exiting", numReads);
+ finished = true;
+ }
break;
}
-
// write block
- if (len == 4 && receivedCmd[0] == 0xA0) {
- if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
- EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
- break;
- }
+ if (receivedCmd[0] == 0xA0) {
+ if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd[1],receivedCmd[1]);
+
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
//nextCycleTimeout = 50;
cardSTATE = MFEMUL_WRITEBL2;
cardWRBL = receivedCmd[1];
break;
- }
-
- // works with cardINTREG
-
+ }
// increment, decrement, restore
- if (len == 4 && (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2)) {
- if (receivedCmd[1] >= 16 * 4 ||
- receivedCmd[1] / 4 != cardAUTHSC ||
- emlCheckValBl(receivedCmd[1])) {
+ if (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2) {
+ if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
+
+ if (emlCheckValBl(receivedCmd[1])) {
+ if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
if (receivedCmd[0] == 0xC2)
cardSTATE = MFEMUL_INTREG_REST;
cardWRBL = receivedCmd[1];
-
+
break;
}
-
// transfer
- if (len == 4 && receivedCmd[0] == 0xB0) {
- if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
- EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
- break;
- }
+ if (receivedCmd[0] == 0xB0) {
+ if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd[1]))
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
}
// halt
- if (len == 4 && (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00)) {
+ if (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00) {
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_HALTED;
if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED. Selected time: %d ms", GetTickCount() - selTimer);
break;
}
-
- // command not allowed
- if (len == 4) {
+ // RATS
+ if (receivedCmd[0] == 0xe0) {//RATS
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
+ // command not allowed
+ if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking");
+ EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
+
// case break
break;
}
// add trace trailer
memset(rAUTH_NT, 0x44, 4);
LogTrace(rAUTH_NT, 4, 0, 0, TRUE);
-
+ if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
+ {
+ //May just aswell send the collected ar_nr in the response aswell
+ cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4);
+ }
+ if(flags & FLAG_NR_AR_ATTACK)
+ {
+ if(ar_nr_collected > 1)
+ {
+ Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
+ Dbprintf("../tools/mfcrack32 %08x %08x %08x %08x",
+ ar_nr_responses[0], // UID
+ ar_nr_responses[1], //NT
+ ar_nr_responses[2], //AR1
+ ar_nr_responses[3], //NR1
+ ar_nr_responses[6], //AR2
+ ar_nr_responses[7] //NR2
+ );
+ }else
+ {
+ Dbprintf("Failed to obtain two AR/NR pairs!");
+ if(ar_nr_collected >0)
+ {
+ Dbprintf("Only got these: UID=%08d, nonce=%08d, AR1=%08d, NR1=%08d",
+ ar_nr_responses[0], // UID
+ ar_nr_responses[1], //NT
+ ar_nr_responses[2], //AR1
+ ar_nr_responses[3] //NR1
+ );
+ }
+ }
+ }
if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, traceLen);
}
+
+
//-----------------------------------------------------------------------------
// MIFARE sniffer.
//
PrintAndLog("Command execute timeout");\r
}\r
\r
- return 0;
-}
-
-int CmdHF14AMfUWrBl(const char *Cmd)
-{
- uint8_t blockNo = 0;
- uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- UsbCommand resp;
-
- if (strlen(Cmd)<3) {
- PrintAndLog("Usage: hf mf uwrbl <block number> <block data (8 hex symbols)>");
- PrintAndLog(" sample: hf mf uwrbl 0 01020304");
- return 0;
- }
-
- blockNo = param_get8(Cmd, 0);
- if (param_gethex(Cmd, 1, bldata, 8)) {
- PrintAndLog("Block data must include 8 HEX symbols");
- return 1;
- }
-
- switch(blockNo)
- {
- case 0:
- PrintAndLog("Access Denied");
- break;
- case 1:
- PrintAndLog("Access Denied");
- break;
- case 2:
- PrintAndLog("--specialblock no:%02x", blockNo);
- PrintAndLog("--data: %s", sprint_hex(bldata, 4));
- UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
- memcpy(c.d.asBytes, bldata, 4);
- SendCommand(&c);
-
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
- uint8_t isOK = resp.arg[0] & 0xff;
- PrintAndLog("isOk:%02x", isOK);
- } else {
- PrintAndLog("Command execute timeout");
- }
- break;
- case 3:
- PrintAndLog("--specialblock no:%02x", blockNo);
- PrintAndLog("--data: %s", sprint_hex(bldata, 4));
- UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};
- memcpy(d.d.asBytes,bldata, 4);
- SendCommand(&d);
-
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
- uint8_t isOK = resp.arg[0] & 0xff;
- PrintAndLog("isOk:%02x", isOK);
- } else {
- PrintAndLog("Command execute timeout");
- }
- break;
- default:
- PrintAndLog("--block no:%02x", blockNo);
- PrintAndLog("--data: %s", sprint_hex(bldata, 4));
- //UsbCommand e = {CMD_MIFAREU_WRITEBL_COMPAT, {blockNo}};
- //memcpy(e.d.asBytes,bldata, 16);
- UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};
- memcpy(e.d.asBytes,bldata, 4);
- SendCommand(&e);
-
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
- uint8_t isOK = resp.arg[0] & 0xff;
- PrintAndLog("isOk:%02x", isOK);
- } else {
- PrintAndLog("Command execute timeout");
- }
- break;
- }
- return 0;
-}
-
-int CmdHF14AMfRdBl(const char *Cmd)
-{
- uint8_t blockNo = 0;
+ return 0;\r
+}\r
+\r
+int CmdHF14AMfUWrBl(const char *Cmd)\r
+{\r
+ uint8_t blockNo = 0;\r
+ uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\r
+ UsbCommand resp;\r
+ \r
+ if (strlen(Cmd)<3) {\r
+ PrintAndLog("Usage: hf mf uwrbl <block number> <block data (8 hex symbols)>");\r
+ PrintAndLog(" sample: hf mf uwrbl 0 01020304");\r
+ return 0;\r
+ } \r
+\r
+ blockNo = param_get8(Cmd, 0);\r
+ if (param_gethex(Cmd, 1, bldata, 8)) {\r
+ PrintAndLog("Block data must include 8 HEX symbols");\r
+ return 1;\r
+ }\r
+\r
+ switch(blockNo)\r
+ {\r
+ case 0:\r
+ PrintAndLog("Access Denied");\r
+ break;\r
+ case 1:\r
+ PrintAndLog("Access Denied");\r
+ break;\r
+ case 2:\r
+ PrintAndLog("--specialblock no:%02x", blockNo);\r
+ PrintAndLog("--data: %s", sprint_hex(bldata, 4));\r
+ UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};\r
+ memcpy(c.d.asBytes, bldata, 4);\r
+ SendCommand(&c);\r
+\r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ uint8_t isOK = resp.arg[0] & 0xff;\r
+ PrintAndLog("isOk:%02x", isOK);\r
+ } else {\r
+ PrintAndLog("Command execute timeout");\r
+ }\r
+ break;\r
+ case 3:\r
+ PrintAndLog("--specialblock no:%02x", blockNo);\r
+ PrintAndLog("--data: %s", sprint_hex(bldata, 4));\r
+ UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};\r
+ memcpy(d.d.asBytes,bldata, 4);\r
+ SendCommand(&d);\r
+\r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ uint8_t isOK = resp.arg[0] & 0xff;\r
+ PrintAndLog("isOk:%02x", isOK);\r
+ } else {\r
+ PrintAndLog("Command execute timeout");\r
+ }\r
+ break;\r
+ default: \r
+ PrintAndLog("--block no:%02x", blockNo);\r
+ PrintAndLog("--data: %s", sprint_hex(bldata, 4)); \r
+ //UsbCommand e = {CMD_MIFAREU_WRITEBL_COMPAT, {blockNo}};\r
+ //memcpy(e.d.asBytes,bldata, 16);\r
+ UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};\r
+ memcpy(e.d.asBytes,bldata, 4);\r
+ SendCommand(&e);\r
+\r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ uint8_t isOK = resp.arg[0] & 0xff;\r
+ PrintAndLog("isOk:%02x", isOK);\r
+ } else {\r
+ PrintAndLog("Command execute timeout");\r
+ }\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+int CmdHF14AMfRdBl(const char *Cmd)\r
+{\r
+ uint8_t blockNo = 0;\r
uint8_t keyType = 0;\r
uint8_t key[6] = {0, 0, 0, 0, 0, 0};\r
\r
PrintAndLog("Command execute timeout");\r
}\r
\r
- return 0;
-}
-
-int CmdHF14AMfURdBl(const char *Cmd)
-{
- uint8_t blockNo = 0;
-
- if (strlen(Cmd)<1) {
- PrintAndLog("Usage: hf mf urdbl <block number>");
- PrintAndLog(" sample: hf mf urdbl 0");
- return 0;
- }
-
- blockNo = param_get8(Cmd, 0);
- PrintAndLog("--block no:%02x", blockNo);
-
- UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
- SendCommand(&c);
-
- UsbCommand resp;
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
- uint8_t isOK = resp.arg[0] & 0xff;
- uint8_t * data = resp.d.asBytes;
-
- if (isOK)
- PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
- else
- PrintAndLog("isOk:%02x", isOK);
- } else {
- PrintAndLog("Command execute timeout");
- }
-
- return 0;
-}
-
-int CmdHF14AMfURdCard(const char *Cmd)
-{
- int i;
- uint8_t sectorNo = 0;
- uint8_t *lockbytes_t=NULL;
- uint8_t lockbytes[2]={0,0};
- bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
- uint8_t isOK = 0;
- uint8_t * data = NULL;
-
- if (sectorNo > 15) {
- PrintAndLog("Sector number must be less than 16");
- return 1;
- }
- PrintAndLog("Attempting to Read Ultralight... ");
-
- UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}};
- SendCommand(&c);
-
- UsbCommand resp;
- if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
- isOK = resp.arg[0] & 0xff;
- data = resp.d.asBytes;
-
- PrintAndLog("isOk:%02x", isOK);
- if (isOK)
- for (i = 0; i < 16; i++) {
- switch(i){
- case 2:
- //process lock bytes
- lockbytes_t=data+(i*4);
- lockbytes[0]=lockbytes_t[2];
- lockbytes[1]=lockbytes_t[3];
- for(int j=0; j<16; j++){
- bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8));
- }
- //PrintAndLog("LB %02x %02x", lockbytes[0],lockbytes[1]);
- //PrintAndLog("LB2b %02x %02x %02x %02x %02x %02x %02x %02x",bit[8],bit[9],bit[10],bit[11],bit[12],bit[13],bit[14],bit[15]);
- PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
- break;
- case 3:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]);
- break;
- case 4:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]);
- break;
- case 5:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]);
- break;
- case 6:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]);
- break;
- case 7:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]);
- break;
- case 8:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]);
- break;
- case 9:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]);
- break;
- case 10:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]);
- break;
- case 11:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]);
- break;
- case 12:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]);
- break;
- case 13:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]);
- break;
- case 14:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]);
- break;
- case 15:
- PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]);
- break;
- default:
- PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
- break;
- }
- }
- } else {
- PrintAndLog("Command1 execute timeout");
- }
- return 0;
-}
-
-int CmdHF14AMfRdSc(const char *Cmd)
-{
- int i;
+ return 0;\r
+}\r
+\r
+int CmdHF14AMfURdBl(const char *Cmd)\r
+{\r
+ uint8_t blockNo = 0;\r
+\r
+ if (strlen(Cmd)<1) {\r
+ PrintAndLog("Usage: hf mf urdbl <block number>");\r
+ PrintAndLog(" sample: hf mf urdbl 0");\r
+ return 0;\r
+ } \r
+ \r
+ blockNo = param_get8(Cmd, 0);\r
+ PrintAndLog("--block no:%02x", blockNo);\r
+ \r
+ UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};\r
+ SendCommand(&c);\r
+\r
+ UsbCommand resp;\r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ uint8_t isOK = resp.arg[0] & 0xff;\r
+ uint8_t * data = resp.d.asBytes;\r
+\r
+ if (isOK)\r
+ PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));\r
+ else\r
+ PrintAndLog("isOk:%02x", isOK);\r
+ } else {\r
+ PrintAndLog("Command execute timeout");\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int CmdHF14AMfURdCard(const char *Cmd)\r
+{\r
+ int i;\r
+ uint8_t sectorNo = 0;\r
+ uint8_t *lockbytes_t=NULL;\r
+ uint8_t lockbytes[2]={0,0};\r
+ bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
+ \r
+ uint8_t isOK = 0;\r
+ uint8_t * data = NULL;\r
+\r
+ if (sectorNo > 15) {\r
+ PrintAndLog("Sector number must be less than 16");\r
+ return 1;\r
+ }\r
+ PrintAndLog("Attempting to Read Ultralight... ");\r
+ \r
+ UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}};\r
+ SendCommand(&c);\r
+\r
+ UsbCommand resp;\r
+ if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ isOK = resp.arg[0] & 0xff;\r
+ data = resp.d.asBytes;\r
+\r
+ PrintAndLog("isOk:%02x", isOK);\r
+ if (isOK) \r
+ for (i = 0; i < 16; i++) {\r
+ switch(i){\r
+ case 2:\r
+ //process lock bytes\r
+ lockbytes_t=data+(i*4);\r
+ lockbytes[0]=lockbytes_t[2];\r
+ lockbytes[1]=lockbytes_t[3];\r
+ for(int j=0; j<16; j++){\r
+ bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8));\r
+ }\r
+ //PrintAndLog("LB %02x %02x", lockbytes[0],lockbytes[1]);\r
+ //PrintAndLog("LB2b %02x %02x %02x %02x %02x %02x %02x %02x",bit[8],bit[9],bit[10],bit[11],bit[12],bit[13],bit[14],bit[15]); \r
+ PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));\r
+ break;\r
+ case 3: \r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]);\r
+ break;\r
+ case 4:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]);\r
+ break;\r
+ case 5:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]);\r
+ break;\r
+ case 6:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]);\r
+ break;\r
+ case 7:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]);\r
+ break;\r
+ case 8:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]);\r
+ break;\r
+ case 9:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]);\r
+ break;\r
+ case 10:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]);\r
+ break;\r
+ case 11:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]);\r
+ break;\r
+ case 12:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]);\r
+ break;\r
+ case 13:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]);\r
+ break;\r
+ case 14:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]);\r
+ break;\r
+ case 15:\r
+ PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]);\r
+ break;\r
+ default:\r
+ PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));\r
+ break;\r
+ }\r
+ }\r
+ } else {\r
+ PrintAndLog("Command1 execute timeout");\r
+ }\r
+ return 0;\r
+}\r
+\r
+int CmdHF14AMfRdSc(const char *Cmd)\r
+{\r
+ int i;\r
uint8_t sectorNo = 0;\r
uint8_t keyType = 0;\r
uint8_t key[6] = {0, 0, 0, 0, 0, 0};\r
\r
int CmdHF14AMf1kSim(const char *Cmd)\r
{\r
- uint8_t uid[4] = {0, 0, 0, 0};\r
- \r
+ uint8_t uid[7] = {0, 0, 0, 0,0,0,0};\r
+ uint8_t exitAfterNReads = 0;\r
+ uint8_t flags = 0;\r
+\r
if (param_getchar(Cmd, 0) == 'h') {\r
- PrintAndLog("Usage: hf mf sim <uid (8 hex symbols)>");\r
+ PrintAndLog("Usage: hf mf sim u <uid (8 hex symbols)> n <numreads> i x");\r
+ PrintAndLog(" u (Optional) UID. If not specified, the UID from emulator memory will be used");\r
+ PrintAndLog(" n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");\r
+ PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");\r
+ PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");\r
PrintAndLog(" sample: hf mf sim 0a0a0a0a ");\r
return 0;\r
- } \r
- \r
- if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) {\r
- PrintAndLog("UID must include 8 HEX symbols");\r
- return 1;\r
}\r
- PrintAndLog(" uid:%s ", sprint_hex(uid, 4));\r
- \r
- UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}};\r
- memcpy(c.d.asBytes, uid, 4);\r
+ uint8_t pnr = 0;\r
+ if (param_getchar(Cmd, pnr) == 'u') {\r
+ if(param_gethex(Cmd, pnr+1, uid, 8) == 0)\r
+ {\r
+ flags |=FLAG_4B_UID_IN_DATA; // UID from packet\r
+ }else if(param_gethex(Cmd,pnr+1,uid,14) == 0)\r
+ {\r
+ flags |= FLAG_7B_UID_IN_DATA;// UID from packet\r
+ }else\r
+ {\r
+ PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols");\r
+ return 1;\r
+ }\r
+ pnr +=2;\r
+ }\r
+ if (param_getchar(Cmd, pnr) == 'n') {\r
+ exitAfterNReads = param_get8(Cmd,pnr+1);\r
+ pnr += 2;\r
+ }\r
+ if (param_getchar(Cmd, pnr) == 'i' ) {\r
+ //Using a flag to signal interactiveness, least significant bit\r
+ flags |= FLAG_INTERACTIVE;\r
+ pnr++;\r
+ }\r
+\r
+ if (param_getchar(Cmd, pnr) == 'x' ) {\r
+ //Using a flag to signal interactiveness, least significant bit\r
+ flags |= FLAG_NR_AR_ATTACK;\r
+ }\r
+ PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ",\r
+ flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):\r
+ flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A"\r
+ , exitAfterNReads, flags,flags);\r
+\r
+\r
+ UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};\r
+ memcpy(c.d.asBytes, uid, sizeof(uid));\r
SendCommand(&c);\r
\r
+ if(flags & 1)\r
+ {\r
+ UsbCommand resp;\r
+ PrintAndLog("Press pm3-button to abort simulation");\r
+ while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {\r
+ //We're waiting only 1.5 s at a time, otherwise we get the\r
+ // annoying message about "Waiting for a response... "\r
+ }\r
+ }\r
+\r
return 0;\r
}\r
\r
while(!feof(f)){\r
memset(buf, 0, sizeof(buf));\r
if (fgets(buf, sizeof(buf), f) == NULL) {\r
- PrintAndLog("File reading error.");\r
+ if(blockNum == 16 * 4)\r
+ {\r
+ break;\r
+ }\r
+ PrintAndLog("File reading error.");\r
return 2;\r
}\r
\r
PrintAndLog("File content error. There must be 64 blocks");\r
return 4;\r
}\r
- PrintAndLog("Loaded from file: %s", filename);\r
+ PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);\r
return 0;\r
}\r
\r
\r
static command_t CommandTable[] =\r
{\r
- {"help", CmdHelp, 1, "This help"},
- {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
- {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
- {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
- {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
- {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
- {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
- {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
- {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},
+ {"help", CmdHelp, 1, "This help"},\r
+ {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},\r
+ {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},\r
+ {"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},\r
+ {"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},\r
+ {"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},\r
+ {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},\r
+ {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},\r
+ {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},\r
{"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"},\r
{"chk", CmdHF14AMfChk, 0, "Test block keys"},\r
{"mifare", CmdHF14AMifare, 0, "Read parity error messages. param - <used card nonce>"},\r