Add: new option 'd' in 'hf mf ekeyprn' to create dumpkeys.bin from emulator memory (#822)

(and whitespace fixes)
This commit is contained in:
pwpiwi 2019-05-22 19:02:58 +02:00 committed by GitHub
parent 9ebbfd898c
commit a39af1cb9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -34,7 +34,7 @@
#include "mifare/ndef.h"
#include "emv/dump.h"
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
static int CmdHelp(const char *Cmd);
@ -65,7 +65,7 @@ int CmdHF14AMfWrBl(const char *Cmd)
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
@ -113,7 +113,7 @@ int CmdHF14AMfRdBl(const char *Cmd)
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
char cmdp = 0x00;
if (strlen(Cmd)<3) {
@ -177,7 +177,7 @@ int CmdHF14AMfRdSc(const char *Cmd)
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t isOK = 0;
uint8_t *data = NULL;
char cmdp = 0x00;
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf rdsc <sector number> <key A/B> <key (12 hex symbols)>");
@ -220,13 +220,13 @@ int CmdHF14AMfRdSc(const char *Cmd)
PrintAndLog("trailer: %s", sprint_hex(data + (sectorNo<32?3:15) * 16, 16));
PrintAndLogEx(NORMAL, "Trailer decoded:");
int bln = mfFirstBlockOfSector(sectorNo);
int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1;
for (i = 0; i < 4; i++) {
PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6]));
bln += blinc;
}
PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1));
int bln = mfFirstBlockOfSector(sectorNo);
int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1;
for (i = 0; i < 4; i++) {
PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6]));
bln += blinc;
}
PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1));
}
} else {
PrintAndLog("Command execute timeout");
@ -371,7 +371,7 @@ int CmdHF14AMfDump(const char *Cmd)
for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
bool received = false;
for (tries = 0; tries < 3; tries++) {
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}};
memcpy(c.d.asBytes, keys[0][sectorNo], 6);
SendCommand(&c);
@ -387,14 +387,14 @@ int CmdHF14AMfDump(const char *Cmd)
// Don't try the other one on success.
if (resp.arg[0] & 0xff) break;
}
} else { // data block. Check if it can be read with key A or key B
} else { // data block. Check if it can be read with key A or key B
uint8_t data_area = sectorNo<32?blockNo:blockNo/5;
if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work
if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work
UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}};
memcpy(c.d.asBytes, keys[1][sectorNo], 6);
SendCommand(&c);
received = WaitForResponseTimeout(CMD_ACK,&resp,1500);
} else if (rights[sectorNo][data_area] == 0x07) { // no key would work
} else if (rights[sectorNo][data_area] == 0x07) { // no key would work
PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo);
if (nullMissingKeys) {
memset(resp.d.asBytes, 0, 16);
@ -405,7 +405,7 @@ int CmdHF14AMfDump(const char *Cmd)
isOK = false;
tries = 2;
}
} else { // key A would work
} else { // key A would work
UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}};
memcpy(c.d.asBytes, keys[0][sectorNo], 6);
SendCommand(&c);
@ -421,13 +421,13 @@ int CmdHF14AMfDump(const char *Cmd)
if (received) {
isOK = resp.arg[0] & 0xff;
uint8_t *data = resp.d.asBytes;
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys.
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys.
memcpy(data, keys[0][sectorNo], 6);
memcpy(data + 10, keys[1][sectorNo], 6);
}
if (isOK) {
memcpy(carddata[FirstBlockOfSector(sectorNo) + blockNo], data, 16);
PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo);
PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo);
} else {
PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo);
break;
@ -530,7 +530,7 @@ int CmdHF14AMfRestore(const char *Cmd)
return 2;
}
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer
bldata[0] = (keyA[sectorNo][0]);
bldata[1] = (keyA[sectorNo][1]);
bldata[2] = (keyA[sectorNo][2]);
@ -721,9 +721,9 @@ int CmdHF14AMfNested(const char *Cmd)
// transfer key to the emulator
if (transferToEml) {
uint8_t sectortrailer;
if (trgBlockNo < 32*4) { // 4 block sector
if (trgBlockNo < 32*4) { // 4 block sector
sectortrailer = trgBlockNo | 0x03;
} else { // 16 block sector
} else { // 16 block sector
sectortrailer = trgBlockNo | 0x0f;
}
mfEmlGetMem(keyBlock, sectortrailer, 1);
@ -1072,8 +1072,8 @@ int CmdHF14AMfChk(const char *Cmd)
uint16_t stKeyBlock = 20;
int i, res;
int keycnt = 0;
char ctmp = 0x00;
int keycnt = 0;
char ctmp = 0x00;
int clen = 0;
uint8_t blockNo = 0;
uint8_t SectorsCnt = 0;
@ -1142,7 +1142,7 @@ int CmdHF14AMfChk(const char *Cmd)
}
PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
(keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2],
(keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6);
(keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6);
keycnt++;
} else {
// May be a dic file
@ -1159,7 +1159,7 @@ int CmdHF14AMfChk(const char *Cmd)
while (fgetc(f) != '\n' && !feof(f)) ; //goto next line
if( buf[0]=='#' ) continue; //The line start with # is comment, skip
if( buf[0]=='#' ) continue; //The line start with # is comment, skip
if (!isxdigit((unsigned char)buf[0])){
PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf);
@ -1200,7 +1200,7 @@ int CmdHF14AMfChk(const char *Cmd)
for (;keycnt < defaultKeysSize; keycnt++)
PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
(keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2],
(keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6);
(keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6);
}
// initialize storage for found keys
@ -1320,7 +1320,7 @@ int CmdHF14AMfChk(const char *Cmd)
void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) {
#define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim()
// cannot be more than 7 or it will overrun c.d.asBytes(512)
// cannot be more than 7 or it will overrun c.d.asBytes(512)
uint64_t key = 0;
typedef struct {
uint64_t keyA;
@ -1329,7 +1329,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack
st_t sector_trailer[ATTACK_KEY_COUNT];
memset(sector_trailer, 0x00, sizeof(sector_trailer));
uint8_t stSector[ATTACK_KEY_COUNT];
uint8_t stSector[ATTACK_KEY_COUNT];
memset(stSector, 0x00, sizeof(stSector));
uint8_t key_cnt[ATTACK_KEY_COUNT];
memset(key_cnt, 0x00, sizeof(key_cnt));
@ -1392,7 +1392,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack
if (setEmulatorMem) {
for (uint8_t i = 0; i<ATTACK_KEY_COUNT; i++) {
if (key_cnt[i]>0) {
uint8_t memBlock[16];
uint8_t memBlock[16];
memset(memBlock, 0x00, sizeof(memBlock));
char cmd1[36];
memset(cmd1,0x00,sizeof(cmd1));
@ -1580,7 +1580,7 @@ int CmdHF14AMfSim(const char *Cmd) {
cardsize == '2' ? "2K" :
cardsize == '4' ? "4K" : "1K",
flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A",
flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A",
exitAfterNReads,
flags,
flags);
@ -1615,7 +1615,7 @@ int CmdHF14AMfSim(const char *Cmd) {
cardsize == '2' ? "2K" :
cardsize == '4' ? "4K" : "1K",
flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A",
flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A",
exitAfterNReads,
flags,
flags);
@ -1951,31 +1951,37 @@ int CmdHF14AMfECFill(const char *Cmd)
return 0;
}
int CmdHF14AMfEKeyPrn(const char *Cmd)
{
int i;
uint8_t numSectors;
uint8_t numSectors = 16;
uint8_t data[16];
uint64_t keyA, keyB;
bool createDumpFile = false;
if (param_getchar(Cmd, 0) == 'h') {
PrintAndLog("It prints the keys loaded in the emulator memory");
PrintAndLog("Usage: hf mf ekeyprn [card memory]");
PrintAndLog("Usage: hf mf ekeyprn [card memory] [d]");
PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
PrintAndLog(" [d] : write keys to binary file dumpkeys.bin");
PrintAndLog("");
PrintAndLog(" sample: hf mf ekeyprn 1");
return 0;
}
char cmdp = param_getchar(Cmd, 0);
switch (cmdp) {
case '0' : numSectors = 5; break;
case '1' :
case '\0': numSectors = 16; break;
case '2' : numSectors = 32; break;
case '4' : numSectors = 40; break;
default: numSectors = 16;
uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00) {
switch (param_getchar(Cmd, cmdp)) {
case '0' : numSectors = 5; break;
case '1' :
case '\0': numSectors = 16; break;
case '2' : numSectors = 32; break;
case '4' : numSectors = 40; break;
case 'd' :
case 'D' : createDumpFile = true; break;
}
cmdp++;
}
PrintAndLog("|---|----------------|----------------|");
@ -1992,9 +1998,35 @@ int CmdHF14AMfEKeyPrn(const char *Cmd)
}
PrintAndLog("|---|----------------|----------------|");
// Create dump file
if (createDumpFile) {
FILE *fkeys;
if ((fkeys = fopen("dumpkeys.bin","wb")) == NULL) {
PrintAndLog("Could not create file dumpkeys.bin");
return 1;
}
PrintAndLog("Printing keys to binary file dumpkeys.bin...");
for(i = 0; i < numSectors; i++) {
if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) {
PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
break;
}
fwrite(data+6, 1, 6, fkeys);
}
for(i = 0; i < numSectors; i++) {
if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) {
PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
break;
}
fwrite(data+10, 1, 6, fkeys);
}
fclose(fkeys);
}
return 0;
}
int CmdHF14AMfCSetUID(const char *Cmd)
{
uint8_t uid[8] = {0x00};
@ -2213,9 +2245,9 @@ int CmdHF14AMfCLoad(const char *Cmd)
PrintAndLog("Cant get block: %d", blockNum);
return 2;
}
if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence
if (blockNum == 1) flags = 0; // just write
if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field.
if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence
if (blockNum == 1) flags = 0; // just write
if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field.
if (gen == 2)
/* generation 1b magic card */
@ -2265,9 +2297,9 @@ int CmdHF14AMfCLoad(const char *Cmd)
for (i = 0; i < 32; i += 2)
sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]);
if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence
if (blockNum == 1) flags = 0; // just write
if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field.
if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence
if (blockNum == 1) flags = 0; // just write
if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field.
if (gen == 2)
/* generation 1b magic card */
@ -2392,17 +2424,17 @@ int CmdHF14AMfCGetSc(const char *Cmd) {
PrintAndLog("block %3d data:%s", baseblock + i, sprint_hex(memBlock, 16));
if (mfIsSectorTrailer(baseblock + i)) {
PrintAndLogEx(NORMAL, "Trailer decoded:");
PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6));
PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6));
int bln = baseblock;
int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1;
for (int i = 0; i < 4; i++) {
PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6]));
bln += blinc;
}
PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1));
}
PrintAndLogEx(NORMAL, "Trailer decoded:");
PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6));
PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6));
int bln = baseblock;
int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1;
for (int i = 0; i < 4; i++) {
PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6]));
bln += blinc;
}
PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1));
}
}
return 0;
}
@ -2599,17 +2631,17 @@ int CmdHF14AMfSniff(const char *Cmd){
uint16_t traceLen = resp.arg[1];
len = resp.arg[2];
if (res == 0) { // we are done
if (res == 0) { // we are done
break;
}
if (res == 1) { // there is (more) data to be transferred
if (pckNum == 0) { // first packet, (re)allocate necessary buffer
if (res == 1) { // there is (more) data to be transferred
if (pckNum == 0) { // first packet, (re)allocate necessary buffer
if (traceLen > bufsize || buf == NULL) {
uint8_t *p;
if (buf == NULL) { // not yet allocated
if (buf == NULL) { // not yet allocated
p = malloc(traceLen);
} else { // need more memory
} else { // need more memory
p = realloc(buf, traceLen);
}
if (p == NULL) {
@ -2628,13 +2660,13 @@ int CmdHF14AMfSniff(const char *Cmd){
pckNum++;
}
if (res == 2) { // received all data, start displaying
if (res == 2) { // received all data, start displaying
blockLen = bufPtr - buf;
bufPtr = buf;
printf(">\n");
PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum);
while (bufPtr - buf < blockLen) {
bufPtr += 6; // skip (void) timing information
bufPtr += 6; // skip (void) timing information
len = *((uint16_t *)bufPtr);
if(len & 0x8000) {
isTag = true;
@ -2676,7 +2708,7 @@ int CmdHF14AMfSniff(const char *Cmd){
num++;
}
bufPtr += len;
bufPtr += parlen; // ignore parity
bufPtr += parlen; // ignore parity
}
pckNum = 0;
}
@ -2737,196 +2769,196 @@ int CmdHF14AMfAuth4(const char *cmd) {
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
int CmdHF14AMfMAD(const char *cmd) {
CLIParserInit("hf mf mad",
"Checks and prints Mifare Application Directory (MAD)",
"Usage:\n\thf mf mad -> shows MAD if exists\n"
"\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n");
CLIParserInit("hf mf mad",
"Checks and prints Mifare Application Directory (MAD)",
"Usage:\n\thf mf mad -> shows MAD if exists\n"
"\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show technical data"),
arg_str0("aA", "aid", "print all sectors with aid", NULL),
arg_str0("kK", "key", "key for printing sectors", NULL),
arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[6] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
void *argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show technical data"),
arg_str0("aA", "aid", "print all sectors with aid", NULL),
arg_str0("kK", "key", "key for printing sectors", NULL),
arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[6] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
CLIParserFree();
CLIParserFree();
if (aidlen != 2 && keylen > 0) {
PrintAndLogEx(WARNING, "do not need a key without aid.");
}
if (aidlen != 2 && keylen > 0) {
PrintAndLogEx(WARNING, "do not need a key without aid.");
}
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) {
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) {
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
if (verbose) {
for (int i = 0; i < 4; i ++)
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(&sector0[i * 16], 16));
}
if (verbose) {
for (int i = 0; i < 4; i ++)
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(&sector0[i * 16], 16));
}
bool haveMAD2 = false;
MAD1DecodeAndPrint(sector0, verbose, &haveMAD2);
bool haveMAD2 = false;
MAD1DecodeAndPrint(sector0, verbose, &haveMAD2);
if (haveMAD2) {
if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
if (haveMAD2) {
if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
MAD2DecodeAndPrint(sector10, verbose);
}
MAD2DecodeAndPrint(sector10, verbose);
}
if (aidlen == 2) {
uint16_t aaid = (aid[0] << 8) + aid[1];
PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid);
if (aidlen == 2) {
uint16_t aaid = (aid[0] << 8) + aid[1];
PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid);
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, sector10, mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, sector10, mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
uint8_t akey[6] = {0};
memcpy(akey, g_mifare_ndef_key, 6);
if (keylen == 6) {
memcpy(akey, key, 6);
}
uint8_t akey[6] = {0};
memcpy(akey, g_mifare_ndef_key, 6);
if (keylen == 6) {
memcpy(akey, key, 6);
}
for (int i = 0; i < madlen; i++) {
if (aaid == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
for (int i = 0; i < madlen; i++) {
if (aaid == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
for (int j = 0; j < (verbose ? 4 : 3); j ++)
PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16));
}
}
}
for (int j = 0; j < (verbose ? 4 : 3); j ++)
PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16));
}
}
}
return 0;
return 0;
}
int CmdHFMFNDEF(const char *cmd) {
CLIParserInit("hf mf ndef",
"Prints NFC Data Exchange Format (NDEF)",
"Usage:\n\thf mf ndef -> shows NDEF data\n"
"\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n");
CLIParserInit("hf mf ndef",
"Prints NFC Data Exchange Format (NDEF)",
"Usage:\n\thf mf ndef -> shows NDEF data\n"
"\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n");
void *argtable[] = {
arg_param_begin,
arg_litn("vV", "verbose", 0, 2, "show technical data"),
arg_str0("aA", "aid", "replace default aid for NDEF", NULL),
arg_str0("kK", "key", "replace default key for NDEF", NULL),
arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
void *argtable[] = {
arg_param_begin,
arg_litn("vV", "verbose", 0, 2, "show technical data"),
arg_str0("aA", "aid", "replace default aid for NDEF", NULL),
arg_str0("kK", "key", "replace default key for NDEF", NULL),
arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1;
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[6] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1;
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[6] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
CLIParserFree();
CLIParserFree();
uint16_t ndefAID = 0x03e1;
if (aidlen == 2)
ndefAID = (aid[0] << 8) + aid[1];
uint16_t ndefAID = 0x03e1;
if (aidlen == 2)
ndefAID = (aid[0] << 8) + aid[1];
uint8_t ndefkey[6] = {0};
memcpy(ndefkey, g_mifare_ndef_key, 6);
if (keylen == 6) {
memcpy(ndefkey, key, 6);
}
uint8_t ndefkey[6] = {0};
memcpy(ndefkey, g_mifare_ndef_key, 6);
if (keylen == 6) {
memcpy(ndefkey, key, 6);
}
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
uint8_t data[4096] = {0};
int datalen = 0;
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
uint8_t data[4096] = {0};
int datalen = 0;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "");
if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) {
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) {
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
bool haveMAD2 = false;
int res = MADCheck(sector0, NULL, verbose, &haveMAD2);
if (res) {
PrintAndLogEx(ERR, "MAD error %d.", res);
return res;
}
bool haveMAD2 = false;
int res = MADCheck(sector0, NULL, verbose, &haveMAD2);
if (res) {
PrintAndLogEx(ERR, "MAD error %d.", res);
return res;
}
if (haveMAD2) {
if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
}
if (haveMAD2) {
if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
}
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
printf("data reading:");
for (int i = 0; i < madlen; i++) {
if (ndefAID == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) {
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
printf("data reading:");
for (int i = 0; i < madlen; i++) {
if (ndefAID == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) {
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
memcpy(&data[datalen], vsector, 16 * 3);
datalen += 16 * 3;
memcpy(&data[datalen], vsector, 16 * 3);
datalen += 16 * 3;
printf(".");
}
}
printf(" OK\n");
printf(".");
}
}
printf(" OK\n");
if (!datalen) {
PrintAndLogEx(ERR, "no NDEF data.");
return 11;
}
if (!datalen) {
PrintAndLogEx(ERR, "no NDEF data.");
return 11;
}
if (verbose2) {
PrintAndLogEx(NORMAL, "NDEF data:");
dump_buffer(data, datalen, stdout, 1);
}
if (verbose2) {
PrintAndLogEx(NORMAL, "NDEF data:");
dump_buffer(data, datalen, stdout, 1);
}
NDEFDecodeAndPrint(data, datalen, verbose);
NDEFDecodeAndPrint(data, datalen, verbose);
return 0;
return 0;
}
static command_t CommandTable[] =
@ -2936,7 +2968,7 @@ static command_t CommandTable[] =
{"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"},
{"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"},
{"chk", CmdHF14AMfChk, 0, "Test block keys"},