Skip to content

Commit

Permalink
Unlocked read and format/wipe of special Mifare cards
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamLaurie committed Sep 6, 2011
1 parent 1a07613 commit 028f310
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 63 deletions.
16 changes: 12 additions & 4 deletions examples/nfc-mfclassic.1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
nfc-mfclassic \- MIFARE Classic command line tool
.SH SYNOPSIS
.B nfc-mfclassic
.RI \fR\fBr\fR|\fBw\fR\fR|\fBu\fR
.RI \fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR
.RI \fR\fBa\fR|\fBb\fR
.IR DUMP
.IR [KEYS]
Expand All @@ -27,18 +27,25 @@ to store the keys and data for all sectors.
Be cautious that some parts of a Mifare Classic memory are used for r/w access
of the rest of the memory, so please read the tag documentation before experimenting too much!

The 'u' option allows writing of special Mifare cards that can be 'unlocked' to allow block 0
The 'W' option allows writing of special Mifare cards that can be 'unlocked' to allow block 0
to be overwritten. This includes UID and manufacturer data. Take care when amending UIDs to set
the correct BCC (UID checksum). Currently only 4 byte UIDs are supported.

Similarly, the 'R' option allows an 'unlocked' read. This bypasses authentication and allows
reading of the Key A and Key B data regardless of ACLs.

*** Note that 'W' and 'R' options only work on special versions of Mifare 1K cards (Chinese clones).

.SH OPTIONS
.BR r " | " w " | " u
.BR r " | " R " | " w " | " W
Perform read from (
.B r
) or unlocked read from (
.B R
) or write to (
.B w
) or unlocked write to (
.B u
.B W
) card.
.TP
.BR a " | " b
Expand All @@ -65,6 +72,7 @@ are covered by the GNU Lesser General Public License (LGPL), version 3.
Roel Verdult <[email protected]>
Romuald Conty <[email protected]>
Romain Tartière <[email protected]>
Adam Laurie <[email protected]>
.PP
This manual page was written by Romuald Conty <[email protected]>.
It is licensed under the terms of the GNU GPL (version 2 or later).
121 changes: 65 additions & 56 deletions examples/nfc-mfclassic.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,60 @@ authenticate (uint32_t uiBlock)
return false;
}

static bool
unlock_card()
{
printf ("Unlocking card\n");

// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Use raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}

iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
// now send unlock
if (!transmit_bits (abtUnlock1, 7)) {
printf("unlock failure!\n");
return false;
}
if (!transmit_bytes (abtUnlock2, 1)) {
printf("unlock failure!\n");
return false;
}

// reset reader
// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Switch off raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
return true;
}

static bool
read_card (void)
read_card (int read_unlocked)
{
int32_t iBlock;
bool bFailure = false;
uint32_t uiReadBlocks = 0;

if(read_unlocked)
if (!unlock_card())
return false;


printf ("Reading out %d blocks |", uiBlocks + 1);

// Read the card from end to begin
Expand All @@ -243,7 +290,7 @@ read_card (void)
fflush (stdout);

// Try to authenticate for the current sector
if (!authenticate (iBlock)) {
if (!read_unlocked && !authenticate (iBlock)) {
printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
return false;
}
Expand Down Expand Up @@ -286,46 +333,9 @@ write_card (int write_block_zero)
uint32_t uiWriteBlocks = 0;


if(write_block_zero) {
printf ("Unlocking card\n");

// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Use raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, false)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}

iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
// now send unlock
if (!transmit_bits (abtUnlock1, 7)) {
printf("unlock failure!\n");
if(write_block_zero)
if (!unlock_card())
return false;
}
if (!transmit_bytes (abtUnlock2, 1)) {
printf("unlock failure!\n");
return false;
}

// reset reader
// Configure the CRC
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
// Switch off raw send/receive methods
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
nfc_perror (pnd, "nfc_configure");
exit (EXIT_FAILURE);
}
}



printf ("Writing %d blocks |", uiBlocks + 1);
// Write the card from begin to end;
Expand Down Expand Up @@ -418,18 +428,18 @@ typedef enum {
ACTION_READ,
ACTION_WRITE,
ACTION_EXTRACT,
ACTION_USAGE,
ACTION_WRITE_UNLOCKED
ACTION_USAGE
} action_t;

static void
print_usage (const char *pcProgramName)
{
printf ("Usage: ");
printf ("%s r|w|u a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf (" r|w|u - Perform read from (r) or write to (w) or unlocked write to (u) card\n");
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 (" *** and only works with special Mifare 1K cards (Chinese clones)\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");
Expand All @@ -447,29 +457,32 @@ main (int argc, const char *argv[])
byte_t *pbtUID;
FILE *pfKeys = NULL;
FILE *pfDump = NULL;
int unlock= 0;

if (argc < 2) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
const char *command = argv[1];

if (strcmp (command, "r") == 0) {
if (strcmp (command, "r") == 0 || strcmp (command, "R") == 0) {
if (argc < 4) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
atAction = ACTION_READ;
if (strcmp (command, "R") == 0)
unlock= 1;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if (strcmp (command, "w") == 0 || strcmp (command, "u") == 0) {
} else if (strcmp (command, "w") == 0 || strcmp (command, "W") == 0) {
if (argc < 4) {
print_usage (argv[0]);
exit (EXIT_FAILURE);
}
atAction = ACTION_WRITE;
if (strcmp (command, "u") == 0)
atAction = ACTION_WRITE_UNLOCKED;
if (strcmp (command, "W") == 0)
unlock= 1;
bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
bUseKeyFile = (argc > 4);
} else if (strcmp (command, "x") == 0) {
Expand All @@ -487,7 +500,6 @@ main (int argc, const char *argv[])
break;
case ACTION_READ:
case ACTION_WRITE:
case ACTION_WRITE_UNLOCKED:
if (bUseKeyFile) {
pfKeys = fopen (argv[4], "rb");
if (pfKeys == NULL) {
Expand Down Expand Up @@ -580,7 +592,7 @@ main (int argc, const char *argv[])
printf ("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);

if (atAction == ACTION_READ) {
if (read_card ()) {
if (read_card (unlock)) {
printf ("Writing data to file: %s ...", argv[3]);
fflush (stdout);
pfDump = fopen (argv[3], "wb");
Expand All @@ -596,10 +608,7 @@ main (int argc, const char *argv[])
fclose (pfDump);
}
} else if (atAction == ACTION_WRITE) {
write_card (0);
}
else if (atAction == ACTION_WRITE_UNLOCKED) {
write_card (1);
write_card (unlock);
}

nfc_disconnect (pnd);
Expand Down
8 changes: 8 additions & 0 deletions examples/nfc-mfsetuid.1
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
nfc-mfsetuid \- MIFARE 1K special card UID setting and recovery tool
.SH SYNOPSIS
.B nfc-mfsetuid
[UID]

.SH DESCRIPTION
.B nfc-mfsetuid
is a MIFARE tool that allows setting of UID on special versions (Chinese clones) of Mifare 1K cards. It will also recover
damaged cards that have had invalid data written to block 0 (e.g. wrong BCC). Currently only 4 Byte UID is supported.
Specify an eight hex character UID or leave blank for the default '01234567'.

.SH OPTIONS
.B -f
Format. Wipe all data (set to 0xFF) and reset ACLs to defaults.

.B -q
Quiet. Suppress output of commands and responses.
.SH BUGS
Please report any bugs on the
.B libnfc
Expand Down
26 changes: 23 additions & 3 deletions examples/nfc-mfsetuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ byte_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
// special unlock command
byte_t abtUnlock1[1] = { 0x40 };
byte_t abtUnlock2[1] = { 0x43 };
byte_t abtWipe[1] = { 0x41 };
byte_t abtWrite[4] = { 0xa0, 0x00, 0x5f, 0xb1 };
byte_t abtData[18] = { 0x01, 0x23, 0x45, 0x67, 0x00, 0x08, 0x04, 0x00, 0x46, 0x59, 0x25, 0x58, 0x49, 0x10, 0x23, 0x02, 0x23, 0xeb };
byte_t abtBlank[18] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0xCC };


static bool
Expand Down Expand Up @@ -134,7 +136,8 @@ print_usage (char *argv[])
printf ("Usage: %s [OPTIONS] [UID]\n", argv[0]);
printf ("Options:\n");
printf ("\t-h\tHelp. Print this message.\n");
printf ("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n");
printf ("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n");
printf ("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n");
printf ("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n");
printf ("\tThis utility can be used to recover cards that have been damaged by writing bad\n");
printf ("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n");
Expand All @@ -144,15 +147,19 @@ print_usage (char *argv[])
int
main (int argc, char *argv[])
{
int arg, i;
int arg, i;
bool format= false;
unsigned int c;
char tmp[3]= { 0x00, 0x00, 0x00 };
char tmp[3]= { 0x00, 0x00, 0x00 };


// Get commandline options
for (arg = 1; arg < argc; arg++) {
if (0 == strcmp (argv[arg], "-h")) {
print_usage (argv);
exit(EXIT_SUCCESS);
} else if (0 == strcmp (argv[arg], "-f")) {
format= true;
} else if (0 == strcmp (argv[arg], "-q")) {
quiet_output = true;
} else if (strlen(argv[arg]) == 8) {
Expand Down Expand Up @@ -322,9 +329,22 @@ main (int argc, char *argv[])
iso14443a_crc_append(abtHalt, 2);
transmit_bytes (abtHalt, 4);
transmit_bits (abtUnlock1,7);
if(format) {
transmit_bytes (abtWipe,1);
transmit_bytes (abtHalt, 4);
transmit_bits (abtUnlock1,7);
}
transmit_bytes (abtUnlock2,1);
transmit_bytes (abtWrite,4);
transmit_bytes (abtData,18);
if(format) {
for(i= 3 ; i < 64 ; i += 4) {
abtWrite[1]= (char) i;
iso14443a_crc_append (abtWrite, 2);
transmit_bytes (abtWrite,4);
transmit_bytes (abtBlank,18);
}
}


nfc_disconnect (pnd);
Expand Down

0 comments on commit 028f310

Please sign in to comment.