From 545a1f385c4e9f3fc28729e3a4c6a50e080c72f9 Mon Sep 17 00:00:00 2001
From: "Merlokbr@gmail.com"
 <Merlokbr@gmail.com@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Date: Thu, 5 Jul 2012 14:05:01 +0000
Subject: [PATCH 1/1] another "magic card" backdoor - command "read block".
 Added several commands to manipulate card data.

---
 armsrc/appmain.c    |   3 +
 armsrc/apps.h       |   1 +
 armsrc/mifarecmd.c  |  95 ++++++++++++++++++++++++-
 client/cmdhfmf.c    | 170 ++++++++++++++++++++++++++++++++++++++++++--
 client/mifarehost.c |  31 ++++++--
 client/mifarehost.h |   2 +-
 include/usb_cmd.h   |   1 +
 7 files changed, 288 insertions(+), 15 deletions(-)

diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index 820a0378..3fdbed5c 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -758,6 +758,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
 		case CMD_MIFARE_EML_CSETBLOCK:
 			MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
 			break;
+		case CMD_MIFARE_EML_CGETBLOCK:
+			MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+			break;
 #endif
 
 #ifdef WITH_ICLASS
diff --git a/armsrc/apps.h b/armsrc/apps.h
index 3723357e..7ed2867d 100644
--- a/armsrc/apps.h
+++ b/armsrc/apps.h
@@ -150,6 +150,7 @@ void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain)
 void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
 void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
 void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);  // Work with "magic Chinese" card
+void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
 
 /// iso15693.h
 void RecordRawAdcSamplesIso15693(void);
diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c
index 4f4ce64d..d63b58e9 100644
--- a/armsrc/mifarecmd.c
+++ b/armsrc/mifarecmd.c
@@ -808,7 +808,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
 			};
 		};	
 
-		// write UID block
+		// write block
 		if (workFlags & 0x02) {
 			ReaderTransmitShort(wupC1);
 			if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {
@@ -859,9 +859,100 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
 	UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
 	LED_B_OFF();
 
-	if (workFlags & 0x10) {
+	if ((workFlags & 0x10) || (!isOK)) {
 		// Thats it...
 		FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
 		LEDsoff();
 	}
 }
+
+void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
+  
+  // params
+	// bit 1 - need wupC
+	// bit 2 - need HALT after sequence
+	// bit 3 - need init FPGA and field before sequence
+	// bit 4 - need reset FPGA and LED
+	uint8_t workFlags = arg0;
+	uint8_t blockNo = arg2;
+	
+	// card commands
+	uint8_t wupC1[]       = { 0x40 }; 
+	uint8_t wupC2[]       = { 0x43 }; 
+	
+	// variables
+	byte_t isOK = 0;
+	uint8_t data[18];
+	uint32_t cuid = 0;
+	
+	memset(data, 0x00, 18);
+	uint8_t* receivedAnswer = mifare_get_bigbufptr();
+	
+	if (workFlags & 0x08) {
+		// clear trace
+		iso14a_clear_tracelen();
+		iso14a_set_tracing(TRUE);
+
+		iso14443a_setup();
+
+		LED_A_ON();
+		LED_B_OFF();
+		LED_C_OFF();
+	
+		SpinDelay(300);
+		FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+		SpinDelay(100);
+		FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+	}
+
+	while (true) {
+		if (workFlags & 0x02) {
+			ReaderTransmitShort(wupC1);
+			if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {
+				if (MF_DBGLEVEL >= 1)	Dbprintf("wupC1 error");
+				break;
+			};
+
+			ReaderTransmit(wupC2, sizeof(wupC2));
+			if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) {
+				if (MF_DBGLEVEL >= 1)	Dbprintf("wupC2 error");
+				break;
+			};
+		}
+
+		// read block
+		if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer) != 18)) {
+			if (MF_DBGLEVEL >= 1)	Dbprintf("read block send command error");
+			break;
+		};
+		memcpy(data, receivedAnswer, 18);
+		
+		if (workFlags & 0x04) {
+			if (mifare_classic_halt(NULL, cuid)) {
+				if (MF_DBGLEVEL >= 1)	Dbprintf("Halt error");
+				break;
+			};
+		}
+		
+		isOK = 1;
+		break;
+	}
+	
+	UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
+	if (isOK) memcpy(ack.d.asBytes, data, 18);
+	
+	// add trace trailer
+	memset(data, 0x44, 4);
+	LogTrace(data, 4, 0, 0, TRUE);
+
+	LED_B_ON();
+	UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
+	LED_B_OFF();
+
+	if ((workFlags & 0x10) || (!isOK)) {
+		// Thats it...
+		FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+		LEDsoff();
+	}
+}
+
diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index eafb2919..4da6067a 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -1387,20 +1387,175 @@ int CmdHF14AMfCLoad(const char *Cmd)
 	}
 }
 
+int CmdHF14AMfCGetBlk(const char *Cmd) {
+	uint8_t memBlock[16];
+	uint8_t blockNo = 0;
+	int res;
+	memset(memBlock, 0x00, sizeof(memBlock));
+
+	if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {
+		PrintAndLog("Usage:  hf mf cgetblk <block number>");
+		PrintAndLog("sample:  hf mf cgetblk 1");
+		PrintAndLog("Get block data from magic Chinese card (only works with!!!)\n");
+		return 0;
+	}	
+
+	blockNo = param_get8(Cmd, 0);
+	if (blockNo >= 32 * 4 + 8 * 16) {
+		PrintAndLog("Block number must be in [0..255] as in MIFARE classic.");
+		return 1;
+	}
+
+	PrintAndLog("--block number:%02x ", blockNo);
+
+	res = mfCGetBlock(blockNo, memBlock, CSETBLOCK_SINGLE_OPER);
+	if (res) {
+			PrintAndLog("Can't read block. error=%d", res);
+			return 1;
+		}
+	
+	PrintAndLog("block data:%s", sprint_hex(memBlock, 16));
+	return 0;
+}
+
+int CmdHF14AMfCGetSc(const char *Cmd) {
+	uint8_t memBlock[16];
+	uint8_t sectorNo = 0;
+	int i, res, flags;
+	memset(memBlock, 0x00, sizeof(memBlock));
+
+	if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') {
+		PrintAndLog("Usage:  hf mf cgetsc <sector number>");
+		PrintAndLog("sample:  hf mf cgetsc 0");
+		PrintAndLog("Get sector data from magic Chinese card (only works with!!!)\n");
+		return 0;
+	}	
+
+	sectorNo = param_get8(Cmd, 0);
+	if (sectorNo > 15) {
+		PrintAndLog("Sector number must be in [0..15] as in MIFARE classic.");
+		return 1;
+	}
+
+	PrintAndLog("--sector number:%02x ", sectorNo);
+
+	flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;
+	for (i = 0; i < 4; i++) {
+		if (i == 1) flags = 0;
+		if (i == 3) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD;
+
+		res = mfCGetBlock(sectorNo * 4 + i, memBlock, flags);
+		if (res) {
+			PrintAndLog("Can't read block. %02x error=%d", sectorNo * 4 + i, res);
+			return 1;
+		}
+	
+		PrintAndLog("block %02x data:%s", sectorNo * 4 + i, sprint_hex(memBlock, 16));
+	}
+	return 0;
+}
+
+int CmdHF14AMfCSave(const char *Cmd) {
+
+	FILE * f;
+	char filename[20];
+	char * fnameptr = filename;
+	uint8_t fillFromEmulator = 0;
+	uint8_t buf[64];
+	int i, j, len, flags;
+	
+	memset(filename, 0, sizeof(filename));
+	memset(buf, 0, sizeof(buf));
+
+	if (param_getchar(Cmd, 0) == 'h') {
+		PrintAndLog("It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml`");
+		PrintAndLog("or into emulator memory (option `e`)");
+		PrintAndLog("Usage:  hf mf esave [file name w/o `.eml`][e]");
+		PrintAndLog(" sample: hf mf esave ");
+		PrintAndLog("         hf mf esave filename");
+		PrintAndLog("         hf mf esave e \n");
+		return 0;
+	}	
+
+	char ctmp = param_getchar(Cmd, 0);
+	if (ctmp == 'e' || ctmp == 'E') fillFromEmulator = 1;
+
+	if (fillFromEmulator) {
+		// put into emulator
+		flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;
+		for (i = 0; i < 16 * 4; i++) {
+			if (i == 1) flags = 0;
+			if (i == 16 * 4 - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD;
+		
+			if (mfCGetBlock(i, buf, flags)) {
+				PrintAndLog("Cant get block: %d", i);
+				break;
+			}
+			
+			if (mfEmlSetMem(buf, i, 1)) {
+				PrintAndLog("Cant set emul block: %d", i);
+				return 3;
+			}
+		}
+		return 0;
+	} else {
+		len = strlen(Cmd);
+		if (len > 14) len = 14;
+	
+		if (len < 1) {
+			// get filename
+			if (mfCGetBlock(0, buf, CSETBLOCK_SINGLE_OPER)) {
+				PrintAndLog("Cant get block: %d", 0);
+				return 1;
+			}
+			for (j = 0; j < 7; j++, fnameptr += 2)
+				sprintf(fnameptr, "%02x", buf[j]); 
+		} else {
+			memcpy(filename, Cmd, len);
+			fnameptr += len;
+		}
+
+		sprintf(fnameptr, ".eml"); 
+	
+		// open file
+		f = fopen(filename, "w+");
+
+		// put hex
+		flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;
+		for (i = 0; i < 16 * 4; i++) {
+			if (i == 1) flags = 0;
+			if (i == 16 * 4 - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD;
+		
+			if (mfCGetBlock(i, buf, flags)) {
+				PrintAndLog("Cant get block: %d", i);
+				break;
+			}
+			for (j = 0; j < 16; j++)
+				fprintf(f, "%02x", buf[j]); 
+			fprintf(f,"\n");
+		}
+		fclose(f);
+	
+		PrintAndLog("Saved to file: %s", filename);
+	
+		return 0;
+	}
+}
+
 static command_t CommandTable[] =
 {
-  {"help",		CmdHelp,				1, "This help"},
-  {"dbg",		CmdHF14AMfDbg,			0, "Set default debug mode"},
+  {"help",		CmdHelp,						1, "This help"},
+  {"dbg",			CmdHF14AMfDbg,			0, "Set default debug mode"},
   {"rdbl",		CmdHF14AMfRdBl,			0, "Read MIFARE classic 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"},
+  {"restore",	CmdHF14AMfRestore,	0, "Restore MIFARE classic binary file to BLANK tag"},
   {"wrbl",		CmdHF14AMfWrBl,			0, "Write MIFARE classic block"},
-  {"chk",		CmdHF14AMfChk,			0, "Test block keys"},
+  {"chk",			CmdHF14AMfChk,			0, "Test block keys"},
   {"mifare",	CmdHF14AMifare,			0, "Read parity error messages. param - <used card nonce>"},
   {"nested",	CmdHF14AMfNested,		0, "Test nested authentication"},
-  {"sim",		CmdHF14AMf1kSim,		0, "Simulate MIFARE card"},
-  {"eclr",  	CmdHF14AMfEClear,		0, "Clear simulator memory block"},
+  {"sim",			CmdHF14AMf1kSim,		0, "Simulate MIFARE card"},
+  {"eclr",		CmdHF14AMfEClear,		0, "Clear simulator memory block"},
   {"eget",		CmdHF14AMfEGet,			0, "Get simulator memory block"},
   {"eset",		CmdHF14AMfESet,			0, "Set simulator memory block"},
   {"eload",		CmdHF14AMfELoad,		0, "Load from file emul dump"},
@@ -1409,7 +1564,10 @@ static command_t CommandTable[] =
   {"ekeyprn",	CmdHF14AMfEKeyPrn,	0, "Print keys from simulator memory"},
   {"csetuid",	CmdHF14AMfCSetUID,	0, "Set UID for magic Chinese card"},
   {"csetblk",	CmdHF14AMfCSetBlk,	0, "Write block into magic Chinese card"},
+  {"cgetblk",	CmdHF14AMfCGetBlk,	0, "Read block from magic Chinese card"},
+  {"cgetsc",	CmdHF14AMfCGetSc,		0, "Read sector from magic Chinese card"},
   {"cload",		CmdHF14AMfCLoad,		0, "Load dump into magic Chinese card"},
+  {"csave",		CmdHF14AMfCSave,		0, "Save dump from magic Chinese card into file or emulator"},
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/client/mifarehost.c b/client/mifarehost.c
index 399f494a..ef70fe97 100644
--- a/client/mifarehost.c
+++ b/client/mifarehost.c
@@ -198,9 +198,9 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * key
 }
 
 int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {
-  UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};
+	UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};
  
-  SendCommand(&c);
+	SendCommand(&c);
 
 	UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
 
@@ -210,9 +210,9 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {
 }
 
 int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) {
-  UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};
+	UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};
 	memcpy(c.d.asBytes, data, blocksCount * 16); 
-  SendCommand(&c);
+	SendCommand(&c);
 	return 0;
 }
 
@@ -228,9 +228,9 @@ int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe) {
 int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint8_t params) {
 	uint8_t isOK = 0;
 
-  UsbCommand c = {CMD_MIFARE_EML_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};
+	UsbCommand c = {CMD_MIFARE_EML_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};
 	memcpy(c.d.asBytes, data, 16); 
-  SendCommand(&c);
+	SendCommand(&c);
 
 	UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
 
@@ -244,3 +244,22 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint
 	}
 	return 0;
 }
+
+int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {
+	uint8_t isOK = 0;
+
+	UsbCommand c = {CMD_MIFARE_EML_CGETBLOCK, {params, 0, blockNo}};
+	SendCommand(&c);
+
+	UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
+
+	if (resp != NULL) {
+		isOK  = resp->arg[0] & 0xff;
+		memcpy(data, resp->d.asBytes, 16); 
+		if (!isOK) return 2;
+	} else {
+		PrintAndLog("Command execute timeout");
+		return 1;
+	}
+	return 0;
+}
diff --git a/client/mifarehost.h b/client/mifarehost.h
index 1d6e0bec..8241ab70 100644
--- a/client/mifarehost.h
+++ b/client/mifarehost.h
@@ -54,4 +54,4 @@ int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
 int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
 int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe);
 int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint8_t params);
-
+int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
diff --git a/include/usb_cmd.h b/include/usb_cmd.h
index a0c6d8a8..4cd6da74 100644
--- a/include/usb_cmd.h
+++ b/include/usb_cmd.h
@@ -115,6 +115,7 @@ typedef struct {
 #define CMD_MIFARE_EML_MEMGET						0x0603
 #define CMD_MIFARE_EML_CARDLOAD					0x0604
 #define CMD_MIFARE_EML_CSETBLOCK				0x0605
+#define CMD_MIFARE_EML_CGETBLOCK				0x0606
 
 #define CMD_SIMULATE_MIFARE_CARD				0x0610
 
-- 
2.39.5