From d2f487af9cc29122d86ca4f349ba825aaf98748c Mon Sep 17 00:00:00 2001
From: "martin.holst@gmail.com"
 <martin.holst@gmail.com@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Date: Fri, 31 Jan 2014 21:17:34 +0000
Subject: [PATCH] Various improvements on the Mifare1kSimulation. Fixed issue
 with tracebuffer not being cleared, fixed issue with 'static' errors, added
 modes for doing reader-only attack, added interactive mode, added possibility
 to set UID from cmdline, either 7-byte or 4-byte. See
 http://www.proxmark.org/forum/viewtopic.php?id=1529 and
 http://www.proxmark.org/forum/viewtopic.php?id=1649&p=3 for some more
 background and discussion

---
 armsrc/iso14443a.c | 442 ++++++++++++++++++++++----------------
 client/cmdhfmf.c   | 512 +++++++++++++++++++++++++--------------------
 include/usb_cmd.h  |   9 +
 3 files changed, 554 insertions(+), 409 deletions(-)

diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 3966d77a..aa97e6e9 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -1926,7 +1926,7 @@ void ReaderMifare(bool first_try)
 	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;
@@ -1974,7 +1974,7 @@ void ReaderMifare(bool first_try)
 	LED_B_OFF();
 	LED_C_OFF();
 	
-  
+
 	for(uint16_t i = 0; TRUE; i++) {
 		
 		WDT_HIT();
@@ -2113,18 +2113,22 @@ void ReaderMifare(bool first_try)
 	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;
@@ -2132,60 +2136,83 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	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();
 
@@ -2193,19 +2220,23 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	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
@@ -2216,56 +2247,54 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 				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
@@ -2285,6 +2314,51 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 				
 				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;
 			
@@ -2308,86 +2382,44 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 				// 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) {
@@ -2401,39 +2433,63 @@ lbWORK:	if (len == 0) break;
 					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;
 					}
@@ -2445,17 +2501,13 @@ lbWORK:	if (len == 0) 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));
@@ -2466,20 +2518,23 @@ lbWORK:	if (len == 0) break;
 				}
 
 				// 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;
 			}
@@ -2541,10 +2596,43 @@ lbWORK:	if (len == 0) 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. 
 // 
diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index 86fbe8df..637ef4a1 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -137,86 +137,86 @@ int CmdHF14AMfWrBl(const char *Cmd)
 		PrintAndLog("Command execute timeout");
 	}
 
-	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;
+}
+
+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;
 	uint8_t keyType = 0;
 	uint8_t key[6] = {0, 0, 0, 0, 0, 0};
 	
@@ -259,135 +259,135 @@ int CmdHF14AMfRdBl(const char *Cmd)
 		PrintAndLog("Command execute timeout");
 	}
 
-  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;
+}
+
+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;
 	uint8_t sectorNo = 0;
 	uint8_t keyType = 0;
 	uint8_t key[6] = {0, 0, 0, 0, 0, 0};
@@ -1144,24 +1144,68 @@ int CmdHF14AMfChk(const char *Cmd)
 
 int CmdHF14AMf1kSim(const char *Cmd)
 {
-	uint8_t uid[4] = {0, 0, 0, 0};
-	
+	uint8_t uid[7] = {0, 0, 0, 0,0,0,0};
+	uint8_t exitAfterNReads = 0;
+	uint8_t flags = 0;
+
 	if (param_getchar(Cmd, 0) == 'h') {
-		PrintAndLog("Usage:  hf mf sim  <uid (8 hex symbols)>");
+		PrintAndLog("Usage:  hf mf sim  u <uid (8 hex symbols)> n <numreads> i x");
+		PrintAndLog("           u    (Optional) UID. If not specified, the UID from emulator memory will be used");
+		PrintAndLog("           n    (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
+		PrintAndLog("           i    (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");
+		PrintAndLog("           x    (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");
 		PrintAndLog("           sample: hf mf sim 0a0a0a0a ");
 		return 0;
-	}	
-	
-	if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) {
-		PrintAndLog("UID must include 8 HEX symbols");
-		return 1;
 	}
-	PrintAndLog(" uid:%s ", sprint_hex(uid, 4));
-	
-  UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}};
-	memcpy(c.d.asBytes, uid, 4);
+	uint8_t pnr = 0;
+	if (param_getchar(Cmd, pnr) == 'u') {
+		if(param_gethex(Cmd, pnr+1, uid, 8) == 0)
+		{
+			flags |=FLAG_4B_UID_IN_DATA; // UID from packet
+		}else if(param_gethex(Cmd,pnr+1,uid,14) == 0)
+		{
+			flags |= FLAG_7B_UID_IN_DATA;// UID from packet
+		}else
+		{
+				PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols");
+				return 1;
+		}
+		pnr +=2;
+	}
+	if (param_getchar(Cmd, pnr) == 'n') {
+		exitAfterNReads = param_get8(Cmd,pnr+1);
+		pnr += 2;
+	}
+	if (param_getchar(Cmd, pnr) == 'i' ) {
+		//Using a flag to signal interactiveness, least significant bit
+		flags |= FLAG_INTERACTIVE;
+		pnr++;
+	}
+
+	if (param_getchar(Cmd, pnr) == 'x' ) {
+		//Using a flag to signal interactiveness, least significant bit
+		flags |= FLAG_NR_AR_ATTACK;
+	}
+	PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ",
+				flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
+											  flags & FLAG_7B_UID_IN_DATA	? sprint_hex(uid,7): "N/A"
+				, exitAfterNReads, flags,flags);
+
+
+  UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};
+  memcpy(c.d.asBytes, uid, sizeof(uid));
   SendCommand(&c);
 
+  if(flags & 1)
+  {
+	  UsbCommand resp;
+	  PrintAndLog("Press pm3-button to abort simulation");
+	  while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+		//We're waiting only 1.5 s at a time, otherwise we get the
+		  // annoying message about "Waiting for a response... "
+	  }
+  }
+
   return 0;
 }
 
@@ -1291,7 +1335,11 @@ int CmdHF14AMfELoad(const char *Cmd)
 	while(!feof(f)){
 		memset(buf, 0, sizeof(buf));
 		if (fgets(buf, sizeof(buf), f) == NULL) {
-      PrintAndLog("File reading error.");
+			if(blockNum == 16 * 4)
+			{
+				break;
+			}
+			PrintAndLog("File reading error.");
 			return 2;
     }
 
@@ -1319,7 +1367,7 @@ int CmdHF14AMfELoad(const char *Cmd)
 		PrintAndLog("File content error. There must be 64 blocks");
 		return 4;
 	}
-	PrintAndLog("Loaded from file: %s", filename);
+	PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);
   return 0;
 }
 
@@ -1864,15 +1912,15 @@ int CmdHF14AMfSniff(const char *Cmd){
 
 static command_t CommandTable[] =
 {
-  {"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"},
+  {"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"},
   {"wrbl",		CmdHF14AMfWrBl,			0, "Write MIFARE classic block"},
   {"chk",			CmdHF14AMfChk,			0, "Test block keys"},
   {"mifare",	CmdHF14AMifare,			0, "Read parity error messages. param - <used card nonce>"},
diff --git a/include/usb_cmd.h b/include/usb_cmd.h
index 2673dcac..a107e392 100644
--- a/include/usb_cmd.h
+++ b/include/usb_cmd.h
@@ -151,6 +151,15 @@ typedef struct {
 
 #define CMD_UNKNOWN                                                       0xFFFF
 
+
+//Mifare simulation flags
+#define FLAG_INTERACTIVE 0x01
+#define FLAG_4B_UID_IN_DATA 0x02
+#define FLAG_7B_UID_IN_DATA 0x04
+#define FLAG_NR_AR_ATTACK 0x08
+
+
+
 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions:
 /* Whether a bootloader that understands the common_area is present */
 #define DEVICE_INFO_FLAG_BOOTROM_PRESENT         	(1<<0)
-- 
2.39.5