昨天悲剧了,把一个不完整的dump写到了饭卡里,控制位全是0,直接导致饭卡的大部分区锁死,万幸的是,关键数据区没损坏,消费,门禁还都好用……
为了防止悲剧的再次发生,给 nfc-mfclassic 添加了 防止控制位误写 功能,以下是 指定读写的块+防止控制位误写 补丁:
Index: nfc-mfclassic.c
===================================================================
--- nfc-mfclassic.c (版本 1416)
+++ nfc-mfclassic.c (工作副本)
@@ -38,6 +38,13 @@
# include "config.h"
#endif // HAVE_CONFIG_H
+#define BYTE_HIGH(X) ( 0XF & (X>>4) )
+#define BYTE_LOW(X) ( 0XF & X)
+#define BYTE_HIGH_NOT(X) ( 0XF & ~BYTE_HIGH(X) )
+#define BYTE_LOW_NOT(X) ( 0XF & ~BYTE_LOW(X) )
+
+#define GET_CX_BIT(half_byte,block) ( 0x1 & (half_byte >> block))
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -71,6 +78,9 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xab, 0xcd, 0xef, 0x12, 0x34, 0x56
};
+//Operate block
+static bool blocks[0xFF];
+static bool bSkip = false;
static const nfc_modulation nmMifare = {
.nmt = NMT_ISO14443A,
@@ -127,11 +137,11 @@
}
static void
-print_success_or_failure (bool bFailure, uint32_t *uiBlockCounter)
+print_success_or_failure (char bFailure)
{
- printf ("%c", (bFailure) ? 'x' : '.');
- if (uiBlockCounter && !bFailure)
- *uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
+ printf ("%c", (bFailure) ? (bFailure==true?'x':'-'): '.');
+// if (uiBlockCounter && !bFailure)
+// *uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
}
static bool
@@ -191,10 +201,10 @@
memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6);
else
memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6);
-
// Try to authenticate for the current sector
if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp))
return true;
+ nfc_initiator_select_passive_target (pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL);
} else {
// Try to guess the right key
for (key_index = 0; key_index < num_keys; key_index++) {
@@ -259,7 +269,7 @@
read_card (int read_unlocked)
{
int32_t iBlock;
- bool bFailure = false;
+ char bFailure = false;
uint32_t uiReadBlocks = 0;
if(read_unlocked)
@@ -275,8 +285,17 @@
if (is_trailer_block (iBlock)) {
// Skip this the first time, bFailure it means nothing (yet)
if (iBlock != uiBlocks)
- print_success_or_failure (bFailure, &uiReadBlocks);
+ print_success_or_failure (bFailure);
+ if (bSkip)
+ {
+ for (int i=iBlock;get_trailer_block(i)==iBlock;--i)
+ if (blocks[i])
+ goto next;
+ bFailure = -1;
+ continue ;
+ }
+next:
// Show if the readout went well
if (bFailure) {
// When a failure occured we need to redo the anti-collision
@@ -291,9 +310,14 @@
// Try to authenticate for the current sector
if (!read_unlocked && !authenticate (iBlock)) {
- printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
- return false;
+// printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
+ bFailure = true;
+ continue ;
+ //return false;
}
+
+ if (bSkip && !blocks[iBlock])
+ continue ;
// Try to read out the trailer
if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
if(read_unlocked) {
@@ -304,15 +328,20 @@
memcpy (mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4);
memcpy (mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6);
}
+ uiReadBlocks++;
} else {
printf ("!\nError: unable to read trailer block 0x%02x\n", iBlock);
}
} else {
+
+ if (bSkip && !blocks[iBlock])
+ continue ;
// Make sure a earlier readout did not fail
if (!bFailure) {
// Try to read out the data block
if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
memcpy (mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
+ uiReadBlocks++;
} else {
bFailure = true;
printf ("!\nError: unable to read block 0x%02x\n", iBlock);
@@ -321,7 +350,7 @@
}
}
}
- print_success_or_failure (bFailure, &uiReadBlocks);
+ print_success_or_failure (bFailure);
printf ("|\n");
printf ("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
fflush (stdout);
@@ -333,7 +362,7 @@
write_card (int write_block_zero)
{
uint32_t uiBlock;
- bool bFailure = false;
+ char bFailure = false;
uint32_t uiWriteBlocks = 0;
@@ -348,8 +377,18 @@
if (is_first_block (uiBlock)) {
// Skip this the first time, bFailure it means nothing (yet)
if (uiBlock != 0)
- print_success_or_failure (bFailure, &uiWriteBlocks);
+ print_success_or_failure (bFailure);
+ if (bSkip)
+ {
+ for (int i=get_trailer_block(uiBlock);i>uiBlock;--i)
+ if (blocks[i])
+ goto next;
+ bFailure = -1;
+ continue ;
+ }
+next:
+
// Show if the readout went well
if (bFailure) {
// When a failure occured we need to redo the anti-collision
@@ -364,28 +403,69 @@
// Try to authenticate for the current sector
if (!write_block_zero && !authenticate (uiBlock)) {
- printf ("!\nError: authentication failed for block %02x\n", uiBlock);
- return false;
+ //printf ("!\nError: authentication failed for block %02x\n", uiBlock);
+ bFailure = true;
+ continue ;
+ //return false;
}
}
+ if (bSkip && !blocks[uiBlock])
+ continue ;
if (is_trailer_block (uiBlock)) {
// Copy the keys over from our key dump and store the retrieved access bits
memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6);
+ // VERY INPORTENT! Verify the AccessBits
+ if ( BYTE_HIGH_NOT(mtDump.amb[uiBlock].mbt.abtAccessBits[0]) != BYTE_LOW(mtDump.amb[uiBlock].mbt.abtAccessBits[2])
+ || BYTE_LOW_NOT(mtDump.amb[uiBlock].mbt.abtAccessBits[0]) != BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[1])
+ || BYTE_LOW_NOT(mtDump.amb[uiBlock].mbt.abtAccessBits[1]) != BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[2])
+
+ )
+ {
+ printf ("\nNOT valid AccessBits! block:%d AccessBits:%02X %02X %02X %02X\n",uiBlock,mtDump.amb[uiBlock].mbt.abtAccessBits[0],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[1],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[2],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[3]);
+ return false;
+ }
+
+ if (
+ GET_CX_BIT/*C3*/(BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[2]),3)==0 ||
+
+ GET_CX_BIT(/*C1*/BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[1]),3)==1 &&
+ GET_CX_BIT(/*C2*/BYTE_LOW(mtDump.amb[uiBlock].mbt.abtAccessBits[2]),3)==1
+ )
+ {
+ printf ("\nThe AccessBits for 'access bits writable' didn't set,This means that you will never be able to change AccessBits again\
+,if you really want to do this,use f option(haven't implement now) AccessBits:%02X %02X %02X %02X C1C2C3:%1X %1X %1X\n",mtDump.amb[uiBlock].mbt.abtAccessBits[0],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[1],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[2],
+ mtDump.amb[uiBlock].mbt.abtAccessBits[3],
+ BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[1]),
+ BYTE_LOW(mtDump.amb[uiBlock].mbt.abtAccessBits[2]),
+ BYTE_HIGH(mtDump.amb[uiBlock].mbt.abtAccessBits[2])
+ );
+ return false;
+ }
+
memcpy (mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4);
memcpy (mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6);
// Try to write the trailer
if (nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp) == false) {
- printf ("failed to write trailer block %d \n", uiBlock);
+// printf ("failed to write trailer block %d \n", uiBlock);
bFailure = true;
}
+ else
+ uiWriteBlocks++;
} else {
+
+ if (bSkip && !blocks[uiBlock])
+ continue ;
// The first block 0x00 is read only, skip this
if (uiBlock == 0 && ! write_block_zero)
continue;
-
// Make sure a earlier write did not fail
if (!bFailure) {
// Try to write the data block
@@ -399,10 +479,12 @@
}
if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp))
bFailure = true;
+ else
+ uiWriteBlocks++;
}
}
}
- print_success_or_failure (bFailure, &uiWriteBlocks);
+ print_success_or_failure (bFailure);
printf ("|\n");
printf ("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
fflush (stdout);
@@ -420,14 +502,16 @@
print_usage (const char *pcProgramName)
{
printf ("Usage: ");
- printf ("%s r|R|w|W a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
- printf (" r|R|w|W - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
- printf (" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
- printf (" *** unlocked read does not require authentication and will reveal A and B keys\n");
- printf (" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
- printf (" a|b - Use A or B keys for action\n");
- printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
- printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
+ printf ("%s r|R|w|W[<,sector[t]>[...]] a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
+ printf (" <r|R|w|W>[<,sector[t|f]]>[...]] - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
+ printf (" the sector to be read or write ,include or exclude trailer block ,can be specified,omit means all sectors include trailer block\n");
+ printf (" example: r,0,15t means only read sector 0 and sector 15 include trailer block\n");
+ printf (" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
+ printf (" *** unlocked read does not require authentication and will reveal A and B keys\n");
+ printf (" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
+ printf (" a|b - Use A or B keys for action\n");
+ printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
+ printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
}
int
@@ -443,10 +527,10 @@
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
- const char *command = argv[1];
+ const char *command = strtok(argv[1], ",");
if (strcmp (command, "r") == 0 || strcmp (command, "R") == 0) {
- if (argc < 4) {
+ if (argc < 4) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
@@ -467,6 +551,23 @@
bUseKeyFile = (argc > 4);
}
+ char *sector = NULL;
+ int isector;
+ while ( (sector=strtok(NULL, ",")) != NULL )
+ {
+ if ( (isector=atoi(sector))==0 && sector[0]!='0' || isector<0 || isector>39)
+ {
+ printf("invalid sector argument: %s\n",sector);
+ exit (EXIT_FAILURE);
+ }
+ bSkip=true;
+
+ for(int i=get_trailer_block(isector<32?isector*4:256-(40-isector)*16) - !(sector[strlen(sector)-1]=='t') ;
+ i>=(isector<32?isector*4:256-(40-isector)*16) ;
+ --i)
+ blocks[i] = true;
+ }
+
switch (atAction) {
case ACTION_USAGE:
print_usage (argv[0]);