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