mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
UL/NTAG new dump file format. Added counters support, simulation
This commit is contained in:
parent
c7a4d7af3a
commit
db3103b531
9 changed files with 123 additions and 74 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff)
|
||||||
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
|
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
|
||||||
- Fix serial of FPC. (@ryan)
|
- Fix serial of FPC. (@ryan)
|
||||||
- Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox)
|
- Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox)
|
||||||
|
|
|
@ -832,8 +832,6 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
|
|
||||||
// PACK response to PWD AUTH for EV1/NTAG
|
// PACK response to PWD AUTH for EV1/NTAG
|
||||||
uint8_t response8[4] = {0, 0, 0, 0};
|
uint8_t response8[4] = {0, 0, 0, 0};
|
||||||
// Counter for EV1/NTAG
|
|
||||||
uint32_t counters[] = {0, 0, 0};
|
|
||||||
|
|
||||||
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
|
||||||
uint8_t response1[] = {0, 0};
|
uint8_t response1[] = {0, 0};
|
||||||
|
@ -848,6 +846,9 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces));
|
memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces));
|
||||||
uint8_t moebius_count = 0;
|
uint8_t moebius_count = 0;
|
||||||
|
|
||||||
|
// some first pages of UL/NTAG dump is special data
|
||||||
|
mfu_dump_prefix_t *mfu_header = tagType == 2 || tagType == 7 ? (mfu_dump_prefix_t *) BigBuf_get_EM_addr() : NULL;
|
||||||
|
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case 1: { // MIFARE Classic 1k
|
case 1: { // MIFARE Classic 1k
|
||||||
response1[0] = 0x04;
|
response1[0] = 0x04;
|
||||||
|
@ -884,13 +885,12 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
case 7: { // NTAG
|
case 7: { // NTAG
|
||||||
response1[0] = 0x44;
|
response1[0] = 0x44;
|
||||||
sak = 0x00;
|
sak = 0x00;
|
||||||
// PACK
|
// PACK, from last page of dump
|
||||||
response8[0] = 0x80;
|
emlGetMemBt(response8, MFU_DUMP_PREFIX_LENGTH + mfu_header->pages * 4, 2);
|
||||||
response8[1] = 0x80;
|
|
||||||
compute_crc(CRC_14443_A, response8, 2, &response8[2], &response8[3]);
|
compute_crc(CRC_14443_A, response8, 2, &response8[2], &response8[3]);
|
||||||
// uid not supplied then get from emulator memory
|
// uid not supplied then get from emulator memory
|
||||||
if (data[0] == 0) {
|
if (data[0] == 0) {
|
||||||
uint16_t start = 4 * (0 + 12);
|
uint16_t start = MFU_DUMP_PREFIX_LENGTH;
|
||||||
uint8_t emdata[8];
|
uint8_t emdata[8];
|
||||||
emlGetMemBt(emdata, start, sizeof(emdata));
|
emlGetMemBt(emdata, start, sizeof(emdata));
|
||||||
memcpy(data, emdata, 3); // uid bytes 0-2
|
memcpy(data, emdata, 3); // uid bytes 0-2
|
||||||
|
@ -1086,12 +1086,17 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
uint8_t block = receivedCmd[1];
|
uint8_t block = receivedCmd[1];
|
||||||
// if Ultralight or NTAG (4 byte blocks)
|
// if Ultralight or NTAG (4 byte blocks)
|
||||||
if (tagType == 7 || tagType == 2) {
|
if (tagType == 7 || tagType == 2) {
|
||||||
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
|
if (block > mfu_header->pages) {
|
||||||
uint16_t start = 4 * (block + 12);
|
// send NACK 0x0 == invalid argument
|
||||||
|
EmSend4bit(CARD_NACK_IV);
|
||||||
|
} else {
|
||||||
|
// first blocks of emu are header
|
||||||
|
uint16_t start = block * 4 + MFU_DUMP_PREFIX_LENGTH;
|
||||||
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
|
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
|
||||||
emlGetMemBt(emdata, start, 16);
|
emlGetMemBt(emdata, start, 16);
|
||||||
AddCrc14A(emdata, 16);
|
AddCrc14A(emdata, 16);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
|
}
|
||||||
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
} else if (tagType == 9 && block == 1) {
|
} else if (tagType == 9 && block == 1) {
|
||||||
|
@ -1110,23 +1115,36 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
}
|
}
|
||||||
} else if (receivedCmd[0] == MIFARE_ULEV1_FASTREAD) { // Received a FAST READ (ranged read)
|
} else if (receivedCmd[0] == MIFARE_ULEV1_FASTREAD) { // Received a FAST READ (ranged read)
|
||||||
|
uint8_t block1 = receivedCmd[1];
|
||||||
|
uint8_t block2 = receivedCmd[2];
|
||||||
|
if (block1 > mfu_header->pages) {
|
||||||
|
// send NACK 0x0 == invalid argument
|
||||||
|
EmSend4bit(CARD_NACK_IV);
|
||||||
|
} else {
|
||||||
uint8_t emdata[MAX_FRAME_SIZE];
|
uint8_t emdata[MAX_FRAME_SIZE];
|
||||||
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
|
// first blocks of emu are header
|
||||||
int start = (receivedCmd[1] + 12) * 4;
|
int start = block1 * 4 + MFU_DUMP_PREFIX_LENGTH;
|
||||||
len = (receivedCmd[2] - receivedCmd[1] + 1) * 4;
|
len = (block2 - block1 + 1) * 4;
|
||||||
emlGetMemBt(emdata, start, len);
|
emlGetMemBt(emdata, start, len);
|
||||||
AddCrc14A(emdata, len);
|
AddCrc14A(emdata, len);
|
||||||
EmSendCmd(emdata, len + 2);
|
EmSendCmd(emdata, len + 2);
|
||||||
|
}
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
} else if ((receivedCmd[0] == MIFARE_ULC_WRITE || receivedCmd[0] == MIFARE_ULC_COMP_WRITE) && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
} else if ((receivedCmd[0] == MIFARE_ULC_WRITE || receivedCmd[0] == MIFARE_ULC_COMP_WRITE) && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
||||||
// cmd + block + 4/16 bytes data + 2 bytes crc
|
// cmd + block + 4/16 bytes data + 2 bytes crc
|
||||||
if (len == 8 || len == 20) {
|
if (len == 8 || len == 20) {
|
||||||
bool isCrcCorrect = CheckCrc14A(receivedCmd, len);
|
bool isCrcCorrect = CheckCrc14A(receivedCmd, len);
|
||||||
if (isCrcCorrect) {
|
if (isCrcCorrect) {
|
||||||
int block = receivedCmd[1] + 12; // first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
|
uint8_t block = receivedCmd[1];
|
||||||
emlSetMem_xt(&receivedCmd[2], block, 1, 4);
|
if (block > mfu_header->pages) {
|
||||||
|
// send NACK 0x0 == invalid argument
|
||||||
|
EmSend4bit(CARD_NACK_IV);
|
||||||
|
} else {
|
||||||
|
// first blocks of emu are header
|
||||||
|
emlSetMem_xt(&receivedCmd[2], block + MFU_DUMP_PREFIX_LENGTH / 4, 1, 4);
|
||||||
// send ACK
|
// send ACK
|
||||||
EmSend4bit(CARD_ACK);
|
EmSend4bit(CARD_ACK);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// send NACK 0x1 == crc/parity error
|
// send NACK 0x1 == crc/parity error
|
||||||
EmSend4bit(CARD_NACK_PA);
|
EmSend4bit(CARD_NACK_PA);
|
||||||
|
@ -1137,10 +1155,9 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
}
|
}
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
} else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && tagType == 7) { // Received a READ SIGNATURE --
|
} else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && tagType == 7) { // Received a READ SIGNATURE --
|
||||||
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
|
// first blocks of emu are header
|
||||||
uint16_t start = 4 * 4;
|
|
||||||
uint8_t emdata[34];
|
uint8_t emdata[34];
|
||||||
emlGetMemBt(emdata, start, 32);
|
memcpy(emdata, mfu_header->signature, 32);
|
||||||
AddCrc14A(emdata, 32);
|
AddCrc14A(emdata, 32);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
|
@ -1151,7 +1168,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
EmSend4bit(0x00);
|
EmSend4bit(0x00);
|
||||||
} else {
|
} else {
|
||||||
uint8_t cmd[] = {0x00, 0x00, 0x00, 0x14, 0xa5};
|
uint8_t cmd[] = {0x00, 0x00, 0x00, 0x14, 0xa5};
|
||||||
num_to_bytes(counters[index], 3, cmd);
|
memcpy(cmd, mfu_header->counter_tearing[index], 3);
|
||||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||||
EmSendCmd(cmd, sizeof(cmd));
|
EmSendCmd(cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
|
@ -1162,15 +1179,13 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
// send NACK 0x0 == invalid argument
|
// send NACK 0x0 == invalid argument
|
||||||
EmSend4bit(0x00);
|
EmSend4bit(0x00);
|
||||||
} else {
|
} else {
|
||||||
|
uint32_t val = le24toh(receivedCmd + 2) + le24toh(mfu_header->counter_tearing[index]);
|
||||||
uint32_t val = bytes_to_num(receivedCmd + 2, 4);
|
|
||||||
|
|
||||||
// if new value + old value is bigger 24bits, fail
|
// if new value + old value is bigger 24bits, fail
|
||||||
if (val + counters[index] > 0xFFFFFF) {
|
if (val > 0xFFFFFF) {
|
||||||
// send NACK 0x4 == counter overflow
|
// send NACK 0x4 == counter overflow
|
||||||
EmSend4bit(CARD_NACK_NA);
|
EmSend4bit(CARD_NACK_NA);
|
||||||
} else {
|
} else {
|
||||||
counters[index] = val;
|
htole24(val, mfu_header->counter_tearing[index]);
|
||||||
// send ACK
|
// send ACK
|
||||||
EmSend4bit(CARD_ACK);
|
EmSend4bit(CARD_ACK);
|
||||||
}
|
}
|
||||||
|
@ -1184,7 +1199,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
// send NACK 0x0 == invalid argument
|
// send NACK 0x0 == invalid argument
|
||||||
EmSend4bit(0x00);
|
EmSend4bit(0x00);
|
||||||
} else {
|
} else {
|
||||||
emlGetMemBt(emdata, 10 + index, 1);
|
emdata[0] = mfu_header->counter_tearing[index][3];
|
||||||
AddCrc14A(emdata, sizeof(emdata) - 2);
|
AddCrc14A(emdata, sizeof(emdata) - 2);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
}
|
}
|
||||||
|
@ -1195,7 +1210,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
} else if (receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) { // Received an authentication request
|
} else if (receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) { // Received an authentication request
|
||||||
if (tagType == 7) { // IF NTAG /EV1 0x60 == GET_VERSION, not a authentication request.
|
if (tagType == 7) { // IF NTAG /EV1 0x60 == GET_VERSION, not a authentication request.
|
||||||
uint8_t emdata[10];
|
uint8_t emdata[10];
|
||||||
emlGetMemBt(emdata, 0, 8);
|
memcpy(emdata, mfu_header->version, 8);
|
||||||
AddCrc14A(emdata, sizeof(emdata) - 2);
|
AddCrc14A(emdata, sizeof(emdata) - 2);
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
EmSendCmd(emdata, sizeof(emdata));
|
||||||
p_response = NULL;
|
p_response = NULL;
|
||||||
|
@ -1291,15 +1306,17 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
|
||||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
||||||
} else if (receivedCmd[0] == MIFARE_ULEV1_AUTH) { // NTAG / EV-1 authentication
|
} else if (receivedCmd[0] == MIFARE_ULEV1_AUTH) { // NTAG / EV-1 authentication
|
||||||
if (tagType == 7) {
|
if (tagType == 7) {
|
||||||
uint16_t start = 13; // first 4 blocks of emu are [getversion answer - check tearing - pack - 0x00]
|
// PWD stored in dump now
|
||||||
uint8_t emdata[4];
|
uint8_t pwd[4];
|
||||||
emlGetMemBt(emdata, start, 2);
|
emlGetMemBt(pwd, (mfu_header->pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd));
|
||||||
AddCrc14A(emdata, 2);
|
if (memcmp(receivedCmd + 1, pwd, 4) == 0) {
|
||||||
EmSendCmd(emdata, sizeof(emdata));
|
p_response = &responses[7]; // precompiled PACK
|
||||||
p_response = NULL;
|
} else {
|
||||||
|
EmSend4bit(CARD_NACK_NA);
|
||||||
uint32_t pwd = bytes_to_num(receivedCmd + 1, 4);
|
uint32_t pwd = bytes_to_num(receivedCmd + 1, 4);
|
||||||
|
|
||||||
if (MF_DBGLEVEL >= 3) Dbprintf("Auth attempt: %08x", pwd);
|
if (MF_DBGLEVEL >= 3) Dbprintf("Auth attempt: %08x", pwd);
|
||||||
|
p_response = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check for ISO 14443A-4 compliant commands, look at left nibble
|
// Check for ISO 14443A-4 compliant commands, look at left nibble
|
||||||
|
|
|
@ -95,6 +95,18 @@ typedef struct {
|
||||||
uint8_t *parity;
|
uint8_t *parity;
|
||||||
} tUart;
|
} tUart;
|
||||||
|
|
||||||
|
// Length must be aligned to 4 bytes (UL/NTAG page)
|
||||||
|
#define MFU_DUMP_PREFIX_LENGTH 56
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t version[8];
|
||||||
|
uint8_t tbo[2];
|
||||||
|
uint8_t tbo1[1];
|
||||||
|
uint8_t pages; // max page number in dump
|
||||||
|
uint8_t signature[32];
|
||||||
|
uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag
|
||||||
|
} mfu_dump_prefix_t;
|
||||||
|
|
||||||
#ifndef AddCrc14A
|
#ifndef AddCrc14A
|
||||||
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
|
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -91,6 +91,12 @@ int32_t le24toh(uint8_t data[3]) {
|
||||||
return (data[2] << 16) | (data[1] << 8) | data[0];
|
return (data[2] << 16) | (data[1] << 8) | data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void htole24(uint32_t val, uint8_t data[3]) {
|
||||||
|
data[0] = (uint8_t) val;
|
||||||
|
data[1] = (uint8_t)(val >> 8);
|
||||||
|
data[2] = (uint8_t)(val >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
//convert hex digit to integer
|
//convert hex digit to integer
|
||||||
uint8_t hex2int(char hexchar) {
|
uint8_t hex2int(char hexchar) {
|
||||||
switch (hexchar) {
|
switch (hexchar) {
|
||||||
|
|
|
@ -93,6 +93,7 @@ uint64_t bytes_to_num(uint8_t *src, size_t len);
|
||||||
void rol(uint8_t *data, const size_t len);
|
void rol(uint8_t *data, const size_t len);
|
||||||
void lsl(uint8_t *data, size_t len);
|
void lsl(uint8_t *data, size_t len);
|
||||||
int32_t le24toh(uint8_t data[3]);
|
int32_t le24toh(uint8_t data[3]);
|
||||||
|
void htole24(uint32_t val, uint8_t data[3]);
|
||||||
uint8_t hex2int(char hexchar);
|
uint8_t hex2int(char hexchar);
|
||||||
|
|
||||||
void LED(int led, int ms);
|
void LED(int led, int ms);
|
||||||
|
|
|
@ -1619,11 +1619,15 @@ void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) {
|
||||||
PrintAndLogEx(NORMAL, "----------+-------------------------+---------");
|
PrintAndLogEx(NORMAL, "----------+-------------------------+---------");
|
||||||
PrintAndLogEx(NORMAL, "Version | %s| %s", sprint_hex(card->version, sizeof(card->version)), sprint_ascii(card->version, sizeof(card->version)));
|
PrintAndLogEx(NORMAL, "Version | %s| %s", sprint_hex(card->version, sizeof(card->version)), sprint_ascii(card->version, sizeof(card->version)));
|
||||||
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo, sizeof(card->tbo)), sprint_ascii(card->tbo, sizeof(card->tbo)));
|
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo, sizeof(card->tbo)), sprint_ascii(card->tbo, sizeof(card->tbo)));
|
||||||
PrintAndLogEx(NORMAL, "Tearing | %-24s| %s", sprint_hex(card->tearing, sizeof(card->tearing)), sprint_ascii(card->tearing, sizeof(card->tearing)));
|
|
||||||
PrintAndLogEx(NORMAL, "Pack | %-24s| %s", sprint_hex(card->pack, sizeof(card->pack)), sprint_ascii(card->pack, sizeof(card->pack)));
|
|
||||||
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo1, sizeof(card->tbo1)), sprint_ascii(card->tbo1, sizeof(card->tbo1)));
|
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo1, sizeof(card->tbo1)), sprint_ascii(card->tbo1, sizeof(card->tbo1)));
|
||||||
PrintAndLogEx(NORMAL, "Signature1| %s| %s", sprint_hex(card->signature, 16), sprint_ascii(card->signature, 16));
|
PrintAndLogEx(NORMAL, "Signature1| %s| %s", sprint_hex(card->signature, 16), sprint_ascii(card->signature, 16));
|
||||||
PrintAndLogEx(NORMAL, "Signature2| %s| %s", sprint_hex(card->signature + 16, 16), sprint_ascii(card->signature + 16, 16));
|
PrintAndLogEx(NORMAL, "Signature2| %s| %s", sprint_hex(card->signature + 16, 16), sprint_ascii(card->signature + 16, 16));
|
||||||
|
PrintAndLogEx(NORMAL, "Counter0 | %-24s| %s", sprint_hex(card->counter_tearing[0], 3), sprint_ascii(card->counter_tearing[0], 3));
|
||||||
|
PrintAndLogEx(NORMAL, "Tearing0 | %-24s| %s", sprint_hex(card->counter_tearing[0] + 3, 1), sprint_ascii(card->counter_tearing[0] + 3, 1));
|
||||||
|
PrintAndLogEx(NORMAL, "Counter1 | %-24s| %s", sprint_hex(card->counter_tearing[1], 3), sprint_ascii(card->counter_tearing[1], 3));
|
||||||
|
PrintAndLogEx(NORMAL, "Tearing1 | %-24s| %s", sprint_hex(card->counter_tearing[1] + 3, 1), sprint_ascii(card->counter_tearing[1] + 3, 1));
|
||||||
|
PrintAndLogEx(NORMAL, "Counter2 | %-24s| %s", sprint_hex(card->counter_tearing[2], 3), sprint_ascii(card->counter_tearing[2], 3));
|
||||||
|
PrintAndLogEx(NORMAL, "Tearing3 | %-24s| %s", sprint_hex(card->counter_tearing[2] + 3, 1), sprint_ascii(card->counter_tearing[2] + 3, 1));
|
||||||
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
|
||||||
PrintAndLogEx(NORMAL, "\nBlock# | Data |lck| Ascii");
|
PrintAndLogEx(NORMAL, "\nBlock# | Data |lck| Ascii");
|
||||||
PrintAndLogEx(NORMAL, "---------+-------------+---+------");
|
PrintAndLogEx(NORMAL, "---------+-------------+---+------");
|
||||||
|
@ -1889,8 +1893,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
mfu_dump_t dump_file_data;
|
mfu_dump_t dump_file_data;
|
||||||
uint8_t get_pack[] = {0, 0};
|
uint8_t get_pack[] = {0, 0};
|
||||||
uint8_t get_version[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
uint8_t get_version[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
uint8_t get_tearing[] = {0, 0, 0};
|
uint8_t get_counter_tearing[][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
|
||||||
uint8_t get_counter[] = {0, 0, 0};
|
|
||||||
uint8_t dummy_pack[] = {0, 0};
|
uint8_t dummy_pack[] = {0, 0};
|
||||||
uint8_t get_signature[32];
|
uint8_t get_signature[32];
|
||||||
memset(get_signature, 0, sizeof(get_signature));
|
memset(get_signature, 0, sizeof(get_signature));
|
||||||
|
@ -1920,8 +1923,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
|
|
||||||
ulev1_getVersion(get_version, sizeof(get_version));
|
ulev1_getVersion(get_version, sizeof(get_version));
|
||||||
for (uint8_t n = 0; n < 3; ++n) {
|
for (uint8_t n = 0; n < 3; ++n) {
|
||||||
ulev1_readTearing(n, get_tearing + n, 1);
|
ulev1_readTearing(n, &get_counter_tearing[n][3], 1);
|
||||||
ulev1_readCounter(n, get_counter, sizeof(get_counter));
|
ulev1_readCounter(n, &get_counter_tearing[n][0], 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -1935,7 +1938,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// format and add keys to block dump output
|
// format and add keys to block dump output
|
||||||
if (hasAuthKey) {
|
// only add keys if not partial read, and complete pages read
|
||||||
|
if (!is_partial && pages == card_mem_size && hasAuthKey) {
|
||||||
// if we didn't swapendian before - do it now for the sprint_hex call
|
// if we didn't swapendian before - do it now for the sprint_hex call
|
||||||
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
|
||||||
// need to swap to keep it the same
|
// need to swap to keep it the same
|
||||||
|
@ -1954,11 +1958,11 @@ static int CmdHF14AMfUDump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//add *special* blocks to dump
|
//add *special* blocks to dump
|
||||||
//iceman: need to add counters and pwd values to the dump format
|
// pack and pwd saved into last pages of dump, if was not partial read
|
||||||
|
dump_file_data.pages = pages - 1;
|
||||||
memcpy(dump_file_data.version, get_version, sizeof(dump_file_data.version));
|
memcpy(dump_file_data.version, get_version, sizeof(dump_file_data.version));
|
||||||
memcpy(dump_file_data.tearing, get_tearing, sizeof(dump_file_data.tearing));
|
|
||||||
memcpy(dump_file_data.pack, get_pack, sizeof(dump_file_data.pack));
|
|
||||||
memcpy(dump_file_data.signature, get_signature, sizeof(dump_file_data.signature));
|
memcpy(dump_file_data.signature, get_signature, sizeof(dump_file_data.signature));
|
||||||
|
memcpy(dump_file_data.counter_tearing, get_counter_tearing, sizeof(dump_file_data.counter_tearing));
|
||||||
memcpy(dump_file_data.data, data, pages * 4);
|
memcpy(dump_file_data.data, data, pages * 4);
|
||||||
|
|
||||||
printMFUdumpEx(&dump_file_data, pages, startPage);
|
printMFUdumpEx(&dump_file_data, pages, startPage);
|
||||||
|
@ -2092,16 +2096,22 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
// read all data
|
// read all data
|
||||||
size_t bytes_read = fread(dump, 1, fsize, f);
|
size_t bytes_read = fread(dump, 1, fsize, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (bytes_read < 48) {
|
if (bytes_read < DUMP_PREFIX_LENGTH) {
|
||||||
PrintAndLogEx(WARNING, "Error, dump file is too small");
|
PrintAndLogEx(WARNING, "Error, dump file is too small");
|
||||||
free(dump);
|
free(dump);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
|
|
||||||
|
|
||||||
mfu_dump_t *mem = (mfu_dump_t *)dump;
|
mfu_dump_t *mem = (mfu_dump_t *)dump;
|
||||||
uint8_t pages = (bytes_read - 48) / 4;
|
uint8_t pages = (bytes_read - DUMP_PREFIX_LENGTH) / 4;
|
||||||
|
|
||||||
|
if (pages - 1 != mem->pages) {
|
||||||
|
PrintAndLogEx(WARNING, "Error, invalid dump, wrong page count");
|
||||||
|
free(dump);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
|
||||||
|
|
||||||
// print dump
|
// print dump
|
||||||
printMFUdumpEx(mem, pages, 0);
|
printMFUdumpEx(mem, pages, 0);
|
||||||
|
@ -2134,7 +2144,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
|
|
||||||
if (read_key) {
|
if (read_key) {
|
||||||
// try reading key from dump and use.
|
// try reading key from dump and use.
|
||||||
memcpy(c.d.asBytes, mem->data + (bytes_read - 48 - 8), 4);
|
memcpy(c.d.asBytes, mem->data + (bytes_read - DUMP_PREFIX_LENGTH - 8), 4);
|
||||||
} else {
|
} else {
|
||||||
memcpy(c.d.asBytes, p_authkey, 4);
|
memcpy(c.d.asBytes, p_authkey, 4);
|
||||||
}
|
}
|
||||||
|
@ -2150,10 +2160,9 @@ static int CmdHF14AMfURestore(const char *Cmd) {
|
||||||
memcpy(c.d.asBytes + 4, authkey, 4);
|
memcpy(c.d.asBytes + 4, authkey, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack
|
// pack now stored in dump
|
||||||
c.arg[0] = MFU_NTAG_SPECIAL_PACK;
|
c.arg[0] = MFU_NTAG_SPECIAL_PACK;
|
||||||
c.d.asBytes[0] = mem->pack[0];
|
memcpy(c.d.asBytes, mem->data + (bytes_read - DUMP_PREFIX_LENGTH - 4), 2);
|
||||||
c.d.asBytes[1] = mem->pack[1];
|
|
||||||
c.d.asBytes[2] = 0;
|
c.d.asBytes[2] = 0;
|
||||||
c.d.asBytes[3] = 0;
|
c.d.asBytes[3] = 0;
|
||||||
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(c.d.asBytes, 4));
|
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(c.d.asBytes, 4));
|
||||||
|
|
|
@ -12,16 +12,16 @@
|
||||||
#include "comms.h"
|
#include "comms.h"
|
||||||
#include "loclass/fileutils.h"
|
#include "loclass/fileutils.h"
|
||||||
|
|
||||||
#define DUMP_PREFIX_LENGTH 48
|
// Length must be aligned to 4 bytes (UL/NTAG page)
|
||||||
|
#define DUMP_PREFIX_LENGTH 56
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t version[8];
|
uint8_t version[8];
|
||||||
uint8_t tbo[2];
|
uint8_t tbo[2];
|
||||||
uint8_t tearing[3];
|
|
||||||
uint8_t pack[2];
|
|
||||||
uint8_t tbo1[1];
|
uint8_t tbo1[1];
|
||||||
|
uint8_t pages; // max page number in dump
|
||||||
uint8_t signature[32];
|
uint8_t signature[32];
|
||||||
//uint8_t counter[3];
|
uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag
|
||||||
uint8_t data[1024];
|
uint8_t data[1024];
|
||||||
} mfu_dump_t;
|
} mfu_dump_t;
|
||||||
|
|
||||||
|
|
|
@ -221,13 +221,16 @@ int saveFileJSON(const char *preferredName, const char *suffix, JSONFileType fty
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
|
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
|
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Tearing", tmp->tearing, sizeof(tmp->tearing));
|
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Pack", tmp->pack, sizeof(tmp->pack));
|
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
|
JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
|
JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
|
||||||
JsonSaveStr(root, "$.Card.Counter", "N/A");
|
JsonSaveBufAsHexCompact(root, "$.Card.Counter0", tmp->counter_tearing[0], 3);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Tearing0", tmp->counter_tearing[0] + 3, 1);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Counter1", tmp->counter_tearing[1], 3);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Tearing1", tmp->counter_tearing[1] + 3, 1);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Counter2", tmp->counter_tearing[2], 3);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Tearing2", tmp->counter_tearing[2] + 3, 1);
|
||||||
|
|
||||||
// size of header 48b
|
// size of header 56b
|
||||||
size_t len = (datalen - DUMP_PREFIX_LENGTH) / 4;
|
size_t len = (datalen - DUMP_PREFIX_LENGTH) / 4;
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
|
|
@ -104,11 +104,11 @@ local function main(args)
|
||||||
-- lua uses start index and endindex, not count.
|
-- lua uses start index and endindex, not count.
|
||||||
-- UID is 3three skip bcc0 then 4bytes.
|
-- UID is 3three skip bcc0 then 4bytes.
|
||||||
-- 1 lua is one-index.
|
-- 1 lua is one-index.
|
||||||
-- 1 + 96 (48*2) new dump format has version/signature/counter data here
|
-- 1 + 112 (56*2) new dump format has version/signature/counter data here
|
||||||
-- 97,98,99,100,101,102 UID first three bytes
|
-- 113,114,115,116,117,118 UID first three bytes
|
||||||
-- 103,104 bcc0
|
-- 119,120 bcc0
|
||||||
-- 105--- UID last four bytes
|
-- 121--- UID last four bytes
|
||||||
local uid = string.sub(dumpdata, 97, 97+5)..string.sub(dumpdata, 97+8, 97+8+7)
|
local uid = string.sub(dumpdata, 113, 113+5)..string.sub(dumpdata, 113+8, 113+8+7)
|
||||||
output = output or (uid .. ".eml")
|
output = output or (uid .. ".eml")
|
||||||
|
|
||||||
-- Format some linebreaks
|
-- Format some linebreaks
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue